boxer

CLI

Every boxer command and flag, its exit codes, output modes and environment variables.

boxer <command> [flags] [args]

A command with no sandbox name acts on the current scope, which is the git worktree you are in by default. boxer, boxer help, -h and --help print the usage text. boxer with no arguments prints it to stderr and exits 2.

stop, rm, backends, integrations add, install and package accept flags anywhere among their arguments. capsule inspect, capsule replay, fork rm and pack take the name first or last. Every other command wants its flags before any positional argument or --.

Commands

CommandDoes
upCreate and start this scope's sandbox
runRun a command in the sandbox
downDelete this scope's sandbox, one by name, or all
statusThis scope's sandbox, as an exit code and a line
restartRelaunch the start services without recreating the sandbox
lsEvery sandbox on the backend
stop, rmStop or remove sandboxes by name or filter
gcReclaim gone, idle and stopped sandboxes and stale packs
url, openWhere this worktree's server is
backendsWhich backends are installed and answering
integrationsWhich harnesses, orchestrators and tools are wired to boxer
doctorThe resolved configuration and what is wrong with it
briefThe agent-facing summary of this checkout
tasksThe commands [tasks] declares
forkBranch copy-on-write children of a smolvm sandbox
trustApprove this worktree's host-affecting configuration
packSave and reuse named snapshots of a sandbox
capsuleRecord the last run and replay it
logsRead the event log
watchStream sandbox state changes and events
installWrite a harness's hooks, MCP entry and skill
uninstallRemove what install wrote
shimWrite PATH shims
shell, acpRun a harness inside the sandbox
hookThe entry point a harness hook calls
mcpThe MCP server
packageRender the published plugin and skill
completionPrint a shell completion script
versionPrint the version

Identity flags

up, run, down, status, restart, doctor, brief, tasks, fork, fork ls, fork rm, pack save, pack use and pack rm accept these. They matter when isolation is session or subagent, and --harness selects the [harness.<name>] override layer.

FlagDefault
--harness NAME$BOXER_HARNESSThe harness the call comes from
--session ID$BOXER_SESSION_IDThe harness session id
--agent ID$BOXER_AGENT_IDThe subagent id

boxer up

boxer up [--detach | --recreate | --rebuild]

Creates this scope's sandbox if it does not exist, starts it, runs setup and start, and waits for ready. It prints the name, the image and why it was chosen, and the mount.

FlagDefault
--detachfalseProvision in a background boxer and return at once
--recreatefalseDelete and recreate the sandbox
--rebuildfalseDrop the cached environment pack, then recreate. Implies --recreate
--jsonfalsePrint a refusal to resolve the scope as JSON on stdout. Provisioning failures are text on stderr only

boxer run

boxer run -c '<shell line>'
boxer run [flags] -- <program> [args...]
boxer run --task <name>

Runs one command in the sandbox and exits with its exit code. -c runs the line with sh -c. -- runs a program with no shell. Stdin, stdout and stderr pass through unchanged. The sandbox is created first when create_on includes run.

FlagDefault
-c LINEA shell line, run with sh -c. Not with -- arguments
--task NAMEA [tasks] entry. Not with -c or arguments. Unknown names fail with NO_SUCH_TASK
--scope NAMERun in another sandbox, such as a fork child, by key or two-word name. The current directory must still be in a repository
--ttyfalseAllocate a terminal in the guest when stdin is not one. Input written before the guest attaches is kept
--junit PATHSComma-separated JUnit XML paths, relative to the worktree, to summarise after the run. Overrides the task's junit and results.auto
--fail-on-test-failuresfalseExit 1 when the command exited 0 and a test in the reports failed
--jsonfalsePrint a refusal to resolve the scope, an unknown --task or an unknown --scope as JSON on stdout. Other refusals, such as NO_SANDBOX, are text on stderr only

Without --tty, boxer allocates a terminal when both stdin and stdout are terminals. Inside a boxer guest, run executes the command directly, and exits 127 when the program cannot be started. From an agent, prefer --task. It runs a command the repository declared, regardless of what intercept catches.

boxer down

boxer down [--all | --scope NAME] [--json]

Deletes this scope's sandbox. A scope with no sandbox is not an error. A --scope name that matches no boxer sandbox is: it exits 1, so a typo is not taken for success. --all goes on past a sandbox it cannot delete, reports it with an error, and exits 1.

FlagDefault
--allfalseEvery boxer sandbox on the configured backend
--scope NAMEOne sandbox by key or two-word name, without resolving a worktree. Works after the worktree is gone
--jsonfalsePrint what was removed

