Docker Sandboxes Claude Code Setup: Run sbx With a Chosen Workspace, a Tight Network Policy and a Clean Teardown

Docker Sandboxes Claude Code setup with sbx: pick a network preset, choose a bind, read-only or clone workspace, allow needed hosts, verify, then tear down.

Diagram of the Docker Sandboxes host proxy deciding an outbound request from a sandboxed agent: a matching deny rule leads to Blocked, a matching allow rule to Connects, and no matching rule to Approval required. A side panel explains that under org governance only org allow rules grant access.Diagram of the Docker Sandboxes host proxy deciding an outbound request from a sandboxed agent: a matching deny rule leads to Blocked, a matching allow rule to Connects, and no matching rule to Approval required. A side panel explains that under org governance only org allow rules grant access.
Deny beats allow at the host proxy. A request no rule matches is held for approval, and under organization governance local allow rules go inactive while local deny rules still apply. Original diagram based on Docker Docs' Local policy and Network access policies pages, fetched Oct 21, 2026.

You want Claude Code to fix a failing test in a real repository. You don’t want it browsing your home directory, reading a stray credentials file or connecting to any host it likes while it works. This Docker Sandboxes Claude Code setup guide takes one developer from a fresh sbx install to a finished task. You will choose a network preset on purpose, create a sandbox against a workspace you picked, narrow outbound traffic to the hosts the job needs, check the boundary yourself and tear everything down at the end. Every command also works for Codex: swap claude for codex.

Docker Sandboxes runs each agent in an isolated microVM with its own Docker daemon, filesystem and network. The get-started walkthrough calls the shared workspace “the one part of your machine the agent can see.” That only holds if you choose the workspace and the network rules yourself instead of accepting whatever the first prompt suggests. The rest of this guide covers those two choices.

The timing: on October 21, 2026, Docker’s blog announced the official BAND AI kit for Docker Sandboxes. The post describes kits as packages that let “a single sbx create command” produce a ready-to-use agent environment. Kits bring their own network rules and credential requests. That’s convenient, and it’s also why you should understand the controls underneath before you run one.

The worked example. A Node service at /home/dev/src/invoice-api has one failing test. A style guide the agent should read but never edit lives at /home/dev/src/api-style-guide. The sandbox is named invoice-claude. The commands below use documented syntax from Docker’s reference pages. Where this guide describes output, it’s what the documentation says you should see, not a transcript we captured. Paths and repository names are illustrative. The steps explain each choice; the section after Step 5 collects the entire example into three copyable scripts.

What you need before the first sandbox

The list is short, but two items change later decisions, so check them before you type sbx create.

  • [ ] The sbx CLI is installed and signed in. Follow Docker’s get-started page, then run sbx login. The usage guide covers headless sign-in for CI runners.
  • [ ] The agent can authenticate. With a Claude Max, Team or Enterprise subscription, you don’t need to set anything up first. Run /login inside the sandbox and the OAuth session token stays on the host. For an API key, store it with sbx secret set. The host-side proxy then injects it, so it never shows up as an environment variable the agent can read. Codex needs its own OpenAI credential.
  • [ ] The repository is committed and clean. A clean git status means every later diff is the agent’s work and nothing else.
  • [ ] You know which hosts the task needs. For this example that’s the npm registry, the model provider’s API and GitHub. Write them down now; Step 4 turns the list into rules.
  • [ ] You know whether your organization governs sandbox policy. Run sbx policy ls. If the summary includes Governance: Managed by <org>, your local allow rules will be inactive and Step 4 works differently. That case is covered there.
  • [ ] A second terminal is open. You’ll inspect the sandbox from outside while the agent works inside it.

Step 1: Choose a network preset with sbx policy init

According to the local policy documentation, Docker Sandboxes sends outbound TCP through a proxy on your host, and that proxy enforces access rules on every connection. The preset is the proxy’s global starting point. The CLI prompts for one before your first sandbox runs. sbx policy init sets it without the prompt, which is what you want in scripts and on headless machines.

Preset (prompt name) sbx policy init value What’s reachable before you add rules Choose it when Watch for
Open allow-all All outbound TCP, the same as an allow rule for "**" A throwaway experiment where the network isn’t the risk you care about Nothing is blocked, so a deny rule is your only control
Balanced balanced A baseline allowlist: AI provider APIs, package managers, code hosts, container registries, common cloud services Everyday work where you want default deny without approving every registry Run sbx policy ls to see what the baseline actually includes before you trust it
Locked Down deny-all Nothing from the preset; only rules you or a kit add Untrusted repositories, or any task where you want to name every host Even the model API is blocked unless a rule (yours or the agent kit’s) allows it

