How bonsai-cli connects to Bonsai
Starting today, connecting a Mac to Bonsai takes one step: install Bonsai for Mac and sign in inside its window. A moment later the Mac is on your Runtimes page under its own name, already enabled for your personal space. There’s no terminal, no bonsai login and no code to compare.
A connection you never see is the goal. But this one lets agents run on your computer when Bonsai asks, so it’s worth knowing exactly what it is. This post follows it from the first request to the steady state, and explains why the app can skip the code check that the command line still asks for.
A runtime calls out, never in
A runtime is the bonsai process on your computer. Bonsai for Mac carries it inside the app and looks after it; on other machines you run it yourself. It’s the part that takes work from Bonsai and hands it to the official harness on your machine, Claude Code or Codex, then streams the session back.
Bonsai never connects to your computer. The runtime opens one outbound WebSocket to Bonsai and keeps it open: runs come down it, session events go back up. So there’s no port to open and no tunnel, it works behind any router, and the only thing that identifies your computer is a credential it holds.
Getting a credential: pairing
The credential is two values, a runtime ID (rt_ and 32 hex characters) and a token (32 hex characters). Bonsai generates both and hands them out exactly once. It only ever stores the token’s SHA-256, so not even Bonsai’s database can give the token back.
Getting them is a device-code flow, the same shape as gh auth login:
- The runtime calls
POST /runtime/pairwith the machine’s name. Bonsai answers with a short code such asBCDF-GHJK, a link, and a secret that only this runtime receives. - Someone signed in to Bonsai approves that code.
- Meanwhile the runtime polls
POST /runtime/pair/pollwith its secret every two seconds. After the approval, the next poll creates the runtime and returns the ID and token, once.
The secret is what keeps anyone else from collecting the token. The code appears on a screen and in a URL; the secret never does. An unapproved pairing expires after ten minutes.
Why the terminal asks you to compare a code, and the app doesn’t
With bonsai login in a terminal, step 2 happens on a page in your browser: add this machine as your runtime? The terminal shows this code. The page tells you to approve only if you just ran bonsai login yourself and the terminal shows the same code.
That comparison is the one real defence in a device-code flow. The risk isn’t that someone steals your token. It’s that someone starts a pairing on their machine and sends you the link. If you approve it, their machine becomes a runtime in your account. It still couldn’t take any work you didn’t give it, but it has no business being there.
Bonsai for Mac skips that page. Once its window shows the signed-in workspace, the app starts a pairing and approves it from inside that page:
POST /app/api/runtime {"op": "pair", "code": "BCDF-GHJK"}
The request is same-origin, carries your session cookie, and includes the page’s CSRF token, exactly like the buttons on the Runtimes page.
This is safe for a simple reason: the same process starts the pairing, approves it and collects the token. The code never leaves the app, so there’s no link anyone could send you. And because approving needs the page’s CSRF token, no other website can make your browser approve a pairing on its behalf.
The name is the Mac’s own, from System Settings › General › About. If you already have a runtime by that name, Bonsai calls the new one ”… 2”. The app tries this once per launch. If it doesn’t work, the menu says why, and Connect this Mac… tries again, falling back to the confirmation page if the window isn’t signed in.
Where the token lives
In ~/.bonsai/bonsai-runtime.toml, readable only by you (mode 0600). It’s written by atomic rename, so anything reading it sees either the old values or the new ones, never a mix. The runtime refuses to start if the file is readable by anyone else.
The app doesn’t write that file itself. It passes the token on standard input to the bonsai binary inside the app bundle (bonsai login --token-stdin), so the app and the command line share one implementation of the format and its checks. The token never appears in a command-line argument, a log line, a launchd plist or the app’s preferences, and it isn’t passed on to the agents the runtime starts: every child process has the runtime’s variables removed from its environment.
The connection itself
With the credential in place, the runtime dials wss://livewithbonsai.com/runtime with Authorization: Bearer <token>. The token is never in the URL, and the server accepts only wss://.
The first message has to be runtime.hello. It describes the machine: which harnesses it has, their models and settings, and the projects it can work in. Each project is an ID the runtime made up plus a normalized git remote such as github.com/you/app, with any credentials stripped from the URL. There’s no local path anywhere in the hello. Paths stay on your computer; Bonsai refers to projects by their remote.
Bonsai replies with runtime.welcome, which names the machine’s owner. From then on:
- The runtime sends
pingevery 25 seconds. If 60 seconds pass without apong, it reconnects. - After a network failure it reconnects with exponential backoff: one second, doubling up to a minute, with some jitter.
- After a reconnect, Bonsai asks the runtime about each run it should know about. The runtime doesn’t replay anything unasked.
Bonsai keeps the last hello, so the Runtimes page can still show a machine’s projects and models while it’s offline. Whether it’s online is only ever what the live connection says.
What a new runtime can do
When a pairing completes, Bonsai enables the new runtime for your personal space with all projects on this machine. Other spaces you belong to are up to you: enable them on the Runtimes page.
So which folders count as this machine’s projects? Only the folders you add. The runtime starts with none and never scans your whole home folder on its own: add a repository, or a folder that holds many, with Add Folder… in the setup window or bonsai folders add <path>. In those folders it looks for git repositories with a remote when it starts and every ten minutes: five levels deep, at most 150, most recently used first, skipping hidden folders, node_modules, target, Library and media folders. Remove next to a folder, or bonsai folders remove, takes its projects away again.
A note can say which repository it’s about, but it can’t point the runtime at a folder. The mapping from a remote to a path exists only on your computer.
Ending it
Delete the runtime on the Runtimes page. Its token stops working at once: Bonsai cancels its runs and closes the connection, and the runtime stops every session Bonsai started on it and doesn’t try to reconnect.
After that, the app doesn’t quietly register the Mac again, because deleting it was deliberate. The menu and the setup window say the Mac was deleted from Bonsai and offer Connect this Mac…, which pairs it again in one click.
The full details, including the command-line route and how to choose folders, are in Connecting your computer.