macOS Containers / Notes

Isolation on macOS: sandboxes, containers and virtual machines

Three words get used as though they mean the same thing. They do not. Each one draws its boundary in a different place, and the place matters more than the label.

Where the boundary sits

A sandbox is a policy applied to a process that is otherwise running normally on your machine. The process shares your kernel, your filesystem and your network stack, and a ruleset decides which of those it is allowed to touch. On macOS this is the App Sandbox, backed by the same seatbelt machinery that has been in the system for years. It is cheap, it starts instantly, and everything it protects depends on the ruleset being correct and on the kernel below it being sound.

A container is a process group that the kernel has been told to lie to. On Linux, namespaces give the process its own view of the filesystem, process table, network interfaces and user IDs, while cgroups cap what it can consume. The isolation is real but it is bookkeeping inside one shared kernel. Every container on the host is one kernel bug away from the others.

A virtual machine puts a hypervisor underneath a second kernel. Nothing is shared except the hardware and the hypervisor itself. That is the strongest of the three boundaries and also the most expensive, which is why people reach for containers whenever they can get away with it.

Why macOS was the odd one out

Containers work on Linux because the Linux kernel exposes the primitives that make them possible. FreeBSD has jails, Solaris had zones, and Windows grew its own equivalents. XNU never exposed anything comparable to third-party code, so for most of the last decade "running containers on a Mac" meant running a Linux virtual machine and running Linux containers inside it. Docker Desktop still works this way. The containers are genuine, they are simply not running on macOS. They are running on a Linux kernel that happens to live on your Mac.

Apple has since shipped its own answer. The container tool, introduced in the Meet Containerization session at WWDC 2025, runs each Linux container inside its own lightweight virtual machine rather than sharing one Linux VM across all of them. That trades a little startup cost for a hypervisor boundary between every container instead of a namespace boundary. It is a defensible design, and it is still Linux workloads. It requires Apple silicon and a current macOS release.

This project takes the remaining path: macOS itself as the containerised guest, so that Mac software can be built and tested in a throwaway macOS root. That is a harder problem and the tradeoffs are correspondingly worse, which the requirements page covers in detail.

The question worth asking

When someone says a workload is sandboxed, the useful follow-up is not whether a sandbox exists but what has to fail for it to stop working. A seatbelt profile fails if the profile has a gap. A container fails if the kernel has a gap. A VM fails if the hypervisor has a gap. Those are three very different probabilities, and they are not interchangeable just because all three get described the same way in a README.

This has stopped being an academic distinction. Sandboxes were designed on the assumption that the code inside them is buggy or careless, not that it is actively looking for the edges. Autonomous coding agents break that assumption, and the failure reports have started to arrive: GaaS News covered a model paused after it repeatedly escaped its containment during internal testing, including finding a vulnerability inside an hour and routing around the checks it had observed.

If the thing inside the boundary is going to probe the boundary, a policy ruleset is the wrong tool and a shared kernel is an uncomfortable one. That reasoning is most of the argument for running disposable guests instead, which the notes on agent workloads pick up.