Initialization happens once. sbx policy reset clears it so you can start over. Under Balanced and Locked Down, a request that matches no rule is blocked and turned into an approval request. It doesn’t just fail silently, so a strict preset is less painful than it sounds.

For the worked example, pick Locked Down. The task needs three kinds of destination, and you want each one to be a rule you can point to.

sbx policy init deny-all
sbx policy ls
  1. Run sbx policy init deny-all once, before any sbx create.
  2. Run sbx policy ls and read the summary. On a machine your organization doesn’t manage, you should see no baseline allow rules from the preset and no governance line.
  3. If you picked the wrong preset, run sbx policy reset. It deletes the local policy store, restarts the daemon (which stops running sandboxes) and prompts you again.

Step 2: Create the sandbox, then attach to it

There are two ways in. sbx run creates the sandbox and attaches in one step, and it mounts the current directory when you give no path. sbx create builds the sandbox without attaching, and it handles the path differently: since sbx 0.42.0, leaving out the path on sbx create gives you a mountless sandbox with no host workspace at all. The sbx create claude reference says that without a path, “the agent then works in the container’s own filesystem instead of on your files.”

Use create so you can inspect the rules before the agent starts, and always pass the path explicitly.

cd /home/dev/src/invoice-api
sbx create --name invoice-claude claude . /home/dev/src/api-style-guide:ro
sbx ls
sbx run --name invoice-claude
  1. cd into the repository. The . that follows is the primary workspace. The agent starts there, and sbx exec uses it as the default working directory.
  2. Create with an explicit name. Without --name, the default is <agent>-<workdir>. A name you chose is easier to scope rules to and to reattach from any directory. Names need at least two characters and must start with a letter or number. default is reserved.
  3. Add the style guide with :ro. An extra path with the :ro suffix is mounted read-only, at the same absolute path it has on the host.
  4. Check sbx ls. The WORKSPACE column should show the repository path. If it’s empty, you created a mountless sandbox; see Troubleshooting.
  5. Attach with sbx run --name invoice-claude. You can leave out the agent name when reattaching. After create, the sandbox stops on its own when no session is keeping it running, and run --name starts it again.
  6. Sign in. With a Claude subscription, run /login in the agent session.

Docker Docs reference page for the sbx create claude command on docs.docker.com, showing the page heading and the start of the command's reference entry.
Docker Docs' sbx create claude reference page, captured from docs.docker.com. The capture shows the top of the page, which introduces the command used in this guide to create a Claude Code sandbox. · Original source

Inside the sandbox, the workspace shows up at /home/dev/src/invoice-api, the same path as on the host. That helps your tooling: absolute paths in error messages, test reports and editor links mean the same thing on both sides.

Step 3: Decide what the agent is allowed to change

The path arguments are your filesystem policy. The sbx create reference and the usage guide define four shapes, and each one changes how you review the agent’s work.

Matrix of four Docker Sandboxes workspace modes for sbx create: direct mount, extra path :ro, --clone and no path, with columns for whether the agent writes host files, where work lands and how to review it. Only the direct mount row shows Yes.Matrix of four Docker Sandboxes workspace modes for sbx create: direct mount, extra path :ro, --clone and no path, with columns for whether the agent writes host files, where work lands and how to review it. Only the direct mount row shows Yes.
Only a direct mount lets the agent write your working tree. The :ro, clone and no-workspace modes keep host files out of reach and change how you review the work. Based on Docker Docs' Usage page and sbx create reference, fetched Oct 21, 2026.

Mode How you create it What the agent can change Where its work lands How you review it
Direct (bind mount) sbx create claude . Your working tree, read-write Your files, right away git diff and git status on the host
Extra read-only path Add /path:ro after the primary path Nothing in that path Nowhere; writes to it fail Nothing to review; confirm the mount refused a write
Clone mode sbx create --clone claude . A private Git clone inside the sandbox; the host repo is read-only at /run/sandbox/source The in-sandbox clone, until you fetch it git fetch the sandbox-<name> remote on the host
No workspace sbx create claude (no path) Only the container’s own filesystem, starting in /home/agent/workspace Inside the sandbox; deleted when you remove it Copy results out with sbx cp

