# CLI reference

> native init, dev, check, test, build, automate, doctor, and skills commands with flags, outputs, and failure modes.

- Repository: vercel-labs/native
- GitHub: https://github.com/vercel-labs/native
- Human docs: https://grok-wiki.com/public/docs/vercel-labs-native-8ccc3580636a
- Complete Markdown: https://grok-wiki.com/public/docs/vercel-labs-native-8ccc3580636a/llms-full.txt

## Source Files

- `src/tooling/dev.zig`
- `src/tooling/doctor.zig`
- `src/tooling/buildgraph.zig`
- `packages/native-sdk/README.md`
- `README.md`

---

---
title: "CLI reference"
description: "native init, dev, check, test, build, automate, doctor, and skills commands with flags, outputs, and failure modes."
---

The `native` CLI is the control plane for Native SDK apps. The entrypoint is `tools/native-sdk/main.zig` (version string `0.4.0`); npm ships it as `@native-sdk/cli` with a Node dispatcher (`packages/native-sdk/bin/native.js`) that execs the per-platform binary and sets `NATIVE_SDK_PATH` to the package that carries SDK source. App verbs (`dev`, `build`, `test`) either drive an owned `build.zig` or synthesize a zero-config graph under `.native/build/` via `src/tooling/buildgraph.zig` and `src/tooling/verbs.zig`.

## Install surface

```bash
npm install -g @native-sdk/cli
native version
native --help
```

| Signal | Meaning |
| --- | --- |
| `native version` on stdout | `native 0.4.0 (commit <sha>, automation protocol v6)` — scripts parse this line |
| `native` / `native help` / no args | Prints usage; **exit 1** when no command was given, **exit 0** for explicit help |
| Unknown command | `unknown command: …` + usage, **exit 1** |

Platform binaries live in optional deps such as `@native-sdk/cli-darwin-arm64`. The dispatcher refuses to start when no binary matches the host OS/arch.

## Command inventory

| Command | Role |
| --- | --- |
| `init` | Scaffold `app.zon` + `src/` (+ frontend shell when requested) |
| `dev` | Debug build + run (markup hot reload); optional frontend server or mobile targets |
| `build` | ReleaseFast binary → `zig-out/bin/<name>` |
| `test` | App test suite via `zig build test --summary all` |
| `check` | Fast markup + `app.zon` validation (model contract when present) |
| `automate` | Drive a running automation-enabled app (dropbox IPC) |
| `doctor` | Host / WebView / CEF / tool probes |
| `skills` | List/print shipped agent skill packs |
| `markup` | Per-file check, dump, LSP |
| `eject` | Own `build.zig` / `build.zig.zon`, or eject one catalog component |
| `validate` | Schema-check `app.zon` only |
| `package` / `package-*` | Distributable layouts |
| `bundle-assets` | Copy frontend/assets into build output |
| `cef` | CEF install/path/doctor helpers |
| `version` | Print CLI version + automation protocol |

Every verb accepts `--help` / `-h` and exits **0** with that verb’s usage. Unknown flags print usage and exit **1** (they never fall through into a real run).

## Shared behavior

### App directory

App verbs resolve relative paths against the process cwd (`assets/`, markup watch, `.zig-cache/native-sdk-automation`). Pass an optional directory or `cd` first:

```bash
native dev path/to/app
native check .
```

Missing directory → `cannot enter app directory …` / `MissingAppDirectory`.

### Zero-config vs ejected builds

```text
app.zon + src/ only          build.zig present (ejected / examples)
        │                              │
        ▼                              ▼
  ensureGeneratedBuild            zig build (owned graph)
  .native/build/build.zig
        │
        ▼
  zig build --build-file … --prefix <app>/zig-out
```

Framework root resolution (`buildgraph.resolveFrameworkRoot`):

1. `NATIVE_SDK_PATH` (npm wrapper sets this)
2. Walk ancestors of the `native` executable (checkout `zig-out/bin/native`, package `bin/native`, npm split `cli` sibling)

