Skip to main content

Audit chain

An append-only, hash-chained record of every tool call and money movement. Exactly-once, tamper-evident, and exportable for compliance.

3 min read
View MarkdownEdit on GitHub

Audit chain

Why it exists

Agents move money. The audit chain is the CFO-grade record of everything they did: every tool call, every payment, every KYC check, written append-only and hash-chained so it can be proven untampered after the fact.

Every governed action in CodeSpar appends an event to a per-tenant audit chain:

  • Append-only. Events are never updated or deleted. Corrections are new events that reference the original.
  • Hash-chained. Each event carries an entry_hash over its contents plus the prev_hash of the event before it, so any retroactive edit breaks the chain and is detectable.
  • Exactly-once. An action is attested once and only once, whether it was dispatched through session.execute(), the chat-loop session.send(), or a raw proxy_execute. Client-SDK tool calls are attested with attested_by: client_sdk; server-side dispatch with the server attestor.
  • Self-auditing exports. Reading the chain out through the export path is itself an audited event.

What gets recorded

Meta-tool calls, raw provider calls, money movement (charge / pay / payout settlement), KYC dispositions, mandate spends, and policy decisions, each with its tool_call_id, resolved rail, idempotency key, and outcome. Completed tool calls land as tool_call.succeeded or tool_call.failed events with the same names and shape on every dispatch path.

Reading the chain

GET /v1/audit/events

A browse-only, paginated listing of your org's chain events. Each event carries sequence_number, event_type, happened_at, payload, prev_hash, and entry_hash. Filters:

Query paramBehavior
event_typeExact match, or prefix match when it ends with a dot: tool_call. matches both tool_call.succeeded and tool_call.failed.
from / toISO 8601 window. Defaults to the last 7 days.
limit1 to 200, default 50.
before_sequenceCursor for older-than pagination. Pass the next_before_sequence from the previous page to walk back.

Browsing is read-only and does not append an export event; it exists so you (and the /dashboard/audit page) can inspect recent activity without dumping the full chain.

Anchors

A background job periodically signs the chain head, the tuple of org, head sequence, and head hash, with HMAC-SHA256 and delivers that anchor record to a configured target outside the database. Anchors are what make tampering provable rather than merely detectable: the chain proves internal consistency, the anchor pins it to a point in time held elsewhere.

EndpointPurpose
GET /v1/audit/anchorsList your org's anchors, newest first, with delivery status.
POST /v1/audit/anchors/verifyPost an anchor record you hold (for example, fetched from your webhook target's storage). The backend recomputes the HMAC signature and cross-checks the (org, sequence, hash) tuple against the row persisted at emit time.

The verify response carries a verdict: verified, signature_ok_but_no_local_record, local_record_diverges, or signature_invalid. A valid signature with a diverging or missing local record is provable tampering on one side or the other.

Export

An org-level export endpoint streams a slice of the chain with a signed manifest for compliance and archival; the export itself appends an audit_export event to the chain.

Audit events also drive the incident lifecycle: anomalous or policy-flagged events can be opened, triaged, and resolved as incidents from /dashboard/audit.

See also

  • Guardrails: the policy decisions that the chain records
  • Wallets: programmable spend, every movement attested
  • Test mode: audit events fire on mocked calls too
Audit chain | CodeSpar