End-to-End Walkthrough (TypeScript)
This walkthrough takes you through the complete receipt lifecycle: emit a receipt event from a TypeScript agent, list the stored chain, and verify its integrity from the CLI. By the end you will have seen the full loop that makes receipts meaningful — not just that a receipt was written, but that it can be independently verified later.
Prerequisites: the daemon is installed and running. If not, complete Daemon Setup first.
Fresh chain assumed: sequence numbers below (1, 2) are correct when the
default chain has no prior receipts. If you have already emitted receipts, run
agent-receipts list to find the current tail and substitute the actual
sequence numbers.
1. Install the SDK
Section titled “1. Install the SDK”npm install @agnt-rcpt/sdk-ts2. Emit a receipt
Section titled “2. Emit a receipt”Create emit.ts:
import { DaemonEmitter } from '@agnt-rcpt/sdk-ts';
async function main() { const emitter = new DaemonEmitter();
try { const err = await emitter.emit({ channel: 'walkthrough', tool: { name: 'fs.write_file' }, decision: 'allowed', }); if (err) throw err; console.log('Receipt emitted.'); } finally { emitter.close(); }}
main().catch(console.error);Run it:
npx tsx emit.tsThe daemon receives the event over its Unix socket, signs it with its Ed25519 key, chains it to any previous receipt in the same chain, and persists it to the SQLite store. The emitter itself never touches the key.
channel is the integration namespace for this emitter — it becomes the prefix
of the action type stored in the receipt (walkthrough.fs.write_file here). Use
a stable, descriptive identifier for your integration: mcp, claude-code,
my-agent, and so on.
emit() returns null on success or an Error on failure — an
EmitTransportError when the daemon is unreachable, a plain Error for caller
bugs such as a missing tool name or invalid decision. close() is synchronous
and releases the socket.
3. List the chain
Section titled “3. List the chain”agent-receipts listYou should see one row: sequence 1, tool fs.write_file, chain default.
To inspect the full receipt:
agent-receipts show 1 --chain-id defaultThis prints a human-readable table of the receipt's fields. To see the full
W3C Verifiable Credential JSON — including the proof block with the Ed25519
signature — pass --json:
agent-receipts show 1 --chain-id default --jsonIn the JSON output, credentialSubject.chain.previous_receipt_hash is null
for the first receipt in a chain — it has no predecessor. The hash linkage
becomes visible once there is a second receipt to point back at it.
4. Verify the chain
Section titled “4. Verify the chain”agent-receipts verifyExample output (on a fresh chain):
Chain default: VALID (1 receipt)The verifier re-derives the hash of each receipt, checks the signature against
the daemon's public key, and confirms the previous_receipt_hash in each receipt
matches the hash of its predecessor. A broken hash link or bad signature produces
a non-zero exit and a description of the failure.
Verify offline
Section titled “Verify offline”The receipt DB and public key are self-contained. Copy them anywhere and verify without a running daemon:
agent-receipts verify \ --db ~/.local/share/agent-receipts/receipts.db \ --public-key ~/.local/share/agent-receipts/signing.key.pub5. Emit a second receipt and re-verify
Section titled “5. Emit a second receipt and re-verify”Rerun emit.ts:
npx tsx emit.tsagent-receipts verifyExample output (count is one higher than after the first emit):
Chain default: VALID (2 receipts)Run agent-receipts show 2 --chain-id default (or substitute the sequence of
your second receipt from agent-receipts list) — unlike receipt 1 (the chain
head), this receipt has a
Previous hash: field containing the hash of receipt 1. That linkage is what
makes the chain tamper-evident: altering receipt 1 changes its hash, invalidates
receipt 2's back-pointer, and verification catches it immediately.
What you have just demonstrated
Section titled “What you have just demonstrated”| Step | What happened |
|---|---|
| Emit | SDK sent an event to the daemon over a Unix socket; daemon signed and stored the receipt |
| List | CLI read the persisted chain from the SQLite store |
| Verify | CLI re-derived hashes, checked signatures, and confirmed chain linkage — all without the daemon being involved |
The daemon is the only process that ever holds the signing key. The agent, the CLI, and any downstream auditor only ever see signed receipts and the public key.
Next steps
Section titled “Next steps”- Receipt Chain Verification — how the hash-chain and signature verification work
- TypeScript SDK API Reference —
DaemonEmitter,ReceiptStore,verifyStoredChain - CLI Commands — full flag reference for
list,show,verify