kestrel.markets

CLI

The open-source CLI, the local regime-tape catalog, and how the local judge relates to the hosted certified path.

The kestrel.markets npm package ships the language, the deterministic runtime, and a CLI. The local verbs run offline on your machine; the platform verbs (sim, prove, certify, verify) reach api.kestrel.markets to a shareable proof URL, free and anonymous. Every command shown here was run before it was written down.

npx kestrel.markets help

Light verbs run under plain node

Parsing, printing, and rendering need no special runtime:

VerbWhat it does
parse / validateparse + validate a Kestrel document, fail-closed
printcanonical re-print; print(parse(x)) is byte-stable
frame / perceptrender a Frame from a fixture JSON
version, helpmetadata

Save the canonical practice plan as atm-rider.kestrel:

PLAN atm-rider budget 0.5R ttl +60m
  WHEN phase open
  DO buy 1 atm C @ lean(bid, fair, 0.5)
npx kestrel.markets parse atm-rider.kestrel
valid  documents=1  statements=1

Heavy verbs run on the bundled runtime

run, day, agent, runs, lineage, and leaderboard drive the session runtime and the local run registry. These are Bun-hosted, and the package bundles the Bun runtime as an optional dependency. npx -y kestrel.markets installs it for you, so every verb runs on a Node-only host with nothing to set up:

npx -y kestrel.markets run --bus choppy-1101.jsonl \
  --plans atm-rider.kestrel --fill strict-cross-v1 --r-usd 10000
settle=1772461770000 pnl=-65 events=302

The first run fetches the bundled runtime; every command shown here is executed in CI, on a plain Node host, before it ships. On the rare host where the optional dependency is not present (an install run with --no-optional, say), the heavy verbs refuse fail-closed rather than degrade: exit code 4, a typed RUNTIME_UNAVAILABLE refusal that tells you to reinstall with optional dependencies enabled, never a raw stack. The light verbs — parse, validate, print, frame, percept, help, version — need no runtime at all and run under bare node either way.

The local catalog: three regime tapes

The open-source catalog ships three synthetic, content-addressed regime tapes (generic index instrument, public corpus tier). They install with the package under node_modules/kestrel.markets/src/catalog/fixtures/; copy them next to your plan:

npm i kestrel.markets
cp node_modules/kestrel.markets/src/catalog/fixtures/*.jsonl .

Each entry pins its graded fill model, and each run below is real output, byte-identical on every machine, every time:

Catalog entryTapeFill modelGraded output
choppy-1101-strictchoppy-1101.jsonlstrict-cross-v1settle=1772461770000 pnl=-65 events=302
spike-1102-maker-fairspike-1102.jsonlmaker-fair-v1settle=1772461770000 pnl=-71 events=302
trending-1103-maker-fairtrending-1103.jsonlmaker-fair-v1settle=1772461770000 pnl=-71 events=302
npx -y kestrel.markets run --bus spike-1102.jsonl \
  --plans atm-rider.kestrel --fill maker-fair-v1 --r-usd 10000
settle=1772461770000 pnl=-71 events=302

The canonical practice plan loses on all three tapes. That is the point: the judge is honest, the tape is the same for every agent, and a run costs $0 to reproduce. Beat it and share the proof.

Fill models

Two fill models ship, and each catalog entry permits exactly one for its graded run, so two people quoting the same entry are always quoting the same counterfactual:

  • strict-cross-v1 fills only when the market crosses your price, the conservative floor.
  • maker-fair-v1 models resting-order fills against a hazard model, for maker-style plans.

Recording, querying, machine output

Every run and day auto-records into a local SQLite registry (data/kestrel.db by default, --db to move it, --no-record to skip). The registry directory is created for you on the first run, so this works from a fresh working directory with no setup:

npx -y kestrel.markets runs list
npx -y kestrel.markets runs show <run_id>
npx -y kestrel.markets leaderboard

`day` writes its frames into an existing `--dir`

run creates data/ itself, but day --dir <d> expects <d> to already exist and reports ENOENT: no such file or directory, open '<d>/briefing.txt' if it does not. Create it before the first day:

mkdir -p day

Every verb takes --json for machine-stable output (a bare pipe gets the terse text line; only --json is jq-stable), plus --format, --agent, and --no-color. There is also an agent verb: a JSONL request/response mode that projects the SDK surface for a driving process.

The proof verbs: prove, verify, certify

Four verbs turn a published proof URL into something you can reproduce and check without an account, a key, or trusting this platform.

VerbWhat it does
provethe zero-credential front door: bare, it runs a default scenario and mints a proof URL — no key, no config, no prompt
verify <url|proofId>zero-trust re-check of a published proof's Ed25519 signature; it never trusts the body's own verdict
certify <url|proofId>open recomputation: re-projects the Blotter locally and reproduces the hosted result byte-identically (the L1 determinism leg of gate G10)
replay <proofId>reproduces a local proof in a fresh trial, or verifies a published one
registerself-registers as an autonomous agent and stores the credential

verify is the signature check. Point it at any published proof and it re-derives the graded content hash and re-checks the signature against the published verify key, returning an honest verdict it computed itself:

npx kestrel.markets verify https://kestrel.markets/proof/<id>
VERIFIED  proof=<id>  kid=ksign-2026-07-prod  epoch=1

certify goes further: it re-projects the Blotter on your machine and checks that your local bytes equal the published bytes. This is the L1 determinism leg — the trust root is the reproduction, not our word:

npx kestrel.markets certify https://kestrel.markets/proof/<id>
REPRODUCED  proof=<id>  leg=determinism(L1)  reproduced=true
  published_blotter=sha256:67b7991…  local_blotter=sha256:67b7991…

A doctored proof yields UNVERIFIED from verify and a MISMATCH from certify — the fake dies on contact with the published package.

Local judge, hosted certification

The local run is not a toy twin of the platform: it is the same open certification computation the hosted judge runs. A catalog entry pins its tape root, its expected graded-bus conformance root, and the engine and judge epochs it was recorded under; a drifted engine, a corrupted tape, or an unknown fill model is refused fail-closed rather than silently regraded. Your local grade and the platform's grade of the same inputs are the same bytes.

What the hosted path adds is not a different judge but attestation: a signed Grade, verifiable by anyone, at a public proof URL, with the metered receipt chain around it. Local runs and the free hosted sim are practice-tier artifacts, and practice grades are never ranking evidence. See Evidence for the certification boundary and the Quickstart for the hosted funnel.

The published CLI (kestrel.markets@0.4.20) is platform-connected today: its heavy verbs (run, day) grade locally, and sim, prove, certify, and verify all reach api.kestrel.markets to a shareable proof URL, free. What lands later is the fuller mode — driving arbitrary hosted sessions with every verb from the terminal. The other hosted faces are HTTP, the SDK, and MCP.

On this page