--- title: Exit codes and JSON output description: How ClawMetry commands behave in scripts and CI — exit codes, the shared --json envelope conventions, and patterns for monitoring wrappers. keywords: clawmetry exit codes, clawmetry json output, clawmetry CI integration, agent monitoring scripts eyebrow: CLI reference --- # Exit codes and JSON output ClawMetry is meant to be scriptable. This page collects the conventions so a wrapper does not have to discover them one command at a time. ## Exit codes | Code | Meaning | |---|---| | `0` | Success | | `1` | The command's own failure condition — an eval suite with failures, a broken integrity chain | | `2` | Usage error — a missing required argument | The important ones: - **`clawmetry eval`** exits `0` on all-pass and `1` on any failure. That is the contract CI depends on. - **`clawmetry verify-integrity`** exits non-zero on a broken chain, and `--json` does not change the exit code — so you can capture the detail and still branch on the status. ## The `--json` convention Read-only commands emit a JSON envelope whose keys are aligned with the matching HTTP endpoint. That alignment is deliberate: a monitoring wrapper that reads `clawmetry tier --json` on a laptop and `GET /api/entitlement` in the cloud parses the same keys. Commands with `--json`: `status`, `tier`, `runtimes`, `features`, `channels`, `nodes`, `retention`, `bundle`, `license`, `activate`, `diagnose`, `verify-integrity`, `extensions`, `eval`, `proxy status`. Envelopes carrying an entitlement decision share three keys: ```json {"tier": "cloud_pro", "grace": true, "enforced": false, "...": "..."} ``` - `tier` — the resolved tier - `grace` — whether checks currently answer "allowed" regardless of tier - `enforced` — whether enforcement is active on this node ## Patterns ### Health check ```bash #!/usr/bin/env bash set -euo pipefail s=$(clawmetry status --json) running=$(jq -r '.daemon.running' <<<"$s") [[ "$running" == "true" ]] || { echo "clawmetry daemon down"; exit 1; } age=$(jq -r '.daemon.last_sync_age_secs // 0' <<<"$s") (( age < 600 )) || { echo "clawmetry daemon stale: ${age}s since last ingest"; exit 1; } ``` ### Fail a build on new eval regressions ```bash clawmetry eval --suite release-gate --json > eval.json || { jq -r '.results[] | select(.passed | not) | "FAIL \(.name): \(.reason)"' eval.json exit 1 } ``` ### Report spend to another system ```bash curl -s localhost:8900/api/local/aggregates \ | jq -c '.rows[] | {date: .day, cost: .cost_usd, tokens: .total_tokens}' \ | while read -r row; do curl -s -X POST "$METRICS_SINK" -H 'content-type: application/json' -d "$row" done ``` ### Detect a locked runtime you are paying for ```bash clawmetry runtimes --json \ | jq -e '[.runtimes[] | select(.detected and (.allowed | not))] | length == 0' \ >/dev/null || echo "detected runtimes are locked — run: clawmetry diagnose" ``` ## Quiet and offline | Variable | Effect | |---|---| | `CLAWMETRY_OFFLINE=1` | Skip every network call. Use in CI so a command cannot block on a fetch. | | `CLAWMETRY_NO_BROWSER=1` | Never open a browser | | `CLAWMETRY_NO_TELEMETRY=1` | Disable ClawMetry's own usage telemetry | | `NO_COLOR=1` | Plain output — worth setting when capturing to a log | ## Authenticating HTTP calls The examples above assume a loopback dashboard with no token. If you set `CLAWMETRY_API_TOKENS`, pass one: ```bash curl -s -H "Authorization: Bearer $CLAWMETRY_TOKEN" localhost:8900/api/local/sessions ``` → [Authentication](/docs/api/auth/)