boxer status

boxer status [--scope NAME] [--json]

Prints this scope's sandbox: state, image, mount, forwarded ports and URLs. The exit code is the state.

ExitState
0running
3exists, stopped
4absent
1refused, or the backend could not be asked
FlagDefault
--scope NAMEAnother sandbox, by key or two-word name. The current directory must still be in a repository
--jsonfalseThe status object

boxer restart

boxer restart

Stops this scope's start services and everything they spawned, launches them again, and waits for ready. The sandbox and what is in it stay: an installed package, a database's files. It acts on this scope only and takes no --scope. Use it after changing something a server reads only at start, or when a service gave up after five quick crashes (see restart).

When a service cannot be signalled, as with docker under Ubuntu's AppArmor, boxer stops and starts the sandbox instead, which ends every process in it and keeps its files. Exits 1 with cause NO_SANDBOX when the sandbox is not running. Takes the identity flags.

boxer ls

boxer ls [-A] [--pr] [--resources] [--no-git] [--json]

Lists boxer's sandboxes on the configured backend with name, key, state, backend, branch, git state (clean, dirty(N) or gone), owner, the first URL or forwarded port, and worktree.

FlagDefault
-A, --all-backendsfalseEvery installed backend
--prfalseEach worktree's pull request, through gh. One network call per worktree
--resourcesfalseMemory, CPU and disk per sandbox
--no-gitfalseSkip reading each worktree's git state
--jsonfalseThe row array

A backend that does not answer is named on stderr, and ls exits 1 after listing the backends that did.

boxer stop and boxer rm

boxer stop [NAME...] [--all | --gone | --stopped] [-A] [-i] [-y] [--json]
boxer rm   [NAME...] [--all | --gone | --stopped] [-A] [-i] [-y] [--volumes] [--json]

stop stops sandboxes without deleting them. rm deletes them and everything boxer kept about them: the run record, the last-used stamp, the lock and any URL. It keeps their named volumes unless you pass --volumes. NAME is a key (sb-7e1852e4a3c3) or a two-word name (swift-crab).

FlagDefault
--allfalseEvery boxer sandbox on the configured backend. With -A, on every backend
--gonefalseSandboxes whose worktree no longer exists
--stoppedfalseSandboxes that are not running
-AfalseLook on every installed backend
-ifalseChoose from a numbered list. The default for a person when nothing is named
-yfalseDo not ask before removing several sandboxes or a filter's matches
--volumesfalserm only. Also delete the sandboxes' named volumes
--jsonfalsePrint what was done

With no name and no filter, an agent or a pipe gets exit 2 and the command to run instead. A name that matches nothing exits 1. So does a backend that does not answer, even with --all, which would otherwise look like a host with nothing to act on. A sandbox that fails is reported and the rest are still acted on. When rm --volumes deletes a sandbox but not its volumes, the sandbox's row says removed: true with an error, and the command exits 1.

boxer gc

boxer gc [--all] [--dry-run] [--json]

Deletes sandboxes whose worktree is gone, fork children whose parent is gone, the named volumes of worktrees gone for 7 days, and packs past idle_timeout or beyond packs_keep_last. A running sandbox unused for its own repository's idle_timeout is stopped, or deleted with idle_action = "delete". It skips a sandbox a command is provisioning, a parent whose fork child is in use, and a pack a create is using. It never deletes a named pack. It looks only at the configured backend; a sandbox left on another one after backend changed is named the next time this worktree's sandbox is created.

FlagDefault
--allfalseIgnore idle_timeout. Also take every stopped sandbox and every unreferenced pack. Running sandboxes are kept
--dry-runfalsePrint what it would delete
--jsonfalseThe decision array

boxer url and boxer open

boxer url [PORT]
boxer open [PORT]
boxer url --all
boxer open --all

Prints the address of this worktree's server, which is its [urls] name or else http://127.0.0.1:<host port>. PORT is the guest port. The default is the first forwarded port, sorted as text. open also opens the address in a browser when a person is at the terminal. The command exits 4 when this scope has no sandbox. It exits 1 when the sandbox forwards no ports, or not the one you named.

--all lists every running sandbox's servers on the configured backend, one name<TAB>address line each, and works outside a repository. open --all also opens each one. It exits 1 when no running sandbox forwards a port.

boxer backends

boxer backends [NAME] [--probe] [--json]

