# CLI

> The zidane command, its subcommands, zidane run, the JSON result, exit codes, environment and upgrades.

The `zidane` command comes with the `zidane-tui` package ([install](https://zidane.si/docs/tui.md#install-and-run)). Bare `zidane` opens the [terminal app](https://zidane.si/docs/tui.md). Its flags, such as `--no-daemon` and `--no-remote`, are on [command-line switches](https://zidane.si/docs/tui.md#command-line-switches).

## Commands

| Usage | Description |
| - | - |
| `zidane` | Open the TUI. --no-daemon runs it in this process, ignoring the daemon setting. --no-remote turns remote hosts off (sets ZIDANE_NO_REMOTE=1). |
| `zidane run [flags]` | Open the TUI and run a prompt. |
| `zidane -p <text> --json-schema '<JSON>'` | Print JSON that matches the schema. No TUI. |
| `zidane daemon [flags]` | Run the shared chat host that syncs windows. |
| `zidane attach [flags]` | Attach a terminal client to the daemon, or to a zidane server with --host <wss-url> --token-file <path>. |
| `zidane server <cmd>` | Serve this computer's chat host to remote windows and manage its device tokens. --help lists the commands. |
| `zidane machine share` | Share folders and a shell on this computer with a host. |
| `zidane machine setup` | Make this computer a machine of a main server, as a service (--host <wss-url> --token-file <path> --name <n> --root <dir>). |
| `zidane --host <wss-url> --token-file <path\|->` | Open the TUI on a remote zidane server (or set ZIDANE_HOST_URL and ZIDANE_HOST_TOKEN). --token \<t\|-> also works, but ps and shell history show argv. ZIDANE_NO_REMOTE=1 or --no-remote blocks it and ignores ZIDANE_HOST_URL with a warning. Headless runs (--json, --json-schema) stay local. |
| `zidane extension <cmd>` | Create, test, pack and publish extensions (create \| test \| pack \| publish). --help lists the flags. |
| `zidane upgrade [flags]` | Update to the latest release. --help lists the flags. |

| Command | Home page |
| - | - |
| `zidane daemon`, `zidane attach` | [The daemon](https://zidane.si/docs/daemon.md) |
| `zidane server` | [Install the server](https://zidane.si/docs/server-install.md) |
| `zidane machine share` | [Remote hosts](https://zidane.si/docs/tui-remote.md#lend-a-machine) and [machines](https://zidane.si/docs/server-clients.md#machines) |
| `zidane --host` | [Remote hosts](https://zidane.si/docs/tui-remote.md#open-the-app-on-one-server) |

## zidane run

`zidane run` runs one prompt. In a checkout, `bun start` takes the same flags.

```bash
zidane run --prompt "Add a /health route that returns 200" --model claude-sonnet-4-5
```

| Output flag | Does |
| - | - |
| None | Opens the terminal app and sends the prompt there, in a new session or the one `--session-id` names |
| `--json` | Runs without the app and prints one result object when the run ends |
| `--stream-json` | Runs without the app, prints each finished turn as a JSON line, then prints the result object |

With `--json` or `--stream-json`, nothing asks for approval. zidane refuses `--host` and ignores `--preset`. `--codemode` adds the codemode tool to these runs. CI recipes: [headless and CI](https://zidane.si/docs/cli-headless.md).

### Flags

| Flag | Default | Description |
| - | - | - |
| `-h, --help` | None | Print help and exit. |
| `-p, --prompt <text>` | None | Prompt to run. |
| `-m, --model <id>` | None | Model id. |
| `-t, --preset` | `basic` | Preset name. One of `basic`. |
| `-s, --system <text>` | None | System prompt override. |
| `--thinking <level>` | `off` | Thinking (reasoning effort) level. One of `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`, `adaptive`. |
| `--provider <name>` | `anthropic` | Model provider. One of `anthropic`, `openai`, `openrouter`, `cerebras`, `xai`, `google`, `google-vertex`, `arcee`, `baseten`, `neuralwatt`, `local`, `openai-compat`. |
| `--base-url <url>` | None | Base URL for local/openai-compat. |
| `--api-key-env <NAME>` | None | Env var with the local/openai-compat API key. |
| `--headers-env <NAME>` | None | Env var with JSON headers for local/openai-compat. |
| `--header 'Name: value'` | None | Extra local/openai-compat header. Repeatable. |
| `--vision` | None | The local/openai-compat model reads images. |
| `--image-in-tool-result` | None | The local/openai-compat model reads images in tool results. |
| `--codemode` | None | Add the codemode tool to a --json or --stream-json run. |
| `--temperature <f>` | None | Sampling temperature for local/openai-compat. |
| `--seed <n>` | None | Sampling seed for local/openai-compat. |
| `-c, --context` | `process` | Execution context. One of `process`, `docker`, `e2b`, `daytona`. |
| `--image <image>` | None | Docker image for --context docker. |
| `--cwd <path>` | None | Tool execution working directory. |
| `--env KEY=VALUE` | None | Set an env var in the context (repeatable). |
| `--pass-env VARNAME` | None | Forward a shell env var into the context (repeatable). |
| `--pregame <file>` | None | e2b/daytona: upload + run this setup script once the sandbox is ready, before prompting (shebang picks the interpreter; a non-zero exit aborts the run). |
| `--sandbox <id>` | None | e2b/daytona: connect to an existing sandbox by id instead of creating one (left running on exit). |
| `--sandbox-on-destroy` | `kill` | e2b/daytona: what to do with a created sandbox at the end of the run (pause preserves state for reconnect via --sandbox; leave relies on provider TTL). One of `kill`, `pause`, `leave`. |
| `--mcp <json-or-path>` | None | MCP config as JSON, or a path to a JSON file. |
| `--session-db <path>` | None | SQLite session DB path. |
| `--session-id <id>` | None | Session id to load or create. |
| `--durability` | None | With --session-db: checkpoint runs; on resumes an interrupted run first (resume-ask never does here). One of `on`, `resume-ask`, `off`. |
| `--json-schema <JSON>` | None | Schema for result.output (implies --json). |
| `--schema <file.json>` | None | Read the output schema from a file. |
| `--json` | None | Wait for the run, then print only the result JSON. |
| `--stream-json` | None | Print each turn as JSONL, then the result JSON. |
| `--format` | `zidane` | JSON shape. provider prints raw provider messages. One of `zidane`, `provider`. |

`--provider` accepts the providers in the table above, which are fewer than the sign-in wizard offers ([providers](https://zidane.si/docs/providers.md)). The default is `anthropic`. `zidane run` rejects the `--restate` flags and exits with code 1. `zidane run` accepts `--durability` but ignores it. Use `bun start` or `bun run headless` with `--session-db` to checkpoint runs ([crash recovery](https://zidane.si/docs/durability.md)). In a checkout, `bun start --restate` runs through a local Restate endpoint.

### Structured output

`--json-schema '<JSON>'` (or `--schema <file.json>`) makes the agent return a matching object in `output`. It implies `--json`, and `run` is optional:

```bash
zidane -p "List the package's runtime dependencies" \
  --json-schema '{"type":"object","properties":{"deps":{"type":"array","items":{"type":"string"}}},"required":["deps"]}'
```

### The result object

stdout carries only the result. Logs go to stderr.

```json
{
  "status": "completed",
  "finalText": "Added GET /health in src/server.ts and a test.",
  "usage": { "input": 18230, "output": 912, "cacheRead": 12800, "cacheCreation": 0, "cost": 0.07 },
  "turns": 6,
  "durationMs": 41200,
  "numToolCalls": 5,
  "sessionId": "…",
  "transcript": []
}
```

| Field | Holds |
| - | - |
| `status` | `completed`, `aborted`, `error` or `timeout` |
| `finalText` | The agent's last answer |
| `output` | The schema-checked object, with `--json-schema` |
| `usage` | Tokens in, out, cache reads and writes, and cost when known |
| `turns` | Model turns |
| `numToolCalls` | Tool calls |
| `durationMs` | Wall time |
| `finishReason` | Why the last turn ended |
| `error` | `message` and `type`, when the run failed |
| `sessionId` | Resume it with `--session-id` |
| `summary` | The run summary: errors, blocked calls, budget events, retries and sub-agent runs |
| `transcript` | The turns of this run |

`--stream-json` first prints one `{"type":"turn","index":0,"turn":{…}}` line for each finished turn. `--format provider` prints the turns as provider messages instead of the result object. The messages use the Anthropic format with `--provider anthropic` and the OpenAI format with any other provider.

### Exit codes

| Code | When |
| - | - |
| `0` | `status` is `completed` |
| `1` | `status` is `error`, a flag was wrong, or zidane refused `--host` |

`zidane run --json` has no timeout. Ctrl+C writes no result and your shell reports 130. For a time limit and the `124` and `130` codes, use [`bun run headless`](https://zidane.si/docs/cli-headless.md#zidane-run-or-bun-run-headless).

## Environment

| Variable | Description |
| - | - |
| `ZIDANE_STORAGE_DIR` | Keep all storage in one dir (legacy layout). If unset and \~/.zidane/ is missing, Linux uses XDG paths. |
| `ZIDANE_PREFIX` | Override the storage prefix (default: .zidane). |
| `ZIDANE_CONFIG_DIR` | Override the XDG config dir (default: $XDG_CONFIG_HOME/zidane on Linux). |
| `ZIDANE_DATA_DIR` | Override the XDG data dir (default: $XDG_DATA_HOME/zidane on Linux). |
| `ZIDANE_STATE_DIR` | Override the XDG state dir (default: $XDG_STATE_HOME/zidane on Linux). |
| `ZIDANE_CACHE_DIR` | Override the XDG cache dir (default: $XDG_CACHE_HOME/zidane on Linux). |
| `ZIDANE_NO_UPDATE` | "1" turns off the background update check. |
| `ZIDANE_NO_DAEMON` | "1" turns the daemon off (same as --no-daemon). |
| `ZIDANE_NO_REMOTE` | "1" turns remote hosts off (same as --no-remote). |
| `ZIDANE_NO_ONBOARDING` | "1" never opens the setup wizard on its own. |
| `ZIDANE_HOST_URL` | Remote zidane server (wss\://) for the TUI. Needs ZIDANE_HOST_TOKEN. |
| `ANTHROPIC_API_KEY` | Anthropic API key (or sign in with OAuth in the TUI). |
| `OPENAI_CODEX_API_KEY` | OpenAI Codex API key (or sign in with OAuth in the TUI). |
| `OPENROUTER_API_KEY` | OpenRouter API key. |
| `CEREBRAS_API_KEY` | Cerebras API key. |
| `XAI_API_KEY` | xAI Grok API key (or sign in with OAuth in the TUI). |
| `GEMINI_API_KEY` | Google Gemini API key (Google AI Studio), or GOOGLE_API_KEY. |
| `GOOGLE_CLOUD_PROJECT` | Google Cloud project for --provider google-vertex. Signs in with gcloud ADC or GOOGLE_APPLICATION_CREDENTIALS. |
| `GOOGLE_CLOUD_LOCATION` | Vertex AI location for google-vertex (default: global). |
| `GOOGLE_CLOUD_API_KEY` | Vertex AI API key, in place of Google Cloud credentials. |
| `LOCAL_LLM_BASE_URL` | Base URL for --provider local/openai-compat. |
| `LOCAL_LLM_API_KEY` | Bearer key for local/openai-compat (optional). |
| `LOCAL_LLM_AUTHORIZATION` | Authorization header value for local/openai-compat, as is. |
| `LOCAL_LLM_HEADERS` | JSON object of extra local/openai-compat headers. |
| `LOCAL_LLM_DEFAULT_MODEL` | Default local/openai-compat model id. |

`ZIDANE_HOST_TOKEN` goes with `ZIDANE_HOST_URL`. Provider key variables: [providers](https://zidane.si/docs/providers.md). What the `ZIDANE_*_DIR` variables move: [files and folders](https://zidane.si/docs/files.md).

## Updating

```bash
zidane upgrade                       # check, then run your package manager
zidane upgrade --in-place            # download the release and swap the binary (macOS and Linux)
zidane upgrade --channel next        # another npm dist-tag
zidane upgrade --force               # reinstall even if up to date
```

The install runs in a background process. Ctrl+C or closing the terminal stops the output, never the package manager (exit code `130`). The log is `update.log` in the cache folder ([files and folders](https://zidane.si/docs/files.md)). A package manager still running after 10 minutes is stopped.

| Flag | Does |
| - | - |
| `--check` | Print the latest version and exit |
| `--dry-run` (or `--dryrun`) | Resolve everything without installing |
| `--in-place` (or `--inplace`) | Skip the package manager. Refused under Volta and on Windows. |
| `--tui-only` | Leave a global `zidane-gui` alone. By default it upgrades too. |
| `--package-manager <pm>` (or `--pm`) | Force `npm`, `pnpm`, `yarn`, `bun` or `volta` |
| `--registry <url>` | Another npm registry |
| `--channel <tag>` | Another dist-tag (default `latest`) |
| `--force` | Install even when up to date, or when the registry check failed |

| Exit code | Means |
| - | - |
| `0` | Upgraded, or `--check` finished (with or without an update) |
| `1` | The upgrade failed. The package manager failed, the download failed, the registry check failed, or the release cannot be downloaded yet. |
| `2` | Unknown flag, or a flag without its value |

The update check in the app: [install and first run](https://zidane.si/docs/tui.md#updates).

## Reference

- [`zidane/headless`](https://zidane.si/docs/reference/headless.md)
- [`zidane/output/terminal`](https://zidane.si/docs/reference/output-terminal.md)
- [`zidane/output/stream-json`](https://zidane.si/docs/reference/output-stream-json.md)
