Container, microVM or full VM: choosing a box for a coding agent
When you let a coding agent work without asking, the box it runs in becomes the safety. The choices run from rules on what one process may touch to a separate virtual machine. They differ in two ways that matter: what they share with your computer, and what the agent can still do inside them.
What you're keeping the agent away from
Three things, in order of how often they bite:
- Your files and keys. In the seven agent disasters we reviewed, the damage was accidental: a cleanup command with one path too many, a token found in the wrong file.
- Your kernel. Hostile code attacks whatever it shares with you, and unless the box has its own kernel, it shares yours.
- The network. Anything the agent can read and send out can leave.
Emil Burzo put the usual goal plainly: "This setup is about preventing accidents, not sophisticated attacks." Decide which one you're guarding against before you pick.
The options side by side
Shayon Mukherjee's walk through the layers of isolation is the clearest map, and this table follows it:
| Box | What separates it from your computer | Shares your kernel? |
|---|---|---|
| Process sandbox | Rules on what one process may read, write and reach | Yes |
| Container | Namespaces, cgroups and a system-call filter | Yes |
| gVisor | A kernel in user space that answers most system calls itself | Through about 70 kinds of call |
| MicroVM | Its own kernel under hardware virtualization, with a small monitor | No |
| Full VM | Its own kernel and a complete virtual machine | No |
Process sandboxes and containers
The lightest options keep the agent on your computer and fence it in. Claude Code's /sandbox wraps its shell commands with Seatbelt on macOS or bubblewrap on Linux. Anthropic's sandbox runtime, srt, wraps the whole Claude Code process, file tools and MCP servers included (guide). On macOS, Agent Safehouse, Eugene's open-source project, does a similar job for over a dozen agents: it starts from deny-everything and blocks ~/.ssh and ~/.aws by default. These start instantly. Their weak point is that everything you care about stays on the same disk, one configuration line away.
Containers go further, but Mukherjee's warning holds: namespaces "are visibility walls, not security boundaries." A container shares your kernel, so a kernel bug or a runtime escape crosses it. Against accidents that's fine. tim's setup for Claude Code in a dev container gives the agent the project and a fine-grained GitHub token for chosen repositories, and no SSH keys from the host. Anthropic's reference dev container runs Claude Code as a non-root user behind a firewall that allows only listed destinations, which is what makes skipping permission prompts reasonable there. Its docs name the catch: the mounted workspace is your real files, changed live.
gVisor and microVMs
gVisor puts a kernel written in Go, running in user space, between the agent and yours. Per Mukherjee, it handles about 200 system calls itself and makes about 70 kinds of call to the host, at a cost for work heavy in system calls and disk I/O.
A microVM gives the agent its own kernel, under a virtual machine monitor kept deliberately small, such as Firecracker. Michael Stapelberg runs coding agents in microVMs on his NixOS desktop with microvm.nix and cloud-hypervisor. Each boots within a few seconds, its writable root disappears at shutdown, and the project folder is shared in from the host. Docker Sandboxes run each agent in a microVM with its own Docker daemon, and send traffic out through a proxy on the host that swaps a stand-in for the real API key, so the key never enters the box:
sbx run claude # from the project folder
Fly.io's Sprites are created in one to two seconds, according to Kurt Mackey, because each server keeps a pool of empty ones ready, as Thomas Ptacek explains.
A full VM
A full VM is the heaviest box and the most familiar. Anthropic's guide to sandbox environments calls a dedicated VM, with its own kernel, the strongest separation, and suggests one for untrusted repositories. Burzo's setup is a good model: Vagrant and VirtualBox, Ubuntu 24.04, 2 CPUs and 4 GB, the project in a synced folder, and Claude Code inside with sudo and no permission prompts. He lists what it doesn't cover just as plainly: the synced project itself (git covers that), an escape by a determined attacker, the network, and data leaving over it.
It isn't absolute. For Trail of Bits, Artem Dinaburg set GPT 5.6-Cyber, running in Codex, to escape the QEMU/KVM guest he used as a sandbox on his Debian 12 machine, and it worked at the task for roughly 12 hours. He counts three escapes: first through recently disclosed bugs in his host kernel; then, once he had updated, through disclosed bugs whose fixes hadn't yet reached his packages; and, after he rebuilt QEMU and its libraries from the latest sources, through several bugs nobody had found before. Against Firecracker it only locked up the host, though he notes it might have done more with more time. His advice: keep the surface small, update fast, give agents the least network access and credentials they need, and start each session clean.
When the agent needs Docker itself
Real projects run Postgres in a container, build images and use Compose. Inside a container, that means Docker-in-Docker, which usually needs --privileged. Mukherjee notes that a privileged container can end up weaker than an ordinary one, and Burzo chose a VM for exactly this reason. A microVM with its own daemon, or a full VM, avoids the problem. Docker runs as it would on any server, and the usual command works:
docker compose up -d --wait # returns once the containers are healthy
What none of them fix
Two things cross every boundary on this list:
- The network. Anthropic's guide warns that any option with outbound access can leak whatever the agent can read. An allowlist, as in the reference dev container, or a proxy that holds the keys, as in Docker Sandboxes, narrows it.
- The keys you hand in. A token you put in the box goes wherever the agent sends it. As tim did, scope it to the job, and revoke it when the job is done.
Isolation also doesn't change what goes to the model. Files the agent reads are still sent to its provider.
Our choice, with its numbers
Every shedix machine is a full VM on Google Compute Engine. That choice costs time: a new machine is ready in about 60 to 110 seconds (we measured Web at 80 s, Python at 59–113 s, and Go & Rust at 80 s), against a second or two for a microVM taken from a ready pool.
What it buys:
- its own kernel and systemd, with sudo, and nothing of yours on it;
- Docker without
--privileged: Postgres 16 pulled in 9.6 s and Redis 7 in 4.8 s on a machine; - Playwright with Chromium on the web stack;
- a disk that survives a stop, so installed dependencies stay;
- a network where machines can't reach each other, and no cloud service account on the machine.
With our guide, a fresh agent had a Python project with Postgres answering in 3 minutes 2 seconds from its first command.
The limits are the ones above. Outbound traffic is open. Sign-ins you add live on the machine, and copies of it carry them. Trail of Bits' point applies too: a VM is only as safe as its patches. Google runs and patches the hypervisor, and wrote in 2017 that Compute Engine doesn't use QEMU. The system inside the machine starts from our image, which we rebuild by hand.
If you run untrusted code at scale, or want a fresh box per task in a second, a microVM service is the better fit. If you want a machine an agent can live on for days, with Docker and a disk that stays, a full VM is simpler. Real Ubuntu shows how shedix machines are set up, and the security page lists what's isolated and what isn't.