# CLI Command Surface — check, run, build, graph, size, fix

> The full set of zero CLI commands, their JSON output contracts, and when to use each. Commands are the only stable agent-facing interface: always pass --json for machine consumption. Key distinction: zero fix --plan is read-only (reports repairs, never edits files). Covers provenance guardrails and the sandbox execution requirement for conformance and native tests.

- Repository: vercel-labs/zerolang
- GitHub: https://github.com/vercel-labs/zerolang
- Human wiki: https://grok-wiki.com/public/wiki/vercel-labs-zerolang-9ab46b2a38e0
- Complete Markdown: https://grok-wiki.com/public/wiki/vercel-labs-zerolang-9ab46b2a38e0/llms-full.txt

## Source Files

- `skill-data/zero-builds.md`
- `skill-data/zero-agent.md`
- `native/zero-c/src/main.c`
- `scripts/snapshot-command-contracts.mts`
- `scripts/native-test-sandbox.mts`
- `conformance/run.mjs`

---

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:

- [skill-data/zero-agent.md](skill-data/zero-agent.md)
- [skill-data/zero-builds.md](skill-data/zero-builds.md)
- [skill-data/zero-diagnostics.md](skill-data/zero-diagnostics.md)
- [docs/articles/cli-reference.md](docs/articles/cli-reference.md)
- [scripts/snapshot-command-contracts.mts](scripts/snapshot-command-contracts.mts)
- [scripts/native-test-sandbox.mts](scripts/native-test-sandbox.mts)
- [conformance/run.mjs](conformance/run.mjs)
- [native/zero-c/src/main.c](native/zero-c/src/main.c)
</details>

# CLI Command Surface — check, run, build, graph, size, fix

The `zero` CLI is the only stable, machine-facing interface to the Zero compiler. Every command that produces structured output supports a `--json` flag that switches from human-readable terminal text to a versioned JSON envelope; agents and automation must always pass `--json` to get stable, parseable results. Text output is for humans and has no stability contract.

This page documents the core commands you will use in daily development and CI — `check`, `run`, `build`, `graph`, `size`, and `fix` — explains their JSON output shapes, describes when to reach for each one, and covers two important operational guardrails: the read-only constraint on `zero fix --plan`, and the sandbox execution requirement for conformance and native tests.

---

## Input Forms

All major commands accept the same three input forms:

| Input | Resolves to |
|---|---|
| `file.0` | A single Zero source file |
| `project/` | A package directory containing `zero.json` |
| `zero.json` | A package manifest directly |

Sources: [docs/articles/cli-reference.md:3-11]()

---

## Command Quickref

| Command | Use it for |
|---|---|
| `zero check <input>` | Parse, typecheck, and report diagnostics |
| `zero run <input>` | Build and run a host executable |
| `zero build <input>` | Emit an executable or object file |
| `zero graph <input>` | Inspect modules, symbols, capabilities, and helper use |
| `zero size <input>` | Explain artifact size, retained helpers, and profile budgets |
| `zero fix --plan --json <input>` | Ask for a typed repair plan (read-only) |
| `zero ship <input>` | Produce a release preview with checksums and metadata |
| `zero doctor` | Check host and target readiness |

Sources: [docs/articles/cli-reference.md:14-28]()

---

## `zero check`

`zero check` is the innermost loop command. It parses source, typechecks it, and reports all diagnostics. It does not emit any build artifact.

```sh
zero check examples/hello.0
zero check --json examples/hello.0
zero check --json --target linux-musl-x64 --emit exe examples/memory-package
```

### When to use it

Run `zero check` after every source edit. It is faster than `build` because it stops before code generation. In an agent edit loop, run `zero check --json <file-or-package>` immediately after patching source to see whether the change introduced or resolved diagnostics.

### JSON output shape

`zero check --json` returns an envelope with these key fields:

| Field | Description |
|---|---|
| `ok` | `true` if no diagnostics |
| `diagnostics` | Array of diagnostic objects (see below) |
| `compileTime` | Bounded `meta` evaluation, sandbox denials, cache key inputs, static values |
| `incrementalInvalidation` | `cacheHits`, `cacheMisses`, `changedInputs` |
| `interfaceFingerprints` | Per-module interface hashes (algorithm `fnv1a64-zero-interface-v1`) |
| `targetReadiness` | Present when `--target` is passed: `ok`, `buildable`, target-specific diagnostics |

Each diagnostic object has:

| Field | Description |
|---|---|
| `code` | Stable code such as `NAM003`, `TAR002`, `BLD003` |
| `message` | Short human summary |
| `path`, `line`, `column`, `length` | Source span |
| `expected`, `actual` | Structured mismatch facts when available |
| `help` | Concise next action |
| `fixSafety` | Safety label for an agent repair |
| `repair` | Optional repair id and summary |
| `related` | Extra spans or facts |