No framework → teaching error: set `NATIVE_SDK_PATH` or use an SDK-local/npm `native` binary.

### Zig toolchain

`dev` / `build` / `test` call `toolchain.resolveZig` (pinned **Zig 0.16.0**):

| Source | Order |
| --- | --- |
| `NATIVE_SDK_ZIG` | Absolute override |
| PATH `zig` | Used when version-compatible with the pin |
| Managed install | Under `NATIVE_SDK_HOME` or `~/.native/toolchains/zig-0.16.0/` |

First managed download prompts for consent unless `--yes`. Decline → `DownloadDeclined` (exit 1). Incompatible PATH zig prints the pin and falls through to managed install.

### Flag forwarding

`dev`, `build`, and `test` forward `-D…` and `--release…` to `zig build` unchanged. Default optimize when none is forwarded:

| Verb | Default |
| --- | --- |
| `dev` | `-Doptimize=Debug` (hot reload + teaching diagnostics require Debug) |
| `build` | `-Doptimize=ReleaseFast` |
| `test` | no default optimize flag; always runs step `test` with `--summary all` |

### Expected failures (no Zig return-trace)

`failVerb` maps teaching failures to silent **exit 1**: `MissingManifest`, `MissingFramework`, `ZigUnavailable`, `DownloadDeclined`, `UnsupportedPlatform`, `ChecksumMismatch`, `ZigBuildFailed`, `InvalidManifest`, `MarkupCheckFailed`, `HostCompileFailed`, `SimulatorUnavailable`, `SimulatorCommandFailed`.

---

## `native init`

```bash
native init [path] [--frontend <native|next|vite|react|svelte|vue>] [--framework <sdk path>] [--full]
```

<ParamField body="path" type="string" default=".">
Destination directory. App name defaults to basename of path (or cwd when path is `.`).
</ParamField>
<ParamField body="--frontend" type="native|next|vite|react|svelte|vue" default="native">
Scaffold shape: pure native markup app, or a WebView shell with a managed frontend.
</ParamField>
<ParamField body="--framework" type="path">
SDK checkout used as the path dependency. Must contain `src/root.zig`. Default: same resolution as build verbs.
</ParamField>
<ParamField body="--full" type="boolean" default="false">
`Shape.full` scaffold (extra editor/config files) vs slim default.
</ParamField>

**Success**

```text
created Native SDK app at my_app (native)

Next steps:
  cd my_app
  native dev
```

For non-native frontend or `--full`, next steps suggest `zig build run` instead of `native dev`.

**Failures**

| Condition | Exit |
| --- | --- |
| Framework path invalid / unlocatable | 1 + error about `--framework` or binary location |
| Invalid `--frontend` | 1 |
| Flag typo | 1 + usage (does **not** scaffold an app named after the flag) |

---

## `native dev`

```bash
native dev [dir] [--yes] [--url url] [--command "npm run dev"] [--timeout-ms n] [-D... zig build flags]
native dev [dir] --target ios|android [--device name] [--yes] [-D...]
native dev --binary path [--manifest app.zon] [--url url] [--command "..."] [--timeout-ms n]
```

### Desktop (default)

1. Requires `app.zon` in the app dir.
2. Resolves zig, builds Debug (unless optimize forwarded).
3. **No frontend.dev in manifest:** `zig build run` (or generated equivalent). Process group owned so Ctrl-C / CLI death kills the app tree.
4. **Frontend with `frontend.dev`:** build binary only, then `dev.zig` starts the dev-server command, waits until the URL answers HTTP 2xx/3xx, sets env, runs the binary.

Environment injected for frontend dev:

| Variable | Value |
| --- | --- |
| `NATIVE_SDK_FRONTEND_URL` | Override or manifest `dev.url` |
| `NATIVE_SDK_MODE` | `dev` |
| `NATIVE_SDK_HMR` | `1` |

Stdout markers:

```text
native dev: building and running <name> (Debug) — hot reload arms in Debug builds
native dev: app exited
native dev: frontend dev flow failed (<error>)
native dev: `zig build` step failed (exit code N)
```

