Integration patterns
Three ways to lay out an agent's record: an entry per action, an entry per run, or a run that opens, records its actions, and closes. Which to pick and how to name the entries.
An agent's record is one record per run, and the question is how many entries a run gets. Three patterns cover most agents. They differ in how much the record says and how many writes it costs; they do not differ in what the check confirms.
Entry per action
Every action the agent takes is an entry, written as it happens. The record reads like the run: the task it was given, each tool call, the decision, the handoff to a person, the message it sent. This is the pattern for an agent that acts on other people's systems or money, and for an agent under evaluation, where the order of its actions and the moment it reached past its test are what a reader will ask about.
| Entry | kind | payloads |
|---|---|---|
| The run opens | agent-run | The instruction, and the limits in force |
| The agent calls a tool | tool-call | The call and its result, as the harness kept them |
| The agent decides | decision | The decision as written |
| The agent hands work to a person | agent-handoff | What it handed over |
| A person approves | approval-given | The approval, written by the tool the person used |
| The agent acts on the world | your word for the action | The action, as sent |
The run closes (lifecycle: 'closed') | agent-run-close | The transcript or the summary |
Cost: one write per action, up to 120 a minute per workspace. For an agent that takes hundreds of actions a minute, fold the small ones into one decision entry that carries several fingerprints, and keep the actions that touch the outside world as entries of their own. An agent in an evaluation and What an agent did are this pattern.
Entry per run
One entry, written when the run ends, carrying the fingerprints of everything that matters: the instruction, the transcript, the output. The record says the run happened, when, on whose instruction, and what it produced, and nothing about the order inside it. This is the pattern for scheduled jobs and for runs where no agent acts on the world, such as a nightly benchmark suite, where the run is the unit and the transcript is a file.
// refOf is the helper on Recording from an agent: it fingerprints a file and keeps its blinding file beside it.
await pac.records.emit({
record: `suite-${jobId}`,
title: `Nightly benchmark suite ${jobId} finished, ${today}`,
kind: 'suite-run',
occurredAt: finishedAt,
actorId: 'suite-runner-2',
instructedBy: 'nightly-schedule',
payloads: [
await refOf(`suites/${jobId}/config.json`),
await refOf(`suites/${jobId}/transcript.jsonl`),
await refOf(`suites/${jobId}/results.json`),
],
idempotencyKey: `suite-${jobId}:finished`,
});Cost: one write per run. The transcript itself stays with you, and the record carries its fingerprint, so a reader who is later handed the transcript and its blinding file can check it is the one that was recorded.
Open, act, close
The first pattern with a start and an end: the run opens with an entry that names it, actions are entries, and the run closes with an entry that carries the summary and lifecycle: 'closed'. After the close, anything that tries to write to the record is recorded as an attempt, marked so, and the record's state does not move. This is the pattern for an agent that must not keep acting after it was told to stop, because the record then shows both the stop and any attempt after it.
Naming
recordis the run's id, made from something you already have:run-${runId},eval-run-${runId},suite-${jobId}. Never the clock.- The first entry's
titleis the record's name. Name the thing, with its date: "Agent-7 runtime decisions, 23 September". kindis your vocabulary, in lower case letters, digits, and hyphens:tool-call,approval-given. A dot or an underscore is refused withRECORD_CONTENT_INVALID. Pick a short list and keep to it; a reader filters by it.idempotencyKeyis the run id joined to the step:run-${runId}:call-${callId}. It is never the record id alone, because every entry needs its own.actorIdis who acted, as you name them: the agent, a monitor, a person.instructedByis the person or system that started the run, and it changes only when a person steps in, for example the person whose approval an action rests on.
References between records
When a run acts on something that has its own record, a model release, a document, another run, the entry can name that record's entry in references: [{ recordKey, entry }]. The referenced entry must already be committed in your workspace. A reader of the run's record can then open the thing it acted on, as it was at the time. A model release shows a run naming the build it runs.
What not to record
Record the fingerprints of the file, the transcript, and the prompt, and keep the things themselves, and their blinding files, with you. Keep secrets, keys, and tokens out of every field; everything under content is sealed, and a field you reveal is shown to whoever you share the record with. Do not record the same action twice under two keys. And do not write an entry for an action that has not happened yet.