Lists smolvm, docker, podman and container: installed or not, version, answering or not, boundary, allowlist support, sandbox count, and known misconfigurations. NAME shows one. Exit 1 when the configured backend is missing or not answering, or a probe failed. Exit 2 for an unknown name.

FlagDefault
--probefalseCreate a sandbox from mirror.gcr.io/library/alpine:3.20 in a throwaway repository on each answering backend, run a command that writes to the worktree, check the host sees it, and delete everything
--jsonfalseThe backend array

boxer integrations

boxer integrations [--json]
boxer integrations add <name> [--user] [--agent NAME] [--source REPO]

Alias boxer harnesses. It lists:

  • every harness, with whether its program is on PATH and whether boxer's files are installed in this repository and for this user
  • the orchestrators conductor and git-hook
  • the tools portless, gh and npx

Files written by another boxer release are marked stale.

add installs one integration. A harness name, all, git or conductor runs boxer install. skill runs npx skills add <source> --skill boxer, and plugin runs npx plugins add <source>. See skills and plugins.

FlagDefault
--userfalseInstall for this user. For skill, passes -g. For plugin, drops -s project. For a harness, runs boxer install --user
--agent NAMEFor skill, the agents, passed as npx skills -a. For plugin, the target, passed as -t
--source REPOBarakChamo/boxerWhere the skill and plugin are published
--jsonfalseThe integration array. Not with add

boxer doctor

boxer doctor [--json]

Prints the version, the backend's capabilities, the git checkout, every configuration file read, each resolved setting with the file or variable it came from, the scope, the image, the sandbox, the environment pack, shims, hook signals, disk use, refused hosts, and warnings about configurations that look correct but do not work. Exit 1 when the configuration could not be resolved.

boxer brief

boxer brief [--json]

Prints the brief the hooks inject and the MCP resource serves: the mount, the mode, the intercept and passthrough lists, and each declared task.

boxer tasks

boxer tasks [--json]

Prints each [tasks] entry's name and description, or its command when it has none.

boxer fork

boxer fork --prepare [--count N] [--json]
boxer fork [--count N] [--json]
boxer fork ls [--json]
boxer fork rm <name> | --all

Branches copy-on-write children off this scope's smolvm sandbox. Children share this worktree. See forking. Stdout carries only the children's names.

FlagDefault
--preparefalseCreate the sandbox if needed and restart it as a branch source. Ends what runs in it
--count N1How many children this scope should have. Existing children count, so a repeat creates none
--jsonfalseAn array of the new children's names

fork ls lists this scope's children. fork rm <name> removes one child and fork rm --all removes all of them. A name that is not a fork child exits 2.

boxer trust

boxer trust
boxer trust --show

Approves this worktree's host-affecting configuration. The worktree is mounted read-write, so code in the sandbox can rewrite boxer.toml or devcontainer.json, which boxer reads on the host. The keys that reach the host — prep, mounts, build, mode, enforcement, passthrough, intercept, secrets, env_passthrough, network, on_sandbox_unavailable, telemetry.path and [harness.*] overrides — are held back until a person who has seen the configuration runs this. Until then the sandbox still runs, with boxer's defaults for those keys; everything else (image, cpus, tasks, ready) takes effect without approval.

--show lists the host-affecting keys and exits without approving. Trust is per worktree, and a changed set of those keys has to be approved again. BOXER_TRUST=1 approves every configuration without a prompt, for CI and other places the repository is yours to begin with.

FlagDefault
--showfalseList the host-affecting keys without approving them

boxer pack

boxer pack save <name>
boxer pack ls [--json]
boxer pack use <name>
boxer pack rm <name>

A named pack is a snapshot of a sandbox's filesystem, not its processes. See packs you name.

Subcommand
save <name>Snapshot this scope's sandbox. smolvm snapshots only a stopped machine, so the sandbox is stopped and started again around it: a command running in it is cut off, and its services restart. NO_SANDBOX when there is none
lsList saved packs, newest first
use <name>Recreate this scope's sandbox from one. NO_SUCH_PACK when it was never saved, before anything is deleted
rm <name>Delete one. Exit 1 when there is no such pack, or while a sandbox is being created from it

boxer checks a pack name before use because it becomes a path segment. An invalid name exits 2.

boxer capsule

boxer capsule new [-o PATH]
boxer capsule inspect <path> [--json]
boxer capsule replay <path> [--allow-dirty] [--allow-drift] [--apply-patch]

A capsule records the last command run in this scope well enough to run it again. See capsules.

