Sessions & Receipts
Create sessions to group related agent actions into hash-chained, cryptographically-signed receipt sequences.
import { Invariance, Session } from '@invariance/sdk';
Overview
A session is a container for a sequence of hash-chained receipts. Every receipt contains the SHA-256 hash of its action data plus the hash of the previous receipt, forming a tamper-evident chain. If any receipt is modified after creation, all subsequent hashes become invalid.
Sessions can be created lazily with `inv.session()` (backend registration happens in the background) or eagerly with `await inv.createSession()` (waits for backend confirmation).
When you close a session with `session.end()`, a close hash is computed over the entire chain and sent to the backend. This seals the session — no more receipts can be added.
Architecture
Sessions manage their own receipt chain state (hash cursor, sequence number). The Transport layer handles batching and network I/O. Sessions are independent — you can run multiple sessions concurrently without interference.
Important Notes
Always call session.end() when done. Un-ended sessions remain "open" on the server and their receipts may not be fully flushed.
inv.session() returns immediately (fire-and-forget). Use inv.createSession() when you need to guarantee the session exists before recording.
Quick Example
const inv = Invariance.init({ apiKey: 'dev_...', privateKey: '...' });
const session = inv.session({ agent: 'swap-bot', name: 'morning-run' });
await session.record({
action: 'search', input: { query: 'ETH price' }
});
await session.record({
action: 'swap', input: { from: 'ETH', to: 'USDC', amount: '1.0' },
output: { txHash: '0xabc...' }
});
session.end();
await inv.shutdown();
Type Definitions
Receipt
interface Receipt {
id: string;
sessionId: string;
agent: string;
action: string;
input: Record<string, unknown>;
output?: Record<string, unknown>;
error?: string;
timestamp: number;
hash: string;
previousHash: string;
signature: string | null;
contractId?: string;
counterAgentId?: string;
counterSignature?: string;
}
A hash-chained, signed receipt of an agent action.
SessionInfo
interface SessionInfo {
id: string;
agent: string;
name: string;
status: 'open' | 'closed' | 'tampered';
receiptCount: number;
}
Information about a session including its status and receipt count.
API Reference
session
Create a new session (lazy — backend registration happens asynchronously).
session(opts: { agent: string; name: string }): Session
Parameters
agentstringAgent identifier
namestringHuman-readable session name
ReturnsSession
createSession
Create a session and wait for backend confirmation.
async createSession(opts: { agent: string; name: string }): Promise<Session>
Parameters
agentstringAgent identifier
namestringSession name
ReturnsPromise<Session>
session.record
Record an action as a hash-chained receipt in this session.
async record(action: Action): Promise<Receipt>
Parameters
actionActionThe action to record
ReturnsPromise<Receipt>
session.end
Close the session. Computes a close hash and seals the chain.
end(status?: 'closed' | 'tampered'): SessionInfo
Parameters
status'closed' | 'tampered'Final session status
ReturnsSessionInfo
session.wrap
Policy check, execute, and record within a session context. Combines policy enforcement with execution and receipt creation in one call.
async wrap<T>(action: Omit<Action, "output" | "error">, fn: () => T | Promise<T>, checkPolicies?: (action: Action) => PolicyCheck): Promise<{ result: T; receipt: Receipt }>
Parameters
actionOmit<Action, "output" | "error">Action metadata (action name, input)
fn() => T | Promise<T>The function to execute
checkPolicies(action: Action) => PolicyCheckOptional policy check function evaluated before execution
ReturnsPromise<{ result: T; receipt: Receipt }>
session.getReceipts
Get all receipts recorded in this session (in-memory). Returns the session's local receipt chain without making API calls.
getReceipts(): readonly Receipt[]
Returnsreadonly Receipt[]
session.traces
Get a chainable TraceQuery over this session's receipts. Enables fluent filtering and analysis of session data.
traces(): TraceQuery
ReturnsTraceQuery
session.verify
Verify this session's receipt chain locally using verifyChain(). Checks hash-chain integrity and optional signature verification.
async verify(publicKeyHex?: string): Promise<VerifyResult>
Parameters
publicKeyHexstringOptional public key (hex) for signature verification. If omitted, only hash-chain integrity is checked.
ReturnsPromise<VerifyResult>
Walkthrough
Session lifecycle from creation to verification
Create a session
Initialize the SDK and create a session.
const inv = Invariance.init({
apiKey: process.env.INVARIANCE_KEY!,
privateKey: process.env.PRIVATE_KEY!,
});
const session = inv.session({
agent: 'research-agent',
name: 'daily-research',
});
Record a chain of actions
Each record call creates a receipt hash-chained to the previous one.
await session.record({
action: 'web_search',
input: { query: 'latest AI research papers' },
output: { results: 15 },
});
await session.record({
action: 'summarize',
input: { paperCount: 5 },
output: { summary: '...' },
});
End and verify
Close the session and verify chain integrity.
const info = session.end();
console.log(info.receiptCount); // 2
import { verifyChain } from '@invariance/sdk';
const receipts = await inv.query({ sessionId: session.id });
const result = verifyChain(receipts);
console.log(result.valid); // true
Error Handling
import { InvarianceError } from '@invariance/sdk';
const session = inv.session({ agent: 'bot', name: 'run' });
session.end();
try {
await session.record({ action: 'search', input: { q: 'test' } });
} catch (err) {
if (err instanceof InvarianceError) {
console.error(err.code); // 'SESSION_CLOSED'
}
}
Use Cases
- Group a multi-step agent workflow into a single auditable session
- Create separate sessions for each user request or task
- Use eager creation (createSession) when session ID is needed before first action
- Run multiple concurrent sessions for parallel agent activities