Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

19. Every command

This is the complete list of zygo commands, every flag, and every default. It is written from the parser (crates/zygo-cli/src/cli.rs) and from the code behind each command. zygo <command> --help prints the same flags; this chapter adds what the help cannot: what each command really does, what it needs, and how it ends.

The commands on one page

  ONE-SHOT                 WARM FUNCTIONS                 A PROJECT (sandbox.toml)
  zygo run                 zygo serve    zygo exec        zygo up      zygo down
                           zygo ps       zygo stop        zygo spec validate | explain
                           zygo logs     zygo shell
                           zygo top      zygo stats

  IMAGES                   ACCESS AND SECRETS             PROGRAMS AND AGENTS
  zygo pull                zygo login                     zygo api
  zygo images              zygo token  mint | ls | revoke zygo mcp
  zygo image rm | prune    zygo secrets keygen | set |    zygo agent test
                                        ls | rm

  THE HOST                 MEASURING                      SHELL HELPERS
  zygo doctor [--fix]      zygo bench warm | cold |       zygo completion
  zygo backend list |                 load | all
               install     (hidden) zygo supervisor run | status | stop

How to read this chapter

Each command has a line showing how to call it, a few sentences on what it does, a table of its flags, and notes on output and exit codes. [x] means optional, … means it can repeat, A | B means one of them. Sizes are written like 256M, durations like 30s; chapter 20 has the exact rules, which are the same for flags and for the file. Exit codes are collected in chapter 21.

Global flags

These work with every command, before or after the command name.

FlagDefaultMeaning
--jsonoffPrint machine-readable JSON instead of tables and lines. Logs become JSON too.
-v, --verbosewarnings onlyMore log output; repeat for more (-v info, -vv debug, -vvv trace). ZYGO_LOG overrides it.
--data-root DIR$XDG_DATA_HOME/zygoUse another data folder: images, caches, tokens, secrets. Also read from ZYGO_DATA_HOME.
-h, --help · -V, --versionHelp for any command · the version.

Flags shared by run, serve and mcp

Two groups of flags describe a sandbox, and they mean the same thing wherever they appear. Each maps to a sandbox.toml field and wins over it.

Limit flagDefaultMeaning
--mem SIZE256MMemory limit (at least 8M).
--cpu CORES1.0CPU quota in cores, e.g. 0.5.
--pids N64Most processes and threads at once; the fork-bomb limit.
--timeout DURATION30sWall-clock limit. 0 needs --allow-unlimited.
--scratch SIZEsmaller of 64M and half of --memSize of the writable /tmp.
--nofile N1024Most open files.
Sandbox flagDefaultMeaning
--isolation ns | gvisor | vmnsWhere the wall is.
--seccomp default | strict | permissivedefaultThe syscall profile (chapter 24).
--net none | egress | full | hostnoneNetwork mode; bridge is accepted for full.
--allow RULE …noneEgress allowlist entry: host:port, *.domain:port, CIDR:port.
--mount HOST:GUEST[:ro|rw] …noneBind mount, read-only unless :rw.
--env KEY=VALUE …noneEnvironment variable.
--user UID1000uid inside the sandbox.
--workdir PATH/appWorking folder inside the sandbox.
--allow-host-netoffPermit --net host, which removes the network boundary.
--allow-private-netoffPermit private and link-local ranges.
--allow-unlimitedoffPermit --timeout 0.

-f, --file PATH names the spec file on every command that reads one; without it, sandbox.toml is searched for upwards from the current folder.


zygo run — a one-shot sandbox

zygo run [FLAGS] IMAGE [COMMAND [ARGS…]]

Builds a fresh sandbox from IMAGE, runs COMMAND in it (or the image’s own entrypoint), and removes everything when it exits. Standard input, output and the exit code pass straight through, so it behaves like the program itself. Everything after IMAGE belongs to the command: zygo run alpine sh -c "echo --mem" does not set a memory limit. Chapter 12 teaches it step by step.

