Engineering story
Why a browser needs a box
Read the headbox engineering story, which compares nine headless browser setups and what each leaves behind after kill -9.
Headless browser launcher
headbox installs a pinned chrome-headless-shell and runs it inside bubblewrap, with every writable path in a size-capped tmpfs. Tests and coding agents talk to it over the Chrome DevTools Protocol; when headbox ends, even by kill -9, the browser and its files are gone.
go install ubunatic.com/headbox@latestProject snapshot · measured 2026-10-26
| Week starting | Commits |
|---|---|
| 2026-08-03 | 0 |
| 2026-08-10 | 0 |
| 2026-08-17 | 0 |
| 2026-08-24 | 0 |
| 2026-08-31 | 0 |
| 2026-09-07 | 0 |
| 2026-09-14 | 0 |
| 2026-09-21 | 0 |
| 2026-09-28 | 0 |
| 2026-10-05 | 0 |
| 2026-10-12 | 0 |
| 2026-10-19 | 10 |
Go 1.26, Cobra, bubblewrap, chrome-headless-shell, YAML + JSON Schema, GoReleaser
Features
headbox install downloads the chrome-headless-shell version pinned in the binary and checks its sha256 before unpacking.
The browser runs in its own PID namespace as a direct child of headbox; when headbox dies, the kernel ends the whole tree.
Profile, caches, /tmp and /dev/shm live in size-capped tmpfs mounts that vanish with the sandbox.
Puppeteer, Playwright's connectOverCDP, chromedp or chrome-devtools-mcp connect through CDP_URL.
headbox exec -- true takes about 0.2 s, including the browser start.
headbox serve keeps a browser for agents and stops it after a period without CDP connections.
Usage
headbox install # once: download + sha256-check the pinned browser
headbox exec -- node check.mjs # browser up, CDP_URL set, browser gone when the command ends
headbox exec -- sh -c 'curl -s "$CDP_URL/json/version"'
# a browser for coding agents, on a fixed port, gone after 30 idle minutes
headbox serve --port 9333 --idle 30m &
chrome-devtools-mcp --browserUrl http://127.0.0.1:9333
| Command | What it does |
|---|---|
install [--zip FILE] |
Download the pinned browser, check its sha256, unpack it to ~/.local/share/headbox/ |
exec -- CMD |
Start the browser, run CMD with CDP_URL, HEADBOX_WS_URL and HEADBOX_CDP_PORT, exit with its code |
serve [--idle 15m] |
Keep a browser for agents until idle, Ctrl-C or SIGTERM |
path |
Print the browser's install dir |
version |
Print the headbox and browser versions |
Sandbox
Chrome's own sandbox stays on inside bwrap. Sizes, browser version, URL and sha256 live in spec/browser.yaml, embedded in the binary.
Install
Requires Linux with unprivileged user namespaces and bwrap (dnf install bubblewrap or apt install bubblewrap), and Go 1.26 or newer to build. Release binaries for x86_64 and aarch64 are on Codeberg.
go install ubunatic.com/headbox@latest
headbox install
Engineering story
Read the headbox engineering story, which compares nine headless browser setups and what each leaves behind after kill -9.
Architecture
Engineering story
The ubunatic.com site checks ran a Flatpak Chromium. On 2026-10-22 its sandbox /tmp , which lives in RAM under /run/user/1000 , held 2.4 GB of old browser profiles and filled the runtime dir; an unrelated tool then failed with "no space lef…
Read the engineering story