### Flags

<ParamField body="--yes" type="boolean">
Consent to managed Zig download without a prompt.
</ParamField>
<ParamField body="--url" type="string">
Override frontend ready URL.
</ParamField>
<ParamField body="--command" type="string">
Space-split override for the frontend dev server argv.
</ParamField>
<ParamField body="--timeout-ms" type="u32">
How long to wait for the dev server HTTP ready probe (default from manifest `dev.timeout_ms`).
</ParamField>
<ParamField body="--target" type="ios|android">
Experimental mobile loop: build embed lib, install/launch simulator or emulator, stream logs.
</ParamField>
<ParamField body="--device" type="string">
Simulator/emulator device name for mobile targets.
</ParamField>
<ParamField body="--binary" type="path">
Legacy path: skip build; only run frontend-server + shell against a prebuilt binary.
</ParamField>

### Failure modes

| Error | Cause |
| --- | --- |
| `MissingManifest` | No `app.zon` |
| `MissingFramework` | Cannot resolve SDK root for generated builds |
| `ZigBuildFailed` | Compile/link/`zig build` non-zero |
| `MissingFrontend` / `MissingDevConfig` | `--binary` / frontend path without `frontend.dev` |
| `Timeout` | Dev server never became ready |
| `InvalidUrl` | Non-http(s) ready URL |

---

## `native build`

```bash
native build [dir] [--yes] [-D... zig build flags]
```

Runs `zig build` with default `-Doptimize=ReleaseFast` when no optimize/`--release` flag is forwarded. Artifacts land under `zig-out/` (generated builds force `--prefix <app-cwd>/zig-out`).

**Success**

```text
native build: built zig-out/bin/<name> (ReleaseFast)
```

**Failures:** same manifest/framework/zig/`ZigBuildFailed` paths as `dev`.

---

## `native test`

```bash
native test [dir] [--yes] [-D... zig build flags]
```

Runs `zig build test --summary all`. Passing runs print:

```text
native test: passed (test tally in the build summary above)
```

Also refreshes `zig-out/model-contract.zon` when the app’s build graph includes the model-contract step — that artifact powers typed binding checks in `native check`.

---

## `native check`

```bash
native check [dir] [--strict]
```

No full app link: walks `src/**/*.native`, validates markup, validates `app.zon`.

| Mode | Behavior |
| --- | --- |
| Without model contract | Structural markup + vocabulary checks; prints a note to run `native test` (or `zig build model-contract` if ejected) |
| With fresh `zig-out/model-contract.zon` | Typed checks: bindings, iterables, message tags, expression types vs Model/Msg; unused model state as warnings |
| `--strict` | Warnings promoted to errors → `MarkupCheckFailed` |

**Success**

```text
checked N markup file(s)[ against the model contract] and app.zon
```

**Failures**

| Condition | Result |
| --- | --- |
| No `app.zon` | `MissingManifest` |
| Markup diagnostics | `MarkupCheckFailed` (parser/validator messages already printed) |
| Invalid manifest | `InvalidManifest` |
| `--strict` with warnings | `MarkupCheckFailed` after promotion line |

Per-file path: `native markup check <file.native>… [--strict]`. Editor integration: `native markup lsp` (stdio LSP). Intermediate form: `native markup dump <file.native> [--out doc.nsui]`.

---

## `native automate`

Drives a **running** app built with automation enabled (`-Dautomation=true`). IPC is file-based under `.zig-cache/native-sdk-automation/` (protocol **v6**). The CLI never creates the dropbox; a missing dir means the app is not publishing.

```bash
native automate <command>
```

### Session launch

```bash
native automate record --out session.journal -- ./zig-out/bin/my-app
native automate replay session.journal [--verify|--no-verify] -- ./zig-out/bin/my-app
```

Sets `NATIVE_SDK_SESSION_RECORD` or `NATIVE_SDK_SESSION_REPLAY` (+ `NATIVE_SDK_SESSION_VERIFY=1|0`) and execs the app. Non-zero app exit fails the command.