Direct mode is what the example uses, because you want the fix in your tree. You review it with an ordinary Git diff, which is why the prerequisites asked for a clean status.

Read-only extras are for reference material: docs, a shared library, a sibling service the agent should read but not touch. The sbx create claude reference adds a useful detail. A read-only argument “may name a single file, which holds that one path out of reach inside a workspace the sandbox can otherwise write.” For example, sbx create claude . /home/dev/src/invoice-api/config/prod.json:ro keeps one file out of reach in an otherwise writable tree. Treat it as a narrow tool; keeping agents away from secret files in general is a bigger topic than this guide covers.

Clone mode works well for several agents on one repository, or whenever you’d rather review commits than live edits. A few rules apply at create time. Clone mode can’t be changed after the sandbox exists. The primary workspace must be a Git repository. It’s rejected from any Git worktree other than the main one. And the clone follows whatever ref your host has checked out; it doesn’t create a branch.

sbx create --clone --name invoice-clone claude .
sbx run --name invoice-clone
# afterwards, on the host
git remote -v
git fetch sandbox-invoice-clone
git log --oneline sandbox-invoice-clone/main

The remote name sandbox-invoice-clone follows the documented sandbox-<name> pattern. The last line assumes the host had main checked out when you created the sandbox and that the agent committed there. Substitute whatever ref the agent actually used.

No workspace is for scratch work, like trying out a library or reproducing a bug from a description. Files there survive stops and disappear on sbx rm. Copy out anything worth keeping with sbx cp invoice-scratch:/home/agent/workspace/output.log ./. The sandbox path must be absolute.

To pick a mode, ask one question per row: should this agent’s keystrokes land in my tree right now? If yes, use direct. If you want a review step first, use clone. If the material is reference only, use :ro. If the task doesn’t touch anything of yours, pass no path.

Step 4: Narrow the network to the hosts this task needs

With Locked Down in place, start by reading what the agent’s kit has already added. Docker notes that built-in agent kits and other kits can add per-sandbox allow rules, even under Locked Down. The preset isn’t an explicit deny that overrides them.

sbx policy ls invoice-claude --source kit --type network --wide

Then add only what the task needs, and scope each rule to this sandbox with --sandbox so it doesn’t apply to every future sandbox on the machine. The sbx policy allow network reference accepts a comma-separated list of hostnames, wildcard domains, IP addresses or CIDR prefixes, each with an optional port.

# package registry and model API, this sandbox only
sbx policy allow network --sandbox invoice-claude "registry.npmjs.org,api.anthropic.com"

# read-only GitHub API access to one repository's paths
sbx policy allow network --sandbox invoice-claude api.github.com --method GET --path '/repos/acme/invoice-api/**'

# git over SSH is non-HTTP TCP, so it needs a host:port rule
sbx policy allow network --sandbox invoice-claude "github.com:22"

# test before handing the agent a task
sbx policy check network --sandbox invoice-claude registry.npmjs.org
sbx policy check network --sandbox invoice-claude example.org
  1. List kit rules first. If the model API is already there, you don’t need to add it. If it isn’t, the agent can’t reach its model under Locked Down.
  2. Allow exact hosts before wildcards. "*.npmjs.org" is valid, but registry.npmjs.org is the host npm install actually contacts. Start narrow, and widen only after sbx policy log shows a blocked request you really need.
  3. Use method and path rules for APIs where reads are enough. Quote the path so your shell doesn’t expand the wildcard. A path without a method is rejected. Each rule takes one path, and --method ANY matches every method.
  4. Add a host:port rule for SSH and other non-HTTP TCP. HTTP rules take hostnames. For an IP address or a CIDR range, add a plain network rule.
  5. Run sbx policy check network. It reports Allowed or Denied, and it exits non-zero on Denied. It only evaluates the host, not the method or path, so a host can show Allowed while an HTTP rule still refuses a specific POST.

Diagram of the Docker Sandboxes host proxy deciding an outbound request from a sandboxed agent: a matching deny rule leads to Blocked, a matching allow rule to Connects, and no matching rule to Approval required. A side panel explains that under org governance only org allow rules grant access.Diagram of the Docker Sandboxes host proxy deciding an outbound request from a sandboxed agent: a matching deny rule leads to Blocked, a matching allow rule to Connects, and no matching rule to Approval required. A side panel explains that under org governance only org allow rules grant access.
Deny beats allow at the host proxy. A request no rule matches is held for approval, and under organization governance local allow rules go inactive while local deny rules still apply. Original diagram based on Docker Docs' Local policy and Network access policies pages, fetched Oct 21, 2026.

