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
| Command | Does |
|---|---|
up | Create and start this scope's sandbox |
run | Run a command in the sandbox |
down | Delete this scope's sandbox, one by name, or all |
status | This scope's sandbox, as an exit code and a line |
restart | Relaunch the start services without recreating the sandbox |
ls | Every sandbox on the backend |
stop, rm | Stop or remove sandboxes by name or filter |
gc | Reclaim gone, idle and stopped sandboxes and stale packs |
url, open | Where this worktree's server is |
backends | Which backends are installed and answering |
integrations | Which harnesses, orchestrators and tools are wired to boxer |
doctor | The resolved configuration and what is wrong with it |
brief | The agent-facing summary of this checkout |
tasks | The commands [tasks] declares |
fork | Branch copy-on-write children of a smolvm sandbox |
trust | Approve this worktree's host-affecting configuration |
pack | Save and reuse named snapshots of a sandbox |
capsule | Record the last run and replay it |
logs | Read the event log |
watch | Stream sandbox state changes and events |
install | Write a harness's hooks, MCP entry and skill |
uninstall | Remove what install wrote |
shim | Write PATH shims |
shell, acp | Run a harness inside the sandbox |
hook | The entry point a harness hook calls |
mcp | The MCP server |
package | Render the published plugin and skill |
completion | Print a shell completion script |
version | Print 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.
| Flag | Default | |
|---|---|---|
--harness NAME | $BOXER_HARNESS | The harness the call comes from |
--session ID | $BOXER_SESSION_ID | The harness session id |
--agent ID | $BOXER_AGENT_ID | The 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.
| Flag | Default | |
|---|---|---|
--detach | false | Provision in a background boxer and return at once |
--recreate | false | Delete and recreate the sandbox |
--rebuild | false | Drop the cached environment pack, then recreate. Implies --recreate |
--json | false | Print 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.
| Flag | Default | |
|---|---|---|
-c LINE | A shell line, run with sh -c. Not with -- arguments | |
--task NAME | A [tasks] entry. Not with -c or arguments. Unknown names fail with NO_SUCH_TASK | |
--scope NAME | Run in another sandbox, such as a fork child, by key or two-word name. The current directory must still be in a repository | |
--tty | false | Allocate a terminal in the guest when stdin is not one. Input written before the guest attaches is kept |
--junit PATHS | Comma-separated JUnit XML paths, relative to the worktree, to summarise after the run. Overrides the task's junit and results.auto | |
--fail-on-test-failures | false | Exit 1 when the command exited 0 and a test in the reports failed |
--json | false | Print 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.
| Flag | Default | |
|---|---|---|
--all | false | Every boxer sandbox on the configured backend |
--scope NAME | One sandbox by key or two-word name, without resolving a worktree. Works after the worktree is gone | |
--json | false | Print 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.
| Exit | State |
|---|---|
0 | running |
3 | exists, stopped |
4 | absent |
1 | refused, or the backend could not be asked |
| Flag | Default | |
|---|---|---|
--scope NAME | Another sandbox, by key or two-word name. The current directory must still be in a repository | |
--json | false | The status object |
boxer restart
boxer restartStops 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.
| Flag | Default | |
|---|---|---|
-A, --all-backends | false | Every installed backend |
--pr | false | Each worktree's pull request, through gh. One network call per worktree |
--resources | false | Memory, CPU and disk per sandbox |
--no-git | false | Skip reading each worktree's git state |
--json | false | The 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).
| Flag | Default | |
|---|---|---|
--all | false | Every boxer sandbox on the configured backend. With -A, on every backend |
--gone | false | Sandboxes whose worktree no longer exists |
--stopped | false | Sandboxes that are not running |
-A | false | Look on every installed backend |
-i | false | Choose from a numbered list. The default for a person when nothing is named |
-y | false | Do not ask before removing several sandboxes or a filter's matches |
--volumes | false | rm only. Also delete the sandboxes' named volumes |
--json | false | Print 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.
| Flag | Default | |
|---|---|---|
--all | false | Ignore idle_timeout. Also take every stopped sandbox and every unreferenced pack. Running sandboxes are kept |
--dry-run | false | Print what it would delete |
--json | false | The decision array |
boxer url and boxer open
boxer url [PORT]
boxer open [PORT]
boxer url --all
boxer open --allPrints 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.
| Flag | Default | |
|---|---|---|
--probe | false | Create 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 |
--json | false | The 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
PATHand whether boxer's files are installed in this repository and for this user - the orchestrators
conductorandgit-hook - the tools
portless,ghandnpx
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.
| Flag | Default | |
|---|---|---|
--user | false | Install for this user. For skill, passes -g. For plugin, drops -s project. For a harness, runs boxer install --user |
--agent NAME | For skill, the agents, passed as npx skills -a. For plugin, the target, passed as -t | |
--source REPO | BarakChamo/boxer | Where the skill and plugin are published |
--json | false | The 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> | --allBranches copy-on-write children off this scope's smolvm sandbox. Children share this worktree. See forking. Stdout carries only the children's names.
| Flag | Default | |
|---|---|---|
--prepare | false | Create the sandbox if needed and restart it as a branch source. Ends what runs in it |
--count N | 1 | How many children this scope should have. Existing children count, so a repeat creates none |
--json | false | An 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 --showApproves 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.
| Flag | Default | |
|---|---|---|
--show | false | List 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 |
ls | List 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.
| Flag | Default | |
|---|---|---|
new -o PATH | capsule.toml | Where to write it. A dirty worktree also gets <name>.patch beside it |
inspect --json | false | Print the manifest as JSON |
replay --allow-dirty | false | Replay even though this worktree has uncommitted changes |
replay --allow-drift | false | Replay even though HEAD differs from the captured one |
replay --apply-patch | false | Apply 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.
| Flag | Default | |
|---|---|---|
--scope NAME | Only events for this sandbox key | |
-n N | 0 | Only the last N events. 0 prints all |
--json | false | An 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.
| Flag | Default | |
|---|---|---|
-A, --all-backends | false | Every installed backend, as ls -A |
--interval D | 1s | How often to compare listings |
--json | false | One object per line |
boxer install
boxer install <harness>... [--user]
boxer install all [--user]
boxer install git
boxer install conductorWrites 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.
| Target | Writes |
|---|---|
claude-code, codex, gemini-cli, grok, kimi, dsh, opencode, pi | That harness's project files |
copilot | Refused at project level: Copilot reads no project file. Use --user |
all | Every harness above except copilot |
git | A 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 |
| Flag | Default | |
|---|---|---|
--user | false | Write 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 conductorRemoves 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.
| Flag | Default | |
|---|---|---|
--user | false | Remove 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.
| Flag | Default | |
|---|---|---|
| (none) | One shim per intercept entry, each running boxer run | |
--harness LIST | Comma-separated inside harnesses. Shims named after their programs, each running boxer shell | |
--shell | false | boxer-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/shims | Where 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.
| Flag | Default | |
|---|---|---|
-e KEY=VALUE | A 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.
| Flag | Default | |
|---|---|---|
--harness NAME | Apply 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.
| Target | Renders |
|---|---|
plugin | The Agent Plugins package in <out>/boxer |
skills | skills/boxer/ and site/public/.well-known/, relative to the current directory. Ignores --out |
<harness> | The files one client reads, in <out>/<harness> |
all | All of the above |
| Flag | Default | |
|---|---|---|
--out DIR | dist | Output 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|fishPrints a completion script for the command names.
boxer version
boxer versionAlso --version and -v. Prints the release version, else the module version go install
recorded, else dev.
Exit codes
| Code | Meaning |
|---|---|
0 | Success. For status, running. For capsule replay, the failure reproduced |
1 | Refused or failed |
2 | Usage error, such as an unknown command, a bad flag, a flag the command does not take (restart --scope) or a missing argument |
3 | For status, the sandbox exists and is stopped |
4 | For status, url and open, this scope has no sandbox |
| n | For 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.
| Mode | When | Output |
|---|---|---|
| human | stdout is a terminal and no agent is detected | Colour, aligned tables, hints, a confirmation before rm of several sandboxes |
| agent | an agent is detected, CI is set, or stdout is not a terminal | Plain text, hints as next: <command> lines, never a prompt |
| json | --json or BOXER_OUTPUT=json | One 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.
| Variable | Effect |
|---|---|
BOXER_OUTPUT | json, text (also agent, plain) or human. Overrides the detected output mode |
BOXER_AGENT | Any value marks an agent whose shell has a terminal |
NO_COLOR | No colour in human mode. TERM=dumb does the same |
BOXER_HARNESS, BOXER_SESSION_ID, BOXER_AGENT_ID | Defaults for the identity flags |
BOXER_SMOLVM | Path to the smolvm binary. Default smolvm on PATH |
BOXER_PORTLESS | Path to the portless binary. Default portless on PATH |
PORTLESS_PORT | Port boxer starts the portless proxy on. Default 1355. Below 1024, boxer refuses and asks you to start the proxy yourself |
BOXER_PACKS | Directory for environment packs. Default $XDG_STATE_HOME/boxer/packs, else ~/.local/state/boxer/packs |
BOXER_TRACE | A path. Turns the event file sink on there, whatever [telemetry] says. See events |
BOXER_NO_RECLAIM | 1 skips the background sweep auto_reclaim starts |
XDG_CONFIG_HOME | Holds the user boxer/boxer.toml. Default ~/.config |
XDG_STATE_HOME | Holds boxer's state, packs and event log. Default ~/.local/state |
XDG_DATA_HOME | Holds the default shim directory. Default ~/.local/share |
boxer sets these for the processes it starts.
| Variable | Where | Value |
|---|---|---|
BOXER_INSIDE | Every guest process | 1. A boxer in the guest runs commands directly |
BOXER_PORTS | boxer shell and boxer acp | Guest port to host port, 3000=61234 8080=61240 |
BOXER_URLS | boxer shell and boxer acp, when [urls] names ports | Guest port to URL, 3000=https://fix-ui.myapp.localhost:1355 |
BOXER_TARGET_OS, BOXER_TARGET_CPU, BOXER_TARGET_LIBC, BOXER_TARGET_FLAGS | prep.commands, on the host | The guest platform |
BOXER_WORKTREE | prep.commands | The worktree's host path |