buttercup.sh updates rev.2

buttercup.sh is open source: an agent harness that lives in your browser

A coding agent with a real toolbelt, running from a single static page — on your laptop or your phone, pointed at a cloud model or at one running on your own machine. No server, no build step, no account. Free forever.

open the harness

What it is

A coding harness — the thing Claude Code, Codex, Cursor and Antigravity all are underneath — is not much: a loop that sends a conversation to a model, hands it a list of tools, runs the tools it asks for, and puts the results back in the conversation. Everything else is scaffolding around that loop.

buttercup.sh is that loop, in a browser tab. It is static HTML, CSS and JavaScript — classic <script> tags, no modules, no bundler, no dependencies, nothing to compile. The whole setup is:

git clone https://github.com/stephenlb/buttercup.sh && open buttercup.sh/index.html

That is not a quickstart with a "production deployment" section hiding behind it. There is no production deployment. The page you open is the program. Read js/agent.js for the loop, js/tools.js for the tools, js/llm.js for the wire protocols, and you have read the harness.

Eighteen tools, one tab

The model gets a working toolbelt on every turn — reading, searching, writing, moving and deleting files; scaffolding projects; running JavaScript; spawning sub-agents; fetching pages, npm metadata and framework docs; previewing what it built; exporting the result as a ZIP:

read  list  glob  grep  todo  export_zip
write  edit  delete  move  scaffold
run_js  run_agent  preview
http_get  npm_info  npm_file  framework_docs

Around them sits the scaffolding you would actually miss: a virtual filesystem in localStorage, a 25-deep undo stack that snapshots the conversation and the files together so /undo rewinds both, drag-and-drop import of files and whole folders, pasted screenshots scaled for the wire, a request queue, auto-compaction of long sessions, and a sandboxed preview with a hand-written ES-module linker so the agent's imports resolve with no server anywhere.

Code the agent writes runs in a sandbox="allow-scripts" iframe on an opaque origin, so it cannot reach the page, the DOM, or your keys. allow-same-origin is never granted.

It works on your phone

This is the part that surprises people. A harness with no backend and no build step has nothing that needs a desktop: the tab talks to a model endpoint over HTTPS, and a phone browser does that as well as a laptop does. So on a narrow screen the machine stacks into one column — the transcript and prompt on top, the file rack, diffs and settings below — and the whole thing keeps working.

Open buttercup.sh on your phone, paste a key, and ask for something on the train. Files land in that browser's storage; export a ZIP when you get somewhere with a keyboard.

Free forever

Not a free tier. Not free-with-an-account. There is no account, because there is no server to hold one.

Nothing sits between the tab and the model you chose. No proxy, no gateway of ours, no telemetry, no analytics, no update check. Your keys, your conversation and your files live in your browser's localStorage and are never transmitted anywhere except to the vendor you explicitly selected. That is not a promise about our intentions — it is a property of a page with no backend, and you can verify it with the network tab in about a minute.

The code is on GitHub. Fork it and the harness is yours. Nothing can be taken away from you later, because there is nothing anyone is hosting on your behalf.

Local models: nothing leaves your machine

Point the harness at Ollama or vLLM and it makes no network request to any third party at all — not for the code it writes, not for anything else. The two local providers drop the API key row and the Authorization header entirely. Both just need CORS permission to accept a call from the tab:

OLLAMA_ORIGINS='https://buttercup.sh' ollama serve
vllm serve <model> --allowed-origins '["https://buttercup.sh"]'

Use your own origin instead if you are serving the harness yourself. Chrome and Firefox exempt http://localhost from mixed-content blocking on an HTTPS page; Safari does not, so on Safari serve the harness over local HTTP (python3 -m http.server).

When you do want a frontier model, eight vendors are wired up:

VendorDefault modelNotes
Ollamaqwen3-coder:30blocal, no key
vLLMyou type onelocal, no key
Anthropicclaude-opus-5adaptive thinking, effort control
OpenAIgpt-5.6chat completions + reasoning effort
xAIgrok-4.1api.x.ai/v1
Googlegemini-3.1-pro-previewSSE streaming
OpenRouteranthropic/claude-opus-4.5anything the account can reach
FreeBuffyou type oneany OpenAI-compatible gateway

Three wire formats cover all eight — Anthropic Messages, Google generateContent, and OpenAI-style /chat/completions, which six of them share. That is why a base url field appears when you pick a chat-completions vendor: any gateway speaking that shape works without a code change.

Keys live in your browser's localStorage. Anything that can run script on that origin can read them. Use a scoped, revocable key.

Why bother

Because the harness is the part of this technology that has been made to look complicated, and it isn't. If you can read a page of JavaScript you can read the whole of an agent loop in an afternoon, change how it thinks, give it a tool nobody shipped, and run it against a model on your own hardware for nothing.

Vintage charm, aggressively anti-dystopian. Emdashes welcome.

open the harness

One lesson a week