> ## Documentation Index
> Fetch the complete documentation index at: https://developers.haia.finance/llms.txt
> Use this file to discover all available pages before exploring further.

# @usehaia/trace-core

> Contracts and the deterministic receipt assembler.

The contracts and deterministic receipt assembler at the heart of Haia Trace.
Most users reach for the [CLI](/cli/overview) or the [x402
adapter](/sdk/x402) instead — depend on `trace-core` directly when you're
**building your own capture adapter** or **embedding the assembler**.

Zero runtime dependencies. ESM only, Node ≥ 20 (the assembler is also
runtime-agnostic; the file-backed store lives behind the `/node` subpath).

## Install

```sh theme={null}
npm install @usehaia/trace-core
```

## The three contracts

* **Event** — the normalized shape every capture adapter emits: a namespaced
  `event_type`, an `occurred_at`, an optional `context_id` grouping one
  operation's events, a `seq`, the observing `role`, and a redacted `payload`.
  Written append-only as NDJSON.
* **Template** — a declarative description of an operation as a sequence of
  milestone stages. Each stage's `match` is a match-set: any one of its events
  closes the stage.
* **Receipt** — the verdict from `(events, template)`. See [Operation
  Receipt](/concepts/operation-receipt).

## Assemble a receipt

```ts theme={null}
import { assembleReceipts, type TraceEvent } from "@usehaia/trace-core";

const events: TraceEvent[] = [ /* ... one run's events ... */ ];
const template = /* an OperationTemplate */;

const { receipts } = assembleReceipts(events, template);
```

The assembler is a **pure, deterministic function**: no LLM, no randomness. The
same events and template always yield the same Receipt, byte for byte. Events are
split into operations by `context_id`, and one Receipt is produced per operation.

`assembleReceiptsProgressively(events, template)` yields the same result as an
iterator of progress snapshots, for streaming a live count over a large run.

<Tip>
  An `OperationTemplate` is plain data; validate an untrusted one (e.g. parsed
  from YAML) with `assertOperationTemplate` before assembling against it.
</Tip>

## Mint events (building an adapter)

`createRecorder` is the one place an adapter mints events — it owns the session's
`seq` counter and stamps `event_id`, `occurred_at`, and `adapter`, so you supply
only the meaningful fields:

```ts theme={null}
import { createRecorder } from "@usehaia/trace-core";

const recorder = createRecorder({ adapter: "trace-x402" });

const event = recorder.event({
  event_type: "x402.payment.required",
  role: "client",
  context_id: requestId,              // from your runtime's async context
  payload: { resource: "/api/data" }, // redacted — never keys or signatures
});
```

## Persist events (the `/node` subpath)

The event sink is a runtime-agnostic contract in the root export (`EventWriter` /
`EventReader`, plus the NDJSON codec `encodeEventLine` / `decodeEventLines`). The
concrete file-backed implementation — the only place `node:fs` is imported —
lives behind the `/node` subpath:

```ts theme={null}
import { readLatestRun, createFileReader } from "@usehaia/trace-core/node";

const reader = readLatestRun(".trace/events");   // or createFileReader(path)
const events = reader?.read() ?? [];
```
