Sessionboxer

Get started

Install Sessionboxer: one line, npm, Docker Compose or the desktop app

What Sessionboxer needs (Docker, Node 22, a Claude, ChatGPT or Devin subscription) and the five ways to install it, from a one-line script to Docker Compose on a home server.

Requirements

  • Linux with Docker Engine (your user must be able to run docker), or macOS with OrbStack or Docker Desktop (see macOS)
  • Node.js 22+
  • A Claude Code subscription, a ChatGPT subscription (for Codex), a Cursor subscription, a Devin account, a Vercel AI Gateway account (for fx; it also runs on a ChatGPT or Grok subscription) a Kimi Code account (for Kimi CLI), a GitHub Copilot subscription (with the CLI enabled, for GitHub Copilot), a Mistral account or API key (for Mistral Vibe), an xAI account or API key (for Grok Build), a Google account or Gemini API key (for Gemini CLI), a free qwen.ai account or an OpenAI-compatible API key (for Qwen Code) and/or, for OpenCode, a login or API key of one of its model providers (Anthropic, OpenAI, OpenCode Zen, Google, …)
  • Optional: Sysbox if you want Docker inside sessions without giving the agent a privileged container (see below)
  • Optional: a Linux host with /dev/kvm for Windows and macOS sessions (see A Windows session, A macOS session)

Install

Pick one. None of them downloads anything at start: the first Session downloads the Sandbox image of its agent, ghcr.io/talayolabs/sessionboxer-sandbox:<version>-<providerId> (1.2–1.4 GB compressed, linux/amd64 and linux/arm64; the New Session page shows the download and the log its progress — see Sandbox images). Then open the log in at http://127.0.0.1:4000/#pair=… link the server prints: that logs the browser in once (see Remote access for how the login works and how to reach it from elsewhere). By default Sessionboxer listens on localhost only.

One line (Linux, macOS): picks npm when Node 22+ is installed, otherwise Docker Compose.

curl -fsSL https://sessionboxer.talayolabs.com/install.sh | sh

Homebrew (macOS, Linux) — the laptop case without thinking about Node: the tap installs the release with Homebrew's Node. Needs Docker.

brew install talayolabs/tap/sessionboxer
sessionboxer serve

npm — the laptop case with your own Node 22+. Needs Docker.

npx sessionboxer serve                 # or: npm i -g sessionboxer && sessionboxer serve

Rather than keeping that terminal open, install it as a background service of your user account — started now and at every login, restarted if it dies, same ~/.sessionboxer: a launchd agent on macOS, a systemd user unit on Linux (loginctl enable-linger keeps it up after you log out of a headless machine). SESSIONBOXER_* and DOCKER_HOST set in the shell that runs install are baked into the service.

npm i -g sessionboxer                  # not npx: the service points at the installed files (the Homebrew install works too)
sessionboxer service install           # prints the login link; then status | stop | start | restart | log | uninstall

Docker Compose — the home server, VPS, Raspberry Pi or Coolify case; only Docker is needed.

curl -fsSLO https://raw.githubusercontent.com/talayolabs/sessionboxer/v1.8.0/docker-compose.yml
docker compose up -d                   # http://127.0.0.1:4000
docker compose logs control-plane      # -d hides the startup box: this shows the one-time login link
docker compose exec control-plane sessionboxer token   # the access token, for the login page of another browser

The Control Plane runs from ghcr.io/talayolabs/sessionboxer with /var/run/docker.sock mounted and its data in the sessionboxer-data volume. Sessions become sibling containers on the same Docker host. Copy .env.example to .env to change the port, listen on all interfaces, set a public URL or a fixed access token. Copy a folder and Pull to folder need the folder to be visible inside the container: uncomment the /workspaces bind mount in the compose file and refer to /workspaces/<name> in the UI. Giving a container the Docker socket is the same as giving it root on the host; it is what lets Sessionboxer create the boxes, so run it only on a machine you would give the agent's boxes anyway.

Releases: GitHub Releases has the notes and the npm tarball for every version; the images are on GHCR (Control Plane, Sandbox). The Control Plane pulls the Sandbox image with its own version number, so the two always match; SESSIONBOXER_IMAGE overrides it.

From source (to hack on it):