Deny beats allow. Deny rules take precedence over allow rules. That’s how you remove a destination a kit allowed: sbx policy deny network --sandbox invoice-claude openrouter.ai. You can also set deny rules when you create the sandbox with --deny-network. The create reference calls this safe under centralized governance “because a local deny can only narrow, never widen, egress.”

If you want a sandbox with no outbound traffic at all, sbx policy deny network --sandbox <name> "**" should work, based on two documented facts: deny rules take the same host patterns as allow rules, and deny wins. Docker’s pages don’t show that exact command, though. Before relying on it, run sbx policy check network against a host the kit allows and confirm it comes back Denied.

What’s always blocked. ICMP is blocked, so a failing ping inside a sandbox is expected, not a misconfiguration. UDP is experimental and off by default. UDP to local-network destinations such as multicast is blocked before any policy is checked.

Requests no rule matches become approvals. Without organization governance, a request that matches no rule is denied once and queued for your approval, as the network access policies page explains. The sandbox gets a message like Approval required for api.example.com. Run sbx policy approval ls, then sbx policy approval respond <id> --option allow or --option dismiss. An approval covers that exact destination and port for that sandbox only. It applies to later requests, so run the blocked operation again afterwards. Approved destinations stay allowed until you remove them; list them with sbx policy ls --wide --created-via approval.

When your organization governs policy. Only organization allow rules grant access. Your local allow rules become inactive, and sbx policy ls hides them unless you add --include-inactive, which lists them with an inactive status. Local deny rules still apply, so you can still narrow access. If a task needs a host the organization doesn’t allow, an admin has to change the organization policy. Another local rule won’t help.

Step 5: Run a kit instead of a built-in agent

The kits documentation explains that claude and codex are already kits: the built-in agent names are shortcuts for kit references. Kits are an Early Access feature, and the create reference marks the --kit flag for mixins as experimental. Any kit can declare network rules, credential bindings and startup commands, so review it like code you’re about to run.

# a published v3 workload, pinned to a version tag
sbx run docker.io/docker/sbx-kit-codex:0.155.1 --name codex-v3-kit

# the BAND kit from Docker's Oct 21 post, pinned
sbx create --name band-repo-doctor docker.io/bandhq/band-python-kit:6.0.0 "$PWD"
sbx policy ls band-repo-doctor --source kit --type network --wide

# a local mixin added to the built-in claude agent
sbx create --name invoice-tools claude . --kit ./my-mixin/

# a kit from a Git repository; quote it because of the &
sbx run "git+https://github.com/<ORG>/<REPOSITORY>.git#ref=<COMMIT>&dir=my-agent"

The BAND post announces the kit at docker.io/bandhq/band-python-kit:latest, but its own walkthrough pins 6.0.0. Use the pinned tag or a digest. The kits page warns that a latest tag can move to a kit that needs a newer sbx release. The post also says the kit “already permits access to BAND and the Python package hosts.” Its example adds api.anthropic.com with a sandbox-scoped allow rule, then uses sbx policy log to confirm the requests match the intended policy. It stores secrets with sbx secret set-custom, which keeps the real keys on the host and gives the agent only placeholder values.

Docker blog post titled Your Agent Runs in a Docker Sandbox. Now It Can Join a Team., captured from docker.com.
Docker's blog post of October 21, 2026, captured from docker.com, which announces the BAND AI kit for Docker Sandboxes. The capture shows the top of the post. · Original source

Before you run any kit that isn’t a built-in agent, go through this checklist.

  • [ ] The reference is pinned to a version tag or a digest, not latest.
  • [ ] You’ve read the publisher’s documentation for the hosts the kit contacts, the credentials it asks for and the commands it runs at startup.
  • [ ] After sbx create, sbx policy ls <name> --source kit --type network --wide shows only hosts you expected. Any surprise gets a sbx policy deny network --sandbox <name> <host>.
  • [ ] You approve credential bindings one at a time. Storing a secret doesn’t give a third-party kit permission to use it.
  • [ ] Where signatures matter, sbx kit verify passes against the publisher’s signing identity, and kit.requireSignature is turned on.
  • [ ] Remote sources stay within kit.allowedSources, which defaults to Docker Hub.

