Sandboxing AI Coding Agents

Isolate agents so you can grant broad permissions without risking your host.

Mac darwin

Recommended: Lima VM

Runs agents inside a managed Debian VM. On Apple Silicon, Lima uses Apple's Virtualization.framework — near-native performance, fast boot, low overhead. One VM serves every workspace you have.

  • Only your managed repos are visible. ~/.baton/repos (repos + worktrees) is mounted into the VM. ~/.ssh, ~/.aws, browser state, host credentials — all invisible to the agent.
  • SSH agent forwarding. Without it, local git work (commit, branch, merge, diff) works perfectly fine inside the VM — only remote-facing actions like git push or private-repo clones fail. You can do those through Baton's UI or from a host terminal instead. Enable forwarding to let the agent push directly: only signing requests cross the boundary; your keys never leave the host.
  • Restrict sudo. Depends on what you need the agent to do. If it should be able to install system packages or edit system files inside the VM, leave sudo unrestricted. For normal development where root isn't needed, turn on "Restrict sudo" to block the agent from making system-level changes.
  • Port forwarding. VM-side services (a dev server the agent spins up, a database running in the VM, etc.) become reachable at http://localhost:… on the host — convenient for hitting them from your browser or other tools. Risk is low but not zero: anything the VM binds to localhost is exposed to every process on your host. Turn off if you want strict containment.
  • Resource-efficient at scale. One VM across N workspaces and M agents is far lighter than Docker-per-workspace, especially on Mac (where Docker already runs inside its own VM — you'd pay the VM tax plus per-container tooling).
  • Easy dependency management. It's just Debian. apt install whatever you need. Baton preinstalls Claude Code, Codex, ripgrep, jq, fzf, python3, and a handful of other standard tools.
  • Memory caveat. Allocated VM memory doesn't return to the host quickly. Start with a modest allocation — if agents feel sluggish or crash, bump memory (or CPUs / disk) in Settings → Sandboxing and restart the VM.

Setup: Settings → Sandboxing → toggle "Containerized agents" → expand "Lima Virtual Machine" → "Set up VM".

Reaching host services from the VM. The host is accessible at host.lima.internal, but most dev services (Postgres, Redis, Node dev servers) bind to 127.0.0.1 by default, which isn't routed into the VM. Two fixes: rebind the service to 0.0.0.0 or the Lima gateway IP (192.168.5.2 on vz) so it's visible on the VM network, or run the service inside the VM itself.

Alternative: Safehouse

Safehouse wraps a command in a macOS sandbox-exec profile restricting filesystem access to allowlisted paths. Lighter than a VM but same-kernel — weaker isolation than Lima.

Baton ships a preconfigured template. Add it from Settings → Sandboxing → Sandbox Methods and select it on workspace creation.

Also good: built-in agent sandboxing

Some agents have meaningful protections built in. Claude Code combines per-command permission prompts, its own OS-level sandboxing, and an auto-accept mode whose AI classifier gauges command risk before running — together that's a solid baseline. Codex CLI ships with explicit sandbox modes (read-only, workspace-write, full-access). These apply only within the agent itself, but for day-to-day development they're often enough on their own. For unattended bypass-permissions runs, pair with Lima or Safehouse.

Linux linux

Recommended: Lima VM

Same Lima-based sandbox as Mac. Install limactl from your package manager (apt install lima, pacman -S lima), then follow the setup flow in Settings → Sandboxing.

Also good: built-in agent sandboxing

Same as Mac — Claude Code's sandbox + classifier and Codex CLI's sandbox modes are often enough for day-to-day development. Pair with Lima for unattended bypass-permissions runs.

Windows win32

No managed VM sandbox yet. Custom methods and built-in agent sandboxing work normally.

Recommended: built-in agent sandboxing

Claude Code's sandbox + classifier and Codex CLI's sandbox modes work the same on Windows and cover most day-to-day development. Pair with a dedicated WSL2 distro (below) for unattended bypass-permissions runs.

Stronger isolation: dedicated WSL2 distro (manual)

A dedicated WSL2 distro reserved for agents gives kernel-level isolation comparable to Lima. We don't have an automated flow yet; rough shape:

  • Distro. Create a separate distro used only for agents. In its /etc/wsl.conf, disable Windows drive automount ([automount] enabled = false) and Windows binary interop ([interop] enabled = false), then restart the distro (wsl --terminate <distro>).
  • Mounts. Expose the same paths Lima does, matching its read-only / read-write split. Read-write: %USERPROFILE%\.baton\repos and %USERPROFILE%\.baton\worktrees. Read-only: %USERPROFILE%\.baton\settings, %USERPROFILE%\.baton\skills, %USERPROFILE%\.baton\vm-shared. With automount disabled you'll mount them manually with mount -t drvfs or entries in /etc/fstab.
  • Wire it up in Baton. In Settings → Sandboxing → Sandbox Methods → Add method:
    • Wrap command: wsl -d agents -- bash -lc "{{command}}"
    • Shell command: wsl -d agents
    • Notify host: the Windows host IP reachable from the distro — usually the default gateway. Find it from inside the distro with ip route show default (the IP after via).
  • Agent notifications (manual). For Lima, Baton automatically writes Claude Code's hook entries inside the VM so agent notifications bubble up to the host. For custom methods there's no equivalent automation — you'll need to configure your agent's hooks inside the distro yourself.

Setting this up — or already running something similar? Reach out. We want to turn WSL2 into a first-class sandbox method (automatic distro provisioning, notifications, MCP), and both working setups and in-progress attempts are the most useful input we can get.

Custom sandbox methods

A sandbox method configured under Settings → Sandboxing → Sandbox Methods has three fields:

  • Wrap command — shell template with a {{command}} placeholder. Example (Safehouse):
safehouse --add-dirs=~/.baton/repos --add-dirs-ro=~/.baton/notify.js:~/.baton/port:~/.baton/baton-node -- {{command}}  
  • Shell command (optional) — what to run for a plain terminal tab in this sandbox.
  • Notify host (optional) — hostname the sandboxed process uses to reach Baton's HTTP server, which backs agent notifications and the Baton MCP server. Blank for same-host (e.g. Safehouse); host.docker.internal for Docker.

Any wrapper that accepts a shell command via argv works — Docker, Podman, systemd-nspawn, bubblewrap, firejail, custom scripts.

Docker Sandbox (sbx)

Docker's sbx CLI launches agents inside an isolated per-project micro-VM with preinstalled tooling, network-policy enforcement, and optional Git worktree isolation via --branch. It's an agent launcher (sbx run claude <workspace>) rather than a shell-command wrapper, so it doesn't slot in here as a sandbox method — configure it as an alternate launch mode on your agent preset instead ( Settings → Agent CLIs → ) that invokes sbx run in place of the default agent binary. Anything the agent needs from your host is reachable at host.docker.internal, and dev-server ports can be exposed with sbx ports <sandbox> --publish <host>:<sandbox> when you want them in your browser.

More questions?

Get in touch — we're actively working on this area.