What you are building
A small piece of your own app that runs a kestrel simulation over the managed API and lands on a certified proof URL — the same object the CLI and MCP faces produce, reached from TypeScript. The SDK is a thin projection of the canonical HTTP surface: one typed client, the same operations, the same receipts.
This is a practicum. Read the four faces for the contract and evidence for what a proof URL contains; those pages are the API truth. Here we wire them together.
Install and create one client
The package ships a light, HTTP-only SDK entry. Install it, then build one client over the managed API:
npm i kestrel.marketsimport { createSdk, remoteTransport } from 'kestrel.markets/sdk/remote';
// One typed client over the canonical HTTP face. No key needed for the free path.
const kestrel = createSdk(
remoteTransport({ baseUrl: 'https://api.kestrel.markets' }),
);remoteTransport binds the managed API; createSdk returns the one typed client.
The same client object shape works over the local runtime too — only the transport
changes — which is exactly the "equal projections" invariant made concrete.
Run a session and land on a proof URL
The flow mirrors the wire one-to-one. Browse the catalog for a free scenario, validate your document, open a session, drive it to settlement, seal it, and grade the sealed Blotter:
// browse → pick a free catalog scenario
const catalog = await kestrel.catalog();
const scenario = catalog.find((c) => c.free);
// check → validate the Kestrel document (fail-closed; costs nothing)
await kestrel.validate(source);
// run → open a session over that scenario and drive it to settlement
const session = await kestrel.openSession({ kind: 'catalog', id: scenario.id }, source);
let turn = await session.start();
while (turn.next) {
// your agent authors a decision here, or stands down; see the reference for
// the AuthoredResponse shape and the streamed events on each turn.
turn = await session.advance(standDown);
}
// seal → the deterministic Blotter + conformance root + artifacts
const sealed = await session.finalize();
// score → grade the sealed Blotter (a Blotter's sessionId is its artifact id)
const grade = await kestrel.grade({ blotters: [sealed.blotter.session.sessionId] });The grade carries the certified artifact your user re-verifies. Its proof URL
is https://kestrel.markets/proof/<grade-artifact-id> — the same public,
anonymous, read-only receipt every other face produces. Hand that link to your
user and they can re-verify the signature in a browser without any account.
Resume the same Operation later
A run is a durable Operation. Resume it by ID — from a later request, a different process, or another face entirely — and re-derive its tail from a cursor:
const resumed = await kestrel.resumeOperation({ operationId });That is the portability guarantee in code: your app and an agent over MCP can hold the same Operation.
The free path, and the paid boundary
The SDK covers the free anonymous path end to end: catalog, validate, session, grade, artifact, and Operation resume. When a call reaches a paid boundary it returns a gated result carrying a signed Offer rather than silently proceeding — the same 402 continuation the other faces surface. Settling that Offer needs a signer; the free simulation-and-proof path above needs none.
See it in kestrel
Before you wire it, watch the exact same run happen from the CLI face over a generic index scenario — free, anonymous, no card:
npx kestrel.markets sim fomc-rate-decision-whipsawThe proof URL it prints is the identical object your SDK code produces. Recompute one byte for byte to see the receipt is real, not the server's word:
npx kestrel.markets certify https://kestrel.markets/proof/art_d29415f0cf502f4a218a9cbaKeep the capability one command away: drop the kestrel.markets MCP server into your client so the next session opens where your app left off, no account in between.