Sources: [skill-data/zero-diagnostics.md:21-33](), [docs/articles/cli-reference.md:58-76](), [scripts/snapshot-command-contracts.mts:361-364]()

### Separating language validity from target buildability

Passing `--target <target> --emit <kind>` keeps these two axes independent:

- Top-level `ok` and `diagnostics` describe parse/typecheck results.
- `targetReadiness.ok`, `buildable`, and nested diagnostics describe predictable backend blockers — without writing any artifact to disk.

This lets an agent check whether code is valid language and whether it would compile for a specific target, in a single invocation, without side effects.

Sources: [docs/articles/cli-reference.md:73-77]()

---

## `zero run`

`zero run` builds a host executable using the direct backend, runs it, passes through stdout/stderr, and exits with the program's own exit status. It is the fastest path from source to execution during local development.

```sh
zero run examples/hello.0
zero run examples/cli-file.0 -- input.txt
```

Arguments after `--` are forwarded to the Zero program. An optional `--out <file>` flag controls where the compiled binary lands; if omitted, the binary is placed in a temporary path.

The generated-C backend is not a fallback path. When the binary exists after `run`, its presence reflects direct compilation. The `.c` extension is never generated alongside the artifact — the command contracts verify `existsSync(runArtifact.c) === false`.

Sources: [skill-data/zero-builds.md:19-27](), [docs/articles/cli-reference.md:42-48](), [scripts/snapshot-command-contracts.mts:649-656]()

---

## `zero build`

`zero build` compiles a source file or package to a native artifact. Pass `--emit exe` for a linked executable or `--emit obj` for a relocatable object file.

```sh
zero build --emit exe examples/hello.0 --out .zero/out/hello
zero build --emit obj examples/hello.0 --out .zero/out/hello.o
zero build --json --emit exe --target linux-musl-x64 examples/hello.0 --out .zero/out/hello-linux
```

Always pass `--target` when building for a non-host platform. Inspecting target names before cross-building:

```sh
zero targets
zero check --target linux-musl-x64 examples/memory-package
```

### Profiles

Profiles control optimization level and size/speed tradeoffs. Common profile names:

| Profile | Semantics |
|---|---|
| `debug` | Full debug metadata, no optimizations |
| `dev` | Fast build, limited optimizations |
| `release-fast` | Optimized for speed |
| `release-small` | Optimized for binary size |
| `tiny` | Maximum size reduction (tiny hello < 10 KB) |
| `audit` | Additional safety checks |

```sh
zero build --profile release-small examples/hello.0
```

### JSON output shape

`zero build --json` returns:

| Field | Description |
|---|---|
| `schemaVersion` | Always `1` |
| `emit` | `exe` or `obj` |
| `target` | Target triple string |
| `hostTarget` | The host platform triple |
| `compiler` | Emitter path such as `zero-elf64` |
| `artifactPath` | Path to the output artifact |
| `artifactBytes` | Byte size of the artifact |
| `generatedCBytes` | Must be `0`; non-zero indicates an unsupported backend |
| `loweredIrBytes` | Lowered IR byte size |
| `profileSemantics` | `canonical`, `profileKey`, `profileBudget` |
| `objectBackend` | `objectEmission.path`, `linking.externalToolchain`, direct facts |
| `releaseTargetContract` | Artifact kind, object format, linker flavor, libc mode, sysroot requirements, emitter readiness, capability facts, repeat-build hash policy |

The `releaseTargetContract.fallbackPolicy` is always `"explicit-direct-never-c-bridge"`, meaning the compiler never silently falls back to the removed C bridge.

Sources: [scripts/snapshot-command-contracts.mts:624-646](), [docs/articles/cli-reference.md:64-84](), [skill-data/zero-builds.md:30-45]()

### Provenance guardrail: `generatedCBytes`

The contract script asserts `generatedCBytes === 0` on every build and ship report. This is the machine-readable provenance guardrail: any non-zero value means the removed generated-C backend was used, which violates the direct-emitter contract. Agents reading build JSON must check this field before treating an artifact as conformant.

Sources: [scripts/snapshot-command-contracts.mts:47-48](), [conformance/run.mjs:38-39](), [skill-data/zero-builds.md:31-32]()

---

## `zero graph`

`zero graph` inspects a program without building it. It reports the complete module graph — all source files, imports, import edges, public symbols, capability use, and static helper facts — without writing any artifact.

```sh
zero graph examples/systems-package
zero graph --json --target linux-musl-x64 examples/memory-package
```

