> ## Documentation Index
> Fetch the complete documentation index at: https://docs.zespan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# CLI overview

> Install @zespan/cli, understand its two binaries (zespan and zespan-gate), and configure it with flags, environment variables, or a committed .zespan.yaml.

`@zespan/cli` is a small, dependency-free command-line tool. It ships two binaries:

| Binary        | What it runs                                                                                         | Status    |
| ------------- | ---------------------------------------------------------------------------------------------------- | --------- |
| `zespan`      | The full command registry — `auth`, `link`, `projects`, `doctor`, `policy` and `gate` as subcommands | New       |
| `zespan-gate` | The [CI quality gate](/sdk/cli) directly, with no subcommand                                         | Unchanged |

<Note>
  `zespan-gate` is not deprecated and nothing about it changed. If you already
  call `zespan-gate` from a CI pipeline, keep doing exactly that — `zespan gate`
  is the same logic reachable through the new binary, not a replacement for it.
</Note>

## Install

<CodeGroup>
  ```bash npm theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  npm install --save-dev @zespan/cli
  ```

  ```bash pnpm theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  pnpm add -D @zespan/cli
  ```

  ```bash yarn theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
  yarn add -D @zespan/cli
  ```
</CodeGroup>

This installs both `zespan` and `zespan-gate` into `node_modules/.bin`. You can also run either without installing:

```bash theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
npx @zespan/cli doctor
npx @zespan/cli gate --name my-prompt --version 3 --dataset-run-id run_abc123 --evaluator-id eval_def456
```

## Commands

```
Usage: zespan <command> [flags]

Commands:
  auth     Sign in to your Zespan account from this machine (login, status, logout)
  link     Choose the project this directory belongs to
  projects List every project your sign-in can reach (projects list)
  doctor   Diagnose SDK setup issues (config, connectivity, data flow, redaction)
  policy   Manage policy-as-code files (init, validate, plan, apply)
  gate     CI quality gate for prompt versions (same binary as zespan-gate)

Flags:
  --help      Show this help
  --version   Print the CLI version

Run `zespan doctor --help`-style flags directly on the doctor command, e.g.:
  zespan doctor --json
  zespan doctor --project <id> --api-key <key>
```

That's the literal output of `zespan --help` (also shown by `zespan` with no
arguments). An unrecognized command prints the same text to stderr and exits `2`.

* **`zespan auth`** — signs this machine in as *you*, with an OAuth 2.0 device grant a human approves in the browser. See [zespan auth](/cli/auth).
* **`zespan link`** / **`zespan projects list`** — choose the project a directory belongs to, and list every project you can reach. See [zespan link](/cli/link).
* **`zespan doctor`** — diagnoses SDK setup problems: bad or missing API key, unreachable API, no data arriving, PII redaction posture, and the most common "I installed the SDK and see nothing" mistake. See [zespan doctor](/cli/doctor).
* **`zespan policy`** — authors, plans and applies guardrail [policy-as-code](/policies/as-code) files. See [zespan policy](/cli/policy).
* **`zespan gate`** — gates a prompt version's quality in CI. Identical to `zespan-gate`; see [CI quality gate](/sdk/cli) for the full flag reference and exit code contract.

## Two credentials, two planes

The CLI can hold two credentials, and they are not interchangeable. Which one a
command uses is decided by what the command does, not by which one you happen to
have set.

|                   | Data plane                                                               | Control plane                                                                           |
| ----------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------- |
| **Credential**    | Project API key                                                          | Your user session                                                                       |
| **Sent as**       | `x-api-key` header                                                       | `Authorization: Bearer` header                                                          |
| **Obtained from** | **Settings → API Keys**                                                  | `zespan auth login`                                                                     |
| **Identifies**    | One project                                                              | One person, with a role in each organization                                            |
| **Used by**       | The SDKs, `/v1/ingest`, guardrail checks, `zespan doctor`, `zespan gate` | `zespan policy pull` / `test` / `plan` / `apply`, `zespan link`, `zespan projects list` |

<Warning>
  **An API key cannot run a control-plane command.** Those routes check your role
  in the organization, and a key authenticates a project — there is no role to
  check. `zespan policy plan` with only `ZESPAN_API_KEY` set now refuses with an
  explanation instead of sending a request that could only be rejected. Run
  [`zespan auth login`](/cli/auth) first.
