UNPKG

kestrel.markets

Version:

A typed, token-efficient language + runtime for agentic trading: agents author bounded plans, the runtime fires them at the tick. CLI + typed library + MCP server.

342 lines (264 loc) 16.9 kB
# API reference — the published entry points `kestrel.markets` ships **eight public entry points**. Each is a subpath export with its own typed surface; you import only the one your program needs. This page documents what each is, when you would reach for it, its headline exports, and a minimal import + usage snippet. It is a map of the shipped surface — for *what each capability actually does at runtime*, keep the [capability-truth](./capability-truth.md) discipline and read the [status page](./status.md). For the command-line surface, see the [CLI reference](./cli-reference.md). ```bash npm i kestrel.markets ``` ## The light / heavy seam The entry points divide on one axis: whether importing them pulls the native, Bun-hosted local runtime. - **Light** faces carry no native dependency and load under Node ≥18, Bun, or a Worker — they speak the wire protocol and never open a second runtime. `./protocol`, `./client`, and `./sdk/remote` are pinned light by a package-boundary test; `./lang` is a pure parser/printer with no native dependency. - **Heavy** faces pull the local execution engine (they use `Bun.*` / `node:fs`) and are Bun-hosted: the root `.`, `./sdk`, `./mcp`, and `./engine`. A remote-only consumer should import a light face so no native weight enters its bundle. | Subpath | Entry | Weight | What it is | | --- | --- | --- | --- | | `kestrel.markets` | the root barrel | heavy | protocol types (flat) + the local `engine` aggregate | | `kestrel.markets/protocol` | wire types | light | the zero-dependency, versioned wire contract | | `kestrel.markets/lang` | the DSL core | light | `parse` / `print` for the four statement kinds | | `kestrel.markets/client` | launch-min client | light | mint → validate → sim → grade over HTTP/SSE | | `kestrel.markets/sdk` | the unified SDK | heavy | one client over local **or** HTTP transports | | `kestrel.markets/sdk/remote` | HTTP-only SDK | light | the SDK with the HTTP transport, no local runtime | | `kestrel.markets/mcp` | the MCP server | heavy | the SDK projected as an MCP JSON-RPC server | | `kestrel.markets/engine` | local engine | heavy · **experimental** | the local-execution capability aggregate | Everything below is a *shape* reference. A type that is present says nothing about whether its runtime behavior is wired; that is graded separately on the status page. --- ## `kestrel.markets` — the root barrel **What it is.** The top-level, Bun-hosted local surface. It re-exports the whole wire **protocol** flat (so `PROTOCOL_VERSION`, `SCOPES`, and the generic `Order` / `Blotter` shapes are on the root) and hangs the local-execution **engine** aggregate under a single `engine` namespace key. **When to import it.** You want both the protocol vocabulary and the local engine from one specifier and you are running under Bun. Remote-only or protocol-only consumers should prefer `./protocol` or `./client` so they pull no native weight. **Why `engine` is namespaced.** The engine tree defines its own `Position` / `Instrument` that differ from the protocol's generic ones; flattening both would be an ambiguous re-export. Under `engine.*` each capability keeps its own names and the protocol's flat vocabulary is never clobbered. ```ts import { PROTOCOL_VERSION, engine, type Blotter } from "kestrel.markets"; console.log(PROTOCOL_VERSION); // the protocol vocabulary, flat const node = engine.lang.parse(source); // the local engine, namespaced ``` --- ## `kestrel.markets/protocol` — the wire contract **What it is.** The canonical, **zero-dependency** wire types — the open, versioned contract the managed backend implements. Shapes only: no signing keys, no commerce logic, and generic instruments (an opaque `symbol: string`); no product ticker is part of the published contract. It imports nothing and typechecks with no native dependency installed. **When to import it.** You are decoding or producing protocol objects — a remote consumer, a server, or anything that needs the type vocabulary without a runtime. **Headline exports.** - **Version + faces:** `PROTOCOL_VERSION`, `FACES` / `Face` (`http` · `sdk` · `cli` · `mcp`). - **Authorization:** `Scope` / `SCOPES`, `WALLET_SIGNABLE_SCOPES`, `isWalletSignable`, `SignerClass` / `SIGNER_CLASSES`, `AttestationRole`, `Envelope` / `EnvelopeRef`, `RootGrant`, `AuthorityEpoch`. - **Commerce + the 402 body:** `Offer`, `SettlementMethod`, `Proof`, `PaymentRequired`, `Capability` / `TrialCapability`. - **Operations:** `Operation`, `OperationState` / `OPERATION_STATES`, `EventCursor`. - **Execution records (generic instruments):** `Instrument`, `Side` / `SIDES`, `Order`, `Fill`, `Position`, `Settlement`, `Blotter`. - **Grades + receipts:** `GradeResult`, `CertifiedGrade`, the `CertifiedReceipt` umbrella, the `AnyReceipt` union with `RECEIPT_KINDS`, and the M2–M4 roots (`InputAdmissionReceipt`, `ResourceValueReceipt`, `PromotionReceipt`, `LiveActivationReceipt`) plus the fail-closed `AdmissionState` (`known` · `unknown` · `omitted`) and `ActivationState`. - **Re-exported additive surface:** the content-addressed `CatalogEntry` (`./catalog`) and the incremental Session transcript (`./session`). The runtime tuples (`SCOPES`, `SIDES`, `RECEIPT_KINDS`, …) are each proven exhaustive against their type, so the wire vocabulary can never silently drift from the union. ```ts import { PROTOCOL_VERSION, type Blotter, type Order } from "kestrel.markets/protocol"; function totalQty(blotter: Blotter): number { return blotter.orders.reduce((n: number, o: Order) => n + o.qty, 0); } ``` --- ## `kestrel.markets/lang` — the DSL core **What it is.** The typed object model that *is* the language: text is a projection of it. The four statement kinds (View / Wake / Plan / Grade), the org nodes (Pod / Book), and the shared lexical core (the trigger algebra, series references, price expressions) live here, with the canonical printer and the inverse parser. **When to import it.** You are authoring, validating, or canonically re-printing Kestrel statements from TypeScript — for example, checking a document before you submit it, or building statements programmatically. **Headline exports.** - `parse(text)` — text → typed nodes; fails closed with `line` / `col` on every error. - `parseMarkdown(text)` — parse the Kestrel fences out of a Markdown document. - `print(node)` — nodes → byte-stable canonical text. - `KestrelParseError` — the typed, fail-closed parse error. - `b` — the ergonomic builders namespace for programmatic authoring. - `assertNever` — the exhaustiveness helper. - The AST node family is re-exported type-only (`export type * from "./ast"`). The load-bearing invariant is round-trip stability: `print(parse(text))` is byte-identical to the canonical form, and `parse ∘ print` / `print ∘ parse` are inverse projections. ```ts import { parse, print, KestrelParseError } from "kestrel.markets/lang"; try { const node = parse(source); const canonical = print(node); // byte-stable canonical text } catch (err) { if (err instanceof KestrelParseError) { console.error(`parse failed at ${err.line}:${err.col}`); } } ``` --- ## `kestrel.markets/client` — the launch-min client **What it is.** The small, dependency-light SDK face for the day-one programmatic flow: mint a trial capability → validate → run a sim → grade the result. It speaks the same canonical wire dialect the CLI's remote backend speaks, over web `fetch` and SSE, so it needs no native dependency (Node ≥18, Bun, or a Worker). **When to import it.** You want the shortest path to the managed backend from code, with a minimal surface and no local runtime. **Headline exports.** - `KestrelClient` — construct once, then `mint()` / `validate(source)` / `sim(input)` / `grade(input)`. The capability is minted lazily on the first effectful call and cached; every effectful POST carries a deterministic idempotency key. - `KestrelClientError` — the fail-closed error, carrying a stable `code` and the HTTP `status`. Agents match on `code`, not prose. - `DEFAULT_API` — the canonical managed API base. - Types: `ClientOptions`, `FetchLike`, `Gated<T>`, `SimInput` / `SimResult`, `GradeInput` / `GradeOutcome`, `ValidateOutcome`, `OperationEventView`. - `contractMockFetch` — an in-process implementation of the contract as a `fetch` stand-in, for local development and CI (no network, no secrets). - Re-exported domain + 402/Offer wire shapes so a consumer needs only one import. A structured **402/Offer is not an error** — it is returned as `Gated` data (`.gated`), never thrown and never a redirect. Everything else off the happy path is a loud, typed throw. ```ts import { KestrelClient } from "kestrel.markets/client"; const client = new KestrelClient(); // → api.kestrel.markets await client.mint(); // trial capability const sim = await client.sim({ source, dataset }); // → Gated<SimResult> if (!sim.gated) { const grade = await client.grade({ blotters: [sim.value.blotter!.sessionId] }); } ``` For offline use, inject the mock transport: `new KestrelClient({ fetch: contractMockFetch })`. --- ## `kestrel.markets/sdk` — the unified SDK **What it is.** The **one** typed Kestrel client over two interchangeable transports. `createSdk(transport)` builds the client; `localTransport()` runs it in-process against the local engine, and `remoteTransport(opts)` runs it against the managed backend over the HTTP wire. A caller writes the flow once and runs it local or remote with byte-identical protocol results — same objects, diagnostics, event cursors, artifact refs, and 402/Offer boundary. **When to import it.** You want the full client surface — the incremental Session lifecycle in addition to validate / grade — and you want the option of running locally. This barrel is **heavy** (it pulls the local transport). A remote-only consumer should import `./sdk/remote` instead. **Headline exports.** - `createSdk`, `SDK_VERSION`. - `localTransport()` and `remoteTransport(options)`. - `SdkLocalError`, and the local projection helpers `toProtocolBlotter`, `gradeOf`, `artifactsOf`, `conformanceRootOf`. - Types: `KestrelSdk`, `KestrelSession`, `Transport`, `Gated`, `GradeRequest` / `GradeOutcome`, `ValidateOutcome`, `SessionRef` / `SessionResponse` / `SessionTranscript`, `Delivery`, `AuthoredResponse` / `BoundResponse`, `ArtifactResult`, `OperationRef` / `OperationResumption`, `SdkFinalized`, and the `EventCursor` resume vocabulary. ```ts import { createSdk, localTransport, remoteTransport } from "kestrel.markets/sdk"; const local = createSdk(localTransport()); // in-process const remote = createSdk(remoteTransport({ baseUrl })); // managed backend const result = await local.validate(source); ``` ## `kestrel.markets/sdk/remote` — the HTTP-only SDK **What it is.** The same unified SDK contract, but the **light** HTTP-only entry: it exposes `createSdk` + `remoteTransport` + the SDK types and drags no local runtime or lake into a bundle (pinned by the package-boundary test). It binds the launch-min client under the one typed SDK contract; a catalog Session is a client-side replay of the server-computed, catalog-pinned transcript, so a remote run's objects are byte-identical to a local run's. **When to import it.** You are a remote-only consumer (a browser, a Worker, a thin service) and want the full SDK contract without native weight. ```ts import { createSdk, remoteTransport } from "kestrel.markets/sdk/remote"; const sdk = createSdk(remoteTransport({ baseUrl: "https://api.kestrel.markets" })); const outcome = await sdk.validate(source); ``` --- ## `kestrel.markets/mcp` — the MCP server **What it is.** The Model Context Protocol face, built as a lossless projection of the SDK. `createKestrelMcpServer({ transport })` constructs `createSdk(transport)` internally and exposes it as a JSON-RPC 2.0 dispatcher over **resources** (the catalog and the immutable, content-addressed artifacts) and **tools** (validate, the incremental Session lifecycle, Grade, and Operation continuation). It is a thin marshaller: it carries the SDK's protocol objects out verbatim and has no runtime semantics of its own. It builds on the full SDK, so importing this entry is Bun-hosted. **When to import it.** You are exposing Kestrel to an MCP client (an agent host) over stdio. **Headline exports.** - `createKestrelMcpServer(options)` and its `KestrelMcpServer` / `KestrelMcpServerOptions`. - `serveStdio(server)` — serve newline-delimited JSON-RPC 2.0 over stdin/stdout. - `TOOL`, `CATALOG_URI_PREFIX`, `ARTIFACT_URI_PREFIX`, `artifactUri`. - `McpProtocolError` and the JSON-RPC error codes `PARSE_ERROR`, `INVALID_REQUEST`, `METHOD_NOT_FOUND`, `INVALID_PARAMS`, `INTERNAL_ERROR`. - Types: `JsonRpcId` / `JsonRpcRequest` / `JsonRpcResponse` / `JsonRpcError`, `Resource`, `ResourceContents`, `ToolResult`, `ToolDescriptor`, `ContentBlock`, `ToolName`. ```ts import { createKestrelMcpServer, serveStdio } from "kestrel.markets/mcp"; import { localTransport } from "kestrel.markets/sdk"; const server = createKestrelMcpServer({ transport: localTransport() }); await serveStdio(server); // JSON-RPC 2.0 over stdin/stdout ``` Pass `remoteTransport({ baseUrl })` instead of `localTransport()` to project the managed backend over MCP. --- ## `kestrel.markets/engine` — the local engine (experimental) > **Experimental / unstable.** The engine is not a stable contract yet. Its charter is the > tick loop — the rule engine, the canonical market state, and ExecutionFair (the `@fair` > anchor) — and that core wiring lands in a later milestone. Today only the pure price > layer and the namespaced capability aggregate ship; treat every name here as subject to > change and read the honest per-capability state on the [status page](./status.md) before > depending on it. **What it is.** The local-execution capability aggregate the package publishes as its own subpath (and, under one key, as `engine` on the root barrel). It is Bun-hosted (`Bun.*` / `node:fs`). **What ships today.** - **Price resolution**`resolvePrice`, `isUnresolvable`, and the `PriceLine` / `PriceCtx` / `PriceResolution` / `PriorResolution` / `RepriceTokenBucket` types: the pure layer between a parsed price line and a concrete order intent. - **Plan scaffolding**`PlanEngine`, `deriveOrderGuard`, and `PlanEngineOptions` / `OrderIntent` / `OrderGuardEvidence` / `OrderRole` / `Gate` / `BusSink` / `InstrumentSpec`. - **Org facts**`BookLedger`, `EngineOrgFacts`, `LedgerFill`, `MultiplierOf`. - **The namespaced aggregate**`lang`, `frame`, `session`, `fill`, `blotter`, `grade`, each under its own key so their domain types never collide. Note `frame` is types-only by charter, so the namespace exists (the materialization contract) while carrying no runtime binding. **View addressing — `AgentConfig.seatViews`.** The `session` namespace exports `AgentConfig`, the harness driver configuration, whose `seatViews` field (`SeatViewsPolicy`: `"founder" | "phase-default"`) is the role-keyed View opt-in. Under `"founder"` the driver passes the acting seat (strategist at the session open, watcher at wakes) into View resolution, so a seat with a **graded founder View** reads it when the session authored none — the precedence is always *explicit View > seat founder View > phase default*. Founder Views are seeds that enter tournaments to be graded, never blessed defaults, so the axis is OFF unless a config opts in; absent (or `"phase-default"`) renders byte-identically to before the axis existed. It is a **ConfigId axis**: it folds into `deriveConfigId` automatically, so a founder-View run occupies a *distinct grid column* — it is never a certified-envelope field. Today this axis is addressable only by constructing an `AgentConfig` programmatically (bench and tournament drivers); the CLI, agent protocol, MCP tools, and SDK facade deliberately carry no View/seat parameter yet (see [the agent protocol](./agent-protocol.md)). ```ts import { resolvePrice, isUnresolvable } from "kestrel.markets/engine"; const resolution = resolvePrice(priceLine, ctx); if (isUnresolvable(resolution)) { // fail closed — never anchor on an unresolvable price } ``` --- ## See also - **[CLI reference](./cli-reference.md)** — the `kestrel` command: verbs, flags, runtime requirements, and the exit-code taxonomy. - **[Capability truth](./capability-truth.md)** and the **[status page](./status.md)** — how to read what each capability actually does at runtime, separately from what its types imply. - **[Overview](./overview.md)** — what Kestrel is and the four statement kinds.