git clone https://github.com/talayolabs/sessionboxer.git
cd sessionboxer
npm install
npm run build
npm start                              # the first Session pulls the published Sandbox image of its agent for this version…
npm run build:image -- --provider codex   # …or build that one here (a few minutes; see Sandbox images below) — tagged with the same name

To update, git pull, npm run build, npm start; npm run build:image again only when images/sandbox changed.

Sandbox images

Each Sessionboxer release publishes one Linux Sandbox image per agent, ghcr.io/talayolabs/sessionboxer-sandbox:<version>-<providerId> (1.6.0-claude-code, 1.6.0-codex, …; the ids are the ones the URL and the API use), all built on the same base, so a second agent downloads only its own layers. A Linux Session uses the image of its agent and pulls it the first time one is needed — a Session, a sign-in from Settings or a Windows/macOS Session, whose Linux helper container runs <version>-base, the same image without an agent — never at start. <version>-all and plain <version> are the image with every agent (2.3 GB compressed), for preloading a machine that is offline later: docker pull it and the Sessions of all agents start without a download. The Environment settings and each Session's settings show which image it runs on; Snapshots remember theirs.

SESSIONBOXER_IMAGE=<reference> makes the Control Plane use that one image for everything, exactly as written (no suffix is added): it must carry the agent of the Session — its io.sessionboxer.providers label lists it — or be an image without the labels (a build of an older release, your own) that has the agent's command on PATH; otherwise the Session is refused with carries fx, not Codex and the like, and Windows/macOS helpers run on it too.

To build locally: npm run build:image -- --provider <id> builds that agent's image (base and all work too) and tags it both ghcr.io/talayolabs/sessionboxer-sandbox:<version>-<id>, which this checkout's Control Plane uses instead of pulling, and sessionboxer/sandbox:dev-<id>; npm run build:image without arguments still builds the all-agents image as <version> and sessionboxer/sandbox:dev. A Session whose local image is missing says so and names the command.

Upgrading to 1.6.0 changes nothing for what exists: your Sessions keep their container and its all-agents image, Stop → Resume starts it again without a download (it refreshes Sessionboxer's own files in the box, not the image or the agent), Snapshots stay usable, and nothing is migrated or deleted — docker image rm ghcr.io/talayolabs/sessionboxer-sandbox:1.5.0 once no Session or snapshot needs it, if you want the space back. New Sessions get the per-agent images. A fork into another agent needs that agent's image of the same release, local or pullable (see Snapshots and forks).

Desktop app (early): installers for Linux (AppImage, deb; x64 and arm64), macOS (dmg; Apple silicon and Intel) and Windows (x64) are on the Releases page (mac-arm64 is Apple silicon, mac-x64 Intel), with SHA256SUMS next to them. They are not code-signed yet, so macOS says the dmg is damaged and can't be opened: clear the quarantine flag on the download first, xattr -d com.apple.quarantine ~/Downloads/Sessionboxer-*-mac-*.dmg, then open the dmg and drag the app to Applications (if the app is still refused, xattr -dr com.apple.quarantine /Applications/Sessionboxer.app or right-click → Open). Windows: More info → Run anyway in SmartScreen. Under the hood it is an Electron tray shell in apps/desktop that starts the same Control Plane in the background, opens the UI in a window and keeps serving when the window is closed — the phone keeps its pairing, tunnels stay up — until you Quit from the tray/menu bar. It needs Docker like everything else, but not Node: the Control Plane runs on the Node inside Electron. If a sessionboxer serve, sessionboxer service or Compose install already answers at http://127.0.0.1:4000 (or SESSIONBOXER_URL), the app attaches to it instead of starting another and leaves it running on quit. Same ~/.sessionboxer as the other installs; the server log is in the app's log folder (~/.config/Sessionboxer/logs, ~/Library/Logs/Sessionboxer, %APPDATA%\Sessionboxer\logs).

npm run build
npm run start -w @sessionboxer/desktop   # run it from the checkout
npm run dist -w @sessionboxer/desktop    # or package it yourself: build/desktop/ (AppImage + deb, dmg + zip, NSIS + zip on the matching OS; `-- --dir` for an unpacked folder)

This chapter is generated from docs/GUIDE.md in the Sessionboxer repository. Found a mistake? Open an issue.