FlagDefaultMeaning
limit and sandbox flagssee above
-f, --file PATHsearchedUse this spec’s [defaults] under the flags; [fn.*] tables are ignored.
-t, --ttyoffGive the sandbox a terminal of its own. Without it, the sandbox shares yours — colours work, but the program can write to your terminal.
--requirements FILEnoneA requirements.txt built once into a shared venv at /venv, /venv/bin first on PATH.
--pull missing | never | alwaysmissingWhen to download the image. never refuses a missing image before anything starts (exit 1, outcome phase: plan).
--outcome FILEnoneWrite why the sandbox ended, as JSON (chapter 21).
--dry-runoffPrint the plan — command, root, mounts, network, seccomp, Landlock, cgroup values — and run nothing. With --json, the full plan including the allowed syscalls.
-q, --quietoffHide Zygo’s own progress lines on stderr. The program’s output is never hidden.

Exit: the program’s own code; 137 if the deadline or the memory limit killed it; 2 for a spec error; 125 if this host cannot run sandboxes; 1 for other Zygo errors. Signals: the first Ctrl-C is passed to the program; a second one kills it.

zygo serve — warm a function or a pool

zygo serve HANDLER --name NAME [FLAGS]
zygo serve --runtime NAME [--image IMAGE] [--agent AGENT] [FLAGS]

The first form builds a sandbox, loads HANDLER in it, and keeps it warm under NAME. The second form warms a runtime pool: an interpreter with no code, for scripts that arrive with each request. It starts the supervisor if none is running. Chapter 13 explains both.

FlagDefaultMeaning
HANDLER—The handler file (.py, .js, .ts, …). Not with --runtime.
--name NAME—The function’s name. Needs a HANDLER.
--runtime NAME—Serve a pool under this name instead.
--image IMAGEthe spec’s, or python:3.12-slim / node:22-slim for the runtimeThe image to warm from.
--agent python | node | PATH—With --runtime: which agent the pool runs.
--min-warm N · --max-warm N1 · larger of min-warm and 4With --runtime: zygotes kept warm, and the most it may grow to.
--requirements FILEnoneShared, cached venv, as for run.
--concurrency N4Requests at once per zygote.
--idle-timeout DURATION10mPause the zygote after this long idle.
--mode function | stdinfunctionHow the handler is called.
--secret NAME …noneDeliver $NAME from this shell as /run/secrets/NAME, per request.
-f, --file PATHsearchedSpec to read.
limit and sandbox flagssee above

Output: the function’s runtime, resident memory, import time and warm-up time. Exit: 0 when warm; 2 for a spec error; 125 if it cannot start.

zygo exec — call a warm function

zygo exec NAME [EVENT]
zygo exec --runtime NAME --script FILE|sha256:… [--entry-point FN] [EVENT]

Sends EVENT (JSON; read from standard input when left out; empty means null) to a warm function and waits. The result goes to stdout; what the handler printed goes to stderr. With --runtime, runs a script in a pool instead; the positional argument is then the event.

FlagDefaultMeaning
--runtime NAME—Run a script in this pool. Needs --script.
--script FILE | sha256:…—A file on this host, or the digest of a script already stored (PUT /scripts).
--entry-point FNhandlerThe function in the script to call.
--batchoffRead one JSON event per line from stdin, run them in parallel, print one answer per line in the same order.
--timeout DURATIONthe function’s timeoutGive up after this long.

Exit: the request’s own code; 137 if its deadline killed it; 75 if the function is busy; 4 if there is no such function; 125 if no supervisor is running. With --batch: 0 only if every line succeeded.

zygo ps — list warm sandboxes

zygo ps

Columns: NAME, STATE (starting, warm, paused, cold, failed), RUNTIME, RSS (resident memory), REQUESTS, FAILURES. It never starts a supervisor: with none running it says so and exits 0.

zygo logs — a function’s recent log

zygo logs NAME [-f] [-n N] [--failed]

The zygote’s own output, and one entry per request with its exit, duration, stdout and stderr. The supervisor keeps the last 500 entries per function, across replacements and cold spells.

FlagDefaultMeaning
-f, --followoffKeep printing new entries (checks every 500 ms).
-n, --tail N50How many recent entries to start with.
--failedoffOnly requests that failed.

With --json, one entry per line.

zygo stop — stop sandboxes

zygo stop NAME
zygo stop --all

Stops one function or runtime pool by name, or everything — every function and every pool — and then the supervisor itself. Give a name or --all, not both. --all with nothing running exits 0; a named stop with no supervisor is an error (125), and a name that is neither a function nor a pool is “no function or runtime pool named …” (exit 4). On a Mac, stop --all also stops the Linux VM afterwards.

