CLI reference
razo-analyzer ships two binaries: razo-analyze runs Claude over your failed tests' razo-steps.json and prints a business-level analysis, razo-upload sends the same artifacts to a razo dashboard project. Both scan a directory recursively by default and accept a single razo-steps.json file or a directory as their target argument.
npm install -D @razohq/razo-analyzerBoth binaries accept -h/--help. See The artifact for the shape of razo-steps.json.
razo-analyze
npx razo-analyze [target] [options]Loads every failed test's razo-steps.json under target, sends it to Claude, and prints a Markdown analysis to stdout — which action failed, a root-cause hypothesis, and a suggested fix.
| Argument / option | Default | Meaning |
|---|---|---|
target | test-results | An razo-steps.json file or a directory to scan recursively |
--out <file> | — | Also write the analysis to a file |
--pr-comment | off | Post/update the analysis as a PR comment (GitHub Actions context) |
--provider <name> | anthropic | Model provider: anthropic or openai |
--model <id> | claude-opus-4-8 (anthropic) | Model id; required with --provider openai |
--dry-run | off | Print the prompt(s) instead of calling the API |
-h, --help | — | Show usage |
| Environment variable | Meaning |
|---|---|
ANTHROPIC_API_KEY | Credentials for the default anthropic provider (or log in once with ant auth login) |
OPENAI_API_KEY | Credentials when using --provider openai |
RAZO_ANALYZE_BUDGET | Prompt budget in characters (default 200000); large suites split into one API call per batch |
GITHUB_TOKEN + PR context | Required by --pr-comment — see CI setup |
| Exit code | Meaning |
|---|---|
0 | Success — including "nothing to analyze" |
1 | API error |
2 | Usage error (bad flag, missing target) |
razo-upload
npx razo-upload [target] --url <ingest-url> --token <rz_...>Uploads razo-steps.json artifacts to a razo dashboard project. Payloads are trimmed to the server's ingest limits before sending — see Size limits below — so an upload never fails because of size.
| Argument / option | Default | Meaning |
|---|---|---|
target | test-results | An razo-steps.json file or a directory to scan recursively |
--url <ingest-url> | $RAZO_INGEST_URL | The dashboard ingest endpoint, e.g. https://razo.ar/api/ingest |
--token <rz_...> | $RAZO_INGEST_TOKEN | The project's ingest token, from the dashboard's project Settings tab |
-h, --help | — | Show usage |
| Environment variable | Meaning |
|---|---|
RAZO_INGEST_URL | Default for --url |
RAZO_INGEST_TOKEN | Default for --token |
GITHUB_* (Actions) | Branch, commit, PR number and CI link are read automatically and attached to the run |
| Exit code | Meaning |
|---|---|
0 | Success — including "nothing to upload" |
1 | Upload failed |
2 | Usage error (missing --url/--token) |
Missing --url or --token (and no corresponding env var) is a usage error, not a network attempt.
Size limits
Neither binary trims silently, and neither fails a build because a suite is large:
razo-analyzebudgets its prompts (default 200k characters ≈ 50k tokens, override withRAZO_ANALYZE_BUDGET). Suites that exceed the budget split into batches, one API call per batch, with the analyses concatenated in order. A single huge test gets its middle passed steps collapsed into a… N steps omitted …marker; failed steps are never dropped.razo-uploadtruncates to the dashboard's ingest limits before sending: 20k characters per error text, 500 steps per test, a 2MB payload, and 200 reports per run. Failed reports are always kept; oversized passed reports are dropped first, and the CLI reports how many. Therazo-steps.jsonfiles on disk are never modified — only the upload payload is trimmed.
--dry-run example (abridged)
--dry-run prints the exact prompt(s) that would be sent, without calling the API — useful for checking what Claude will see, or for token budgeting:
$ npx razo-analyze --dry-run
Analyzing 1 failed test(s)...
Analyze the following 1 failed test(s).
## Test: export a model without choosing quality
File: tests/demo.spec.ts — status: failed
Narrated steps:
- [passed] Type "mi-llavero" into field "Filename"
- [passed] Choose "3MF" in select "Format"
- [passed] Click button "Export"
- [failed] Assert label "Export status" has text "Exported mi-llavero.3mf (Standard)"
expected: "Exported mi-llavero.3mf (Standard)"
actual: "Error: missing fields"
error: expect(locator).toHaveText(expected) failed
Test-level error:
Error: expect(locator).toHaveText(expected) failed
...
A suite that exceeds RAZO_ANALYZE_BUDGET prints one prompt per batch, separated by ===== NEXT BATCH =====.
Next steps
- CI setup — full workflow YAML for both binaries.
- Dashboard & plans — what an uploaded run looks like, and how hosted analysis quotas work.