Skip to main content
Agent sandboxesOffline by defaultFork in secondsMCP

A throwaway computer
for every agent.

A real Linux VM for each task, on the Mac you already own. No network card unless you give it one. Fork it into four, try four ideas, keep the one that works, and throw the rest away.

Terminal — zsh
$ curl -fsSL https://zyvorai.github.io/zyvor-fluxvm/install.sh | bash

Measured, not promised

Cheap enough to be disposable

Seconds to a clean machine, and a copy of it for every idea. Every number below came from a real run on one Apple M4 mini.

4.5 sA fresh offline sandboxcold boot, no network card; a default sandbox claiming a warm slot takes about 1 s
~4 sFork into 4 running copiesthey share the parent’s memory snapshot
0.3 sFour fixes tried and testedin parallel, one in each copy
66MCP toolscounted on 0.4.11 and 0.4.13 builds; VMs, sandboxes, sessions, speculate/changesets; read-only unless you allow writes

Verified on M4 Two runs of the demo; the timings above are from both. Your Mac, disk and image will differ.

Install

One command, no sudo

The installer downloads the release package for your machine, verifies its SHA-256 and links the binaries into ~/.local/bin. Run it again to upgrade; --version rolls back. Current is 0.4.18 on macOS: fluxctl agent, sessions and --host-gpu are in the package (fluxctl agent --help confirms it).

curl -fsSL https://zyvorai.github.io/zyvor-fluxvm/install.sh | bash

# with the daemon at login and an MCP client wired up:
curl -fsSL https://zyvorai.github.io/zyvor-fluxvm/install.sh | bash -s -- --service --client claude-code

# it verifies the SHA-256, needs no sudo, writes under ~/.local;
# --dry-run prints the plan, --version X pins or rolls back, --uninstall reverses it.

fluxctl --version   # 0.4.18
fluxctl agent --help

macOS 14+ on Apple silicon; Linux x86_64 from the same installer when the release has that asset (check the release page; the package is built in ubuntu:22.04). Every option, upgrade and uninstall · Homebrew notes

The loop

Four ideas. One survivor.

An agent’s test fails. It forks the sandbox into four running copies, tries a different fix in each, runs the tests in all four at once, and keeps whichever passes. This is the real output of examples/agent-sandbox-demo/run.sh.

agent-sandbox-demo — M4 mini
$ examples/agent-sandbox-demo/run.sh
1. offline sandbox
   b1c1624a-d1bd-4be8-9542-68bfa337f12f ready in 4.4 s; network: lo UNKNOWN 127.0.0.1/8 ::1/128
2. a project whose test fails
   before the fix: FAILED (failures=1) | exit=1
3. fork into four running copies
   4 copies running in 4.0 s (parent snapshot 677 ms, slowest child 3303 ms)
4. four different fixes, tried in parallel
   all four tried and tested in 0.3 s
   attempt-1: tests PASS
   attempt-2: tests fail (rc=1)
   attempt-3: tests fail (rc=1)
   attempt-4: tests fail (rc=1)
5. keep the one that passes
   -    return sum(xs) / len(xs) + 1   # bug: an off-by-one nobody asked for
   +    return sum(xs) / len(xs)
   the other four are deleted

Every attempt is isolated

A broken rm or a half-applied patch happens in a copy that is deleted a second later. Nothing leaks into the next attempt or onto your Mac.

Parallel, not sequential

The four copies run at the same time, so four attempts cost the time of one. The fork took about four seconds; the four test runs took 0.3.

Plain MCP tools

sandbox_create, sandbox_exec, vm_fork, vm_delete. The script is those same calls over REST; a model drives them the same way.

Agent sessions

One handle, not five primitives

A session wraps a sandbox with a workspace, a network policy, checkpoints and a ledger of what was done. It adds no new isolation: it composes the sandbox, snapshot, fork and changeset calls that already exist.

fluxctl agent — M4 mini, abridged
$ fluxctl agent run codex --policy offline --ttl-seconds 900
  session 14bd10ba  backend vz  capabilities {snapshot: true, fork: true, pty: false}
