Set up microVM isolation
For: cluster operators.
Configure the supported microVM path for the node platform.
microVMs
/work into whatever the VM's monitor can see. On Linux that is only what tier 1 lets the monitor see (below), which is why a node never runs one outside it.A microVM boots a tool's container image with a Linux kernel of its own, in a virtual machine per server. A tool that escapes its MCP server is inside that kernel; to reach the node it must break the kernel and then the virtual machine monitor, and on Linux the monitor itself runs in tier 1. It is the strongest isolation OZ0 has, and the slowest to start: about a second and a half per server here, against a fifth of a second for the same image in Docker.
A tool asks for one in its manifest. Its plugin's agents then require isolation.microvm=ready (and the image's architecture), not runtime.oci=ready: a microVM node needs no Docker.
tools:
- id: acme_fetch
package: oci:ghcr.io/acme/fetch-mcp@sha256:4f6c0d1b5e8a…
isolation: microvm # boots in a VM of its own, never in a container
container: {memory_mb: 512, cpus: 1}
A node without microVMs leaves the tool out, Docker or not (it runs only in a microVM, which this node does not offer (...)). A tenant's --oci gvisor requirement does not apply to such a tool: it runs in its VM.
| Node | microVMs |
|---|---|
| Linux, amd64 or arm64, with KVM and tier 1 (bubblewrap) | smolvm 1.24.0, inside tier 1 |
| macOS 26 on Apple silicon | Apple's container 1.5.0 or later |
| macOS before 26 on Apple silicon | not yet: smolvm's monitor has no tier-1 sandbox on macOS, and the node never runs it without one |
| Intel Macs | no: neither runtime runs on them |
| Windows | not yet: smolvm needs the Windows Hypervisor Platform and Developer Mode or an administrator |
Set up a Linux node
- Give the node's user
/dev/kvm:sudo usermod -aG kvm <user>(log in again, or restart the node's service). - Download smolvm 1.24.0 for your architecture from its GitHub releases (
smolvm-1.24.0-linux-x86_64.tar.gzor-linux-arm64.tar.gz), check its SHA-256 against the table below (smolvm's releases are not signed), and unpack it somewhere the node's user can read but not write, such as/opt/smolvm. - Put its
smolvmon the node'sPATH(ln -s /opt/smolvm-1.24.0-linux-x86_64/smolvm /usr/local/bin/smolvm), or name the folder:OZ0_MICROVM=/opt/smolvm-1.24.0-linux-x86_64 oz0-node run. - Restart the node. It checks every file of smolvm it loads against the release it pins, boots one VM inside tier 1, and logs
smolvm booted inside tier 1; the edge labels itisolation.microvm=ready, andoz0 node show <node>and the Nodes page have a MicroVMs line.orchestrator-zero-node sandbox vm --probe --guest "$(command -v orchestrator-zero-node)"asks the same without starting the node. The first start takes about ten seconds more (smolvm unpacks its disk templates once), later ones a second and a half.
| Release | Archive | SHA-256 |
|---|---|---|
| 1.24.0 | smolvm-1.24.0-linux-x86_64.tar.gz | df4cf6efcac4cff61238b98d30fe589e3ccfc5d57ade3c04401c808a54050b73 |
| 1.24.0 | smolvm-1.24.0-linux-arm64.tar.gz | d08c51a10b49737c9b20501a018be62772d29e39ad9aae82f4e0e1c0fe32dcd0 |
A smolvm the node binary does not pin is refused: smolvm is not a release this node pins, so it does not run it (...). Naming its folder with OZ0_MICROVM runs it anyway, and the node's facts then say pinned: false with a warning. OZ0_MICROVM=off turns microVMs off. A node whose test VM does not boot inside tier 1 (no tier 1, no access to /dev/kvm, a kernel or bubblewrap that refuses it) offers no microVMs and says why in its log and in oz0 node show --json (facts.microvm.reason). OZ0 never downloads or updates smolvm.
How a tool runs in one
orchestrator-zero-node sandbox vm starts each server's VM: smolvm machine create, start, exec with the tool's MCP over its input and output, and delete, whatever ended it: the tool, the end of its input, a cancelled call (which stops a job's server), or the node stopping.
| The monitor | in tier 1: bubblewrap's namespaces, no capabilities, no nested user namespace, the vmm seccomp filter (tier 1's, with userfaultfd allowed), /dev/kvm its only device; smolvm's own seccomp filter and Landlock rules on top (SMOLVM_SECCOMP and SMOLVM_LANDLOCK set to enforce) |
| Network | no network device at all (smolvm's --net is never used). With the plugin's egress, the node's egress proxy's socket is mapped into the VM and the node binary's bridge listens on its loopback, so the tenant's and the plugin's hosts are reachable and nothing else |
| Files | the job's work folder at /work, the one folder the VM shares (an installed plugin's server shares a folder of the runtime's own); with egress also the node binary, read-only, at /oz0. The VM's own disk is its own, and goes with it. A file a call is given is placed under /work/.oz0-files/ and the call's _meta["oz0/files"] names it there, so the tool opens it inside the VM |
| User | the node's uid and gid inside the VM, HOME=/tmp |
| Secrets | the plugin's settings and secrets by name: smolvm reads each value from its own environment, so none is on a command line, and no process outside the VM holds one under its own name (each passes through as OZ0_VMENV_<name>). A microVM tool may not name a variable PATH, HOME, TMPDIR, a proxy's (HTTPS_PROXY and the like), or LD_*, DYLD_*, SMOLVM_* or OZ0_VMENV_* |
| Limits | the tool's memory (--mem) and CPUs, rounded up to whole vCPUs; the monitor's sandbox gets the node's tier-1 limits on top |
| Data | each VM's smolvm data folder is its own, so no VM can touch another's disks. It lives under the temporary directory (oz0-vm-<id>-<random>, because smolvm's agent socket inside it must have a short path), named by the VM's record in <data dir>/microvm/vms/, and goes with the VM |
macOS 26
Install Apple's container 1.5.0 or later (its signed installer, from its GitHub releases), and run container system start in the node's user session.
The node finds container on PATH, checks its version and that its services answer, and runs each tool with container run --rm --network none --read-only --cap-drop ALL, the node's user, whole CPUs, --ulimit nproc (
Apple's runtime has no process limit), and with egress the egress proxy's socket file and the node binary.
Apple's runtime has no no-new-privileges, and its VMs are started by its own launchd services, so they are not inside tier 1: their kernel is the boundary.
The CLI starts with a clean environment (CVE-2026-64786), and the tool's variables reach it only in an env file only the node's user may read, removed when the tool stops (a value with a line break is refused).
A Mac that has Apple's container fetches the Linux node binary the VM's bridge needs from its edge, by the release's signed manifest, of its own version only, after it found the runtime (a Mac without it, an Intel Mac and a Windows node never fetch it); a node built without a release key has no microVMs.
Older versions' copies under <data dir>/microvm/guest/ are removed at the node's start.
Neither macOS path has run on a Mac yet: scripts/test-macos-microvm.sh checks one.
What is tested
make e2e-oci-tools runs a microVM node where /dev/kvm exists. A node without Docker, in a container given /dev/kvm, finds smolvm on its PATH, checks its pins and boots it inside tier 1. The plugin's microVM tools run there alone; a node with Docker leaves them out.
The check verifies that the guest has its own kernel and no network without egress. Its only write visible to the host is in its work folder. An allowed host is reachable through the proxy's socket and another is refused. The monitor shows tier 1's seccomp filter and smolvm's, no capabilities and no new privileges. Stopping the node takes its VMs with it. OZ0_E2E_MICROVM=0 skips the check.
Earlier section link