Sandboxing AI Coding Agents
Isolate agents so you can grant broad permissions without risking your host.
On this page
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 pushor 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 installwhatever 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\reposand%USERPROFILE%\.baton\worktrees. Read-only:%USERPROFILE%\.baton\settings,%USERPROFILE%\.baton\skills,%USERPROFILE%\.baton\vm-shared. With automount disabled you'll mount them manually withmount -t drvfsor 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 withip route show default(the IP aftervia). -
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, pointing them at Baton's notify script in the mounted
vm-shareddirectory and making sureBATON_NOTIFY_HOSTactually reaches the agent process (typically viaWSLENVon Windows). Reach out and we'll help you stitch it together.
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.internalfor 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 → <agent>) 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.