Output: one line per thing stopped — stopped NAME for a function, stopped runtime.NAME for a pool, and stopped the supervisor when --all ended it — so you can see which kind went. nothing to stop means just that. A name that is both a function and a pool stops both: stop means “forget this name”. To stop only one of the pair, use the API, which keeps them apart: DELETE /fn/{name} never reaches a pool, and DELETE /runtimes/{name} never reaches a function.

zygo top — live resource table

zygo top [-i SECONDS] [--once]

ps on a timer, plus rates. Functions: NAME, STATE, RSS, REQ/S, REQUESTS, FAILURES. Pools: RUNTIME, WARM, PAUSED, ROOM (how many more zygotes it may start), IN/QUEUE, RSS, REQUESTS, FAILURES. Rates need two samples, so the first frame shows —.

FlagDefaultMeaning
-i, --interval SECONDS2Time between frames.
--onceoffOne frame, then exit — for scripts. --json implies it.

zygo stats — latency and outcome summary

zygo stats [NAME]

For each function and pool: STATE, REQUESTS, FAILURES, SAMPLES, p50 (a usual request), p99 (the slowest 1 in 100), MAX, KILLED. Counters run from when the function was warmed; latencies come from the log ring. p99 is shown only with 100 samples or more. KILLED counts timeouts and other 137 exits (usually out of memory).

zygo up — start a whole project

zygo up [-f PATH] [--relock]

Serves every [fn.*] in the spec, in the order they are written. A function whose spec, secret values, handler and requirements are all unchanged is left warm; a changed one is replaced blue/green: the new one warms, then takes new requests, while running ones finish on the old. One failure does not stop the others. It writes zygo.lock (chapter 20). [runtime.*] pools are not started by up, and the --allow-* flags do not exist here, on purpose.

FlagDefaultMeaning
-f, --file PATHsearchedSpec to read.
--relockoffAccept an image that moved under an unchanged tag, and rewrite zygo.lock.

Output: one line per function — ✓ started or replaced, · unchanged, ✗ failed with the reason. Exit: 1 if any function failed.

  zygo up, for one changed function
  old ──────── serving ──────────────── finishing running requests ──▶ stopped
  new            └─ warming ─▶ ready ─▶ takes every new request ──────────────▶

zygo down — stop a project

zygo down [-f PATH]

Stops the functions the spec declares, and nothing else. With no supervisor running, it says so and exits 0.

zygo spec — check and explain the spec

zygo spec [-f PATH] validate
zygo spec [-f PATH] explain [NAME]

validate resolves every function and every pool, so limits, names and network rules are really checked, and prints the warnings once each. explain NAME prints the final settings for one function or one pool after every layer is merged — and says, for each value, which layer it came from. A pool is resolved the way serve --runtime resolves it (strict unless a layer says otherwise) and shows its min_warm and max_warm too; a name that is both a function and a pool is explained as the function. explain with no name shows what zygo run would use. Both need a sandbox.toml.

zygo pull — download an image

zygo pull IMAGE [--platform OS/ARCH[/VARIANT]]

Downloads an image into the local store, with progress lines. On Linux it then builds the Python bytecode layer once, if the image needs one (chapter 15).

FlagDefaultMeaning
--platformthis host’sPull for another platform, e.g. linux/amd64.

zygo images — list local images

zygo images

Columns: reference, digest (first 12 characters), layers, size, and when it was pulled.

zygo image rm — remove images

zygo image rm IMAGE…        (alias: zygo image remove)

Removes an image, the derived +system images built on it, and any layers only they used. Refused while a warm function runs on it: stop the function first.

zygo image prune — free disk space

zygo image prune [--dry-run] [--unused-for DURATION] [--blobs]

With no flags, deletes only what nothing can reach any more: layers of removed images, and venvs, flattened roots and derived-layer records whose image is gone, plus leftover temporary roots. It prints what a flag would also collect.

FlagDefaultMeaning
--dry-runoffSay what would go, and how much it would free; delete nothing.
--unused-for DURATIONoffAlso delete venvs and flattened roots not used for this long, e.g. 30d.
--blobsoffAlso delete the compressed copy of every unpacked layer. Roughly halves the store; a lost layer then means a new download.

