Skip to content

ca-sandbox: Explore Untrusted Code

ca-sandbox is one of codeArbiter’s four sibling plugins (ADR-0007). But unlike ca, ca-codex, and ca-pi, it is not a governance host. It carries no gates, no .codearbiter/ orchestration, and no relationship to the test-first/review/commit-gate pipeline the rest of this site documents. It is an infrastructure plugin with one job: run code you do not trust without exposing your machine.

Give it a repo URL and it clones into a Docker named volume, builds an image, and starts an execution container. These are different boundaries: acquisition and builds can use the network; build preparation copies source into a host temporary directory named ca-sbx-checkout-* and attempts cleanup afterward. Failed cleanup can leave that copy on the host. The execution container’s no-bind-mount/offline policy does not mean source never reaches the host or that acquisition was offline. Review the privacy policy for storage, credentials and retention before handling sensitive or untrusted material.

ca-sandbox is a Feature Forge preview plugin. Its automated suite is green, but the --with-claude path (running Claude Code inside the box) is verified only against a dummy token, not yet a real interactive session. See What’s in the Forge for the fuller writeup and how to help promote it.

The isolation holds by construction, not by trust:

  • No bind mounts: the repo lives on a named Docker volume at /work/repo, dependencies out-of-tree at /deps.
  • No /var/run/docker.sock mount; never --privileged.
  • --cap-drop ALL, --security-opt no-new-privileges, read-only root filesystem, non-root user, resource caps.
  • Explicit execution-output export is host-initiated (sandbox cp, a docker cp pull); the execution container has no bind-mounted export directory. This is separate from the host temporary source copy used during build preparation.
  • Network defaults to offline (--network none); clone-then-cut allows egress for the clone/build only, then severs it; an experimental allowlist mode exists but is not the recommended posture.
  • A working Docker engine (Linux containers): Docker Desktop (Windows/macOS, WSL2 backend) or native Linux.
  • nixpacks on PATH, or on Windows inside a WSL distro (see the ca-sandbox README for the WSL-bridge build path). Without it, ca-sandbox falls back to a generated Dockerfile with narrower stack coverage.

Register the self-hosted marketplace first if codearbiter is not already listed, then install the sandbox sibling:

/plugin marketplace add arbiterForge/codeArbiter
/plugin install ca-sandbox@codearbiter

The sandbox plugin is Claude Code-specific and has its own /ca-sandbox: namespace. It does not activate through .codearbiter/.

Start with the default offline policy:

/ca-sandbox:sandbox "https://github.com/owner/repository"

The command checks Docker, clones into a named volume, builds the dependency-cached image, and returns a sandbox ID. Save that ID for the remaining commands.

Before running untrusted code, inspect the reported container configuration. It should have no bind mount, no Docker socket, no privileged mode, all capabilities dropped, a read-only root filesystem, and --network none.

/ca-sandbox:sandbox-shell "<id>"
/ca-sandbox:sandbox-exec "<id> -- npm test"

Use sandbox-shell for interactive exploration. Use sandbox-exec for a bounded, scriptable command that returns separate stdout, stderr, exit code, and a truncation flag.

On Git Bash, wrap container paths to prevent MSYS rewriting:

/ca-sandbox:sandbox-exec "<id> -- sh -c 'ls /work/repo'"

PowerShell and cmd do not need that workaround.

Copy only the artifact you intentionally want:

/ca-sandbox:sandbox-cp "<id>:/work/repo/report.json ./review/report.json"

The host invokes docker cp; the container never receives a host path. Inspect the copied file as untrusted data before opening it with a privileged application.

Then tear the box down:

/ca-sandbox:sandbox-destroy "<id>"

Destroy removes the container and named volume and reports any failed Docker operation. A non-zero result is not success: use the destroy command’s --prune recovery path and confirm no objects with the ca.sandbox=1 label remain. --keep-volume deliberately retains source state and therefore is not a complete teardown.

SymptomLikely causeRecovery
Docker preflight stops
Daemon unavailable or not using Linux containers
Start Docker, confirm docker info, retry
nixpacks is unavailable
Missing host tool or Windows WSL bridge
Install nixpacks in the documented host/WSL location, or accept the narrower fallback
Clone succeeds but later network access fails
Offline or clone-then-cut policy is working
Use the least permissive policy that supports the task; do not jump to experimental allowlist by default
Exec times out
Untrusted process exceeded its bounded operation deadline
Inspect captured output, destroy the box, retry only with a justified narrower command
Destroy reports failures
Docker could not remove one or more labeled objects
Run the explicit prune recovery and verify the remaining-object count

ca-sandbox shares the marketplace with ca, ca-codex, and ca-pi, and its CI is path-scoped and versioned independently of them (ADR-0007). It does not read or write .codearbiter/, and installing or removing it has no effect on gate enforcement in any repository. If you’re looking for the governance hosts instead, see Install, Claude Code + Codex evidence, or Pi.

Full detail, including the Git Bash path-conversion caveat and image-caching behavior, lives in the ca-sandbox README.