</Warning>

If both are available, the sign-in wins on the control plane and the API key is
left untouched for the data plane — the two identities never silently mix. A
stored sign-in that is expired, or that was minted against a different API host,
produces a refusal naming the fix rather than a quiet fallback to the API key.

## Configuration file — `.zespan.yaml`

Both `zespan` commands read an optional `.zespan.yaml` from the current working directory. It supports a flat `key: value` format only — no nested maps, lists, or multi-line scalars. A line the parser can't make sense of is silently ignored rather than rejected, so a `.zespan.yaml` written for a future CLI version degrades gracefully on an older one instead of breaking it.

```yaml .zespan.yaml theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
project: 3f9c2e10-...
environment: production
```

| Key           | Aliases     | Maps to          |
| ------------- | ----------- | ---------------- |
| `project`     | `projectId` | Project id       |
| `environment` | `env`       | Environment name |

<Warning>
  **`.zespan.yaml` never carries your API key or your API URL**, even though
  the parser would technically accept `apiKey:` or `apiUrl:` lines — neither
  key is in the recognized set, and both are silently ignored. This is
  deliberate, not an oversight: `.zespan.yaml` is meant to be committed to
  your repository, and a secret in a committed file is a leaked secret. A
  committed file that could choose *where* your key gets sent is the same
  leak in one more hop — a malicious `apiUrl` could redirect your
  `ZESPAN_API_KEY` to an attacker-controlled host via the `x-api-key` header.
  Set the API key only via `--api-key` or `ZESPAN_API_KEY`, and the API URL
  only via `--api-url` or `ZESPAN_API_URL`.
</Warning>

## Environment variables

| Variable             | Equivalent flag | Notes                                                                                                                                                                                                       |
| -------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ZESPAN_API_KEY`     | `--api-key`     | Never read from `.zespan.yaml` — see above.                                                                                                                                                                 |
| `ZESPAN_API_URL`     | `--api-url`     | Never read from `.zespan.yaml` — see above. Defaults to `https://api.zespan.com/v1`.                                                                                                                        |
| `ZESPAN_PROJECT_ID`  | `--project`     | Set this when it should differ from the project your API key resolves to. If it's set AND doesn't match, `doctor`'s Data flow check fails with a plain "wrong project" diagnosis instead of a raw HTTP 403. |
| `ZESPAN_ENVIRONMENT` | `--env`         | Surfaced by `doctor`'s Environment check, and recorded by `zespan link` as this directory's default environment.                                                                                            |
| `ZESPAN_APP_URL`     | `--app-url`     | `zespan auth login` only. The dashboard origin to open the approval page on. Normally unnecessary — the API tells the CLI where to send you.                                                                |

## Precedence

For every value except the API key and the API URL: **flags > environment variable > `.zespan/config.json` > `.zespan.yaml` > built-in default**. The API key and the API URL both skip both files entirely — they only ever come from `--api-key`/`ZESPAN_API_KEY` and `--api-url`/`ZESPAN_API_URL` respectively.

`.zespan/config.json` is written by [`zespan link`](/cli/link) and carries the project and org. It sits above `.zespan.yaml` because it is the newer, explicit act; a project with no `.zespan/config.json` behaves exactly as before.

## Next steps

<CardGroup cols={2}>
  <Card title="zespan auth" icon="log-in" href="/cli/auth">
    Sign in as yourself, and what the approval screen checks.
  </Card>

  <Card title="zespan link" icon="link" href="/cli/link">
    Link a project to a directory, and list what you can reach.
  </Card>

  <Card title="zespan doctor" icon="stethoscope" href="/cli/doctor">
    What each check verifies, sample output, and how to read a failure.
  </Card>

  <Card title="zespan policy" icon="file-code" href="/cli/policy">
    Author, plan and apply guardrail policies from your repository.
  </Card>

  <Card title="CI quality gate" icon="git-branch" href="/sdk/cli">
    The `zespan gate` / `zespan-gate` flag reference and exit code contract.
  </Card>

  <Card title="API keys" icon="key" href="/account/api-keys">
    Create and rotate the key `zespan doctor` and `zespan gate` authenticate with.
  </Card>
</CardGroup>