zygo login — a private registry

zygo login REGISTRY [-u USER] [--password-stdin]

Asks for the password with echo off, checks it against the registry, and only then stores it in Zygo’s own auth.json. There is no --password flag: an argument is visible to every user in ps and lands in shell history. Zygo reads ~/.docker/config.json too, but never writes to it; where both have a credential, Zygo’s wins. docker.io, index.docker.io and registry-1.docker.io are the same registry.

FlagDefaultMeaning
-u, --username USERaskedThe account name.
--password-stdinoffRead the password from standard input, for CI.

zygo secrets — the per-tenant secret store

zygo secrets keygen
zygo secrets set TENANT NAME [--stdin]
zygo secrets ls TENANT          (alias: list)
zygo secrets rm TENANT NAME

An encrypted store of secrets per tenant, used by functions served through the API. keygen prints a new 32-byte key; put it in ZYGO_SECRETS_KEY (or a file named by ZYGO_SECRETS_KEY_FILE) before the supervisor starts. A passphrase is refused, and a lost key means every stored secret is lost. set reads the value with echo off, or from stdin with --stdin (at most 64 KiB); there is no --value flag. ls prints names, never values; there is no way to read a value back. Chapter 14 explains how the store and --secret fit together.

zygo token — API tokens

zygo token mint [--tenant TENANT]
zygo token ls                   (alias: list)
zygo token revoke ID

mint creates a token and prints its secret — zygo_ and 64 hex characters — on stdout, once; only a hash is stored. Without --tenant it is an operator token (the host’s); with it, a tenant token (one customer’s, and the tenant is created if new). Because the secret goes alone to stdout, ZYGO_API_TOKEN=$(zygo token mint) works. ls lists id, scope and state; revoke works from the next request, and keeps the record so old logs still make sense.

zygo api — the HTTP API

zygo api [-f PATH] [--listen ADDR] [--no-auth] [--allow-deploy]
         [--allow-private-net] [--openapi]
         [--otlp-endpoint URL] [--otlp-interval D] [--usage-webhook URL]
         [--usage-interval D]

Runs the HTTP API in the foreground, starting the supervisor if needed. By default every caller needs a bearer token — ZYGO_API_TOKEN, or one from zygo token mint. Chapter 17 has every route.

FlagDefaultMeaning
--listen ADDR[api] listen, else 127.0.0.1:7700IP:PORT, or unix:///path.
--no-authoffNo tokens. Refused except on a unix socket or a loopback address.
--allow-deployoffLet the bootstrap token create and destroy sandboxes, not only call them. That makes it a shell as your user; think twice.
--allow-private-netoffLet what deploy callers serve name private and link-local addresses in allow. A request body can never set this. Does nothing without --allow-deploy.
--openapioffPrint the OpenAPI 3.1 document and exit.
--otlp-endpoint URL$OTEL_EXPORTER_OTLP_ENDPOINTPush metrics to an OpenTelemetry collector (/v1/metrics is added).
--otlp-interval DURATION60sHow often to push.
--usage-webhook URLnonePOST batches of usage events for billing, at least once.
--usage-interval DURATION10sHow often to deliver them.

zygo mcp — tools for an AI agent host

zygo mcp [-f PATH] [--workspace DIR] [--python-image I] [--node-image I]
         [--sh-image I] [limit and sandbox flags]

Speaks the Model Context Protocol on stdin and stdout, which is how an agent host starts a tool server. The flags are a ceiling the model cannot raise: no tool accepts an image, mount, network or limit.

FlagDefaultMeaning
--workspace DIRa temporary folder, removed on exitMounted read-write at /work for every run_code.
--python-imagepython:3.12-slimImage for language: "python".
--node-imagenode:22-slimImage for language: "node".
--sh-imagealpine:3Image for language: "sh".
limit and sandbox flagssee aboveApplied to every run_code.

zygo shell — a debug shell inside a warm sandbox

zygo shell NAME [-- COMMAND…]

Starts a fresh process inside the function’s namespaces: it sees the sandbox’s files, processes, network and host name. The warm zygote is not touched and keeps serving. The shell holds no capabilities, but it is on purpose not under seccomp, Landlock or the function’s cgroup, so the memory limit cannot kill your debugging session. It runs bash, sh or busybox sh, or COMMAND if given.

