Chapter · full VMs

Full VMs: when boring actually wins

A VM does not care how clever the agent is. It has its own kernel, its own devices and its own disk, and the only way out is a hypervisor bug or a host service you deliberately exposed. That is worth a gigabyte of RAM.

Why the boring answer keeps winning

Everything else in this guide is a compromise. Containers share the kernel. Process sandboxes share everything and add policy. MicroVMs give you a real kernel but ask you to assemble it. App kernels reimplement Linux and break your tools. WASM cannot run a shell.

A full VM is the only option that is simultaneously complete, well understood, and enforced by hardware. Inside it you can be as sloppy as you like: the agent can have root, install packages, run Docker, break systemd, fill the disk. The blast radius is the guest.

What you are actually paying for it

  • Memory. A usable Linux guest is 1–4 GB, whether or not the agent is doing anything.
  • Boot time. Seconds, not milliseconds. Mitigated by keeping one VM per project alive, or by snapshotting.
  • File sharing. Virtiofs, 9p and shared folders are slower than a bind mount, particularly for many small files. This is the most common day-to-day annoyance.
  • A second machine to configure. Your toolchain, your dotfiles, your editor setup all have to exist inside the guest. This is the cost people underestimate, and it is the reason devcontainer-style reproducibility matters so much in VM setups.

Why it is often closer than you think

On Windows you are probably already running one. WSL2 is a Hyper-V utility VM with a real Linux kernel. On macOS, Lima, UTM, Tart, Multipass and Apple's container runtime all do the same job with different ergonomics — and Lima is not a macOS-only tool: it manages Linux guests on Linux hosts as well, which is where it was tested for this guide. On Linux you have been able to install a hypervisor in one command for twenty years. The "VMs are heavy" intuition comes from desktop virtualisation circa 2010, not from anything current.

GUEST VM — you may be as sloppy as you like in here agent + toolchain (root is fine) containers inside GUI apps + browser guest kernel — separate from the host's snapshot / clone / discard the whole thing HYPERVISOR (KVM · Hyper-V · HVF) hardware virtualisation — the escape has to get through this ONE SHARED FOLDER, READ-ONLY the share list is your exposure list — keep it tiny
The VM trade: give up convenience at the boundary, gain the freedom to let the agent break anything it likes inside. The one place to be careful is the host share, because that is where the boundary is actually porous.

The tools, and which one to pick

QEMU + KVM MATURE

The reference implementation. Complete device emulation, GPU passthrough, snapshots, live migration, virtio-fs — and the largest attack surface in this guide, which is exactly why Kata wraps it in a sandbox. Never drive it by hand; use a manager.

Complaints: ergonomics and size, not correctness. Every problem you hit has a 2014 Stack Overflow answer.

Incus MATURE

The best Linux power-user option. One tool, one API, two isolation levels: LXC system containers and QEMU/KVM VMs, with snapshots, projects, profiles and a pluggable storage backend. On ZFS or Btrfs, forking an agent machine per task is nearly free.

Be precise about which level you are on. An Incus container is an LXC system container: unprivileged by default, so container root maps to an unprivileged host UID — but it shares the host kernel and does not use KVM at all, so a kernel bug is still a host bug. An Incus VM is a real QEMU/KVM virtual machine with its own guest kernel, and that is the one to use for code you would not run as your own user. Both are created from the same CLI, which is convenient and also the reason people mix them up.

Complaints: a learning curve around storage pools and profiles, subordinate-ID mapping that can fail before anything else does, and documentation that assumes you know the LXD lineage. Not available on Windows or macOS hosts.

Full assessment →

Lima MATURE

