Audit log
Requires the Pro plan or higher — see Billing.
The append-only, hash-chained record of every governed action. Not a log you can edit and not a log you can delete a row from without it showing.
Each entry commits to the hash of the entry before it, so changing any row — even one deep in the history — breaks every hash that comes after it. Tamper-evident here means editing is detectable, not impossible.
Reading the list
Each row is one governed action, with the columns that matter for scanning a long history quickly: when it happened, who or what did it, what it acted on, a shortened form of its own hash, and its state. Selecting a row opens its full detail: exactly where it sits in the chain, both hashes in full with a copy affordance, a plain-language summary of what happened, and a link to that call's trace when one exists.
| Field | What it is |
|---|---|
| Sequence | Per-tenant, monotonically increasing. Ordering by sequence reconstructs the chain exactly, and a row's detail states its exact position. |
| Event / Resource | What happened and to what. |
| Actor | Who or what caused it — a human identity, an agent, or an API key with no identity behind it at all. |
| Trace | Where a call's trace exists, a row links straight into Traces for the full step-by-step detail. Absent on older rows or when tracing is off. |
| Row hash / Previous hash | The chain. A row's hash is computed from the previous row's hash plus its own contents; the next row must point back to it exactly. |
Actor name/email and agent name are resolved for display at read time — they are enrichment, not part of what gets hashed. Renaming an identity or an agent later never breaks the chain; it just changes what a historical row shows for the same underlying id.
Status
Every entry is written with exactly one of four underlying statuses, shown in the list as one of four plain visual states rather than as these words directly:
| Status | Shown as | What it means |
|---|---|---|
| Final | Ready (✓) | The call completed and was delivered normally. The only status that counts as a success. |
| Pending | Working (◐, pulsing) | A reservation written the moment a call begins, before it is known whether it will finish as Final, Failed, or Blocked. This should resolve almost immediately — a row stuck here points to a call that did not complete cleanly. |
| Blocked | Attention (▲) | The call completed and was billed, but its result was withheld by a policy decision, such as a guardrail or the Tool Registry. The row's detail carries why. |
| Failed | Failing (✕) | The call itself broke — for example, a provider error — and was refunded. The row's detail carries why. |
The hash chain
Every row's hash is computed from the previous row's hash plus its own contents, and the next row must point back to exactly that value. Walk the chain in sequence order and each link either matches or it does not — there is no partial credit. Editing a row, or deleting one and closing the gap, changes a hash somewhere in the chain, and every hash after that point stops matching.
That is the whole mechanism. It does not require a blockchain, a third party, or an external anchor — just that nobody with write access to the table can also recompute every hash after the point they'd need to change, without the mismatch being checkable by someone who did not do the editing.
The list states this chain's verdict as plainly as the rows themselves: verified, or a count of broken links with each offending row marked directly in the list below it.
The audit chain is written by the control plane inside the governed transaction itself, so it does not depend on the trace store being up — if tracing is misconfigured or Traces is unreachable, the audit chain still gets its row and the chain stays provable. A refusal that never reaches the provider still writes an audit row too (see Errors and refusals), which is what makes a burst of denied calls visible in the same record as everything that succeeded.

