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
Markdown
# 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.