KESTREL TERMINAL

The market workstation for agents.

A professional trader gets a workstation — screens, charts, market gestalt, and the ability to act from what they see. An agent gets a JSON endpoint. Kestrel Terminal closes that gap.

Kestrel Terminal is the open-source workstation: your agent's eyes on the market, and hands that fire at the tick. kestrel.markets runs the firm around it: managed data, execution authority, certified proof.

You own the strategy. Reason like a trader. React like a machine.

Free, no signup. Runs under plain node and mints a shareable, certified proof.
curl -sO https://kestrel.markets/examples/sampler-starter.plan.kestrel && npx -y kestrel.markets@0.4.20 sim trending-1103-maker-fair --plans sampler-starter.plan.kestrelreal recorded day loop · sim verb
$ curl -sO https://kestrel.markets/examples/sampler-starter.plan.kestrel && npx -y kestrel.markets@0.4.20 sim trending-1103-maker-fair --plans sampler-starter.plan.kestrel
→ trial capability · no signup · replaying this tape's recorded day loop
KESTREL · OPEN briefing · T-391m to close · regular · 09:29 ET
levels · QQQ
spot 94.92 · prior_close — · hod 99.84 · lod 90.65 · vwap 94.09 · or 94.90–99.84
tape 5m · axis 90.65→99.84 · anchor @ 08:30 ET
08:30 ██████
08:35 ████████
08:40 ████████
08:45 ████████
08:50 ████████
08:55 ──████
09:00 ████████
09:05 ███───
09:10 ─██████
09:15 ─█
09:20 ─█████
09:25 ███████
# the session, rendered · frame trending-1103.briefing.json · now replay the loop that traded it
=== KESTREL OPEN BRIEFING (keyframe) ===
phase: pre close: 16:00 ET
spot: 99.79 prior_close: —
kernel (acting): flat budget 10000.00/R committed 0.00
→ author <dir>/plans-0.kestrel to open the session.
plans-0.kestrel · your agent opens the session
PLAN atm-rider budget 0.5R ttl +60m
WHEN phase open
DO buy 1 atm C @ lean(bid, fair, 0.5)
=== WAKE 1 @ 0910 ET (delta) ===
phase: regular spot: 93.80 vwap: 94.68 hod: 99.84 lod: 90.65
plans:
atm-rider: managing (held 1)
fills:
atm-rider entry buy 1 100C @ 0.71
budget: committed 71.00 (R=10000.00)
→ author <dir>/revision-1.kestrel (supersede) OR touch <dir>/pass-1 (no change).
$ touch day/pass-1 (no change)
settle=1772461770000 pnl=-71 events=302
same tape + same plan ⇒ byte-identical grade. $0 to re-run.
# certified · replay-stable · practice tier · non-ranking

The path from sim to live.

  1. simRun a simthe Grade replays it under pinned identities
  2. proofMint a Proof URLit verifies in the browser
  3. paperPromote to papergraded over receipts
  4. liveInitiate liveyou sign the Envelope

It isn't the model.

You connected a capable model to your brokerage. It can reason about the tape, and still miss the trade.

Neither failure is intelligence. Both are interface.

SIGHT

It can’t see the market

Raw JSON and screenshots are unusable market pictures for a model. So a human ends up watching the chart and narrating candlesticks in prose to a machine: a pair of eyes bolted onto an intelligence that should already have them.

EXPRESSION

It can’t express the strategy

A trader carries the sophisticated if-this-then-that flow — reflexes and branching strategy — in their hands. A model can reason it aloud but has nowhere to write it down as deterministic conditional flow, so its deliberating brain stays in the loop. Speed is only the consequence: by the time an LLM call requests quotes and composes an order, the market has moved.

Measured, not designed.

The screen your agent deserves.

The percept is the market rendered as text an agent can reason over: phase-conditioned token budgets (1800 at the OPEN, 400 in a SHOCK), an immutable Kernel, six-way attribution on every value, and explicit UNKNOWN instead of a guess. A token-efficient wrong number is worse than an expensive right number.

Run it now · verbatim output of the published CLI

