Skip to content

Configure sandbox policies

Whether an agent run is sandboxed is decided on the server, at boot (--sandbox). The Enable sandboxing toggle and the Backend picker under Settings → Server → Diagnostics & privacy are preferences stored on your device. The Sandboxing card’s host detection reports what the server host can wrap.

Two controls reach a run and this guide covers both: the action rules at Settings → Workspace → Agent permissions, which decide what an agent may push, open or reach, and the server’s own --sandbox flag.

An agent is held by six things. The first is the OS sandbox and it is the one that is conditional — the other five hold on every host.

Boundary What it does
The OS sandbox Seatbelt on macOS, bubblewrap on Linux and WSL2. Wraps the Claude Code CLI, ACP adapters and the harness bash tool. Absent on Windows and on Linux without bwrap and socat
Its own worktree Each conversation gets a copy-on-write checkout. The original checkout is folded into the run as a deny-write path and the sandbox is what enforces it
Brokered credentials The credential broker mints a per-run environment and revokes it at teardown. Its GitHub token can read but not push: a push goes through Control Center, which asks the push rule first
Action guardrails Every mutating tool declares its effect classes and the guard resolves them before the call runs. A prompt with no approver connected is denied
Environment sanitisation ACP and the harness bash tool get a filtered environment. Claude Code through NoSandboxAdapter inherits the host environment
The mode’s tool surface A read-only mode removes the worktree-mutating tools outright and pins the mode’s own output verb so it can still deliver

Three things stay weaker than they look:

  • Only the built-in harness enforces the tool gate, completion contracts and structural mode rules. The Claude Code adapter does not. Claude Code in particular is launched with --dangerously-skip-permissions, because a non-interactive claude -p would otherwise block forever on its own prompt — so Claude’s own read, write and edit calls are neither seen nor gated by Control Center and its bash commands are checked only by a hook that reads the command line. Where the sandbox is on, it is the boundary around them.
  • The harness’s in-process file tools (read, write, edit, apply patch, search, find, search_files) run inside the server process, so no sandbox profile constrains them. Only the bash tool goes through the sandboxed command runner. Those tools are bounded by their own path confinement plus the action guardrails.
  • On a host with no backend the first row does not apply at all. ACP and the harness bash tool fall back to environment sanitisation plus the command policy; Claude Code inherits the host environment through NoSandboxAdapter. The server says so in its startup log. Check yours below.

There is no per-agent switch for git push, GitHub, ticketing or the network. Each is an action rule:

Rule Built-in default What it covers
Push to a remote Ask first Every git push to GitHub, whatever the adapter
Open a pull request Ask first gh pr create and the pull-request tools
Publish a review or merge Ask first gh pr merge, gh pr review, gh pr comment, gh pr close
Write to an external tracker Ask first Ticket writes through Control Center’s tools and gh issue writes
Access the network Allow Whether the sandbox has a network at all, and the harness’s web tools
  1. Go to Settings → Workspace → Agent permissions
  2. Pick the scope — Workspace, Agent or Space — and on the rule’s row pick Allow, Ask first or Deny

Branch-constrained push rules, such as one that denies pushes to main, apply too: see Guardrails.

Checkpoint: ask the agent to push a branch. Under Ask first you get an approval naming the repo and the refs; under Deny, git prints ! [remote rejected] <ref> (Control Center policy: …).

How each rule reaches the run:

  • Push is enforced by what the run holds. Its GitHub token is a read-only GitHub App installation token that can read contents and work with pull requests. Its git configuration sends every GitHub push to a loopback gateway on cc_server, which asks the rule and only then forwards the push on a write token the agent never sees. The gateway forwards only to the worktree’s own repo or a GitHub repo linked to the workspace. This holds for every adapter.
  • Pull requests and issues from a shell are recognised by command line, in the harness bash tool and, through a hook, in Claude Code’s Bash tool. An agent that hides the command (a script, eval, a raw API call) gets past this check, but not past the push gateway.
  • Ticketing keys are never placed in the sandbox. Agents write tickets through Control Center’s MCP tools, which ask the rule.
  • Network is resolved once, when the run starts. Deny turns the sandbox’s network off; Allow and Ask first leave it on, and under Ask first the harness’s web_fetch and web_search tools still ask per call. While the network is on, GitHub is always on the egress allowlist.

