Guides

Audit trails that hold up later

An audit trail for AI agents records who asked, what exactly, who approved, and what the machine did. What to record, what to omit, and how to keep it honest.

Last reviewed: August 2026. This guide is kept current in place, so its address never changes when it is refreshed.

An audit trail for AI agents is an append-only record of every consequential action the system took and every human decision that authorised one: who asked, what exactly, who approved, what the machine did, and when each of those happened. It is written as events occur, by the code that causes them, and nothing edits it afterwards.

The distinction that matters most is not technical. It is about the intended reader. Logs are written for whoever is debugging right now. An audit trail is written for someone who was not there — a colleague three months later, a customer asking what happened to their data, an auditor, or you, at two in the morning, trying to establish whether a bot did something it was told to do or something it invented.

Agent systems raise the stakes on this because the actor is not a person and cannot be asked. A human who did something surprising can explain their reasoning. A bot’s reasoning is not available in a form anyone should rely on, so the record of what it was authorised to do is the only durable account of intent.

Logs are not a trail

Four properties separate the two, and dropping any one of them turns a trail back into logs with good intentions.

Fixed shape. The set of recorded event types is decided deliberately and changes rarely. Log lines evolve with whoever last touched the code; an audit event that changes shape every release cannot be queried across a year.

Append-only. No update path, no delete path, no administrative tidy-up. This is a property of the code, not of a policy document. If there exists a function that edits an audit row, the trail’s evidentiary value is exactly the trustworthiness of everyone with access to that function.

Written with the action. The record and the state change happen in one transaction. A trail written afterwards by a separate process records what a healthy system did and goes quiet in precisely the failures worth investigating.

Retained on purpose. Someone decided how long, and why. NIST’s guide to log management makes the same point about ordinary logs: retention that emerges from disk pressure is not a policy.

Regulation is arriving at the same shape from outside. The EU AI Act’s Article 12 requires high-risk systems to log events automatically over their lifetime, and the AU control family in NIST SP 800-53 has treated non-repudiation and record protection as separate controls for years. Neither will tell you what your agent’s events are. Both assume you can produce them on request.

The four questions a row answers

Who asked. The account that initiated the action, not the service identity that carried it out. “The system” is not an actor.

What exactly. The verb and its full parameters, at the granularity the machine acted on. “Updated configuration” is not an audit record. Where parameters contain anything sensitive, record a digest and store the value where it belongs — the digest is what proves later that the approved thing and the executed thing were the same thing.

Who approved. Present or explicitly absent. A row that omits this because the action needed no approval should say so, because “no approval was required” and “approval was not recorded” look identical in a trail that leaves the field blank.

What the machine did. The outcome, including the boring ones: refused, expired, delivered but never claimed. A trail that records only successes is a marketing artefact.

Record the non-events

The events that matter most in an investigation are the ones where nothing happened.

Klingbar writes an audit row for every command transition, in the same transaction as the status change, and the transitions include the unhappy ones by design. A command that was delivered to a runner and never acknowledged is re-queued after five minutes with the attempt count incremented and the redelivery recorded; after five attempts it is failed with the reason “delivery lost”. A command that began executing and stopped reporting for thirty minutes is failed with the reason “runner stopped reporting” rather than left executing forever. A command whose time-to-live passed without a claim is expired, and the expiry is a row.

This is the difference between a trail that answers “what happened” and one that answers only “what succeeded”. The second kind produces the worst possible outcome of an investigation: a gap that everyone fills with their own theory.

The same discipline governs the reading surfaces on top of the trail. A state the system cannot verify is never rendered as a healthy one, which is the rule discussed at more length in what an agent control plane is.

Bind the approval to the action

An approval row that says “Dana approved” is nearly worthless, because it does not say what Dana approved.

Klingbar mints approvals through a passkey ceremony, and the resulting proof is bound to a hash of the command’s parameters and to one freshly-minted command identifier, single-use. What lands in the trail is therefore not “someone clicked yes” but “this identity approved this exact parameter set, once”. An approval of one bot’s offboarding cannot be replayed against another. An approval of a document edit cannot be spent after the document’s base version has moved, because the base digest is a parameter and therefore inside the fingerprint the approval covers.

That binding is what makes the trail useful in the argument that actually happens, which is never “did someone approve something” and always “did they approve this”. The full mechanism, and the three gate shapes it serves, are in human approval workflows.

Placement matters too: the identity that may approve is declared in an org chart written as code, so the trail’s approver field refers to something a reader can look up rather than to whoever happened to hold a session.

Two clocks

Every audit row in a distributed agent system has at least two timestamps: when the event occurred on the machine, and when the control plane learned about it. They can differ by minutes, and in the incidents worth reconstructing they will.

Record both. A trail with a single timestamp forces a later reader to guess which clock they are looking at, and the guess will be wrong exactly when the gap between the clocks is the story.

Keep less, on purpose

The instinct to record everything is the enemy of a trail anyone will keep for years.

Decision records are small, structurally uniform, and worth retaining for a long time. Content is neither. When a Klingbar command fetches a document body for a person to read, the fetched body is cleared from the queue an hour later; a later view of that command reads expired rather than showing content that has since changed. The decision to fetch it, who asked, and when, are permanent. The payload is not.

Applying one retention policy to both halves fails in both directions at once — deleting the decisions too early and keeping the payloads far too long. Splitting them is a modest amount of work and the difference between a trail you can defend and one your lawyers ask you to stop keeping.

The same reasoning bans values outright. Snapshots and audit rows in Klingbar carry handles and short references, and an entropy check on the ingest path treats a secret-shaped string as a defect rather than as data, because a credential that reaches a durable store has already failed — see sealing agent credentials.

Reading one after an incident

A good trail supports one specific motion: pick the surprising outcome, walk backwards, and stop at the first row where a human is named.

Start at the effect. Find the command that caused it. Read its parameters, which are recorded exactly as executed. Read the approval bound to those parameters, and the identity that minted it. Read the transitions between the approval and the effect, including the delays. If that walk produces a coherent story every time — including for the commands that failed, expired, or were vetoed at the machine — the trail is doing its job.

If any step requires correlating three systems by timestamp, it is not a trail yet. It is source material for one.

Frequently asked

What is an audit trail for AI agents?

It is an append-only record of every consequential action an agent system took and every human decision that authorised one. Each entry names who asked, the exact action and parameters, who approved it, what the machine did, and when. It is written as events occur, not reconstructed afterwards.

How is an audit trail different from application logs?

Logs are diagnostic output written for whoever is debugging, at a volume and format that changes with the code. An audit trail is a fixed set of events written for a reader who was not there, kept append-only, retained on purpose, and never edited to make a chart look better.

What should never be written into an audit trail?

Secrets, tokens, keys, and the plaintext bodies of documents an agent fetched. Record a handle, a hash, or a short reference instead. An audit trail is the longest-lived store in most systems, which makes it the worst possible place for a value that was supposed to be transient.

How long should agent audit records be kept?

Keep decision records as long as the decisions matter, which is usually years, and keep fetched content for minutes. Those are different retention questions with different answers, and a system that applies one policy to both either deletes evidence too early or stores payloads far too long.

Give your bots an organization

Klingbar is in early access. Join the waitlist and we'll reach out as capacity opens.

Join waitlist

Read the other guides