Skip to content

macOS sandboxes

Use an Apple Silicon host running macOS 14+, zoo-node, zoovm and a prepared macOS guest. The guest must run zoo-guest. Desktop viewing and VNC input work independently of Accessibility permission; window inspection and Accessibility tools require Apple’s guest-side grant. The host/guest OS pair must be compatible with the restore image and VM helper. Keep sufficient disk/RAM for the base and the configured slots.

Zoo caps a Mac at two running macOS VMs, counting a running base. Administrators remain responsible for applicable platform licensing.

To install the control plane and enroll this same Mac, start Docker Desktop and run:

Terminal window
curl -fsSL https://github.com/chann44/zoo/releases/latest/download/install.sh | \
sudo bash -s -- --admin-email you@example.com

A full Mac install starts fresh. It removes the selected installation’s .env, the zoo Docker project’s containers and volumes, and Zoo Docker sandbox/helper containers. This deletes the old accounts, database and object-store data. Other Docker applications and native macOS VM disks are retained. --check makes no changes. To refresh or retry host setup without resetting the control plane, use --node below.

The local dashboard uses http://localhost:3000 and the API uses http://localhost:8000, independent of the Mac’s Wi-Fi address. Native guests reach the published API through their discovered virtual-network gateway. For hosts on other machines, configure a reachable domain with --domain instead of localhost.

Use the dashboard’s Add server → Mac command with its one-time token, control-plane URL and API-provided key. The native daemon enrolls and dials the gateway over mTLS. install.sh --node can prepare the base; --ipsw PATH selects a restore image and --no-base defers preparation until the first macOS sandbox or Prepare macOS action.

Zoo prepares the base template and guest tools automatically. Remote Servers shows preparation progress and the current stage. You can create a macOS sandbox while the host is preparing; its provisioning job waits for the template to become ready. If preparation fails, its message explains the failed stage and Retry preparation restarts preparation. An existing unprepared base can use Prepare macOS to continue.

The normal flow does not require opening the base screen, entering a guest password, or running a setup script manually. Advanced template controls let administrators open the prepared template to customize apps; stop it afterward to use those changes for new sandboxes. Host/guest endpoints must resolve and trust the deployment’s API certificate; there is no configurable guest-URL alternate path.

Use the same Zoo node setup command to enroll a new Mac, refresh its installed helpers, or resume interrupted preparation. The command installs the host integration, enrolls the node before downloading/restoring macOS, and starts preparation in the background. The Mac appears under Remote Servers while preparation runs; the terminal need not stay open.

For a new Mac, copy the complete one-time command from Servers → Add server → Mac. For a Mac already enrolled with your deployment, run this single command under the VM-owning account (replace the URL with your deployment):

Terminal window
curl -fsSL http://your-zoo-server:8000/v1/nodes/install/install.sh | \
sudo bash -s -- --node --control-plane http://your-zoo-server:8000

An enrolled Mac keeps its existing registration and certificates; rerunning --node setup does not create a second server or spend another join token. The installer refreshes its restricted root-owned helper and resumes the existing node service. Base preparation resumes automatically; there are no separate guest-account or repair commands.

After a fresh control-plane installation, use the complete new Add server command to replace an old registration. Its one-time token pins the new control plane’s certificate authority, including when changing from a LAN URL to localhost. Replacement is staged and rolls back on failure; it does not delete native VM disks.

--check performs preflight checks without installing or preparing a VM. --no-base defers background preparation until a sandbox is requested. --ipsw PATH selects a readable local Apple restore image when a base must be installed; an existing installed base is reused. The native runtime stays in place by default; add --version VERSION to request a verified release upgrade. An upgrade is deferred while native VMs or an installation are active, so a running VM’s runtime is preserved.

Preparation downloads and restores macOS only when the base is absent. Retrying an installed base reuses its disk and bootstrap state; successful guest account creation is not repeated. Preparation logs are in ~/.zoovm/install.log on the host. Status and the runner PID are in ~/.zoovm/preparation/zoo-macos-base/ (using the configured base name). A stopped or interrupted runner reports a failure; retry preparation to continue. An API restart can resume guest verification without restoring macOS again.

The base is a native macOS guest prepared with Zoo’s guest tools. It does not run the Linux XFCE desktop or a Docker image. Zoo caches this prepared base on the Mac and creates independent sandbox disks using APFS copy-on-write clones. The base can remain stopped between allocations. Each sandbox still boots its own native VM and uses its own memory; disk cloning does not establish a measured startup time or eliminate VM resource costs.

The default template contains Apple’s macOS and Zoo’s guest tools; it does not add Xcode or Homebrew. The native VM tool caches the downloaded Apple restore image in ~/.zoovm/cache/restore/, outside the base bundle, so deleting the base does not erase that download. Cache writers are serialized and images are checked against Apple’s restore metadata before reuse. This cache requires the updated native zoovm release; updating only the API container does not replace an existing host binary.

Use --ipsw PATH during host installation to select a specific Apple restore image. The image must support that Mac’s hardware; an older macOS version is not necessarily compatible with a newer Mac. Third-party prepared images such as Cirrus Labs’ vanilla templates avoid developer-tool bundles, but Zoo does not currently import their OCI/Tart format.

Saved-state contract: unique reserved slots

Section titled “Saved-state contract: unique reserved slots”

Saved-state reuse is restricted to a pre-reserved VM slot with its own hardware identity, disk and saved state. The state must originate from that slot on the same compatible Mac/account and configuration. Restore it as that slot, then hand off sandbox identity through the required guest. Never run two allocations from the same slot simultaneously.

Do not copy one saved state into arbitrary clones with new machine identifiers, attach a different disk to it, or treat it as portable memory for another host/account. A saved state captures credentials and memory; handle it as sensitive data and keep the disk/state pair consistent. Incompatible or unavailable state is an explicit failure, not permission to use an undocumented alternate create path.

Base/slot updates must happen while allocations are drained and must capture state from the actual prepared slot. APFS disk clones alone do not establish that a saved-memory clone is valid. Actual slot preparation, resume/reidentification and cleanup need native runtime validation before this path is declared accepted.

Shell, files, terminals, windows, apps, accessibility and secrets use zoo-guest. The native gateway owns the active VNC session for screenshots, input and viewing. Missing required guest capabilities fail explicitly.

Snapshots, disk transfer and saved-state restore have different identity constraints. Do not promise saved memory will move with a disk. Real lifecycle recovery and the boot timing targets remain unmeasured.