$ fluxctl agent exec 14bd10ba -- 'echo parent > /tmp/p'
$ fluxctl agent checkpoint 14bd10ba --tag before
$ fluxctl agent fork 14bd10ba --count 2
  2 children running in 2.5 s (identity: best-effort)
$ fluxctl agent exec <child-1> -- 'cat /tmp/p; echo child1 > /tmp/who'
  parent
$ fluxctl agent exec 14bd10ba -- 'cat /tmp/who'
  cat: /tmp/who: No such file or directory      # the parent never saw it
$ fluxctl agent timeline 14bd10ba
  session.create · exec · checkpoint · fork

Policy, compiled

offline, developer-safe or your own host list, turned into the allow-list the host already enforces. Method and path limits per host are enforced by the egress proxy where the sandbox's traffic reaches it, and refused at create where it cannot.

Host list: verified on M4

Checkpoint and roll back

A memory checkpoint reverted a file change on restore. Restore takes seconds, not milliseconds; a disk-only checkpoint is smaller but cold-boots.

Verified on M4

A ledger, not a recording

Every exec, checkpoint, restore and fork made through the session is logged with its exit code and duration. Replay and streaming terminals are not built; preview URLs are (run on the Mac NAT).

MVP

Create 4.6 s, first exec 0.4 s, checkpoint 0.7 s, restore 3.9 s, fork into 2 running children 2.5 s: median of 5 runs on one M4 mini, debug build, offline session. The tables · Agent README · API

Controls

What you can hold an agent to

Implemented, reviewed and covered by unit and router tests. Not yet run through a live guest: treat them as ready to trial, and use the checks in the guide on your own hosts before you rely on them.

Filesystem confinement

--confine --fs-write /data: every command, job, file and git call runs under Landlock and seccomp in a Linux guest. Create fails, with the reason, where the guest cannot enforce it.

Tests

Approvals

process.ask holds a matching command until an operator approves exactly that command, once. A session token cannot approve its own request.

Tests

Scoped tokens

Give an agent a token for one session and a list of operations, not the admin credential. It expires and dies with the session.

Router tests

Jobs that stream

Long-running commands with separate stdout and stderr, resumable offsets, stdin and EOF, a timeout and tree-wide signals. The command’s own exit status survives the output cap.

Tests

Credentials the agent never sees

A grant injects an Authorization header for named hosts, optionally only for given methods and paths, and ends with the session.

Tests

Budgets and big files

Limits on commands, compute time, jobs, forks, output and workspace size; resumable, checksum-verified uploads of files up to 2 GiB.

Tests

The practical guide (policy, tokens, approvals, jobs, transfer, budgets, fork and promote, troubleshooting) · API reference

Private by construction

No network card. Still smart.

An offline sandbox has no network device at all: only a loopback. Commands and files still work over vsock. When the agent needs a model, one allow-listed port relays to a server on the Mac, so the code and the prompts never leave the machine.

Offline

sandbox_create {"offline": true}. The guest can reach nothing: ip -br a shows lo only.

Verified on M4

Allow-listed

allow_hosts opens ports 80 and 443 to the names you list, through a proxy on the host that refuses everything else. Run through a session: the listed host answered 200, another host was refused, and a direct connection had no route.

Verified on M4

Host inference (host_gpu)

fluxctl agent run --host-gpu (or host_gpu: true) relays guest OPENAI_BASE_URL to the Mac’s Metal/MLX or llama.cpp server over vsock. No network card. host-inference

Verified on M4, small model

The model run used a deliberately tiny 135M-parameter model, so its answers are weak: it proves the path, not answer quality. A stand-in server (fluxctl infer serve --stand-in) is enough for path tests.

Versus microsandbox

Where we are ahead, and where we are not

microsandbox is a good, fast, embeddable runtime. The left column is what its README and releases say; the right is what we ran. We have not benchmarked them against each other.

