What’s installed#
uv tool install claude-sandbox installs the host launcher. It selects a
prebuilt image containing the files below. A custom devcontainer gets the
same files through uvx claude-sandbox install.
For the configuration they read, see configuration.
The published image also includes Vim for terminal editing. Installing the sandbox into a custom devcontainer leaves the choice of editor to that project.
Browser testing is optional. The shipped browser-testing skill provides an
outer-container installer for Playwright, Chromium and system dependencies,
plus an in-sandbox smoke check. It preserves project dependencies and caches
browser downloads under /cache/ms-playwright; browsers are not baked into
the image. Run the setup script from an outer container terminal:
sh /usr/libexec/claude-sandbox/skills/browser-testing/scripts/install-browser-deps.sh
After setup, chromium opens the browser from an outer-container terminal
with a working display. Its profile persists under /cache/chromium-home.
See browser automation for setup checks
and example testing prompts.
VS Code automation is also optional. The shipped vscode-headless skill
provides an outer-container installer, a virtual-display launcher and a UI
driver. See VS Code automation for setup
and example editor and debugging workflows.
Container-scoped#
Preinstalled in the published image. In a custom devcontainer, re-established
by uvx claude-sandbox install, typically wired into postCreate.sh.
The apt step also installs passt (which provides pasta, the userspace
network forwarder the egress jail attaches to
Claude’s private netns). The jail’s one container-side requirement —
--device=/dev/net/tun in devcontainer.json’s runArgs — is not
something the installer can add (a runArg is a container-launch setting); on a
host missing it the jail fails closed and claude refuses to launch with a
message naming the fix. The PyPI host launcher adds the tun device automatically.
Path |
Source |
Purpose |
|---|---|---|
|
Anthropic installer ( |
The real Claude binary, kept off the user’s PATH so the shadow always wins |
|
|
Shadow that wraps the real binary in |
|
OpenAI installer ( |
The real Codex CLI package (the client for GPT-6 Astra) — |
|
|
The same shadow under the other agent’s name; it picks its profile from |
|
|
Pi profile of the shared wrapper; always installed, even with |
|
|
Fixed launch guard that checks sandbox markers before starting Pi; see Pi guard limitations |
|
Latest Pi standalone release on fresh install, verified against release checksums; optional |
Pi executable and assets, read-only inside the sandbox; Linux x64 and arm64. Existing installs are kept on re-run. No separate Node.js runtime needed |
|
|
Helper CLI ( |
|
|
The recommended Claude status line, which |
|
|
Pi footer extension showing the host and container tag, which |
|
Stamped by |
Lets |
|
Stamped by |
What |
|
Generated |
Curated gitconfig — regenerated from |
|
jq-merged by |
Disables the vendor updater with |
|
Written by |
Codex’s soft managed tier — |
|
Bundled |
Sandbox config for all three agents. See configuration |
Disabling the auto-updater is root-cause removal: Claude Code’s updater
otherwise re-creates ~/.local/bin/claude on a version bump, which can
launch the real binary unwrapped and self-entrench. With the updater
off, newer agents come from a deliberately updated image or fresh installation.
Reinstalling the sandbox keeps existing agent binaries and reasserts their
wrappers. See Upgrade and the
shadow-on-PATH explanation.
The Codex CLI gets the same treatment through its own managed tier — the
bypass it closes is identical.
Three agents, one sandbox#
claude, codex, and pi are wrapped by the same shadow file, which resolves a
per-agent profile from argv[0]. The bwrap argv, the egress jail and the
script(1) pty wrap are shared code; only the binary to exec, the $HOME
paths bound for login state, and the injected flags differ
(ADR 18).
Each agent sees only its own credentials: a codex session binds
~/.codex and gets no ~/.claude/~/.claude.json, and vice versa. Both
sessions get the same workspace bind, the same forge credentials (unless
no-forge), and the same egress jail.
Run WITH_CODEX=0 uvx claude-sandbox install in a custom devcontainer to skip
fetching the Codex binary. The codex
shadow is installed either way.
User-scope ~/.claude#
The installer seeds a statusline preference.
Path |
Behaviour |
|---|---|
|
Statusline — seeded only if absent (an owner-customised one survives) |
|
|
claude-sandbox doctor --fix replaces both with the recommended status line and
saves a .bak- copy of each file first.
User-scope ~/.codex#
CODEX_HOME. Created if absent so the shadow’s bind succeeds on a first
launch; its contents (config.toml, auth.json, sessions/) are yours and
are never rewritten. Like ~/.claude, it joins the /user-terminal-config
share when one is mounted, so a Codex login survives a devcontainer rebuild —
it is one vendor login, not a repo-scoped forge PAT
(ADR 6).
User-scope ~/.agents/skills#
Skills shared by every agent. Created if absent (by the shadow at launch) and
bound read-write into Claude, Codex and Pi sessions alike. Codex and Pi load
skills from it natively; Claude loads one only when you symlink it into
~/.claude/skills. Its contents are yours and are never rewritten. When
/user-terminal-config is mounted, it joins the share, so the skills survive
a rebuild. Only the skills directory is bound or shared; the rest of
~/.agents stays outside the sandbox
(ADR 25,
share skills between agents).
Not placed: CLAUDE.md and README-CLAUDE.md live in the meta-repo for
dogfooding.