### Live dropbox commands

| Command | Purpose |
| --- | --- |
| `wait` | Block until `snapshot.txt` has `ready=true` from a live publisher |
| `list` | Print `windows.txt` (requires live snapshot) |
| `snapshot` | Print `snapshot.txt` accessibility/state dump |
| `assert [--absent] [--timeout-ms 30000] <regex>…` | Poll snapshot until patterns match (or are absent); max 32 patterns |
| `screenshot <view-label> [scale]` | Deterministic PNG via reference renderer |
| `reload` / `resize <w> <h> [scale]` | Runtime control |
| `widget-click` / `widget-action` / `widget-hold` / `widget-drag` / `widget-wheel` / `widget-key` | Drive retained-canvas widgets |
| `widget-context-press` / `widget-context-menu` | Context menu paths |
| `menu-command` / `native-command` / `shortcut` / `tray-action` | Command routing entry points |
| `focus` / `focus-next` / `focus-previous` | Focus control |
| `profile on\|off` | Frame timing in subsequent snapshots |
| `bridge <request-json>` | Host↔content bridge round-trip → `bridge-response.txt` |
| `provenance <view> <id\|at x y>` | Authorship spans for a live widget |
| `edit <view> <id> set-attr\|remove-attr\|set-text …` | Minimal-diff write-back into markup (requires hot-reload watch) |

Command delivery uses exclusive `command-<n>.txt` queue slots; success prints `delivered <action> -> <dir>` only after the app consumes the entry (~one presented frame). Full/stale queues time out ~10s with teaching errors.

### Assert / wait failure signals

- Timeout names missing/present patterns and prints a `snapshot.txt` tail
- Stale publisher (dead `publisher_pid`) or protocol skew refuses before false passes
- No automation dir: run from the app cwd; app must be automation-built

### Edit refusals (never write the file)

- Provenance not `authored=markup`
- App not watching (`MarkupOptions.watch_path`)
- On-disk hash ≠ loaded hash (concurrent edit)
- Checked span edit or whole-closure validation failure

---

## `native doctor`

```bash
native doctor [--strict] [--manifest app.zon] [--web-engine system|chromium] [--cef-dir path] [--cef-auto-install]
```

Prints a host report: OS/display, GPU software note, and probes.

| Check id (examples) | What it probes |
| --- | --- |
| `zig` | `zig version` on PATH |
| `log-path` | Resolved runtime log file (`NATIVE_SDK_LOG_DIR` overrides) |
| `manifest` | Optional: validate path from `--manifest` |
| `webview-system` | WKWebView / WebKitGTK 6 / WebView2 by OS |
| `webview-chromium` | CEF layout when chromium resolved; unsupported on Windows CEF host today |
| `codesign` / `notarytool` / `hdiutil` | macOS packaging tools |
| `app-icon` | Built-in icon pipeline availability |
| `ios-static-lib` / `android-static-lib` | Documented embed build triples |

`--strict` + any problem status → `DoctorProblems` (exit 1). Without `--strict`, problems are reported but the command succeeds.

Invalid flags → `InvalidArguments`.

---

## `native skills`

```bash
native skills list
native skills get <name> [--full]
native skills get --all [--full]
```

Discovers `SKILL.md` under `skills/` and `skill-data/` near the package root (or `NATIVE_SDK_SKILLS_ROOT`).

| Skill name | Role |
| --- | --- |
| `core` | Shared foundation, WebView shells, packaging, bridge |
| `native-ui` | Markup + Model/Msg/update authoring |
| `automation` | Running-app automation and verification |
| `native-sdk` | Discovery stub (`hidden: true`; omitted from `list`) |

`list` prints `name\tdescription` for non-hidden skills. `get` writes full `SKILL.md` to stdout; `--full` appends `references/` and `templates/` files. Unknown name → exit 1. Missing skill roots near the binary → exit 1.

---

## Related commands (brief)

### `native eject`

```bash
native eject [dir]
native eject component <name> [dir]
```