Capabilitymicrosandbox (documented)FluxVMStatus
IsolationmicroVMs (libkrun)vz on a Mac; KVM, Firecracker, Cloud Hypervisor, QEMU on LinuxRun on vz
Startupunder 100 ms guest boot (their M1 figure)4.6 s offline, 6.8 s on the NAT (M4, debug build)Behind
Fork a running sandboxyesoffline vz sessions and in-tree KVM; not a NAT sandboxRun on vz
Checkpoint / restorefull snapshots, branches, --cow-memmemory+disk or disk-only per sessionRun on vz
Review before applynot documentedspeculate, changeset, approve, applyTests
Network policyhost allow-list, CONNECT proxyhost allow-list; eBPF CIDR/DNS/rate rules on LinuxRun on vz; eBPF not run
Secrets kept out of the VMyes (TLS interception)credential broker with per-sandbox grantsTests
Embeddable, no daemonyesno: needs fluxctl serveBehind
SDKsTS, Rust, Python, Go, RubyGo, Python, TypeScript (sessions: Go, Python)Behind
Windows hostyes (WHP)noBehind
Fleet of Macs, tenantsnot documentedcentral, leases, FluxMeshSimulator only

We are behind on startup time, embeddability, SDK languages and Windows. We are different in running one control plane over several VMMs with a fleet layer, and in ending a speculative run as a changeset you can review. The full comparison, with sources

What it costs

Memory you can plan with

Resident size per sandbox as macOS reports it, on a 16 GB M4 mini, idle. It varies a lot, so we show the lowest and the highest value seen, not a single number.

ProfileConfiguredStartSandboxes sampledResident MiB, lowest to highest
tiny512 MiBcold boot7347 to 779
small1 GiBcold boot7623 to 788
standard2 GiBclaims a warm slot7205 to 712

Plan on about 800 MiB per active sandbox: the lowest value is a floor, not a plan. On a 16 GB Mac that leaves room for roughly a dozen active sandboxes next to macOS and your apps; that last line is an estimate, not a measurement. Idle and hibernated sandboxes cost less. Measured: 21 sandboxes. Not measured: guests doing real work, eight or more at once, Mac Studio sizes. The full table

Plugs into your agent

Two commands from a clean Mac

Claude Code, Cursor, Claude Desktop, Codex, VS Code, Windsurf and Gemini CLI each get a fluxvm MCP server in their own config. Tested end to end from a fresh home directory on the published package: handshake, 66 tools in 0.4.11, a sandbox created, a command run, a fork, a delete.

Terminal — zsh
# once per Mac
curl -fsSL https://zyvorai.github.io/zyvor-fluxvm/install.sh | bash -s -- --service

# once per agent client
fluxctl mcp install claude-code --allow-write

# then, in the agent: sandbox_create {"offline": true}
#   sandbox_exec {"vm": id, "command": "pytest -q"}
#   vm_fork {"vm": id, "count": 4}   ...   vm_delete

Write tools (--allow-write) can create, run commands in and delete VMs; leave them off for a read-only agent. MCP reference

What to know before you rely on it

  • Only an offline (or no-NAT) sandbox can fork. A default sandbox sits on the Mac’s NAT, and its copies would share its address, so the daemon refuses.
  • Forked copies keep the parent’s identity (hostname, machine id, SSH host keys): an offline sandbox has no guest agent over SSH for the reset. Fine for throwaway attempts; not for anything that registers itself somewhere.
  • The first sandbox on a fresh daemon took 61 s while the image was prepared; later ones took about 4.5 s, and about 1 s when claiming a warm slot.
  • This page is about Linux guests. macOS guests are a different, less proven workflow: see FluxVM on Mac.
  • Everything here ran on one Apple M4 with macOS 27.2. The package is ad hoc signed; vmnet, bridged networking and USB passthrough need a Developer ID build.

The full list of what is verified →

Give your agent a clean machine.

curl -fsSL https://zyvorai.github.io/zyvor-fluxvm/install.sh | bash, then run the demo and watch four attempts become one.