zygo doctor — can this host run sandboxes?

zygo doctor [--fix [--yes]]

Tries each requirement for real rather than reading a setting: kernel version, user namespaces, /proc, cgroup v2 delegation, whether moving a process into a cgroup can stall (cgroup moves), whether the systemd unit holding the sandboxes would be stopped by one of them being OOM-killed (systemd OOM policy), overlayfs, Landlock, seccomp, subordinate uids, KVM, the guest kernel, runsc, and the network helpers. Each line says ok, degraded, - (absent) or FAIL, with the fix under it. On a Mac it checks the host side and then the VM’s own doctor. Chapter 11 walks through it.

FlagDefaultMeaning
--fixoffApply the fixes that are one command each — the AppArmor user-namespace rule, cgroup delegation, the passt and nftables packages, the AppArmor profile on pasta, and cgroup2’s favordynmods option (on the host, never in a container) — after printing every command and what it costs, and asking.
--yesoffWith --fix: do not ask.

Exit: 0 if no check failed.

zygo backend — optional isolation backends

zygo backend list
zygo backend install gvisor | vm

list shows ns, gvisor and vm and whether this host can use each. install gvisor downloads gVisor’s runsc from Google’s release bucket, checks its SHA-512 before unpacking, and installs it under the data folder. install vm downloads nothing: it needs a build with the vm feature and a guest kernel in place, and says how to get one.

zygo agent test — check an agent against the protocol

zygo agent test BINARY [--script F] [--script-spawn F] [--pool-script F] [-- ARGS…]

Runs your agent and has the conversation the supervisor would have: READY, PING, a fork per request, the wait for GO, output kept apart, two requests at once, a bad message, cancel, streaming, heartbeats, shutdown. Chapter 18 describes each check. Exit 1 if any failed.

FlagMeaning
--script FILEA script in the agent’s language, to check that a script sent with a request is loaded in the child.
--script-spawn FILEA script whose top level starts a program, to check the child’s filter is on before the script’s first line.
--pool-script FILEThe agent holds no handler: send this file with every request (the runtime-pool shape).
-- ARGS…Arguments for the agent.

zygo bench — measure this host

zygo bench warm  [--n 10000] [--rate R] [--cpu C] [--no-cgroup] [--pool [--scripts 1000]] [-- CMD…]
zygo bench cold  [--n 50] [--image python:3.12-slim] [--command "…"]
zygo bench load  [--seconds 10] [--concurrency 4] [--cpu C]
zygo bench all   [--quick]

warm measures the warm path (or warm-exec with -- CMD, or a pool with --pool); cold measures zygo run with a pulled image; load measures throughput with several clients; all runs every published measurement and compares it with the numbers in chapter 25. Each prints PASS or FAIL against its budget. all exits 2 — “no verdict” — when the machine was throttled or busy while it ran, because such a number is not about Zygo.

zygo completion — shell completion

zygo completion bash | zsh | fish | elvish | powershell

Prints a completion script, generated from the parser itself so it can never drift from the real flags.

zygo completion zsh > "${fpath[1]}/_zygo"

zygo supervisor — the warm pool’s own process (hidden)

zygo supervisor run | status | stop

Not shown in --help, because serve, up, api, token and secrets start a supervisor when they need one. run keeps it in the foreground, which is how you see why it will not start. status prints its version, pid and socket (exit 1 if none). stop stops the supervisor only; it goes through the socket, or through the pid file and SIGTERM when a version mismatch means the socket will not listen.

Which commands start or need a supervisor

Starts one if neededNeeds one running (else exit 125)Fine without one
serve, up, api, token …, secrets set/ls/rmexec, logs, top, stats, shell, stop NAMErun, ps, down, stop --all, pull, images, image …, login, doctor, spec …, backend …, completion, secrets keygen

On a Mac

The zygo on a Mac is a small forwarder. completion, doctor, agent test and api --openapi run on the Mac itself; everything else runs inside the Linux VM Zygo manages, with the same arguments, folder and streams. Every path you pass — mounts, -f, --requirements, --outcome, handler files — must be under your home folder, because only that is shared with the VM. Chapter 11 explains the VM.