Check whether your agent runs are sandboxed

Section titled “Check whether your agent runs are sandboxed”

Two things decide it, both on the server: whether the host offers a backend and whether --sandbox is on. Check them in that order.

  1. Go to Settings → Server → Diagnostics & privacy
  2. Read the Sandboxing card. The Host fact is the machine cc_server runs on, not the machine you are looking at. The Backend field lists Native sandbox (Seatbelt on macOS, bubblewrap on Linux and WSL2) or No isolation. The In force fact is this device’s preference, not the wrap the server actually uses.
  3. Read the server’s startup log. It prints exactly one of three lines:
    • agent sandbox ON plus the backend note — runs are wrapped
    • no OS-native agent sandbox on this host plus an install hint where there is one — runs are not wrapped
    • agent sandbox DISABLED by --sandbox off — a deliberate opt-out

GET /healthz does not report sandbox state, so the startup log is the check.

To turn the sandbox off deliberately — a host where the profile misbehaves is the reason it exists — start the server with --sandbox off, or set CC_SERVER_SANDBOX=off. The default is on and on means “use a backend if the host has one”, never “require one”.

Two situations never get a native sandbox wrap. On Windows the native probe always reports unavailable and there is nothing to install — agent dispatch uses none. The microvm backend is separate (interactive terminals and rigs) and is probe-gated on its own runtime. On Linux and WSL2 both bwrap and socat must be on the PATH; without them the probe reports unavailable and names the missing packages.

On Linux/WSL2 with bubblewrap installed, the standard policy’s secret-file globs cannot be enforced for files an agent creates later. Such a native run now fails instead of silently ignoring the rules. A positive boot probe therefore does not guarantee that a Linux dispatch can start. --sandbox off is a deliberate unconfined opt-out, not a substitute security boundary.

Mode is stored per space and feeds the guardrail resolver as the mode preset layer. Three of the four modes are read-only and a read-only mode refuses eleven effect classes outright:

Mode Worktree Refused by the preset
Agent (chat) Writable Nothing — the built-in defaults apply
Plan Read-only Delete a file, write outside the worktree, commit, push, open a PR, publish or merge, write to an external tracker, install a package, run a process, change workspace structure, boot or drive an enclosure
Review Read-only The same eleven. Not user-selectable — the composer offers only Agent, Plan and Orchestrate
Orchestrate Read-only The same eleven

Network access and secret access are deliberately not refused by a read-only mode: research is the point of one.

Approval is a guardrail decision, not a sandbox setting.

  1. Go to Settings → Workspace → Agent permissions
  2. Set the action class to Ask first at the workspace, agent or space scope

An Ask first decision interrupts the run and asks you. With no approver connected it fails closed and the action is denied. See Configure guardrails for the full resolution order.

An agent cannot push and I never denied it

Section titled “An agent cannot push and I never denied it”

Read what git printed. Control Center policy: … means a rule denied the push or an Ask first went unanswered. … is not linked to this workspace means the push targets a repo that is neither the worktree’s own nor linked to the workspace. Control Center has no GitHub credential that can push … means the GitHub App is not installed on that repo and no fallback credential could push: install the App on it or connect GitHub.

The Sandboxing card reports no native sandbox

Section titled “The Sandboxing card reports no native sandbox”

Then agent runs on that host are not wrapped by Seatbelt or bubblewrap and the remaining boundaries are what you have. On Linux and WSL2, install both missing tools — sudo apt-get install bubblewrap socat — and restart the server; the startup log should then say the sandbox is on. On Windows there is no native backend to install, so tighten the guardrails instead: see Configure guardrails.

An agent reached a file outside its worktree

Section titled “An agent reached a file outside its worktree”

Which tool reached it decides whether this is expected.

The harness’s in-process file tools (read, write, edit, apply patch, search, find, search_files) run in the server process, so no sandbox profile applies to them — their bound is their own path confinement plus the guardrails. A bash command or the Claude Code CLI is wrapped where a backend exists and your registered checkouts are deny-write inside that wrap in every mode, including their symlink-resolved spellings (on macOS a path reached through /tmp or /var/folders resolves under /private and both spellings are now denied). On a host with no backend none of that applies. Either way, guardrails can refuse Write outside the worktree outright.