Skip to main content
selo runs a Selo release test from a terminal or a CI job and turns the verdict into an exit code a pipeline can trust. It authorizes your endpoint, runs the free preflight, pays Selo once from a dedicated, capped wallet, and blocks the release unless every release check passed with evidence. It also verifies Selo’s signed attestations offline.

Install and run

The CLI lives in the Selo repository as the private workspace package @selo/cli. It is not published to a package registry: you run it from a checkout. Requirements: Node 24 or later and pnpm 10. The repository pins pnpm 10.33.0 through its packageManager field.
Terminal
The root package.json defines the script that pnpm selo runs:
package.json
packages/cli/bin/selo.js registers tsx and loads src/main.ts, so the CLI runs its TypeScript source directly. There is no build step.
  • pnpm selo … works from anywhere inside the checkout.
  • Relative paths you pass (--body, --contract, --summary, --attestation, and the files selo verify reads) resolve against the directory you ran the command in. The run state directory .selo/runs/ is created there too.
  • Under pnpm, that directory comes from INIT_CWD, which pnpm sets for you. When you call node packages/cli/bin/selo.js directly, as the GitHub Action does, it is the current directory.
pnpm prints a short script header before the CLI output and, after a non-zero exit, an ELIFECYCLE Command failed with exit code … line. The exit code itself passes through unchanged. Run pnpm --silent selo … to see only the CLI’s own output.

Commands

selo auth

Prove you control the endpoint before Selo will touch it.

selo preflight

Free eligibility check with the target fee, Selo’s cap and Selo’s price.

selo test

The paid release gate: one payment, five checks, one exit code.

selo verify

Check a signed verdict offline for an exact release, URL and method.

Output files

The run state, the selo.gate.v1 summary, the attestation and the job summary.

GitHub Action

The composite action that runs the CLI in a workflow.

Global behaviour

Syntax

  • Flags take a value as --flag value or --flag=value. Boolean flags (--approve-mainnet, --resume) take none.
  • Values are trimmed. An empty value counts as missing.
  • Unknown flags and positional arguments are usage errors.
  • A leading -- is ignored, so pnpm selo -- test … behaves like pnpm selo test ….

Help

selo, selo help, selo --help and selo -h print the full usage and exit 0. So does any command that has help, --help or -h among its arguments. There is no per-command help: one usage text covers every command.
selo --help (excerpt)

Usage errors exit 3

Invalid input is caught before any network request. The CLI prints the problem on stderr, followed by (run selo --help), and exits 3:
Terminal

Unexpected errors exit 2

Any other error stops the CLI with exit 2 and this line on stderr:
An unexpected error never exits 0.

Output streams

Results go to stdout. Usage errors, refusals, preflight failures, recovery instructions and selo verify failures go to stderr.

Shared validation

These rules apply to every command that takes the flag.

Environment variables

Never pass the mnemonic as a flag or commit it to a file in your repository. In CI, store it as a secret of a protected environment. See GitHub Action security.

Exit codes

Every command uses the same four codes. selo test is the release gate: only 0 allows a release. What each code means per command: The CLI does not trust a verdict label on its own. selo test recomputes the verdict from the report’s own checks with the same reducer Selo uses, and blocks with exit 2 on any disagreement or gap. See How the gate decides and Verdicts and the gate.

Payment approval rules

Only selo test pays, and it pays Selo once per run. It never retries a payment on its own.
1

Before any request

--network mainnet needs both --approve-mainnet and --pay-to <Selo's payTo>, or the CLI exits 3 with --network mainnet needs --approve-mainnet and --pay-to <Selo's payTo address>. A missing or invalid SELO_PAYER_MNEMONIC also exits 3.
2

Before signing

The CLI reads Selo’s 402 and shows the price, network, payee, payer and tag. It refuses to sign, and exits 3 (2 while resuming), when:
  • the 402 does not offer exactly one exact Algorand USDC requirement (ASA 31566704 on Mainnet, 10458941 on Testnet);
  • the 402 asks for payment on a network other than --network;
  • --pay-to is set and the 402 names another payee;
  • the payer is the payee (self-payment);
  • the price is zero or above 5.00 USDC;
  • the price is above --max-usdc.
3

After sending

If the outcome cannot be confirmed (a timeout, a lost connection, a redirect, a held settlement), the CLI records the attempt in .selo/runs/<release>.json and exits 2. Further runs for that release refuse to pay until you rerun the same command with --resume. See Recover an interrupted run.
Use a dedicated payer wallet that holds only what a few release tests cost, and opt it in to USDC. A release test costs Selo’s price, 1.00 USDC on the public API. Selo pays the target’s own price from its wallet. See Payments and spend limits.

Network access

The CLI makes requests to these hosts: Each request to Selo, and the key download in selo verify, times out after 300 seconds. A release test is one long request: Selo waits for its own settlement and the call to your endpoint before it answers. A timeout on the paid request counts as an unconfirmed outcome, never as a failure that is safe to retry.

Scope

quick profile only, GET and POST targets, Algorand USDC on Mainnet or Testnet. Any other method or network exits 3. The public API at https://api.useselo.xyz runs on Algorand Mainnet; --network testnet is for a Selo deployment that runs on Testnet.