Documentation menu

SchemaClient CLI command reference

Every @schemaclient/cli command and flag: run, send, validate, schema lint/mock/infer — variables, reporters, data-driven runs, and the exit-code contract.

Updated

This is the full command and flag reference for @schemaclient/cli 0.2, built for scanning — every flag below is spelled exactly as the CLI spells it. For the narrative version of why the CLI exists and how collections and schemas fit together, read the CI runner guide; this page is for when you already know what you want.

Install

npm install -g @schemaclient/cli

Requires Node.js 20+. Two equivalent binaries are installed: schemaclient and the short alias scli. It is scli rather than sc because on Windows sc is already the built-in Service Control tool, and shadowing a system utility is not a trade worth making.

Global flags

These work on every command:

| Flag | Effect | | --- | --- | | -V, --version | print the version and exit | | -v, --verbose | extra diagnostics and full stack traces | | -s, --silent | suppress diagnostics; reporter output still goes to stdout | | --no-color | disable ANSI colour | | --ci | force non-interactive output (auto-detected in most CI environments) |

run — the collection runner

schemaclient run <target>

<target> is a collection file, or a single URL. Everything below applies to run.

Variables and secrets

| Flag | Effect | | --- | --- | | --var <key=value> | inline variable (repeatable) | | --secret-var <key=value> | like --var, but masked to •••••• in all output | | -e, --env <file> | JSON file of environment variables (collection mode) | | --env-passthrough | expose every environment variable to the collection, not just SCHEMACLIENT_VAR_* ones — see environment variables |

Precedence, lowest to highest: process environment → config file → suite → folder → --env file → data row → --var → captures → script writes. The practical version: --var pins a value for the whole run, and a value written in the collection beats one that happens to be exported in your shell.

Data-driven runs

| Flag | Effect | | --- | --- | | -n, --iterations <count> | run the collection this many times | | -d, --data <file> | CSV or JSON data file — one iteration per row | | --parallel <n> | run this many iterations concurrently | | --seed <n> | make generated variables ({{$uuid}}, {{$randomInt}}, …) deterministic |

CSV headers may declare a type so values are not all sent as strings:

id:number,active:boolean,meta:json
1,true,{"tier":"pro"}

Under --parallel, iterations are isolated — a variable written in one iteration is never visible to a sibling — and --seed derives values per iteration, so a parallel run reproduces a sequential one.

Request control

| Flag | Effect | | --- | --- | | --bail [mode] | stop the run early on failure; mode is failure (default) or folder | | --timeout <ms> | per-request timeout | | --delay <ms> | pause between requests, for rate-limited APIs | | --max-redirects <n> | how many redirects to follow (0 disables following) | | -k, --insecure | accept self-signed or mismatched TLS certificates | | --proxy <url> | route requests through an HTTP proxy |

Sidecar assertions

| Flag | Effect | | --- | --- | | --tests <file> | assertions sidecar (default: <collection>.tests.json) | | --no-tests | ignore the sidecar assertions file | | --collection <name> | which collection to run from a multi-collection export |

Collections exported from the desktop app do not carry assertions, so assertions live in the sidecar: the app owns the requests, the sidecar owns the CI contract.

Debugging

| Flag | Effect | | --- | --- | | --dry-run | resolve and print every request without sending anything | | --print-vars | with --dry-run, show the resolved variables and their scopes | | --unresolved <policy> | undefined {{var}} handling: error (default), warn, ignore |

An unresolved variable fails the request by default instead of sending {{baseUrl}} into a URL as literal text — a typo should name itself, not surface as a DNS error. --unresolved=warn restores the looser behavior if an old collection depends on it.

Output

| Flag | Effect | | --- | --- | | --reporter <name> | cli (default), junit, json, html, tap, or github | | --out <file> | write the report to a file instead of stdout | | --suppress-exit-code | always exit 0, even when assertions fail |

github is the cli output plus ::error annotations in the PR checks UI; json is machine-readable with secrets redacted; html is a single self-contained file; junit is the XML most CI dashboards render natively.

Schema and scripts

| Flag | Effect | | --- | --- | | --schema-strict | fail on response fields the schema does not declare (default: warn) | | --no-scripts | skip all pre-request and test scripts |