Write the decision down where your team can see it. For the worked example the record is short:

Sandbox Kit reference Why this kit Kit network rules reviewed Extra rules added Credentials
invoice-claude built-in claude The task needs only Claude Code and the repo’s toolchain Yes, via the --source kit listing registry.npmjs.org, api.anthropic.com, GitHub GET on one repo, github.com:22 /login OAuth; token stays on the host
band-repo-doctor docker.io/bandhq/band-python-kit:6.0.0 The agent must join a BAND room Yes; BAND and Python package hosts api.anthropic.com sbx secret set-custom, scoped to the sandbox

A sandbox keeps the kit configuration it was created with. To try a different kit or set of mixins, create a new sandbox under a new name.

The whole worked example in three copyable scripts

Here is the complete invoice-claude example as files you can save and adapt. Each command uses the syntax documented on the Docker pages cited above. We haven’t run these scripts against a live sandbox, so the comments describe what the documentation says should happen, not captured output. Change the three variables at the top of each script for your own repository.

The example splits into three scripts because of how sandboxes behave. After sbx create, the sandbox stops when no session keeps it running, and sbx exec works on a running sandbox. So you set up first, attach the agent in one terminal, run the in-sandbox checks from a second terminal while the agent session is open, and tear down at the end.

Script 1, 01-setup.sh: run before the agent starts.

#!/usr/bin/env bash
# 01-setup.sh: illustrative; documented sbx syntax, not a captured run
set -euo pipefail

REPO=/home/dev/src/invoice-api
DOCS=/home/dev/src/api-style-guide
NAME=invoice-claude

# 0. Refuse to start from a dirty tree, so every later diff is the agent's
if [ -n "$(git -C "$REPO" status --porcelain)" ]; then
  echo "Commit or stash changes in $REPO first" >&2
  exit 1
fi

# 1. Global preset. One-time setup: run this line on a fresh machine only.
#    Use 'sbx policy reset' if you need to choose again.
# sbx policy init deny-all
sbx policy ls

# 2. Create without attaching: explicit primary workspace, read-only docs
cd "$REPO"
sbx create --name "$NAME" claude . "$DOCS:ro"
sbx ls   # WORKSPACE column should show $REPO

# 3. See what the agent kit already allows, then add only this task's hosts
sbx policy ls "$NAME" --source kit --type network --wide
sbx policy allow network --sandbox "$NAME" "registry.npmjs.org,api.anthropic.com"
sbx policy allow network --sandbox "$NAME" api.github.com \
  --method GET --path '/repos/acme/invoice-api/**'
sbx policy allow network --sandbox "$NAME" "github.com:22"

# 4. Prove the policy before any agent session exists
sbx policy check network --sandbox "$NAME" registry.npmjs.org   # expect Allowed
if sbx policy check network --sandbox "$NAME" example.org; then
  echo "example.org is reachable: the policy is broader than intended" >&2
  exit 1
fi
echo "Setup done. Attach with: sbx run --name $NAME"

Then, in terminal one, attach with sbx run --name invoice-claude, run /login, and give the agent this task: “Run npm test, find the one failing test, fix the code (not the test), and run npm test again. Read the style guide at /home/dev/src/api-style-guide but do not change it.”

Script 2, 02-verify.sh: run from terminal two while the agent session is open.

#!/usr/bin/env bash
# 02-verify.sh: illustrative; run while 'sbx run --name invoice-claude' is attached
set -uo pipefail

REPO=/home/dev/src/invoice-api
DOCS=/home/dev/src/api-style-guide
NAME=invoice-claude
fail=0

# Check 1: the agent's default working directory is the host path
sbx exec "$NAME" -- pwd            # expect /home/dev/src/invoice-api

# Check 2: the :ro mount refuses writes
if sbx exec "$NAME" -- touch "$DOCS/probe"; then
  echo "FAIL: $DOCS is writable inside the sandbox" >&2
  fail=1
fi
[ -e "$DOCS/probe" ] && { echo "FAIL: probe file reached the host" >&2; fail=1; }

# Check 3: the allowed registry is reachable from inside
sbx exec "$NAME" -- npm view left-pad version || { echo "FAIL: npm registry blocked" >&2; fail=1; }

# Check 4: a host that isn't on the list is refused
if sbx policy check network --sandbox "$NAME" example.org; then
  echo "FAIL: example.org is allowed" >&2
  fail=1
fi