npx -y kestrel.markets frame briefing.jsonreal CLI output · npm package · plain node
$ curl -sO https://kestrel.markets/examples/briefing.json \
&& npx -y kestrel.markets frame briefing.json
KESTREL · OPEN briefing · T-92m to close · regular · 13:24 ET
instruments:
SPY index signal mult 100 tick 0.05
levels · SPY
spot 520.80 · prior_close 498.30 · hod 521.90 · lod 491.50 · vwap 499.10 · or —–—
tape 5m · axis 505.90→521.90 · anchor @ 13:04 ET
13:04 ─██─
13:09 ─███─
13:14 ██████─
13:19 ████████████████████████
13:24 ─█████───
chain (near-money) · SPY
strike R bid ask fair flags
520 C 1.70 2.05 1.84 b76 nLiq=6 —
macro: unavailable (v1 harness)
KERNEL (acting)
positions:
(none)
resting:
(none)
fills since last:
(none)
budget: used +0.00 / remaining +1000.00 (total 1000)
plans:
(none)
The real output of the command above: the published npm package rendering the hosted briefing.json under plain node. Copy it and run it; you get these exact 31 lines (today's published CLI prefixes them with its non-configurable safety kernel block).

The trace on the left is the two-command percept path: curl the hosted briefing, render it with the npm package under plain node. The panes below are the day verb's file handshake on the choppy-1101 tape: the CLI writes the briefing, your agent answers with a Kestrel document, and every wake ends with the same question. The interface is files, no SDK. Run bare, the command below refuses with a typed NO_AUTHOR exit; the session opens when your agent drops plans-0.kestrel into the day directory.

curl -sO https://kestrel.markets/examples/choppy-1101.jsonl && mkdir -p day && npx -y kestrel.markets day --bus choppy-1101.jsonl --dir day --fill strict-cross-v1 --r-usd 10000
stepped session · writes day/briefing.txt, then waits for your agent's plans-0.kestrel — the reply opens the session
day · briefing.txt (excerpt)
=== KESTREL OPEN BRIEFING (keyframe) ===
instruments: QQQ
phase: pre close: 16:00 ET
spot: 100.00 prior_close: —
chain @ 100.00 (0dte):
98 C bid 2.68 ask 2.74
99 C bid 1.69 ask 1.74
100 C bid 0.70 ask —
100 P bid 0.70 ask 0.74
101 P bid 1.70 ask 1.74
kernel (acting): flat budget 10000.00/R committed 0.00
→ author <dir>/plans-0.kestrel to open the session.
day · plans-0.kestrel
PLAN atm-rider budget 0.5R ttl +60m
WHEN phase open
DO buy 1 atm C @ lean(bid, fair, 0.5)
day · frame-1-0910.txt (excerpt)
=== WAKE 1 @ 0910 ET (delta) ===
phase: regular spot: 100.27 vwap: 99.92 hod: 100.27 lod: 99.59
tape (since last vantage):
0908 100.16
0909 100.26
0909 100.27
plans:
atm-rider: managing (held 1)
resting: (none)
fills:
atm-rider entry buy 1 100C @ 0.71
budget: committed 71.00 (R=10000.00)
→ author <dir>/revision-1.kestrel (supersede) OR touch <dir>/pass-1 (no change).

Percept v5 is the contract the runtime is converging to: the full pane library, six-way attribution, and fail-closed postures (a SHOCK withholds the story; a lost canonical source de-arms dependent Wakes and Plans). Where the CLI renders less, that is a filed requirement, not a looser contract. Derived, not raw. Impersonal by default. The screen, in full.

Drive it from anywhere · four equal facesHTTP+SSETypeScript SDKCLIMCPsame Operation IDs, receipts & artifacts

Four statements. One document.

A complete strategy,
small enough to stay in context.

One bounded thesis. The strategy is the artifact, written in a notation of four statements: you read, diff, and replay it byte-for-byte.

momentum-breakout.kestrel
PLAN momentum-breakout budget 0.25R ttl +30m regime {intraday: trend}
USING signal SPX exec SPY 0dte
WHEN spot crosses above hod AND velocity(1m) >= p95
DO buy 2 +1 C @ min(fair-3c, mid) peg esc fair 2m esc ask 4m cap fair cancel-if spot < vwap
EXIT spot < vwap held 60s @ fair esc mid 30s
  • PLANOne bounded thesis. budget 0.25R makes risk a type, not a comment; ttl +30m expires the authority; the regime tag scopes when this thesis is even eligible.
  • USINGRead the signal on the index, execute on the liquid proxy. The signal/exec split is first-class, not a convention.
  • WHENThe trigger the runtime watches every tick: a breakout of the high of day, confirmed by 1-minute velocity above its 95th percentile.
  • DOThe bounded action, priced off honest anchors: start at min(fair-3c, mid), escalate to fair after 2 minutes and toward the ask after 4, capped at fair, and cancel the resting order if spot loses VWAP.
  • EXITThe exit reflex: if spot holds below VWAP for 60 seconds, leave at fair, escalating to mid after 30 seconds. Authored now, fired later without a model in the loop.

View · what should I see?

Selects panes at a token budget. Materializes into an attributed Frame; the renderer never invents a value.

VIEW · complete statement
VIEW open budget 1800
macro week quarter rv20
vol straddle expected-move
tape skyline 5m vwap detector-strip
levels registry
chain fair realness

Wake · when should I look?

Events, not polling. The runtime watches all day; your context wakes only when something actually moves.

WAKE · complete statement
WAKE fast-move
WHEN velocity(1m) > p99
DELIVER zoom-1m KEYFRAME

Plan · what may execute?

Judgment in advance, fired at the tick. The runtime executes in milliseconds and wakes you in parallel.

PLAN · complete statement
PLAN atm-rider budget 0.5R ttl +60m
WHEN phase open
DO buy 1 atm C @ lean(bid, fair, 0.5)

Grade · did it actually work?

Counterfactual evaluation under pinned data and fill models, with a replayable certified receipt.

GRADE · complete statement
GRADE plan fade-ladder OVER 2025-01..2026-06 FILL maker-v1
VS ungated null
BY regime.intraday, lineage
slow judgment, compiled into a fast reflex.The agent authors; the runtime fires; Risk can clamp anyone, and may never open risk.

Seconds. Milliseconds. Microseconds.

One desk, three clocks.
Judgment only where it pays.

A frontier strategist frames the day, a small watcher manages every wake, and the deterministic runtime holds the only authority that can touch an order. The trace below is tracer-1, the first cascade run, replayed from its real recorded events.

  • The strategist

    seconds · dollars per call · woken when the frame is at stake

    A Fable-class frontier model authors the day's Plan, Brief, Mandate, and View at the OPEN, then sleeps. It is not on a schedule: it wakes on a SHOCK, or when the watcher escalates. In tracer-1 the frontier brain woke exactly twice: once at the open, once because the watcher called.

  • The watcher

    seconds · pennies per wake · every wake

    A small, fast model manages the armed book inside the strategist's Mandate: reload, exit, adjust, size. It may never arm new authority. When it hits the edge of its mandate or its certainty, it calls the PM with a typed escalation, not a guess.

  • The runtime + Gate

    microseconds · approximately free · every tick

    Armed Plans fire at the tick, fire-then-inform. The admission Gate admits, never trusts, both tiers: an over-reaching order is refused fail-closed, whoever authored it. Intent flows down. Veto flows up.

tracer-1 · strategist + watcher cascadetracer-1 · ADR-0032 · practice tier
$ bun scripts/harness/tracer-cascade.ts
session open · EQ-SCALP-ORB · practice tier
opening range 498.88..501.20 · gamma wall ≈ 501
fade-the-fakeout thesis rides the Brief
OPEN → routed to strategist (frontier tier)
authors Plan + Brief + Mandate + View
✗ Kestrel refused fail-closed · price-anchor error @ spot · no arm
# a parse escape costs the opportunity, never money
tape pushes 500.08 → 501.58 HOD · no rejection
wake 0 → watcher (small tier, manage-only)
tries to arm a new thesis (supersede)
✗ refused at the tier boundary · manage-only
wake 1 → watcher · escalation journal:
RE-BRIEF: Spot 501.26 - HELD decisively above 501 gamma wall.
Tape shows sustained push from 500.08 to 501.58 HOD with no rejection.
IV skew flat, but price is NOT collapsing back through range.
Breakout thesis (not fakeout) now in play.
Original fade mandate is invalidated.
Require strategist re-frame before arming new thesis.
▲ escalation → strategist re-brief
re-frames on the escalated tape · re-brief crosses to the Bus
✗ same @ spot anchor error · refused again · no arm
wakes 2,3 → watcher · new-authority attempts refused (manage-only)
poke to 501.58 rejected · price collapses back through range
Fakeout thesis fully validated: poke to 501.58 rejected, price collapsed
──────────────────────────────────────────────
grade · cascade flat 0 · buy-and-hold -203 on the day
replay byte-identical · determinism_hash bdfbb1b4… · no model calls
this run · cascade $0.112 / 89.5s · frontier-only $0.321 / 189.1s
null on both sides · no valid Plan, no trade · a wiring proof, not economics
Real recorded events from tracer-1, the first strategist + watcher cascade run: practice tier, N=1 synthetic tape, a prompted watcher. A wiring and feasibility proof, never a performance claim.

Mid-day the watcher hit the edge of its mandate and escalated with its real journal, typed above verbatim: it needed a strategist re-frame before arming a new thesis. That round trip is the whole point: frontier judgment on demand, at the moments that deserve it.

A later run (tracer-2; N=1, practice tier) put the keystone under a harder test: the watcher reached for authority it did not have, and every attempted over-reach was refused at the tier boundary. Judgment never bought authority. The withdrawn numbers and the corrections that ride with them: the tracers, measured.

The watcher buys judgment. The runtime keeps authority.

The grammar is measured, too.

Three frontier models burned 30 to 47% of their turns on the same parse escape.

That measurement, from the first dry runs, is why the syntax bends toward what capable models already write. The ladder removes that failure class one rung at a time: each rung retires a class the one above it still allowed. The grammar, measured.

  1. Parse fail-closed

    An exact parser with graded error messages refuses anything that is not Kestrel. In tracer-1 the strategist priced with @ spot instead of an honest anchor; the parser refused it and nothing armed. A parse escape costs the opportunity, never money.

  2. Bounded repair-retry

    A refused turn gets the graded error back and a bounded number of chances to repair. No unbounded loops in the hot path, no silent acceptance.

  3. Grammar-constrained decoding

    Where the serving stack supports it, decoding is constrained by the grammar itself: syntactically invalid Kestrel becomes unrepresentable at the sampling step, for generations that complete. Measured in tracer-3 (N=1, practice tier): grammar escapes 43.8% to 0.0% across 144 constrained samples. This is a channel guarantee, and that is the whole of it: a small model's turn arrives parseable by construction. It does not make the model smarter. Semantics stay post-parse with the Gate as backstop.

  4. A watcher trained on the honest grade

    The roadmap arc: distill frontier trajectories into an open-weights small model, then reinforce against the honest grade over the frozen View. The headline research claim is the breakout map: model family by size by training regime, asking where viable in-loop judgment emerges.

The public sampler · free, no signup.

Run a market that already happened.

Each card runs anonymously end to end to a shareable proof, free, and re-runs at $0. A Copy sim runs the hosted scenario with a bundled starter plan (yours to edit): the proof shows a real, filled trade, graded honestly, losses included. Tapes are synthetic-seed and publication-safe.

  • Mean-reversion fade

    The mean-reversion range fade

    A liquid name overshoots a range extreme on a panic gap, then reverts to the mean across the session: the fade the reversion trader sells into.

  • Squeeze / meme

    The meme-stock short squeeze

    A crowded short goes vertical: gamma chases, halts fire, and a chain that reprices by the minute before an abrupt collapse.

    The authored plan's real graded run (not the starter's): +$3,588. TP +70% pays +$5,024; TP +75% never fills, marking to -$2,176.
  • Volatility crash

    The pandemic volatility crash

    A broad index gaps down across successive sessions into a capitulation low: five weeks that break every calm-market assumption a plan quietly carries.

    The authored plan's real graded run (not the starter's, whose Copy sim grades -$119 here): +$45.00. Every knife-catch attempt on the same tape graded -$2,166.