FlagDefault
new -o PATHcapsule.tomlWhere to write it. A dirty worktree also gets <name>.patch beside it
inspect --jsonfalsePrint the manifest as JSON
replay --allow-dirtyfalseReplay even though this worktree has uncommitted changes
replay --allow-driftfalseReplay even though HEAD differs from the captured one
replay --apply-patchfalseApply the capsule's patch with git apply first

replay exits 0 when the failure reproduced, which means the same exit code and, when the capsule lists failing tests, the same failing tests. It exits 1 when it did not reproduce or was refused.

boxer logs

boxer logs [--scope NAME] [-n N] [--json]

Prints the event log when the file sink is on. Exit 1 when there is no log.

FlagDefault
--scope NAMEOnly events for this sandbox key
-n N0Only the last N events. 0 prints all
--jsonfalseAn array of events

boxer watch

boxer watch [-A] [--interval 1s] [--json]

Streams sandbox state changes on the configured backend, and events from the file sink when it is on, until interrupted. Exit 1 when the backend cannot be listed.

FlagDefault
-A, --all-backendsfalseEvery installed backend, as ls -A
--interval D1sHow often to compare listings
--jsonfalseOne object per line

boxer install

boxer install <harness>... [--user]
boxer install all [--user]
boxer install git
boxer install conductor

Writes the files a harness reads so its commands reach the sandbox: hooks or a plugin, and, where the harness takes them, an MCP entry, an instruction file and the skill. Each harness's setup page lists exactly what it writes. Run it inside the repository.

TargetWrites
claude-code, codex, gemini-cli, grok, kimi, dsh, opencode, piThat harness's project files
copilotRefused at project level: Copilot reads no project file. Use --user
allEvery harness above except copilot
gitA post-checkout hook running boxer up --detach in each new worktree. Not part of all
conductor.conductor/settings.toml with harness shims and a setup script that warms the sandbox
FlagDefault
--userfalseWrite the user files instead: ~/.claude/settings.json, ~/.codex/config.toml, or ~/.copilot. claude-code, codex and copilot only. all --user is those three

boxer install takes the integration's name (claude-code, gemini-cli). boxer shell takes the program's (claude, gemini).

boxer uninstall

boxer uninstall <harness>... [--user]
boxer uninstall all [--user]
boxer uninstall git
boxer uninstall conductor

Removes what the same boxer install wrote, and only that. Files boxer created go. In files it merged into (.claude/settings.json, .mcp.json, AGENTS.md, opencode.json), only boxer's entries go and the rest of the file is kept, including your own hooks in a group boxer's hook shares. Directories left empty are removed. Running it twice is harmless.

Some files serve several harnesses: .mcp.json's boxer server (Claude Code, Grok), the skill in .agents/skills/boxer (Codex, Grok, Kimi, DSH) and the AGENTS.md section (OpenCode, pi). Each is kept while another harness that uses it is still installed, and removed with the last of them.

Left for you, and named in the output: the tools.exclude entry in Gemini CLI's settings, which may be yours too; the hooks you appended to ~/.kimi-code/config.toml by hand; and an opencode.json left holding only $schema, which boxer cannot tell from one you wrote.

FlagDefault
--userfalseRemove what install --user wrote. claude-code, codex and copilot only. git and conductor refuse it with exit 2

boxer shim install

boxer shim install [dir]
boxer shim install --harness a,b [dir]
boxer shim install --shell [dir]

Writes files on PATH that forward to boxer. See PATH shims.

FlagDefault
(none)One shim per intercept entry, each running boxer run
--harness LISTComma-separated inside harnesses. Shims named after their programs, each running boxer shell
--shellfalseboxer-bash, a bash whose every command runs in the sandbox, for a harness with a configurable shell path
dir$XDG_DATA_HOME/boxer/shims, else ~/.local/share/boxer/shimsWhere to write

boxer removes its own shim directories from PATH when it starts, so it never calls itself through a shim.

boxer shell and boxer acp

boxer shell <harness> [-e KEY=VALUE]... [-- args...]
boxer acp <harness> [-e KEY=VALUE]...

shell runs the harness itself in the sandbox, with a terminal when you have one. acp runs its ACP server in the sandbox with stdio piped. Both set integration = "inside". See running the harness inside.

FlagDefault
-e KEY=VALUEA variable for the guest process, passed by name so its value is not in a command line. -e KEY passes the host's value. Repeatable

Harnesses are claude, codex, copilot, fx, gemini, grok, kimi, opencode and pi. fx and pi have no ACP server.

boxer hook