# Check 5: every outbound request so far matched a rule you wrote or a kit rule you reviewed
sbx policy log

exit "$fail"

Script 3, 03-teardown.sh: run after you’ve reviewed the result.

#!/usr/bin/env bash
# 03-teardown.sh: illustrative; documented sbx syntax
set -euo pipefail

REPO=/home/dev/src/invoice-api
NAME=invoice-claude

# 1. Review what the agent changed in the bind-mounted tree
git -C "$REPO" status --short
git -C "$REPO" diff --stat

# 2. Remove this sandbox's rules while its name still identifies them
sbx policy rm network --sandbox "$NAME" --resource registry.npmjs.org
sbx policy rm network --sandbox "$NAME" --resource api.anthropic.com
sbx policy rm network --sandbox "$NAME" --resource api.github.com \
  --method GET --path '/repos/acme/invoice-api/**'
sbx policy rm network --sandbox "$NAME" --resource "github.com:22"

# 3. Stop, then remove the sandbox (sbx rm asks for confirmation)
sbx stop "$NAME"
sbx rm "$NAME"

# 4. Preview any other stopped sandboxes you may want to prune
sbx prune --dry-run

How to read the results of the three scripts:

Script Line What the docs say you should see What a different result means What to do
01-setup.sh sbx ls invoice-claude with /home/dev/src/invoice-api under WORKSPACE An empty WORKSPACE means a mountless sandbox Check the . argument, sbx rm, rerun
01-setup.sh kit listing A short list of agent-kit hosts, possibly including the model API Hosts you can’t explain sbx policy deny network --sandbox invoice-claude <host>
01-setup.sh check ... example.org Denied, with a non-zero exit, so the script continues Allowed: an Open preset or a broad wildcard is in effect Inspect sbx policy ls --wide; consider sbx policy reset
02-verify.sh touch "$DOCS/probe" A read-only filesystem error and a non-zero exit The write succeeded, so :ro was missing Remove and recreate with "$DOCS:ro"
02-verify.sh npm view A version number printed Approval required for registry.npmjs.org The allow rule is missing or inactive under org governance; check --include-inactive
02-verify.sh sbx policy log Entries only for hosts you allowed or reviewed An unexpected host Deny it and find out why the agent wanted it
03-teardown.sh git diff --stat Changes only under the source files the fix needed Edited tests, lockfiles or config git restore those paths, then rerun with a narrower task or a :ro file mount

The example uses npm view left-pad version as a harmless registry probe: it reads package metadata and changes nothing in the repository. Any read-only request to an allowed registry works as well. If set -e in Script 3 stops on a policy rm line, that rule was probably already removed; delete the line and run again.

Verify the boundary before you hand over a task

Run these checks from your second terminal once the sandbox exists, before you give the agent real work. Script 2 automates most of them. The expected results come from Docker’s documentation. If you see something different, stop and fix the configuration first.

# Check Command Expected result If you see something else
1 The agent sees the workspace at the host path sbx exec -it invoice-claude bash, then pwd The shell starts in /home/dev/src/invoice-api, and sbx ls lists that path under WORKSPACE No path means a mountless sandbox; recreate it with .
2 The :ro mount refuses writes sbx exec invoice-claude -- touch /home/dev/src/api-style-guide/probe The command fails with a read-only error and a non-zero exit, and no probe file appears on the host The :ro suffix was missing; recreate the sandbox
3 An allowed registry is reachable sbx policy check network --sandbox invoice-claude registry.npmjs.org, then npm install inside The check reports Allowed and the install completes Read sbx policy log for the blocked host and add it
4 A host that isn’t on the list is refused sbx policy check network --sandbox invoice-claude example.org Denied, with the reason no matching allow rule (default deny), and a non-zero exit A broad wildcard or the Open preset is in effect; inspect sbx policy ls --wide
5 Clone-mode commits reach the host git fetch sandbox-invoice-clone, then git log on the fetched ref The agent’s commits appear on the remote-tracking branch Have the agent commit inside the sandbox first, or check which ref the clone followed
6 Only the intended hosts were contacted sbx policy log after the task Every entry is a host you allowed, matched to the rule you expected Deny the stray host and find out why the agent wanted it

Check 4 is the one people skip. A Denied result with a non-zero exit is the clearest single sign that the policy does what you wrote, which is why Script 1 fails the setup if that check comes back Allowed.

Troubleshooting: symptom, cause, fix, and what you should see after

