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

# CLI reference

> Every subcommand and flag of the plurai and plurai-scan-contract command-line tools.

The SDK installs three command-line tools:

| Tool | What it is |
| - | - |
| `plurai` | Local data handling and backend reads. This page. |
| `plurai-scan-contract` | Checks the scan's conclusions against your own files. [Below](#plurai-scan-contract). |
| `plurai-run-simulation` | The runner. See [Run simulations](https://docs.plurai.ai/sdk/run-simulations.md). |

## Common behavior

* **Backend and login.** Commands that reach the backend use your saved login from `plurai login`, or the
  `PLURAI_URL` and `PLURAI_TOKEN` pair when both are exported. There is no URL or token flag. See
  [Environment variables](https://docs.plurai.ai/reference/environment-variables.md).
* **Anonymization posture.** The `ingest-*` commands read the posture from the top-level `anonymize:` key in
  `plurai.config.yaml`. It is a workspace setting, never a per-run flag. Under `anonymize: true` they scrub
  personal data locally before upload and refuse to run without the `anonymize` extra. See
  [Data and privacy](https://docs.plurai.ai/security/data-and-privacy.md).
* **Disclosure and audit.** Before any upload, every `ingest-*` command prints what it is about to send (sizes,
  posture, hashes, scrub summary) to stderr and writes it to `.plurai/uploads/disclosure-<kind>.txt`. Every upload
  is recorded in `.plurai/uploads/audit.log`.
* **Output.** stdout carries only what a caller parses (a manifest, an id, a JSON entry). Diagnostics go to
  stderr.
* **`--overrule FILE`.** `convert-trace`, `ingest-bundle`, `ingest-corpus`, `ingest-doc-examples`, `ingest-run`,
  `ingest-run-report` and `ingest-traces` take overrules for their gate findings: a YAML or JSON list of
  `{gate_id, fingerprint, reason}`. An overrule lapses when the evidence changes. Security and invariant gates are
  never lifted.

### --workspace-root

Every `ingest-*` command, `convert-trace` and `folder-names` take `--workspace-root DIR` (default `.`). The
`.plurai/` folder (anonymization key, disclosure and audit log) is created under it, and `plurai.config.yaml` is
looked up at `<root>/plurai.config.yaml`, then `<root>/plurai_sim/plurai.config.yaml`. The plugin passes the
`plurai_sim` folder. Pick one spelling per workspace and keep it: under the `anonymized` posture, a second
spelling mints a second key and breaks pseudonym stability across uploads.

### Global flags

| Flag | Prints |
| - | - |
| `plurai --version` | The installed version, for example `plurai 0.28.31`. |
| `plurai --identity` | Which build is running (a commit or content hash), not only its declared version. |

## capabilities

```bash theme={null}
plurai capabilities
```

Prints this build's identity and surface as JSON: `version`, `identity`, `commands` (read off the live CLI),
`features`, `overrule_commands`, `trace_selection_keys` (per trace source, the source-config keys that narrow an
export) and `trace_formats` (the built-in `convert-trace` readers). Check a feature here rather than comparing
version strings.

| Feature | Means |
| - | - |
| `parts-only-upload` | Every upload sends raw parts only, which current backends require. |
| `content-addressed-parts` | `ingest-traces` and `ingest-corpus` print a part entry, and `ingest-descriptions` exists. |
| `corpus-domain-member` | `ingest-corpus --domain-file` exists. |
| `plan-only-parts` | `--plan-only` and `--expect-sha256` exist on `ingest-traces`, `ingest-corpus` and `ingest-descriptions`. |
| `export-dir-traces` | `ingest-traces --source-kind export_dir` reads a saved trace export. |

## ingest-traces

Exports production traces from your observability platform locally, applies the posture, and uploads them as one
content-addressed part. See [Trace sources](https://docs.plurai.ai/integrations/trace-sources.md) for each source's config.

```bash theme={null}
plurai ingest-traces --source-kind langsmith --source-config ls.json --out-dir plurai_sim/traces
```

| Flag | Required | Meaning |
| - | - | - |
| `--source-kind KIND` | Yes | `langsmith`, `langfuse` or `export_dir`. |
| `--source-config FILE` | | A JSON file of the source's config, credentials included. It stays local. |
| `--out-dir DIR` | Yes | Where the export is written. A re-run replaces the previous export there, and refuses a `traces/` folder holding files it did not write. |
| `--limit N` | | At most N traces (or N conversations, when exporting by `thread_ids`). |
| `--declared-names FILE` | | A JSON list of names your agent declares (tools, fields, arguments). Under `anonymized`, those names are kept through the scrub. |
| `--plan-only` | | Build the part exactly as a real run does, print its entry with `"planned": true`, and stop. No request is made and no credentials are read. |
| `--expect-sha256 sha256:HEX` | | The hash the approved plan printed. A part that hashes differently is refused before anything is disclosed or sent. |
| `--workspace-root DIR`, `--overrule FILE` | | See [Common behavior](#common-behavior). |

stdout is one part entry: `{kind, name or label, sha256, bytes, posture, anon_key_fingerprint}`.

## ingest-corpus

Extracts a RAG or SQL knowledge corpus locally, applies the posture, and uploads it as one part. Your data
source's credentials stay local.

| Flag | Required | Meaning |
| - | - | - |
| `--source-kind KIND` | Yes | The extractor source, for example a directory of documents. |
| `--source-config FILE` | | A JSON file of the extractor's source config. |
| `--out-dir DIR` | Yes | Where the extraction is written. |
| `--root PATH` | | A directory source root: a folder or one file. Repeat; every root lands in one corpus. |
| `--scan-contract FILE` | | For a directory source: the scan's `scan_contract.json`, whose recorded suffixes set what is ingested. |
| `--suffixes [SUFFIX ...]` | | For a directory source, instead of `--scan-contract`: the extra suffixes the scan used. Alone, the default set. |
| `--domain JSON` | | Inline JSON domain hints recorded in the local manifest. |
| `--domain-file FILE` | | A JSON object with an optional `"domain"` object and optional `"questions"` list, at most 256 KiB, added to the part unscrubbed as `domain.json`. |
| `--chunk-mode {section,tokens}` | | `section` (markdown headings, the default) or `tokens` (a sliding window). |
| `--chunk-size N` | | Maximum tokens per chunk. |
| `--chunk-overlap N` | | Token overlap between windows. |
| `--extract-only` | | Extract into `--out-dir` and stop before anything leaves the machine. stdout reports chunk, relationship and document counts, so you can re-chunk before you publish. |
| `--label NAME` | | The part's label (default `kb`). |
| `--declared-names FILE`, `--plan-only`, `--expect-sha256` | | As for `ingest-traces`. `--plan-only` cannot be combined with `--extract-only`. |
| `--workspace-root DIR`, `--overrule FILE` | | See [Common behavior](#common-behavior). |

## ingest-descriptions

Delivers your agent's descriptions as content-addressed parts: `plurai.config.yaml`, `simulation_prd.md` and
`scenario_variables.yaml`, whichever exist. They are sent as written, with no posture.

| Flag | Meaning |
| - | - |
| `--descriptions-dir DIR` | The folder holding the files. Default: `--workspace-root`. |
| `--scan-contract FILE` | Also deliver the scan's `scan_contract.json`. |
| `--plan-only` | As for `ingest-traces`; every entry is marked `"planned": true`. |
| `--expect-sha256 NAME=sha256:HEX` | Repeat once per part. The parts built must be exactly those named. |
| `--workspace-root DIR` | See [Common behavior](#common-behavior). |

stdout is one JSON array of part entries.

## ingest-doc-examples

Scans a folder of example documents, applies the posture, and uploads them so generated documents follow your
real formatting.

| Flag | Required | Meaning |
| - | - | - |
| `--source-dir DIR` | Yes | The folder of example documents. |
| `--out-dir DIR` | Yes | Where the local extraction is written. |
| `--workspace-root DIR`, `--overrule FILE` | | See [Common behavior](#common-behavior). |

stdout is the upload manifest. Under `anonymized`, images and PDFs need the `anonymize-binary` extra.

## ingest-bundle

Applies the posture to a prepared scenario bundle (real records, or a converted trace) and uploads it.

| Flag | Required | Meaning |
| - | - | - |
| `--bundle-dir DIR` | Yes | The bundle folder, for example the `--out-dir` of `convert-trace`. |
| `--workspace-root DIR`, `--overrule FILE` | | See [Common behavior](#common-behavior). |

## ingest-run

Uploads a finished Run's saved artifacts, so the backend can re-score them without re-running.

| Flag | Required | Meaning |
| - | - | - |
| `--run-dir DIR` | Yes | The runner's `--out` folder. |
| `--eval-set-id ID` | | The eval set this Run was scored against. Omit rather than guess. |
| `--scenario-set-id ID` | | The scenario set this Run was driven from. Omit rather than guess. |
| `--harness-fingerprint DIGEST` | | An opaque digest of the harness, passed through verbatim, so a later replay can tell the harness changed. |
| `--agent-version TAG` | | Override the agent version. Normally omitted: the Run's transcripts record it. |
| `--workspace-root DIR`, `--overrule FILE` | | See [Common behavior](#common-behavior). |

## ingest-run-report

Uploads a Run's rendered report, to attach to that Run's upload.

| Flag | Required | Meaning |
| - | - | - |
| `--run-dir DIR` | Yes | The runner's `--out` folder the report was rendered into. With no report there, stdout is `{"absent_reason": ...}` (`stale_run` or `not_rendered`) and nothing is uploaded. |
| `--workspace-root DIR`, `--overrule FILE` | | See [Common behavior](#common-behavior). |

## convert-trace

Converts a trace export into a scenario bundle that resumes the real conversation where it stopped. It runs
locally and uploads nothing; publish the result with `ingest-bundle`.

| Flag | Required | Meaning |
| - | - | - |
| `--export PATH` | Yes | One trace export, or a folder of them (for example an `ingest-traces` `--out-dir`). Each thread is converted or skipped on its own. |
| `--out-dir DIR` | Yes | The bundle folder to write: one folder per thread with `ROLES.md`, `resume_pin.json` and `transcript.md`, plus `BUNDLE.md`. |
| `--source-format NAME` | | A built-in reader (`plurai capabilities` lists them under `trace_formats`), or the name of an adapter committed under `plurai_adapters/<name>.yaml` in your workspace. |
| `--into FOLDER` | | Convert into an existing hand-authored folder under `--out-dir`, keeping its materials. Requires a single `--export`. |
| `--start-node NAME` | | The graph node your harness enters on the resumed leg's first turn. |
| `--cut-turn K` | | Resume from user turn K instead of from the end. Turns count from 0 over user messages. |
| `--trim-mid-turn-tail` | | Accept a trace captured between a tool call and its result by dropping the incomplete tail. |
| `--render-only` | | Write only each thread's numbered `transcript.md`, to choose a `--cut-turn`. |
| `--workspace-root DIR`, `--overrule FILE` | | See [Common behavior](#common-behavior). |

A resumed scenario needs a `seed_state` that applies the resume seed. See
[Write a harness](https://docs.plurai.ai/sdk/write-a-harness.md#seed_state). Exit code `2` only when nothing was written.

## stash-doc

Stashes one generation input (a PRD, a `scenario_variables.yaml`) on the backend from disk and prints its input
doc id, so the document never passes through a model's context.

```bash theme={null}
ID=$(plurai stash-doc /abs/path/simulation_prd.md simulation_prd)
plurai stash-doc /abs/path/simulation_prd.md simulation_prd --out plurai_sim/.prd_upload_id
```

| Argument or flag | Meaning |
| - | - |
| `FILE` | The UTF-8 document. Pass an absolute path. |
| `LABEL` | The key the backend files it under. Characters `[A-Za-z0-9._-]`. |
| `--out ID_FILE` | Also write the id to `ID_FILE`, atomically, only on success. A failed run removes any file already there. |

The id is content-addressed: an unchanged file gives the same id.

| Exit code | Meaning |
| - | - |
| `0` | Stashed. |
| `1` | File missing, empty or unreadable, or a non-loopback URL with no token. |
| `2` | Transport failure, or no id in the answer. |
| `3` | The backend predates this command. |
| `4` | Token rejected. |
| `5` | The document was refused: not UTF-8, blank, or too large. |
| `64` | Usage error. |

## fetch

Downloads backend-owned files. Both commands write through a temp file and a rename, so a failed fetch never
truncates a good file.

### fetch policies

```bash theme={null}
plurai fetch policies <eval_set_id> --out plurai_sim/policies_config.yaml
```

| Argument or flag | Meaning |
| - | - |
| `EVAL_SET_ID` | The eval set. |
| `--out FILE` | Required. The file to write. |
| `--allow-draft` | Also write an open edit session's draft. Without it, a draft is refused (exit `3`) and the file is untouched. |

Prints `state=<promoted|draft|unknown|absent>`.

### fetch artifact

```bash theme={null}
plurai fetch artifact <artifact_id> policies_config.yaml generation_trace.md --dir plurai_sim
```

| Argument or flag | Meaning |
| - | - |
| `ARTIFACT_ID` | The artifact. |
| `RELPATH ...` | One or more files inside it. |
| `--dir DIR` | Write each file to `DIR/<relpath>`. One of `--dir` or `--out` is required. |
| `--out FILE` | Write the one file to `FILE`. |

Prints `wrote <path>` or `missing <relpath>` per file, and exits `1` when any file is missing.

## job

```bash theme={null}
plurai job status <job_id>
plurai job wait <job_id> [--max-seconds N]
```

| Command | Meaning |
| - | - |
| `job status JOB_ID` | One read of the job; prints its envelope as JSON. |
| `job wait JOB_ID` | Blocks until the job is done or failed, printing a timestamped line per status change. The exit code is the result, so never pipe it. |
| `--max-seconds N` | For `wait`: the wall-clock budget, clamped to 30–540 seconds (default 540). |

A job id that is not one the backend issues is refused before any request.

## backend

```bash theme={null}
plurai backend identity
code=$(plurai backend probe [--path /healthz] [--timeout 5])
```

| Command | Meaning |
| - | - |
| `backend identity` | Prints which deployment the backend is, as one line of JSON. |
| `backend probe` | Prints the HTTP code of `GET PATH` (`000` for no answer). Exits `0` only on a 2xx. |
| `--path PATH` | For `probe`: the path to check (default `/healthz`). |
| `--timeout S` | For `probe`: seconds for the whole exchange (default 5). |

## Other commands

### correct-scores

```bash theme={null}
plurai correct-scores --run-dir plurai_sim/runs/nightly
```

Overwrites, on your connected Langfuse or LangSmith, the score of every eval whose verdict was corrected after the
Run. Prints one line per eval: `written`, `not_recorded`, `unsupported` or `failed`. With no platform connected, it
prints a skip line. Exits `0`, except `2` when the Run folder or a `verdicts.json` cannot be read.

### More commands

| Command | What it does |
| - | - |
| `login`, `login --status` | Sign in through your browser and save a key, or show who you're signed in as. See [Sign in](https://docs.plurai.ai/sdk/overview.md#sign-in). |
| `logout` | Revoke the saved key and remove it from this machine. If the backend can't be reached, the file is kept so you can try again (exit `75`). |
| `diagnose` | Print a bundle to paste into a support issue. It never includes a token. See [Get help](https://docs.plurai.ai/sdk/overview.md#get-help). |
| `folder-names [TEXT ...]` | Prints the local map of pseudonymized scenario folder names (anonymized bundle uploads), or the given text with each pseudonym replaced. Local only. |
| `verdicts`, `scores` | Write a conversation's `verdicts.json` and recompute a Run's scores. The plugin uses these; you do not need them. |

## plurai-scan-contract

Runs the scan's conclusions against the files they were drawn from, on your machine, before generation spends
anything.

### check

```bash theme={null}
plurai-scan-contract check --corpus ./docs --out plurai_sim/artifacts
```

Writes `scan_contract.json` and `pre_generation_findings.md` to `--out`, plus an internal record under
`.plurai/gate_authority/` that you should never commit or upload.

| Flag | Default | Meaning |
| - | - | - |
| `--corpus PATH` | required | A corpus root: a folder or one file. Repeat. |
| `--facts FILE` | | Typed scan facts (YAML or JSON) to verify against the corpus. |
| `--out DIR` | `.` | Where the artifact and report are written. |
| `--corpus-id ID` | | The built corpus id the source fingerprint is stored beside. |
| `--against FILE` | | A previous `scan_contract.json`, to report source drift. |
| `--source-root DIR` | | The tree each fact's `source:` citation resolves against (your agent's code). Repeat. |
| `--state-schema FILE` | | `scenario_state_schema.yaml`. |
| `--stateless-finding TEXT` | | What the scan established about an agent that reads no turn-0 state. Instead of `--state-schema`. |
| `--variables FILE` | | `scenario_variables.yaml`. |
| `--prd FILE` | | Accepted and not read. |
| `--suffixes SUFFIX` | every format the SDK reads | An extra plain-text suffix to admit. Repeat. A binary suffix is refused. |
| `--service-indicators FILE` | | A YAML map of `service name: [ENV_VAR, ...]`, merged into the built-in table of external services. |
| `--probe-budget N` | `3` | How many verified absences generate an adversarial probe. |
| `--probe-consent` | off | You consent to probing the live agent. Without it, no probe runs. |
| `--agent-command CMD` | | A command that reads one probe question on stdin and prints your agent's reply. Needed with `--probe-consent` to fire probes. |
| `--smoke-budget N` | `4` | Hard cap on probes fired at the live agent. |
| `--probe-timeout S` | `120` | Seconds one probe may take. |
| `--overrule FILE` | | Overrules for held findings. |

`check` touches nothing but your files unless you pass both `--probe-consent` and `--agent-command`. Then it sends
one derived question per probe to your own command, never to a Plurai service, and refuses any question that
opens with a state-changing instruction. The replies are kept in the report as evidence, so review the artifact
before you commit or upload it.

| Exit code | Meaning |
| - | - |
| `0` | No held finding. |
| `1` | A held finding: a fact your files refute, or a corpus root that admitted no file. |
| `2` | Usage error or malformed input, including a malformed `--overrule` file. |
| `5` | The checker itself failed. |

### recheck

```bash theme={null}
plurai-scan-contract recheck --corpus ./docs --against plurai_sim/artifacts/scan_contract.json
```

Re-hashes your files and reports drift against a recorded scan. Always exits `0`: drift is advisory.

| Flag | Meaning |
| - | - |
| `--corpus PATH` | Required. A corpus root, in the same order as the recording. Repeat. |
| `--against FILE` | Required. The `scan_contract.json` whose inventory is the baseline. |
| `--facts FILE` | Re-verify these facts against your files as they are now. |
| `--policies FILE` | A suite's `policies_config.yaml`, to name the evals a refuted fact takes down. |
| `--dataset-metadata FILE` | A scenario set's `dataset_metadata.yaml`, to name the scenarios a refuted fact takes down. |
| `--suffixes SUFFIX` | An extra suffix, used only for a baseline that recorded no scope. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.