# CLI Output Contract (/docs/cli/output)



This page is a contract between the CLI and anything that parses it: shell scripts, CI pipelines, and AI coding agents. Behavior here is asserted by tests; changes to it are breaking changes.

## Streams [#streams]

* **stdout carries data only.** Tables, JSON, IDs, rotated secrets. Everything on stdout is safe to pipe.
* **stderr carries diagnostics and errors.** Env identity, request lines, row counts, warnings, failures. Humans read it; scripts redirect it away.
* `--help`, `--version`, and empty invocation print usage to stdout with no runtime chatter and exit 0.

## JSON envelope [#json-envelope]

Every data command accepts `--json` and emits one object:

```json
{
  "data": {}
}
```

One shape for every command, no metadata mixed into data. (`apps list` also accepts the legacy `--format=json` spelling; both produce the envelope.)

## Exit codes [#exit-codes]

| Code | Meaning                                                                                                            |
| ---- | ------------------------------------------------------------------------------------------------------------------ |
| `0`  | Success. For `status` and `doctor`, every probe/check passed.                                                      |
| `1`  | Usage error, auth failure, remote failure, environment failure, or any failed probe/check. stderr names the cause. |
| `3`  | Reserved: client below minimum supported version (update checker).                                                 |

## Prompt discipline [#prompt-discipline]

* The CLI never prompts without an interactive terminal. Piped and CI runs fail loud with a non-zero exit instead of hanging.
* The CLI never prints full secret values except the two once-only deliveries (`keys rotate`, token creation), each labeled copy-once.
* Errors are named shapes (`insufficient_scope`, `insufficient_binding`, `invalid_grant`), never generic strings. Retry logic keys off codes: scope and binding failures never resolve by retrying; grant failures need a fresh login.

## Modes [#modes]

`--json` > `--quiet` > `--verbose` > default. `--quiet` shows errors only. `--verbose` restores request URLs, row counts, probe chatter, and the target line. Default prints clean tables; failures always name their target.