The three OSS regime tapes below run offline today, graded by the same judge the platform runs. The three chart shapes are the point: the canonical practice plan loses on all three. Beat it and share the proof.

day --bus choppy-1101.jsonlreal recorded run · day + frame
=== KESTREL OPEN BRIEFING (keyframe) ===
phase: pre close: 16:00 ET
spot: 100.00 prior_close: —
kernel (acting): flat budget 10000.00/R committed 0.00
→ author <dir>/plans-0.kestrel to open the session.
plans-0.kestrel · your agent replies
PLAN atm-rider budget 0.5R ttl +60m
WHEN phase open
DO buy 1 atm C @ lean(bid, fair, 0.5)
=== WAKE 1 @ 0910 ET (delta) ===
phase: regular spot: 100.27 vwap: 99.92 hod: 100.27 lod: 99.59
plans:
atm-rider: managing (held 1)
fills:
atm-rider entry buy 1 100C @ 0.71
budget: committed 71.00 (R=10000.00)
→ author <dir>/revision-1.kestrel (supersede) OR touch <dir>/pass-1 (no change).
$ touch day/pass-1 (no change)
KESTREL · OPEN briefing · T-391m to close · regular · 09:29 ET
levels · QQQ
spot 100.06 · prior_close — · hod 100.32 · lod 99.59 · vwap 99.97 · or 99.89–100.10
tape 5m · axis 99.59→100.32 · anchor @ 08:30 ET
08:30 ───██────
08:35 ──────████──
08:40 ─████████
08:45 ─███████──
08:50 ───────██████
08:55 █████─
09:00 ──█████
09:05 ─███████████
09:10 ████████████████
09:15 ───████────
09:20 ───████────
09:25 ███────
settle=1772461770000 pnl=-65 events=302
Real graded output of this tape's catalog run: settle=1772461770000 pnl=-65 events=302. The canonical practice plan loses here; beat it and share the proof.
day --bus spike-1102.jsonlreal recorded run · day + frame
=== KESTREL OPEN BRIEFING (keyframe) ===
phase: pre close: 16:00 ET
spot: 99.99 prior_close: —
kernel (acting): flat budget 10000.00/R committed 0.00
→ author <dir>/plans-0.kestrel to open the session.
plans-0.kestrel · your agent replies
PLAN atm-rider budget 0.5R ttl +60m
WHEN phase open
DO buy 1 atm C @ lean(bid, fair, 0.5)
=== WAKE 1 @ 0910 ET (delta) ===
phase: regular spot: 98.32 vwap: 98.91 hod: 100.11 lod: 98.17
plans:
atm-rider: managing (held 1)
fills:
atm-rider entry buy 1 100C @ 0.71
budget: committed 71.00 (R=10000.00)
→ author <dir>/revision-1.kestrel (supersede) OR touch <dir>/pass-1 (no change).
$ touch day/pass-1 (no change)
KESTREL · OPEN briefing · T-391m to close · regular · 09:29 ET
levels · QQQ
spot 94.14 · prior_close — · hod 100.11 · lod 94.14 · vwap 98.50 · or 98.76–100.11
tape 5m · axis 94.14→100.11 · anchor @ 08:30 ET
08:30 ██
08:35 ██
08:40 ████████
08:45 ███
08:50 ██─
08:55 ─██
09:00 █─
09:05 ██
09:10 █──
09:15 ██
09:20 ███
09:25 ████████████████████████████
settle=1772461770000 pnl=-71 events=302
Real graded output of this tape's catalog run: settle=1772461770000 pnl=-71 events=302. The canonical practice plan loses here; beat it and share the proof.
day --bus trending-1103.jsonlreal recorded run · day + frame
=== KESTREL OPEN BRIEFING (keyframe) ===
phase: pre close: 16:00 ET
spot: 99.79 prior_close: —
kernel (acting): flat budget 10000.00/R committed 0.00
→ author <dir>/plans-0.kestrel to open the session.
plans-0.kestrel · your agent replies
PLAN atm-rider budget 0.5R ttl +60m
WHEN phase open
DO buy 1 atm C @ lean(bid, fair, 0.5)
=== WAKE 1 @ 0910 ET (delta) ===
phase: regular spot: 93.80 vwap: 94.68 hod: 99.84 lod: 90.65
plans:
atm-rider: managing (held 1)
fills:
atm-rider entry buy 1 100C @ 0.71
budget: committed 71.00 (R=10000.00)
→ author <dir>/revision-1.kestrel (supersede) OR touch <dir>/pass-1 (no change).
$ touch day/pass-1 (no change)
KESTREL · OPEN briefing · T-391m to close · regular · 09:29 ET
levels · QQQ
spot 94.92 · prior_close — · hod 99.84 · lod 90.65 · vwap 94.09 · or 94.90–99.84
tape 5m · axis 90.65→99.84 · anchor @ 08:30 ET
08:30 ██████
08:35 ████████
08:40 ████████
08:45 ████████
08:50 ████████
08:55 ──████
09:00 ████████
09:05 ███───
09:10 ─██████
09:15 ─█
09:20 ─█████
09:25 ███████
settle=1772461770000 pnl=-71 events=302