boxer hook <harness>

The command a harness hook runs. It reads the hook's JSON on stdin and answers on stdout. Harnesses are the install names above plus copilot. An unknown harness exits 1. Input that is not JSON exits 0, so a parse failure in boxer never breaks a session. Inside a guest it does nothing.

boxer mcp

boxer mcp [--harness NAME]

Serves MCP over stdio. See MCP server.

FlagDefault
--harness NAMEApply the [harness.<name>] overrides

boxer package

boxer package plugin|skills|<harness>|all [--out DIR]

Renders what boxer publishes. You need it only to release boxer.

TargetRenders
pluginThe Agent Plugins package in <out>/boxer
skillsskills/boxer/ and site/public/.well-known/, relative to the current directory. Ignores --out
<harness>The files one client reads, in <out>/<harness>
allAll of the above
FlagDefault
--out DIRdistOutput directory

The output is the same for every user apart from the version. Configuration reaches the agent at run time through boxer brief, the hooks and the MCP resource.

boxer completion

boxer completion bash|zsh|fish

Prints a completion script for the command names.

boxer version

boxer version

Also --version and -v. Prints the release version, else the module version go install recorded, else dev.

Exit codes

CodeMeaning
0Success. For status, running. For capsule replay, the failure reproduced
1Refused or failed
2Usage error, such as an unknown command, a bad flag, a flag the command does not take (restart --scope) or a missing argument
3For status, the sandbox exists and is stopped
4For status, url and open, this scope has no sandbox
nFor run, the command's own exit code

A refusal prints boxer: <reason> on stderr with scope, worktree, cause and fix lines. The causes are listed under errors. With on_sandbox_unavailable = "passthrough", run runs the command on the host when the sandbox cannot be provisioned, and exits 127 when the program cannot be started there.

Output modes

ls, stop, rm, backends and integrations format their output in one of three modes. open starts a browser only in human mode.

ModeWhenOutput
humanstdout is a terminal and no agent is detectedColour, aligned tables, hints, a confirmation before rm of several sandboxes
agentan agent is detected, CI is set, or stdout is not a terminalPlain text, hints as next: <command> lines, never a prompt
json--json or BOXER_OUTPUT=jsonOne JSON document on stdout

boxer detects an agent when CLAUDECODE, BOXER_AGENT or BOXER_INSIDE is set. A command that would have asked a person refuses in agent mode and says what to pass. BOXER_OUTPUT=json also switches every other command that has a JSON form.

Environment variables

Variables that set a boxer.toml key, such as BOXER_BACKEND, are listed in the configuration reference. These have no key.

VariableEffect
BOXER_OUTPUTjson, text (also agent, plain) or human. Overrides the detected output mode
BOXER_AGENTAny value marks an agent whose shell has a terminal
NO_COLORNo colour in human mode. TERM=dumb does the same
BOXER_HARNESS, BOXER_SESSION_ID, BOXER_AGENT_IDDefaults for the identity flags
BOXER_SMOLVMPath to the smolvm binary. Default smolvm on PATH
BOXER_PORTLESSPath to the portless binary. Default portless on PATH
PORTLESS_PORTPort boxer starts the portless proxy on. Default 1355. Below 1024, boxer refuses and asks you to start the proxy yourself
BOXER_PACKSDirectory for environment packs. Default $XDG_STATE_HOME/boxer/packs, else ~/.local/state/boxer/packs
BOXER_TRACEA path. Turns the event file sink on there, whatever [telemetry] says. See events
BOXER_NO_RECLAIM1 skips the background sweep auto_reclaim starts
XDG_CONFIG_HOMEHolds the user boxer/boxer.toml. Default ~/.config
XDG_STATE_HOMEHolds boxer's state, packs and event log. Default ~/.local/state
XDG_DATA_HOMEHolds the default shim directory. Default ~/.local/share

boxer sets these for the processes it starts.

VariableWhereValue
BOXER_INSIDEEvery guest process1. A boxer in the guest runs commands directly
BOXER_PORTSboxer shell and boxer acpGuest port to host port, 3000=61234 8080=61240
BOXER_URLSboxer shell and boxer acp, when [urls] names portsGuest port to URL, 3000=https://fix-ui.myapp.localhost:1355
BOXER_TARGET_OS, BOXER_TARGET_CPU, BOXER_TARGET_LIBC, BOXER_TARGET_FLAGSprep.commands, on the hostThe guest platform
BOXER_WORKTREEprep.commandsThe worktree's host path

On this page