Scripts run in a node:vm sandbox with no require or process access — but that sandbox is isolation, not a hardened security boundary. Running a collection someone else wrote? Use --no-scripts.

send — one ad-hoc request

schemaclient send GET http://127.0.0.1:8009/api/products/1/
schemaclient send POST https://api.example.com/graphql \
  -H "Content-Type: application/json" -d '{"query":"{ products { id } }"}'

curl-shaped, with validation bolted on:

| Flag | Effect | | --- | --- | | -H, --header <"Key: Value"> | header (repeatable) | | -d, --data <body> | request body, sent as-is | | --schema <file> | validate the response against a schema file | | --expect-status <code> | assert the response status code | | --timeout <ms> | timeout, default 30000 |

A bare host works: localhost, 127.0.0.1, 0.0.0.0 and [::1] get http://, everything else gets https://.

validate — offline, no network

schemaclient validate response.json --schema schemas/product.sc

Checks a JSON file against a schema without sending anything. --schema is required.

schema — work with .sc files

| Command | Purpose | | --- | --- | | schema lint <file.sc> | compile the schema and report diagnostics | | schema mock <file.sc> | generate mock data (--name picks a schema in the file, --seed for deterministic output) | | schema infer <response.json> | infer a schema from a JSON response body |

infer is the fast way to bootstrap a contract from a live endpoint:

curl -s https://api.example.com/products/1 > response.json
schemaclient schema infer response.json --method GET --path "/products/{id}"

--method and --path produce an @http response block (--status sets its status code, default 200); --name infers a bare named type instead. The engine behind all three subcommands is the same one the desktop app uses for schema validation, so a contract behaves identically in both.

init — scaffold a suite

schemaclient init my-api-suite

Creates a starter suite and an example schema in the directory (default: the current one). --force overwrites existing files.

Exit codes

The exit codes are a stable contract — script against them:

| Code | Meaning | | --- | --- | | 0 | everything passed | | 1 | at least one assertion or test failed | | 2 | usage error — bad flag or missing argument | | 3 | load error — a file was missing or malformed | | 4 | internal error — a bug; please report it |

--suppress-exit-code forces 0 after test failures. It does not mask a 2: a mistyped flag is still a mistyped flag.

Environment variables

Only variables named SCHEMACLIENT_VAR_<NAME> are visible to a collection, as {{NAME}} — and they arrive pre-masked as secrets:

SCHEMACLIENT_VAR_TOKEN=abc123 schemaclient run suite.scoll.json   # provides {{TOKEN}}

The restriction is deliberate. A collection is executable input, and you will run collections other people wrote — if the whole environment were readable, any shared collection could exfiltrate {{AWS_SECRET_ACCESS_KEY}} just by interpolating it into a URL. The prefix makes exposure a decision instead of a default. --env-passthrough opts into the full environment for when you wrote the collection yourself and want the convenience.

A minimal CI job

# .github/workflows/api-tests.yml
- uses: actions/setup-node@v4
  with: { node-version: 20 }
- run: npx @schemaclient/cli run ./suite.scoll.json --reporter junit --out reports/junit.xml
  env:
    SCHEMACLIENT_VAR_TOKEN: ${{ secrets.API_TOKEN }}

For the collection format, sidecar files, and the schema language itself, continue with the CI runner guide.

Frequently asked questions

How do I pass variables to the SchemaClient CLI?

Four ways: --var key=value for inline values, --secret-var for values that must be masked in output, -e env.json for an environment file, and SCHEMACLIENT_VAR_NAME environment variables, which appear to the collection as {{NAME}} and are masked automatically. Inline --var beats both the data file and the environment.

What do the SchemaClient CLI exit codes mean?

0 = everything passed, 1 = at least one assertion or test failed, 2 = usage error (bad flag or missing argument), 3 = load error (missing or malformed file), 4 = internal error. --suppress-exit-code forces 0 after test failures but never masks a usage error.

How do I run a collection once per row of a CSV file?

schemaclient run suite.scoll.json -d rows.csv runs one iteration per row. Column headers can declare types — id:number,active:boolean,meta:json — so values are not all sent as strings. Add --parallel 4 to run iterations concurrently and --seed to keep generated values reproducible.