Writes owned `build.zig` + `build.zig.zon` **once** (`AlreadyEjected` if present). Component eject copies one library composite into `src/components/` (did-you-mean on typos).

### `native validate [app.zon]`

Manifest schema only; non-ok diagnostic → exit 1. File missing → teaching path error.

### `native package`

```bash
native package [--target macos|windows|linux|ios|android] [--output path] [--binary path]
  [--assets path] [--web-engine system|chromium] [--cef-dir path] [--cef-auto-install]
  [--signing none|adhoc|identity] [--identity name] [--entitlements path] [--team-id id]
  [--optimize ReleaseFast] [--archive]
```

Defaults binary discovery to `zig-out/bin/<name>` after `native build`. Shortcuts: `package-windows`, `package-linux`, `package-ios`, `package-android`.

### `native cef`

```bash
native cef install|path|doctor [--dir path] [--version version] [--source prepared|official] [--force]
```

Chromium/CEF layout helpers used when packaging or doctoring chromium engines.

---

## Environment variables

| Variable | Effect |
| --- | --- |
| `NATIVE_SDK_PATH` | Framework checkout (source + build graph) |
| `NATIVE_SDK_ZIG` | Zig executable override |
| `NATIVE_SDK_HOME` | Managed toolchain root (default `~/.native`) |
| `NATIVE_SDK_SKILLS_ROOT` | Override skills discovery root |
| `NATIVE_SDK_LOG_DIR` | Runtime log directory (doctor `log-path`) |
| `NATIVE_SDK_FRONTEND_URL` / `NATIVE_SDK_MODE` / `NATIVE_SDK_HMR` | Set by `native dev` frontend flow |
| `NATIVE_SDK_SESSION_RECORD` / `REPLAY` / `VERIFY` | Set by `automate record|replay` |

---

## Typical workflows

<Steps>
  <Step title="Scaffold and run">
    `native init my_app && cd my_app && native dev` — Debug binary, hot-reload `.native` views.
  </Step>
  <Step title="Fast validation loop">
    Edit markup → `native check` (ms) → `native test` when Model/Msg or tests change → `native build` for ReleaseFast.
  </Step>
  <Step title="Agent / smoke automation">
    Build with automation, run app, then `native automate wait`, `snapshot`, `assert`, widget commands, or `record`/`replay` journals.
  </Step>
  <Step title="Environment diagnosis">
    `native doctor --manifest app.zon --strict` before packaging or CEF/WebView work.
  </Step>
</Steps>

## Failure quick map

| Symptom | First check |
| --- | --- |
| `no app.zon here` | Wrong cwd; pass `[dir]` or `native init` |
| Cannot locate framework | `NATIVE_SDK_PATH`, npm install completeness, or `--framework` on init |
| Zig pin / download declined | Install Zig 0.16.0 or re-run with `--yes` |
| Dev no hot reload | Ensure Debug (default); Release optimize disables reload |
| Automate silent no-op | App not running, wrong cwd, not built with automation, protocol skew |
| Check only structural | Run `native test` to emit model contract |
| Orphan app after killing CLI | Fixed for `dev` via process groups where supported; still kill by hand if unsupported |

## Next

<CardGroup>
  <Card title="Installation" href="/installation">
    Install @native-sdk/cli, platform packages, and binary success signals.
  </Card>
  <Card title="Quickstart" href="/quickstart">
    native init → native dev → first live window.
  </Card>
  <Card title="Agent skills" href="/agent-skills">
    Skill packs discoverable via native skills.
  </Card>
  <Card title="Testing" href="/testing">
    native test, headless truth drivers, and frame-level checks.
  </Card>
  <Card title="Automation" href="/automation">
    Dropbox protocol, snapshots, record/replay, screenshots.
  </Card>
  <Card title="Packaging" href="/packaging">
    Release binaries to distributable bundles.
  </Card>
  <Card title="Testing in CI" href="/testing-ci">
    Gate scripts and reproducible headless checks.
  </Card>
</CardGroup>
