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 harnessWhat 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:
| Vendor | Default model | Notes |
|---|---|---|
| Ollama | qwen3-coder:30b | local, no key |
| vLLM | you type one | local, no key |
| Anthropic | claude-opus-5 | adaptive thinking, effort control |
| OpenAI | gpt-5.6 | chat completions + reasoning effort |
| xAI | grok-4.1 | api.x.ai/v1 |
gemini-3.1-pro-preview | SSE streaming | |
| OpenRouter | anthropic/claude-opus-4.5 | anything the account can reach |
| FreeBuff | you type one | any 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.