BrainwriteDocs
Self-hosting

Self-hosting Brainwrite

Run the harness and desktop app on infrastructure you control.

Brainwrite is local-first by default: the harness listens on loopback, agent CLIs run on your machine, and application state lives under ~/.brainwrite.

Quickest: one command with Node

On any machine with Node 24 or newer (a VPS, a Mac mini, a Raspberry Pi):

npx brainwritebot serve

It starts the server, keeps your data in ~/.brainwrite, and prints a pairing link with a QR code: scan it with the phone, or open it on the laptop. Sign the engine CLIs in on the same machine as usual (claude, codex, …). Three ways to make it reachable from elsewhere:

  • On your Tailscale network, no domain needed: npx brainwritebot serve --tailscale. Tailscale terminates HTTPS with its own certificate and the link uses this machine's MagicDNS name, so only devices on your tailnet can reach it. Needs Tailscale signed in and HTTPS certificates enabled for the tailnet (admin console → DNS).
  • Behind your own proxy or domain: npx brainwritebot serve --public-url https://your.domain, with the proxy rules from the networking guide.
  • A public address with no domain, proxy or open port: npx brainwritebot login once to sign this machine in and reserve its address, then npx brainwritebot serve --tunnel. The machine gets a stable https://c-….brainwrite.in link through the same managed Cloudflare tunnel the desktop app uses; every request arrives as if through a proxy, so it still needs a paired session. npx brainwritebot logout releases the address.

Later: npx brainwritebot pair --label "Kitchen iPad" for another device (--client for one that may chat but not change settings), and npx brainwritebot sessions to see or revoke them. Run it under systemd or pm2 to keep it up; brainwritebot serve is a plain foreground process.

Typical self-hosted setup

  1. Run Brainwrite on your personal macOS, Windows, or Ubuntu computer.
  2. Install and authenticate the agent CLIs you want to use separately; the npm Brainwrite package does not include them. Use the same operating-system account for setup and the running server.
  3. Add optional third-party keys only for the services you need.
  4. Keep the harness on loopback.
  5. Use it from other devices by pairing them: a browser, the desktop app or the phone, over a public address, your own domain or your tailnet. See Deploy on a VPS.

What is still third party

Self-hosting Brainwrite does not self-host every optional provider:

  • Agent providers authenticate and bill through their own CLI or API.
  • Composio owns connected-app OAuth grants unless you replace that integration.
  • Box owns managed cloud computers.
  • ElevenLabs synthesizes speech when voice is enabled.

These services are optional. Local chat through a locally installed agent CLI does not require them.

Run headless during development

pnpm install --frozen-lockfile
pnpm dev:server

The main harness listens on 127.0.0.1:8799 by default. Keep it private; it owns agent processes, approvals, computers, and workspace configuration.

Remote access with paired sessions

A headless server can be used from any browser through the built-in pairing gate. Run npx brainwritebot pair (or pnpm pair from a checkout) on the server to print a /pair#code=… link with a short-lived pairing code; opening it and entering the code creates a session (an HttpOnly same-origin cookie for the served UI, a bearer token for native clients). Sessions come in admin and client scopes, last 30 days, and every proxied request is refused until it carries one — the pairing gate is the login. An SSH tunnel to localhost:8799 remains supported as a simpler private route.

From the desktop app, use the Server menu: "Add Server from Copied Pairing Link…" reads the link you copied from the server, asks once, and opens that server's own UI in the app; the app stays signed in to it across restarts, and the menu switches between Local and any saved server (on Windows and Linux press Alt to show the menu bar). While a remote server is shown, this computer's screen, microphone, files and local control are not offered to it. "Forget" signs the app out of that server; revoke the session on the server too if the device is gone.

From the iOS app, scan the same QR code (or paste the /pair#code=… link into the pairing screen's address field) to pair directly with the server's own sessions — no companion sidecar needed on a VPS or Mac mini running npx brainwritebot serve. The phone gets a client-scope session of its own: it can chat, approve, and read, but creating bots or sections, changing models, and connecting apps or cloud computers stay with the owner in the server's own UI, so the app hides those controls. Forgetting the connection on the phone ends its session on the server too. The companion sidecar pairing flow (node --experimental-strip-types companion/src/index.ts) is still supported for pairing with the desktop app directly.

On this page