Declarative Linux VMs on macOS and Linux hosts, with a choice of drivers (Apple's vz, QEMU, or libkrun for GPU) and a YAML template per instance. Lima creates real virtual machines with their own guest kernel — it is not a container tool with VM-shaped marketing. CNCF incubating, and the substrate under Colima, Rancher Desktop, Finch and Podman Desktop.

Windows hosts: Lima also ships Windows-host drivers — wsl2 (since 0.18) and hcs (since 2.3, Windows 11, plain mode only) — and its own documentation labels both experimental with significant restrictions. That is a documented, narrow path rather than a general-purpose one, and our own attempt to use Lima on a Windows host never reached a usable instance (a single anecdote, kept on Field Notes, not a verdict on the project).

Complaints: host/guest file sharing performance, driver-specific behavioural differences, and — on a Linux host with neither /dev/kvm nor another hypervisor backend — a fallback to QEMU's TCG software emulation, which is too slow to use. The first two are configuration problems rather than defects; the third is a property of your host.

Full assessment →

UTM, Tart, Multipass MATURE

UTM is QEMU with a good GUI — the right choice if you want to see your VM. Tart (now hosted under OpenAI's organisation on GitHub) targets fresh disposable Apple-Silicon VMs, which is exactly the shape for per-task agents. Multipass is Ubuntu VMs in one command on all three platforms, and is badly underrated as a cheap hard boundary.

Apple's container runtime TEST FIRST

Version 1.0 landed in June 2026, OCI-compatible, Apple-silicon only, and — critically — it gives each container its own micro-VM through the Virtualization framework. On Apple silicon the container boundary moved from shared namespaces to a hypervisor. Agent tooling is already adopting it as a backend.

Caveats: needs macOS 26 and Apple silicon, no Compose, roughly 4× worse cold start than Docker Desktop, and Apple's CLI rejects some flags (no --security-opt, no --pids-limit), which limits how much hardening you can express.

Windows: Hyper-V and Windows Sandbox TEST FIRST

Hyper-V is a real hypervisor and Microsoft services it as a security boundary — which is more than can be said for process isolation on the same platform. Windows Sandbox is a disposable Hyper-V desktop with a .wsb config file. Both are covered in the Windows chapter, including why Windows Sandbox is stronger but harder to fit into a workflow.

Correction: Lima is not macOS-only

An earlier version of this page described Lima as a macOS tool. It is not. Lima's own documentation says it "also supports non-macOS hosts (Linux, NetBSD, etc.)", and QEMU is the default driver on a Linux host. It is a virtual-machine manager in both cases: the guest gets its own kernel, and the boundary is a hypervisor.

Our own test used Lima 2.2.0 from the Linux x86_64 release inside Linux, and the Alpine instance it created booted through networking — under QEMU's TCG software emulation, because that host had no /dev/kvm and no hardware acceleration was available. TCG was far too slow for the SSH and guest-agent handshake to complete in a practical time, so the instance was removed. That is a statement about the host, not about Lima, and a later run on a Linux host that did expose /dev/kvm is recorded in Field Notes.

The platform caveat that survives is narrower than the one this page originally carried. Windows hosts are supported only through Lima's own wsl2 and hcs drivers, which the project labels experimental and restricts heavily (the hcs path is Windows 11 only, plain mode only, one instance at a time). On Windows, WSL2 remains the useful route to a real Linux boundary, and Lima is not a substitute for it.

Making VMs pleasant enough that you actually use one

1 · One VM per project, kept warm

Booting a VM per task is the wrong pattern; keeping one per project alive and starting agents inside it is the right one. Booting becomes a daily event rather than a per-task one.

2 · Snapshot before you fan out

Take a clean snapshot after provisioning, then clone per agent task. On a copy-on-write backend this is near-instant and costs almost no disk, which turns "I will just let it try" into a cheap decision.

3 · Keep the host share narrow

One directory, ideally read-only, ideally the guest pulling changes rather than pushing them. The share is the only place the boundary is porous, so treat the share list as your exposure inventory.

4 · No credentials in the guest

A VM does not help if your ~/.aws is mounted into it. Broker credentials at the VM's egress, or use short-lived tokens issued to the guest.

5 · Run the agent in a container inside

This is what most experienced users actually do: VM as the outer boundary, rootless Podman inside for cheap disposable lanes, and a process sandbox around the agent as a third wall. Nested isolation is the norm, not paranoia.

6 · Diff on the host, not in the guest

Whatever the agent produces should come back as a reviewable diff. That single habit converts a sandbox from "I hope it is fine" into "I will read what it did", which is the only control that survives contact with a capable model.

The honest comparison

Where each boundary stops. "Kernel" means the workload's own kernel, which is the line that matters for hostile code.
BoundaryOwn kernel?Stops accidentsStops exfiltrationStops hostile codeTypical startTypical RAM
Separate OS userNoMostlyPartlyNoinstant~0
Process sandboxNoYesWith egress policyNoinstant~0
ContainerNoYesWith egress policyNo0.1–0.5 stens of MB
Application kernel (gVisor)Its own syscall layerYesYesLargely~0.1 stens of MB
MicroVMYesYesYesYes0.1–1 s32–256 MB
Full VMYesYesYesYes2–20 s1–4 GB
WASM runtimeNo kernel at allYesYesYes, within its API<1 ms~0

"Stops hostile code" is deliberately coarse. It means the boundary credible against an adversary who is trying, based on the measured evidence in Reality Check. Every Yes still depends on you not having handed over a socket, a helper or a host share.

If you take one thing from this chapter The best local setup for most people is: one VM per project, kept warm; rootless containers inside it for per-task lanes; credentials brokered at the VM's egress; and the host share limited to one read-only directory. That stack uses each layer for what it is good at, and it is the same shape as the "sandbox stacks" practitioners describe when they are honest about what they run.