Desktop app for using coding agents (Claude Code, Codex) with a shared UX. Built on Go 1.26, Wails v3, and Svelte 5. Inspired by t3-code.
This is a direct test release. There is no auto-update or code signing,
so Gatekeeper / SmartScreen will warn on first launch. Install from the
artifact bundle with install.sh; build from source only if you're
developing the app.
When something breaks, runtime logs and the SQLite DB live in your
platform's config directory (see Files & locations below). Zip the
logs/ folder and send it with what you were doing.
The app writes everything under your OS's user-config directory:
| Platform | Config root |
|---|---|
| macOS | ~/Library/Application Support/agent-overflow/ |
| Linux | ~/.config/agent-overflow/ (honors $XDG_CONFIG_HOME) |
| Windows via WSL | WSL distro Linux config root, e.g. ~/.config/agent-overflow/ |
| Windows launcher | %APPDATA%\agent-overflow\ for launcher config/logs only |
Inside that root: agent-overflow.db (SQLite — every thread, item,
payload, attachment metadata), logs/ (NDJSON provider stdio capture
when AGENT_OVERFLOW_DEBUG=provider, plus runtime logs), attachments/
(uploaded image / file bytes referenced by the DB), and settings.json.
Requires Go 1.26.6+, Node 24+, and pnpm 10+. On Linux, Wails v3 also needs
libgtk-4-dev, libwebkitgtk-6.0-dev, pkg-config, and gcc
(install via your distro's package manager; the GTK4 / WebKitGTK 6.0
stack ships on Ubuntu 23.04+ / Debian 13+).
make install # installs wails3 CLI (via go.mod tool directive) + pnpm depsThe normal tester path is a GitHub release asset install. The script
auto-detects Linux, macOS, or WSL, downloads the matching artifact,
verifies SHASUMS256, and copies it into the platform install location.
curl -fsSL https://github.com/randalmurphal/agent-overflow/releases/latest/download/install.sh | shPin a specific release when you do not want "latest":
curl -fsSL https://github.com/randalmurphal/agent-overflow/releases/download/v0.0.1/install.sh | sh -s -- --version 0.0.1Before an official release exists, use the same installer against a local
release directory. make release writes artifacts to
dist/release/<version>/; the --source path makes the installer read
from that directory instead of GitHub. A Linux/WSL host can produce the
Linux and WSL artifacts; the macOS zip is produced on macOS unless a
working wails-cross Docker image is available.
make release
./scripts/install.sh --linux --download --source ./dist/release/0.0.1
./scripts/install.sh --macos --download --source ./dist/release/0.0.1
./scripts/install.sh --wsl --download --source ./dist/release/0.0.1Linux installs to ~/.local/bin and writes the desktop entry/icon under
~/.local/share. macOS installs to ~/Applications/Agent Overflow.app.
The WSL installer must be run from inside WSL; it copies the Windows
launcher to %LOCALAPPDATA%\Programs\Agent Overflow\agent-overflow.exe
on the Windows filesystem and creates a Start Menu shortcut at
%APPDATA%\Microsoft\Windows\Start Menu\Programs\Agent Overflow.lnk.
That shortcut is what makes Agent Overflow show up in Windows app search
with its icon, and the local %LOCALAPPDATA% copy keeps Windows from
running it through \\wsl.localhost.
Use --dry-run to preview, --system for system locations where
supported, and --uninstall to remove app-owned install files. Passing a
local artifact path still works when you want to bypass download mode:
./scripts/install.sh --linux ./dist/release/0.0.1/agent-overflow-linux-amd64
./scripts/install.sh --macos ./dist/release/0.0.1/agent-overflow-darwin-arm64.zip
./scripts/install.sh --wsl ./dist/release/0.0.1/agent-overflow-wsl-amd64.exeA release also carries agent-overflow-headless-linux-amd64, the same backend
built without GTK or WebKit, for a machine you reach from elsewhere rather than
sit at. It is not an install.sh target — it wants no desktop entry and no
icon; copy it onto PATH and run agent-overflow serve. See
serve-mode.md.
The installer download path has a local smoke test:
./scripts/test-install-download.shmake dev # dev mode with hot reload (local supervisor)
make build # production build (wails3 build)The native Windows backend isn't fully supported (terminals and
provider lifecycle are stubs); production Windows runs the WSL launcher
under cmd/agent-overflow-windows/. To dev the Windows path from
inside a WSL shell:
make dev-wsl # cross-compile Linux ELF + Windows .exe, then launch
# the .exe with --distro $WSL_DISTRO_NAME so the picker
# is skipped (you're already shelled into your distro).
# The .exe opens on the Windows desktop via WSL interop.
make build-wsl # build only; hand the .exe off without launching.make dev-wsl is non-persistent — it doesn't overwrite the saved
distro choice in %APPDATA%\agent-overflow\wsl.json, so a dev session
won't change which distro a production double-click of the .exe lands
in.
make check # go build + frontend type check
make test # go test + frontend unit tests
make verify # full release gateAgent Overflow's transport (the HTTP+WebSocket layer between the Svelte
SPA and the Go backend) defaults to loopback-only and binds to a fresh
ephemeral port at every launch. Every page gets a one-time ticket and
exchanges it, on its first load, for an HttpOnly session cookie — so no
page script ever holds a credential. A URL a person opens carries the
ticket (http://127.0.0.1:<port>/?t=<ticket>), stripped from the address
bar once spent, so a copied URL opens exactly one session. The embedded
webview's URL carries no credential at all: the same process that mints
the ticket owns the window, so it hands the loaded page its ticket
directly rather than putting it somewhere copyable.
A handful of opt-in modes extend that:
--listen <addr>binds the transport to a different interface (e.g.0.0.0.0:54321for LAN). Settings → Remote access renders a share URL for the bound interface; each render carries its own one-time ticket, so a second device needs the panel read again. Equivalent to flipping the "Allow remote access" toggle in Settings → Network, which persists the preference across launches.--connect <endpoint | pairing link | backend>runs the desktop binary as a thin client against a remote backend. The local process boots a stub static-asset server, keeps the upstream credential in Go, and carries the webview's WebSocket to the remote backend. No local transport, store, or providers are started. Three forms:ws://host:port/ws?token=<value>— a backend on this machine, or one reached through an SSH tunnel. The upstream's launch token authenticates the hop.- a pairing link copied from the other machine's Settings → Remote access — for a backend across a network, where a launch token is not enough. The terminal shows a six-digit verification number to compare and confirm on that machine; once confirmed, this installation holds a device credential it renews on its own and pins that backend's TLS certificate with.
- the paired backend's name or endpoint — reuses that stored credential, so pairing happens once per machine.
- Tailnet access (Settings → Remote access) joins this backend to your own
Tailscale network as its own machine, so it is reachable from anywhere
you are signed in — with no port forwarded, no public listener, and no
tunnel process to run. Turning it on gives you a link to approve the
machine in your tailnet; once approved, the panel shows the address it
answers on. It answers the same routes and demands the same paired
session as every other way in: joining a tailnet is how a device
REACHES this backend, never how it gets in. If your tailnet has HTTPS
enabled, the address is
https://with a certificate browsers already trust. Turning the feature off keeps the machine's identity, so turning it back on rejoins as the same device; "Forget this node" is the separate act that deletes it. - Windows + WSL silent mode (
agent-overflow-windows.exe) drops the Linux backend into a chosen WSL distro, runs it headless, and forwardslocalhost:<port>from inside the distro to the Windows host via WSL2's vEthernet bridge. The WebView2 attaches like any other local launch.
Anyone holding the session token — or a live page cookie — can RPC the
host as the user that launched the binary. The token never rides a page
URL (a URL carries a one-time ticket, exchanged once for an HttpOnly
cookie), so page script cannot read a credential back out; that narrows
how a credential leaks, not what one is worth. A peer that is not on this
machine has to name a paired device's session, and every call it makes is
checked against that session's granted scopes — with a host tier
(terminal spawn, editor open, updater, credential retrieval) that no
session can be granted at all. That's defense-in-depth, not a security
boundary you can expose to the public internet.
For non-trusted networks, reach the backend over a network you control rather than exposing a port on one you do not:
- Tailnet access (above) — the built-in form, and the one to prefer: no listener on any public interface, and every path in is one you enrolled.
- SSH local port forward (
ssh -L 54321:localhost:54321 host). - Tailscale Serve, run outside the app, if you would rather manage the node yourself.
- Reverse proxy (Caddy / Nginx / Cloudflare Tunnel) terminating TLS in front of the backend.
The token lives in the launch URL — which means it persists in browser history, shell history, and any place that records URLs. Treat it as a password. The token is regenerated on every launch, so closing and reopening the app rotates it; if you've shared a launch URL, restart to invalidate.
Other machines you attach to are stored as PAIRED DEVICE SESSIONS, not as saved tokens: one file per backend under the app config directory, each holding a rotating credential this installation renews and the certificate fingerprint it pinned when it paired. Nothing there is a bearer token you can copy, and nothing is ever handed to the page — the local backend carries the connection itself.
Start at AGENTS.md for the project overview, stack,
principles, and repo map. Area-specific guides live alongside the code
as nested AGENTS.md files. Deep-dive design notes are under
docs/architecture/; external reference repos
and the spike-test policy are under docs/references/.