### JSON output shape

| Field | Description |
|---|---|
| `schemaVersion` | Always `1` |
| `sourceFile` | Entry source file resolved |
| `sourceFiles` | All transitive source files |
| `imports` | Import module names |
| `importEdges` | `from`, `to`, `path` for each import edge |
| `symbols` | All symbols with `name`, `kind`, `public` |
| `functions` | Per-function metadata |
| `compileTime` | Same as `check` — static evaluation, sandbox facts |

`zero graph` includes the `compileTime` object, giving visibility into bounded `meta` evaluation results and sandbox denials without triggering code generation.

Test-internal symbols (names starting `__zero_test_`) are excluded from graph output, so the graph reflects only the public and private program surface.

Sources: [scripts/snapshot-command-contracts.mts:365-393](), [docs/articles/cli-reference.md:58-69](), [scripts/snapshot-command-contracts.mts:534-537]()

---

## `zero size`

`zero size` explains why an artifact is the size it is. It does not build a final artifact but does require the compiler to lower IR in order to compute size facts.

```sh
zero size --json examples/hello.0
zero size --json --profile tiny examples/hello.0
zero size --json --profile debug --target linux-musl-x64 examples/memory-primitives.0
```

### JSON output shape

| Field | Description |
|---|---|
| `profileSemantics` | `canonical`, `profileKey`, `profileBudget` |
| `profileCatalog` | All available profiles |
| `profileBudget` | Budget policies for the selected profile (e.g. `debugMetadataAllowed`, `helperBudgetPolicy`) |
| `sizeBreakdown` | `functions`, `sections`, `stdlibHelpers`, `imports`, `runtimeShims`, `debugMetadata` |
| `retentionReasons` | Why each retained function is included (`retainedBy` such as `"entry point"`) |
| `optimizationHints` | Actionable size hints with `id` |

Example: for `--profile debug`, `sizeBreakdown.sections` includes a `"debug-metadata"` entry, `profileBudget.debugMetadataAllowed` is `true`, and `optimizationHints` includes `"profile-debug-metadata"` to prompt switching to a smaller profile.

Sources: [scripts/snapshot-command-contracts.mts:674-685](), [docs/articles/cli-reference.md:65](), [skill-data/zero-builds.md:62-67]()

---

## `zero fix --plan` — Read-Only Repair Planning

`zero fix --plan --json` is the only form of `zero fix` supported by the current compiler. It reports candidate typed repairs but **never edits files**. This is a hard design constraint, not a missing feature.

```sh
zero fix --plan --json examples/broken.0
zero fix --plan --json --target linux-musl-x64 examples/target-fail.0
```

### Why plan-only matters for agents

Because `zero fix --plan` is read-only, an agent can call it safely on any source file at any time without risk of modifying the working tree. The output is a repair proposal; the agent decides whether and how to apply it. Never assume the fix plan edits files — verify the change independently after applying the suggestion.

Sources: [skill-data/zero-diagnostics.md:19](), [docs/articles/cli-reference.md:26](), [docs/articles/cli-reference.md:151]()

### Fix safety levels

Each proposed repair carries a `safety` label. The full set, from safest to least safe:

| Safety | Meaning |
|---|---|
| `format-only` | Formatting or trivia only; no semantic change |
| `behavior-preserving` | Intended not to change runtime behavior |
| `api-changing` | Signatures, exports, or call sites may change |
| `target-changing` | Target support or capability use may change |
| `requires-human-review` | The compiler cannot prove the edit is safe |

The `--plan` JSON includes a `safetyLevels` summary and per-fix `safety` fields. Apply only the edit you can justify from source and the fix plan. Treat `requires-human-review` as a planning hint, not an automatic patch.

Sources: [skill-data/zero-diagnostics.md:38-46]()

---

## `zero check` vs `zero fix --plan` — Decision Flow

```text
Source change
     │
     ▼
zero check --json          ← fast, no artifacts, always first
     │
     ├─ ok: true           → proceed to build/test
     │
     └─ ok: false
           │
           ├─ Inspect diagnostic fields (code, span, expected, actual, help)
           │
           ├─ zero explain <code>      ← structured explanation
           │
           └─ zero fix --plan --json  ← read-only: inspect safetyLevels,
                                         apply manually, then re-check
```

Sources: [skill-data/zero-agent.md:26-38](), [skill-data/zero-diagnostics.md:62-68]()

---

## Conformance and Native Tests: Sandbox Execution Requirement

Conformance tests and command contract snapshots emit native artifacts (compiled binaries). Running them locally requires either:

1. **Vercel Sandbox** — the default path via `pnpm run conformance` or `pnpm run command-contracts`, which uses `scripts/native-test-sandbox.mts` to provision an isolated remote environment.
2. **Explicit local opt-in** — setting `ZERO_NATIVE_TEST_ALLOW_LOCAL=1` before running `conformance/run.mjs` or `scripts/snapshot-command-contracts.mts` directly.

Without one of these, the scripts exit immediately with a clear error:

```
conformance emits native test artifacts; run `pnpm run conformance`
for Vercel Sandbox execution or set ZERO_NATIVE_TEST_ALLOW_LOCAL=1
to opt into local artifacts.
```

Sources: [conformance/run.mjs:7-10](), [scripts/snapshot-command-contracts.mts:8-11]()

### Why sandboxing is required

The conformance runner builds and executes native ELF and Mach-O binaries. Running untrusted compiled output locally is a security boundary; the sandbox provides an isolated Linux environment (default runtime `node24`, 16 vCPUs, 10-minute timeout) that does not copy native test binaries back to the developer's machine.

The sandbox flow:

```
Developer machine
  │
  ├─ Create source archive (excludes .git, .zero, node_modules, dist)
  │
  ├─ Upload to Vercel Sandbox (VERCEL_OIDC_TOKEN required)
  │
  │   Sandbox (linux/x64)
  │   ├─ Extract source
  │   ├─ pnpm install --frozen-lockfile
  │   ├─ make -C native/zero-c    (build compiler)
  │   └─ Run conformance/command-contracts
  │
  └─ Exit code and stdout/stderr streamed back; binaries stay in sandbox
```

Snapshots can be reused between runs via `ZERO_NATIVE_TEST_SANDBOX_SNAPSHOT_ID` to avoid re-provisioning. Set `ZERO_NATIVE_TEST_SANDBOX_REFRESH=1` to force a fresh environment.

Sources: [scripts/native-test-sandbox.mts:144-170](), [scripts/native-test-sandbox.mts:194-255](), [scripts/native-test-sandbox.mts:257-292]()

### Conformance platform detection

The conformance runner detects whether it can execute built binaries and skips execution (but not building) when the host platform doesn't match the target:

```js
const runnableDirectTarget =
  process.platform === "darwin" && process.arch === "arm64" ? "darwin-arm64" :
  process.platform === "linux" && process.arch === "x64" ? "linux-musl-x64" :
  null;
```

On an unsupported host, `assertDirectRuntimeRequired` still builds the artifact and verifies the JSON contract; it only skips the actual execution step. This means conformance is partial on non-Linux/non-ARM64-mac hosts — which is why the sandbox (always `linux/x64`) is the canonical execution environment.

Sources: [conformance/run.mjs:15-19](), [conformance/run.mjs:65-77]()

---

## JSON as the Agent-Stable Interface

The command contracts script (`scripts/snapshot-command-contracts.mts`) is the authoritative reference for what each command's JSON envelope must contain. It asserts every field that agents are permitted to rely on, and it runs in the sandbox on every CI pass. Key invariants enforced by the contracts:

- `schemaVersion` is always `1` on check, build, ship, size, and test JSON.
- `generatedCBytes` is `0` on every build, ship, and size report.
- `cBridgeFallback` is `false`.
- `releaseTargetContract.fallbackPolicy` is `"explicit-direct-never-c-bridge"`.
- Repeat builds produce bit-identical artifacts (`sha256File` comparison).
- `--json` flag on error commands still writes JSON to stdout (not stderr), with a non-zero exit code.
- ANSI control bytes are absent from error output (`hasAnsiControlBytes` check).

The final invariant matters for piping: even when a command fails, its `--json` output is machine-parseable JSON on stdout. Do not scrape stderr when `--json` is available.

Sources: [scripts/snapshot-command-contracts.mts:195-197](), [scripts/snapshot-command-contracts.mts:47-50](), [scripts/snapshot-command-contracts.mts:566-570]()

---

## Summary

The `zero` CLI's six core commands form a stable, layered surface: `check` gives the fastest feedback loop; `graph` adds module and capability visibility without artifacts; `size` explains artifact composition by profile; `run` closes the local development loop; `build` and `ship` produce versioned release artifacts with provenance contracts. `zero fix --plan` is strictly read-only — it proposes repairs but never patches files, making it safe to call from any automated context. Conformance and native test suites must run inside Vercel Sandbox (or with an explicit local override) because they build and execute native binaries. Pass `--json` on every command that supports it; the `generatedCBytes === 0` invariant is the single most important signal that an artifact was produced by the conformant direct emitter.

Sources: [docs/articles/cli-reference.md:1-159](), [scripts/snapshot-command-contracts.mts:195-217]()