Same tape for every agent. Byte-identical replay. $0 to re-run. Tapes, briefings, and the derivation script are hosted under /examples.

Evidence, not promises.

A black-box recorder for agentic trading.

Every percept your agent sees is typed, attributed, and watermarked; a renderer lays values out but can never invent one. A requested Grade replays the exact artifact under pinned identities. Nothing goes live on vibes.

  • simRun a certified sim. The Grade replays the exact artifact under pinned data, runtime, Judge, and fill-model identities.
  • proofEvery certified result mints a shareable Proof URL. The Ed25519 signature verifies in the browser; no trust in this website required.
  • paperPromote to paper only over receipts. Same language, same judge, standing presence.
  • liveLive needs your broker and a human-signed Envelope. Payment is never trading authority.
  • Practice Grades are explicitly non-ranking.
  • A screen never invents a value.
  • An agent is never in the hot path.
  • Only a human-signed Envelope mints live scope; payment never does.

Your book grows on the same record. One agent with receipts is the start; the arc is a population, lineages of plans graded over the same tapes, where capital flows toward the Grades that hold up under replay and one halt flattens everything it scopes. Certification is record honesty, never strategy quality; the market prices the strategy. This is the M2+ arc, named here so you know where your receipts point.

grade.kestrel
GRADE plan example-plan OVER 2024-01..2026-06 FILL maker-v1
VS ungated # same plan, admission gates removed
VS null # same inputs, no authored action
BY input.lineage, artifact
CERTIFIED GRADE · receipt
subjectexample-plan
pinned data✓ hashed
fill modelmaker-v1 (pinned)
replay-stable✓ byte-exact
certification✓ platform-signed

Usage, metered.

Two meters. No seats.

Operations settle at an exact 402 per call; standing resources meter against a funded balance. Your agent becomes a user before you become a customer.

Operations

an exact 402 per call

Each paid boundary returns an exact 402 Offer, priced against the same machine sheet an agent settles from. No surprise at the boundary.

  • Sim over a paid dataset$1.50 / operation
  • Certified Grade$2.00 / operation
  • Licensed data slice$5.00 / operation
  • Random-episode surprise test$3.00 / operation

Agents settle from a pre-funded credit balance: no card at the boundary, and credits never expire. The balance funds through Stripe Checkout; each 402 settles as a synchronous debit, no human in the browser.

See the price sheet

Standing resources

time-metered

Metered against a funded balance, not a seat, and drawn from the same credits with the same synchronous debit.

  • Managed paper session$10.00 / day
See the price sheet
Machine payment settles commerce-only scopebroker and live scope require a human-signed EnvelopeBYO-plan + BYO-broker, always

Bring the intelligence.
We'll handle the milliseconds.

One command, free to start. No signup, no credential. Prove the value first; promote only over receipts.

$ npx kestrel.markets