Concepts
The core ideas behind AgentReceipt. Understanding these will help you get the most out of the SDK and the dashboard.
Sessions
A session is one end-to-end agent run. One invoice processed, one ticket handled, one report generated. Sessions group events together into a single receipt. Name your sessions clearly. The name shows up in the dashboard and in the receipt summary.
When you use a wrapper like wrapOpenAI, the SDK creates a session automatically based on the sessionName you provide. If you need more control, use startSession to manage sessions manually.
Session status
Each session has a status that is computed automatically:
| Status | Meaning |
|---|---|
| running | Last event was less than 3 minutes ago. |
| complete | No new events for 3 minutes and no errors. |
| error | At least one event with type "error" exists. |
Completing a session
Sessions complete automatically 3 minutes after the last event. To complete a session immediately, call session.end() at the end of your agent run. This triggers summary generation and Rekor anchoring right away rather than waiting for the timeout.
const session = ar.startSession("Process invoice #441")
try {
// your agent logic
} finally {
await session.end() // always call this when your agent finishes
}Event limit
Each session can hold up to 200 events. If a session hits 200 events, the ingest endpoint stops accepting new events for that session and records a system error event. The receipt shows exactly where and why it stopped. If your agent runs need more than 200 events, start a new session at a logical boundary in your workflow.
Events
An event is a single action within a session. Every LLM call, tool execution, decision, and human review is recorded as an event. Events are immutable once written.
| Type | When it fires |
|---|---|
llm_call | Any LLM completion, streaming or not. |
tool_call | Any function wrapped with trackTool. |
decision | Any call to trackDecision. |
human_review | Any call to trackHumanReview. |
error | Any error captured by the SDK or recorded by the system. |
context_change | A mid-session change to rules, thresholds, or permissions. See Decision context. |
Each event stores the input, output, duration, and a SHA-256 hash. Raw input and output payloads are stored separately in Cloudflare R2, not in the main database. This keeps the event metadata small and queryable while allowing large payloads.
Receipts
A receipt is the human-readable view of a completed session. It shows a timeline of every event, a plain-English summary generated by AI, and a hash chain verification badge. Receipts are read-only. Nothing can be edited after the fact.
The summary is generated the first time someone views a receipt. It uses the event names and types (not the raw payloads) to produce a 3-5 sentence description of what the agent did. The summary is cached so it only needs to be generated once.
You can see what a receipt looks like on the demo page.
Sharing receipts
Any complete receipt can be shared with a public link. Generate one from the Share button on any session detail page. Anyone with the link can view the full receipt without signing in. The timeline, summary, hash chain status, and Rekor anchor badge are all visible. Links can be revoked at any time from the same button. By default, all receipts are private.
Hash chain
Every event stores a SHA-256 hash of its own data combined with the hash of the previous event. This creates a chain. If any event is modified after the fact, the chain breaks and the dashboard shows "Tampered" instead of "Verified".
The chain is verified every time someone loads a receipt. The verification checks each event's hash against a freshly computed hash of the same data plus the previous event's hash. If any hash does not match, the entire chain is marked as tampered.
This means even AgentReceipt itself cannot silently modify your data. Tampering is always detectable. If you need to prove to an auditor that your agent logs have not been altered, the hash chain verification badge is that proof.
The first event in a session has no previous hash. Its hash is computed from its own data only. Every subsequent event's hash depends on the event before it, forming the chain.
External verification
Pro and Business receipts are anchored to the Sigstore Rekor transparency log after the session completes. Rekor is a public, append-only log run by the Linux Foundation. The anchor proves the receipt existed at a specific time and has not been changed since. Click the "Anchored on Rekor" badge on any receipt to verify the entry independently.
Compliance metadata
Any event can be tagged with a compliance object. This lets you flag events that contain sensitive data, categorize them, and set custom retention periods.
{
containsPII?: boolean
dataCategory?: string // e.g. "health", "financial", "personal"
retentionOverride?: number // days
}Events tagged with containsPII: true show a PII badge in the receipt. Your compliance team can filter for these events to review what sensitive data your agent handled.
The retentionOverride field sets a custom retention period for that event, overriding the project default. Use this for healthcare data (HIPAA requires 6 years) or any data with specific retention requirements.
await session.trackTool(
'fetch-patient-record',
{ patientId: 'P-12345' },
async () => {
return await ehr.getPatient('P-12345')
},
{
compliance: {
containsPII: true,
dataCategory: 'health',
retentionOverride: 2190 // 6 years in days
}
}
)Decision context
Knowing what an agent did is not enough. An auditor needs to know why it was valid at the time. Decision context captures the conditions that informed an action: the system prompt, the rules that were active, the permissions the agent had, and the state it was looking at when it made a choice.
Decision context works at two levels. Session context captures the baseline operating environment when the agent run starts. Event context captures the specific conditions that applied to an individual action.
Session context
Passed once when you start a session. It describes the environment the agent was running in. The receipt shows this as a collapsible "Decision context" panel.
const session = ar.startSession('Process invoice #441', {
context: {
systemPrompt: 'You are an accounts payable agent...',
activeRules: [
{
id: 'auto-approve-threshold',
description: 'Auto-approve payments under $5,000 for verified vendors',
parameters: { threshold: 5000, currency: 'USD' }
}
],
permissions: ['read:invoices', 'write:payments'],
environment: { region: 'us-east-1', accountTier: 'business' }
}
})| Field | What it captures |
|---|---|
systemPrompt | The instructions given to the agent at the start of the run. |
activeRules | Guardrails, policies, and thresholds. Each rule has an id, description, and optional parameters. |
permissions | What the agent is allowed to do. Displayed as a list of scopes. |
environment | Any application-specific state relevant to the run (account tier, region, user role, etc.). |
All fields are optional. Pass whatever is relevant to your use case. Even just the system prompt on its own adds significant audit value.
Event context
Attached to individual events, typically decisions or tool calls. It answers: "For this specific action, what rules were checked and what state was the agent looking at?"
await session.trackDecision(
'approve-payment',
'Amount $3,200 is under threshold. Vendor verified.',
'approved',
{
context: {
rulesEvaluated: ['auto-approve-threshold', 'vendor-must-be-verified'],
stateAtDecision: {
invoiceAmount: 3200,
approvalThreshold: 5000,
vendorVerified: true
}
}
}
)Event context is stored alongside the input and output in the event payload. In the receipt, it appears as a "Context" tab when you expand an event.
Context changes
If rules, permissions, or thresholds change mid-session, record it with trackContextChange. This creates a context_change event in the hash chain, so the receipt shows exactly when and what changed.
await session.trackContextChange(
'approval-threshold-updated',
{ threshold: 5000 }, // previous
{ threshold: 10000 } // current
)Context changes render as a distinct event in the timeline with a "Previous" and "Current" view instead of the usual Input/Output.
Automatic capture
The OpenAI and Anthropic wrappers automatically extract the system prompt from LLM calls and attach it as event context. You get partial context capture for free without any extra code. For business rules and permissions, you need to pass them explicitly since those are specific to your application.