Symptom Likely cause Fix What you should see after the fix
The agent says the project is empty after sbx create No path was passed, so the sandbox is mountless sbx rm invoice-claude, then sbx create --name invoice-claude claude . sbx ls shows the repository under WORKSPACE
npm install fails, or the agent reports Approval required for registry.npmjs.org Locked Down with no matching allow rule sbx policy allow network --sandbox invoice-claude registry.npmjs.org, or respond to the entry in sbx policy approval ls sbx policy check network reports Allowed and the retried install goes through
git push over SSH hangs or is refused Non-HTTP TCP needs a host:port rule sbx policy allow network --sandbox invoice-claude "github.com:22", or switch the remote to HTTPS with sbx secret set github --command 'gh auth token' The push connects, and sbx policy log shows the :22 rule matched
A local allow rule changes nothing Organization governance is active Run sbx policy ls and look for Governance: Managed by <org>; confirm with --include-inactive; ask your admin The rule shows as inactive; access opens only after the org policy changes
Old experiments still allow hosts you’d forgotten Local rules and approvals have piled up sbx policy reset (add --force to skip the prompt); running sandboxes will stop The preset prompt comes back and sbx policy ls shows only the new baseline
A GET works but a POST to the same API is refused An HTTP method or path rule Run sbx policy ls --type http to find it You can see which method and path rule applies
You need clone mode on an existing sandbox Clone mode is fixed at create time Remove the sandbox and recreate it with sbx create --clone git remote -v on the host lists sandbox-<name>

Tear down, recover and start over

Sandboxes persist after the agent exits. Installed packages, images and configuration survive restarts. When the task is done, or when it went wrong, clean up in this order. Script 3 covers steps 2, 4, 5 and 6 for the direct-mode example.

  1. Save clone-mode work first. Removing a clone-mode sandbox deletes the clone inside it. Run git fetch sandbox-invoice-clone, then merge or cherry-pick what you want to keep.
  2. Review direct-mode changes on the host. git diff and the test suite decide whether the fix stays. The agent’s changes are already in your tree, so git restore or git stash is your undo.
  3. Copy out anything you need from a mountless sandbox with sbx cp.
  4. Remove sandbox-scoped rules you won’t reuse with sbx policy rm network --sandbox invoice-claude --resource registry.npmjs.org, once per resource. Do this before you remove the sandbox, while its name still identifies the rules.
  5. Stop, then remove. Run sbx stop invoice-claude, then sbx rm invoice-claude. sbx rm asks for confirmation. --force skips the prompt and also removes a sandbox that has an active session.
  6. Clear stopped leftovers. sbx prune --dry-run shows what would go, and sbx prune removes all stopped local sandboxes. Running sandboxes are never pruned.
  7. Tidy the Git remote. If git remote -v still lists sandbox-invoice-clone, remove it with git remote remove sandbox-invoice-clone.
  8. Reset the policy only if you want a clean slate. sbx policy reset removes all local rules and approvals and asks you to pick a preset again.

When a run fails, don’t loosen the rules inside the failed sandbox and carry on. Remove it and rerun with a narrower setup: a :ro mount instead of read-write, clone mode instead of direct, or one fewer allowed host. For repeated throwaway work, sbx run --rm claude removes the sandbox when the agent exits.

You’ve succeeded when you can show three things. The task finished inside the sandbox. git diff (or the fetched clone ref) touches only the paths you intended. And sbx policy log lists only the hosts you allowed.

Where this sits among your other agent controls

A microVM boundary is a strong default, but it’s only one layer. The sandbox escapes covered in The Sandbox Is a Suggestion show why the boundary has to cover credentials and instruction files, not just tool calls. Docker Sandboxes keeps secrets on the host proxy, which handles part of that list. A sandbox won’t fix a broken toolchain either. Golden images and lockfiles belong in the environment readiness gate, and a saved sbx template can carry them into the sandbox.

If the threat model is new to you, start with Securing AI Agents. For unattended runs, the headless trust tier explains why the flags you launch with matter more there than at your desk. Inside Claude Code itself, the power user’s field guide covers hooks and permission modes that work alongside a sandbox. Treating permission modes as fleet policy shows how to keep every machine configured the same way. sbx policy log tells you what the network did; fleet replay covers keeping the session records that tell you what the agent did.

Sources

YOU'RE THROUGH THIS ONE.

Keep connecting the dots.

Back to the library