brig docs

Concepts

Architecture

On this page

On macOS, three programs run a sandbox: the CLI, the runtime and the VMM. Brig decides what the agent gets, hull prepares the guest, and hvi runs it as a microVM. All three are Apache 2.0.

The programs behind one sandbox on macOS On your Mac, brig starts hull and a network gateway. hull starts hvi, the microVM monitor, which runs on Hypervisor.framework. hvi owns the guest's memory and vCPUs and serves its virtio devices, and it reaches the gateway over a Unix socket. The gateway reaches only the internet hosts an egress policy allows. In the sandbox, a Linux kernel talks to hvi through virtio devices, an init wrapper and urunit prepare the guest, and the agent runs in /work/demo. Your Mac Apple silicon Internet hosts the policy allows Sandbox microVM, own kernel brig profile, credentials, policy Network gateway DHCP, DNS, egress rules hull image, root filesystem, VMM hvi RAM, vCPUs, virtio devices Seatbelt: deny by default Hypervisor.framework vCPUs and guest memory, in macOS Unix socket virtio: blk, net, vsock, fs claude the agent, in /work/demo init wrapper, urunit prepare the guest, run the agent Linux kernel virtio-mmio drivers, no PCI
One sandbox on the default hvi backend. Each arrow shows which program starts or reaches which.

Each repository documents its own design. This page gives the overview and links to the detail.

On Linux, Brig drives nerdctl, and urunc boots the sandbox on Cloud Hypervisor. Runtimes covers that path.

The programs #

Layer Program What it does
CLI brig Resolves the profile, the guest home, the credentials and the egress policy. It runs the runtime as a subprocess and links none of its code.
Runtime hull Pulls the OCI image, prepares the root filesystem and starts the VMM. Its network-gateway subcommand carries the sandbox's network. hull never calls a hypervisor itself.
VMM hvi Owns the guest's memory and vCPUs, and implements the guest's virtio devices and console. It runs on Hypervisor.framework.

hull and its VMMs #

hull starts one VMM process per sandbox, and that process owns the guest. Three things follow from the split:

  • Only the VMM needs a hypervisor entitlement. hull holds none.
  • When the VMM exits, the sandbox stops with it. hull ps reports what is left.
  • hull can start a different VMM for each sandbox. Brig uses vz-runner, on Virtualization.framework, for the claude-desktop window. Runtimes compares hvi, vz and qemu.

hull's architecture and backends pages cover its store and each backend.

hvi #

hvi is a VMM for Linux guests, and it calls Hypervisor.framework directly. It maps the guest's memory and runs the vCPUs. Its own code serves the guest's virtio devices and its console.

Device What it carries
virtio-blk A disk image
virtio-net The guest's network, relayed to the gateway
virtio-vsock The exec channel that hull exec uses
virtio-fs The project and the guest home. hvi serves the guest's FUSE requests itself.

The virtio devices sit on virtio-mmio, so the guest needs no PCI bus. hvi loads the kernel into guest memory and starts it at EL1, with no firmware and no bootloader.

The interrupt controller comes from Hypervisor.framework (hv_gic_*). It first shipped in macOS 15, so hvi needs macOS 15 or newer.

hvi also runs on Linux under KVM, with arm64 and x86-64 guests. Brig uses it on macOS. CI boots each backend on real hardware.

hvi's architecture page has the memory maps, the boot protocols and the device model.

The boundary in hvi #

hvi treats the guest as hostile. Two mechanisms keep the guest inside its VM:

  • VM isolation comes from the hypervisor. The guest reaches only the memory hvi maps for it. An access to a virtio device or the console exits to hvi.
  • Process confinement is hvi's own. hvi enters a Seatbelt profile before the first vCPU starts, so a bug in a device backend runs inside that profile.

hvi does this work in five places:

Where What hvi does
Guest memory Every read and write goes through one type, GuestRam. It checks each address against the regions the guest owns, and refuses a range that crosses from one region into the next.
Virtqueues A descriptor-chain walk refuses an index outside the ring. It also stops after as many descriptors as the ring holds, so a loop in the chain ends.
Seatbelt The profile denies by default. Each shared directory adds one rule for its own path: read for a read-only share, read and write for a writable one.
Selftest hvi sandbox-selftest installs the shipped profile and probes it both ways: what a confined thread keeps, and what it loses. It needs no hypervisor, so any CI host can run it.
Console hvi passes guest text and an allowlist of display escape sequences to your terminal. It drops the rest, such as a sequence that writes the clipboard.

At boot, hvi prints whether confinement is on:

[hvi] seatbelt sandbox: on (deny default)

Limits

  • hvi has had no external security audit and no formal verification. CI boots every backend on real hardware and runs the confinement selftests. That is testing, not assurance.
  • Confinement narrows what the process may ask the kernel for. hvi changes no uid, gid or capability.
  • Side channels from shared hardware, such as speculative execution and cache timing, are the platform's to mitigate.

hvi's security model and limitations pages give the full threat model.

The network gateway #

Brig starts one gateway for each isolated sandbox. It is a hull network-gateway process with a user-mode TCP/IP stack from gVisor, a layer 2 switch, DHCP and DNS. hvi relays the guest's frames to it over a Unix socket, which needs no entitlement and no root.

Every network packet the guest sends out passes the gateway, so Brig enforces an egress policy there. See Enforcement, and hull's egress page for how a rule is matched.

Linux on a Mac #

A Linux guest on a Mac meets three problems that a VMM on an x86 Linux server does not. The list says how hvi and hull handle each one, and the hvi and hull architecture pages give the detail.

  • Memory ordering. Apple silicon is arm64, which can reorder memory writes that x86 keeps in order. hvi completes disk and network requests on worker threads while the guest runs on another core. When it publishes completed requests, it writes the results first and the index the guest reads last, with a release fence (dmb) before the index. Without the fence, the guest can see the new index before the results, and its virtio driver fails with id 65 is not a head!.
  • Randomness at boot. An x86 guest can use RDRAND. A guest on Hypervisor.framework has no hardware random source at boot: no RNDR and no SMCCC TRNG. hvi writes fresh random seeds into the devicetree for every boot, and the guest kernel seeds its random pool and its KASLR offset from them.
  • Case in file names. A Mac volume is case-insensitive by default, and Linux package trees hold names that differ only by case, such as xt_CONNMARK.h and xt_connmark.h. Unpacked onto such a volume, the two become one file, and the guest fails later in a way that is hard to trace. hull keeps its store on a case-sensitive APFS volume and refuses any other.

Read the source #

At commit c6df2a9, hvi has 14,224 lines of Rust code and 8,735 lines of tests, as tokei counts them.

Parts of hvi's x86-64 backend follow Firecracker, and hvi's NOTICE names each file. hull uses urunc for its generic container boot.

To report a problem in hvi, follow its SECURITY.md. For Brig and hull, see Report a vulnerability.

Type a command, a flag or an error message.