When you build a tool around Hankweave – a dashboard that reads run state, a script that parses the event stream, a reporter that walks per-codon transcripts – you need the same shapes the server itself uses. Rather than define stubs by hand, you can import Hankweave's own TypeScript types and Zod schemas from the published package. This page is the reference for that surface: what the package exports, what it deliberately does not, and how to use the exports for the common reading tasks. If you are looking for WebSocket client code instead, that lives in WebSocket quickstart.
What Hankweave exports#
The published hankweave package has exactly three public import paths. Two of them, ./schemas and ./types, are the library surface for external consumers; the third is the CLI entry and carries no types at all.
| Export | Purpose | Useful shape or symbols |
|---|---|---|
. | The CLI entry at dist/index.js. | It has no types condition and no published dist/index.d.ts; an import from hankweave therefore has no typed library surface and raises TypeScript diagnostic TS7016 unless suppressed. |
./schemas | Zod schemas and inferred types for server events, per-codon log messages, and content blocks. | serverEventSchema, ServerEvent, event-data schemas, category classifiers, logMessageSchema, and content-block schemas and types. |
./types | TypeScript types and utilities for state, configuration, branded IDs, and execution data. | HankweaveState, configuration types, CodonId and related constructors, getCodonCost, getCodonTokens, and isTerminalCodonStatus. |
The . row explains a common surprise: importing from bare hankweave gives you no typed surface, because the CLI entry has no types condition. Repository-relative imports such as hankweave/server/* are not additional package exports either. Everything you can legitimately import comes from hankweave/schemas or hankweave/types, and the next two sections catalog each path.
hankweave/schemas – events and log messages#
The hankweave/schemas entry point contains the complete ServerEvent union, selected named schemas for validating individual event shapes, and the schemas for per-codon log messages and their content blocks. The table groups the exports by the job they do:
| Category | Exported symbols | Use |
|---|---|---|
| Events | serverEventSchema, ServerEvent; individual event schemas and types for CodonStartedEvent, CodonCompletedEvent, CodonExtendedEvent, AssistantActionEvent, ToolResultEvent, FileUpdatedEvent, ErrorEvent, TokenUsageEvent, SentinelLoadedEvent, SentinelOutputEvent, SentinelErrorEvent, SentinelTriggeredEvent, SentinelUnloadedEvent, RigSetupCompletedEvent, RigSetupFailedEvent, RigOutputEvent, LoopIterationCompletedEvent, InfoEvent, BudgetSummaryEvent, and ServerReadyEvent | The union has 36 members. Individual event schemas are exported for 20 members; the other 16 are available through the union and inferred type. |
| Event data | assistantActionEventDataSchema, codonStartedEventDataSchema, codonCompletedEventDataSchema, tokenUsageEventDataSchema, toolResultEventDataSchema, rigSetupCompletedEventDataSchema, rigSetupFailedEventDataSchema, sentinelLoadedEventDataSchema, sentinelOutputEventDataSchema, sentinelUnloadedEventDataSchema, and loopIterationCompletedEventDataSchema | Parse a selected event's data object without parsing the surrounding event again. |
| Classifiers | isServerStateEvent, isAgenticBackboneEvent, isSentinelEvent, isConnectionStateEvent | Each function is a type guard that narrows a ServerEvent to its category union. |
| Log messages | logMessageSchema, LogMessage, assistantMessageSchema, AssistantMessage, resultMessageSchema, ResultMessage, systemMessageSchema, SystemMessage, userMessageSchema, UserMessage | Parse per-codon agent-session JSONL and distinguish assistant, result, system, and user messages. |
| Content blocks | textContentSchema / TextContent, thinkingContentSchema / ThinkingContent, toolUseContentSchema / ToolUseContent, toolResultContentSchema / ToolResultContent, and messageContentSchema | Validate content inside a log message. |
Two details in that table are worth keeping in mind. The union has 36 members, but individual schemas exist for only 20 of them; the rest are reachable through the union and its inferred type. And the event-data schemas let you parse a selected event's data object on its own, without re-parsing the surrounding event.
A consumer that needs several event and log-message symbols pulls them all from the same public path:
import {
serverEventSchema,
type ServerEvent,
type CodonCompletedEvent,
type AssistantActionEvent,
type ToolResultEvent,
logMessageSchema,
type LogMessage,
type AssistantMessage,
type ResultMessage,
type ToolUseContent,
type ThinkingContent,
type TextContent,
isServerStateEvent,
isAgenticBackboneEvent,
isSentinelEvent,
isConnectionStateEvent,
} from "hankweave/schemas";
hankweave/types – state, config, and utilities#
The second entry point covers the rest of the vocabulary: state and execution records, configuration shapes, branded IDs, and a small set of runtime helpers. One term matters before the table: a hank is the work definition Hankweave loads, the hank.json file whose required hank array lists the codons and loops that form the immutable logic sequence. Several configuration types below describe values read from that file.
| Category | Exported symbols | Useful constraint or example |
|---|---|---|
| State and execution | HankweaveState, Run, CodonExecution, ExecutionCodonEntry, CodonStatus, CompletedCodon, FailedCodon, CompletingSentinelsCodon, InitializingCodon, PreparingCodon, RunningCodon, SkippedCodon, StartingCodon, StartingConditions, SentinelState, TokenUsage, FailureReason | CodonStatus is preparing | starting | initializing | running | completing-sentinels | completed | failed | skipped. ExecutionCodonEntry is the shape used in the state's executionPlan array. |
| Configuration | Codon, CodonConfig, HankFile, HankMeta, HankweaveConfig, Loop, RigSetupItem, RigShellCommand | These types describe values read from Hankweave configuration and hank files. |
| Branded IDs | CodonId, RunId, SessionId, EventId | Each constructor accepts a string and returns its corresponding branded string type, such as CodonId("my-codon"). |
| Utilities | getCodonCost(execution), getCodonTokens(execution), isTerminalCodonStatus(status) | The cost and token helpers read a CodonExecution; the terminal-status guard recognizes completed, failed, and skipped. |
The state row carries the two constraints you will hit first: CodonStatus is exactly preparing | starting | initializing | running | completing-sentinels | completed | failed | skipped, and ExecutionCodonEntry is the element type of the state's executionPlan array.
Because this path mixes type-only exports with runtime values (the ID constructors and the utility functions), it is good practice to keep the two import kinds separate:
import type {
HankweaveState,
Run,
CodonExecution,
CompletedCodon,
FailedCodon,
CodonStatus,
TokenUsage,
} from "hankweave/types";
import {
CodonId,
RunId,
isTerminalCodonStatus,
getCodonCost,
getCodonTokens,
} from "hankweave/types";
What is not exported#
The public package surface is closed: ., ./schemas, and ./types are the only public paths. Everything else that might look importable is not, and the failure modes are worth knowing in advance.
Three specific non-exports cause most of the confusion:
@hankweave/typesdoes not exist. The package is the unscopedhankweave;@southbridgeai/hankweaveis the private repository name, not an install target.- Deep imports such as
hankweave/server/websocket-log-readerand otherhankweave/server/*paths are internal rather than public API. - The command definitions in
command-schemas.tsare internal, not package exports. The 14-command reference, includingserver.force_shutdown, belongs to the WebSocket protocol. Likewise,TestWSClientfrom the test suite is not a public export.
Use the exported types#
The remainder of this page walks through the reading tasks these exports support, in the order you are likely to meet them: reading state, parsing and filtering events, computing cost, constructing IDs, and parsing transcripts. First, install the unscoped package:
npm install hankweave@0.10.0
# or
bun add hankweave@0.10.0
Then import each shape from the path that owns it:
import { serverEventSchema, type ServerEvent } from "hankweave/schemas";
import type { HankweaveState, Run, CodonStatus } from "hankweave/types";
import {
CodonId,
isTerminalCodonStatus,
getCodonCost,
} from "hankweave/types";
Two environment details affect whether these imports work. The schemas are Zod v3 objects, and zod is a regular dependency of hankweave@0.10.0 rather than a peer dependency, so it arrives transitively; the package does not re-export Zod. And the verified consumer settings for these package exports are module: "Node16", moduleResolution: "Node16", target: "ES2022", strict: true, and types: ["node"].
The typecheck-exports fixture is the recorded check that all of this holds: it typechecks the imports against the published package and runs its parser against real state.json and events.jsonl files. Its clean output is the evidence that hankweave/schemas and hankweave/types resolve as documented:
bun install v1.3.14 (0d9b296a)
Resolved, downloaded and extracted [216]
warn: incorrect peer dependency "zod@3.25.76"
warn: incorrect peer dependency "@anthropic-ai/sdk@0.91.1"
+ @types/node@22.20.1 (v26.4.1 available)
+ typescript@5.9.3 (v7.0.2 available)
+ hankweave@0.10.0
267 packages installed [1217.<ms>ms]
Blocked 2 postinstalls. Run `bun pm untrusted` for details.
typecheck-exports: clean
exit=0
Read state with the exported types#
HankweaveState provides the type for parsed state.json data, and isTerminalCodonStatus identifies the completed, failed, and skipped codons. Together they are enough to walk every run and pick out finished work:
import type { HankweaveState } from "hankweave/types";
import { isTerminalCodonStatus } from "hankweave/types";
import { readFile } from "node:fs/promises";
const statePath = "state.json";
const state: HankweaveState = JSON.parse(await readFile(statePath, "utf8"));
for (const run of state.runs) {
for (const codon of run.codons) {
if (isTerminalCodonStatus(codon.status)) {
console.log(codon.status);
}
}
}
Parse events with Zod#
For the event stream, parse each non-empty JSONL line with serverEventSchema. The result is a ServerEvent narrowed from the 36-member union, so downstream code gets full type discrimination on event.type:
import { serverEventSchema, type ServerEvent } from "hankweave/schemas";
declare const line: string;
const event: ServerEvent = serverEventSchema.parse(JSON.parse(line));
Filter events by category#
When you only care about one category, filter a ServerEvent[] with an exported classifier. Each classifier is a type guard, so the filtered array is narrowed to that category's union rather than staying ServerEvent[]:
import { isServerStateEvent, type ServerEvent } from "hankweave/schemas";
declare const events: ServerEvent[];
const serverStateEvents = events.filter(isServerStateEvent);
The same pattern applies to isAgenticBackboneEvent, isSentinelEvent, and isConnectionStateEvent.
Compute codon cost without double-counting#
Cost is the easiest place to get wrong answers from otherwise correct parsing, so the rules come before the code. For state data, call getCodonCost on a CodonExecution. For an event-stream reported-codon-cost view, establish run boundaries from state.transition, retain the final codon.completed cost for each (runId, codonId), and keep continuation runs and loop runtime IDs distinct. Deduplicate retransmitted event IDs before retaining or summing records. The completion cost is the authoritative persisted cost and includes accumulated retry cost; do not add token.usage, retry, or extension totals again. This view is not a provider invoice and does not establish accounting for interrupted or skipped work, unpriced routes, sentinels, or health checks. budget.summary is a runtime, state-based summary rather than a provider invoice or a guarantee of retry-inclusive accounting.
The implementation below applies those rules: it tracks the current run from state.transition events, skips retransmitted event IDs, and keeps only the final codon.completed record per (runId, codonId) before summing.
import { type ServerEvent } from "hankweave/schemas";
export function reportedCodonCosts(events: ServerEvent[]): Map<string, number> {
let currentRunId: string | undefined;
const costs = new Map<string, number>();
const seenEventIds = new Set<string>();
for (const event of events) {
if (seenEventIds.has(event.id)) continue;
seenEventIds.add(event.id);
if (event.type === "state.transition") {
if (event.data.transitionType === "RunStarted") {
currentRunId = event.data.runId;
} else if (["RunCompleted", "RunFailed", "RunCrashed"].includes(event.data.transitionType)) {
currentRunId = undefined;
}
}
if (event.type === "codon.completed" && currentRunId) {
const key = `${currentRunId}:${event.data.codonId}`;
costs.set(key, event.data.cost);
}
}
return costs;
}
// Sum only after the final record for each (runId, codonId) is retained.
export function reportedTotal(events: ServerEvent[]): number {
return [...reportedCodonCosts(events).values()].reduce((total, cost) => total + cost, 0);
}
For state data, the direct utility remains the shorter lookup:
import {
getCodonCost,
isTerminalCodonStatus,
type CodonExecution,
} from "hankweave/types";
declare const codon: CodonExecution;
const cost = getCodonCost(codon);
const terminal = isTerminalCodonStatus(codon.status);
Construct IDs without mixing them#
Construct a branded ID where a string becomes a Hankweave identifier. The branded type prevents accidental mixing of codon IDs, run IDs, and plain strings during type checking.
import { CodonId, RunId } from "hankweave/types";
const cid = CodonId("my-codon");
const rid = RunId("my-run");
Parse per-codon transcripts#
Use logMessageSchema for an agent-session transcript when the consumer needs to distinguish assistant messages, tool results, system messages, and user messages.
import {
logMessageSchema,
type AssistantMessage,
type ResultMessage,
} from "hankweave/schemas";
declare const line: string;
const message = logMessageSchema.parse(JSON.parse(line));
From client-library snippets to real exports#
WebSocket client code with event buffering, waitForEvent, and connection retries belongs to WebSocket quickstart, not this exports reference. The command catalog belongs to the WebSocket protocol. This page shows the import side of those patterns: when client code from those pages handles events or state, the types behind it come from hankweave/schemas or hankweave/types, never from a deep server import.