An audit trail your AI agent can't skip
Sooner or later, someone asks you to prove it. A security reviewer, an external auditor, a customer's procurement team, or your own CFO wants the record: every action your AI agent took in production last quarter, what it touched, and on whose authority. This is the moment a lot of teams discover that their "audit trail" is whatever their application code happened to write to a log — and that an agent with write access can do plenty their logs never mention.
There is a real difference between logging and an audit trail, and it matters more for agents than for anything we've deployed before. Logging is something your code does when it remembers to. An audit trail is a record the actor cannot avoid producing. Where that record gets made decides whether anyone should trust it.
Why "we log our agent" isn't an audit trail
Most homegrown agent logging shares the same weak spot: it's written by the same code path the agent is driving. If a path doesn't call the logger, there's no record of what happened on it. That gap opens quietly and often — a refactor that moves a write, a new tool nobody wrapped in tracing, an exception that skips the block where you log, or an agent that takes a route the developer never pictured. The actions that hurt most in an incident are usually the ones nobody thought to instrument.
Two more problems compound it. Application logs are typically mutable, so "we think it did X" is a story, not proof. And coverage is opt-in by design: you log the calls you decided were worth logging. An audit trail that only contains the events you anticipated is exactly no help when something you didn't anticipate goes wrong.
Regulators have started drawing this line explicitly. The EU AI Act's record-keeping rule for high-risk systems (Article 12) requires the automatic recording of events over a system's lifetime, kept for at least six months. Automatic is the operative word: not "documented when someone remembers," but generated by the system itself. "We'll add logging in the app" is precisely the posture that requirement is written against.
What an audit trail actually has to answer
A trail earns the name when a stranger can reconstruct what happened without taking your word for any of it. In practice that means five questions:
- What did the agent do? The concrete action, not a tidy summary of intent.
- What did it act on? The exact record, file, or endpoint — identifiable, not "a customer row."
- Under what authority? Which scoped credential and which policy allowed it, and whether a human approved the step.
- What did it cost? Tokens, tool calls, and wall-clock time, so spend and behavior sit in the same record.
- Can I trust the record? Is it tamper-evident, and was it produced independently of the agent's own code?
The last one is the question most setups quietly fail. If the agent's code writes the log, then the agent's code can be wrong about the log — and an audit trail you can't trust is just a longer story.
Move the record off the app and onto the substrate
Here is the part a standard stack doesn't give you by default. On WordPress with a logging middleware, or a serverless function shipping events to a log aggregator, the audit record lives in application code. Its completeness depends on a developer remembering to log every path and the agent staying on paths that log. Give that same setup an agent with production write access and you're trusting the least predictable actor in the system to stay inside the parts you instrumented.
OBTO puts the record one layer down. Every agent action runs through the platform's execution and write path, and that path emits the receipt — we call it the Glass Receipt — whether or not any application code asked for it. The record is a property of where the action executes, not of whether someone instrumented it. An agent can't take an unlogged action, because the logging isn't in the code the agent controls. A per-action receipt reads like this:
{
"action": "patch_page",
"actor": "agent:weekly-content",
"target": { "collection": "pltf_page", "name": "pricing" },
"authority": { "scope": "www:pltf_page:write", "human_approved": false },
"integrity": { "check": "anchor_match", "expected": "<h2>Team</h2>", "result": "verified" },
"change": { "lines": "142-142", "before_sha": "9c1e…", "after_sha": "4b7a…" },
"cost": { "tokens": 3120, "tool_ms": 240 },
"at": "2026-07-09T05:12:04Z"
}
The checks that gate the write are what the receipt proves
An agent writing directly to production — no git, no CI, no human in the deploy loop — sounds reckless until you look at what stands in for the human review step. On OBTO, a patch to a live page is refused if its anchor text doesn't match what's actually live. A new file is refused if its bytes don't hash to the sha256 that was promised. These are structural gates, not conventions: an edit that doesn't accurately describe the current reality simply doesn't apply.
The audit trail records the outcome of those gates. The receipt doesn't say "the agent claims it edited line 142." It says the platform verified the anchor, applied the change, and here are the before and after hashes. That's the difference between evidence and a diary: the record is produced by the thing that did the work and checked it, not by the thing that asked for it. It's the same argument we make about running agents you can see into rather than trust blindly — the theme behind why AI agents break in production and the runtime safety model in our AI helpdesk automation guide.
How to build one, even if you're not on OBTO
You can approximate this on any stack. If you're rolling your own, aim for five properties:
- Record at the boundary, not in the handler. Emit the audit event where the tool call actually executes or the write actually commits — the one place every path funnels through — not in each feature's code, where it's easy to forget.
- Make it non-optional. The action and its record should be the same transaction. If the record fails to write, the action fails too. An audit event you can skip on the unhappy path isn't one.
- Capture authority, not just action. Log which scoped credential and which policy permitted the step, and whether a human approved it. "Who allowed this" is the first question in every incident review.
- Make it tamper-evident. Append-only, hashed, or shipped to storage the app can't rewrite — so "we edited the log" is never on the table.
- Keep it queryable and retained. Six months is a floor for regulated systems. Make it searchable by agent, run, and resource, or nobody will open it when it counts.
None of this is exotic; it's mostly a decision about where the record lives. The reason it's the default on OBTO rather than a project is that we couldn't run our own agents responsibly without it — including the agent that writes and publishes this very blog each week. Cost tracking rides the same rails, which is why the receipt that proves what an agent did is the same one that shows what it cost, and why observability and auditability are two readings of one ledger, as covered in our agent observability guide.
Getting started
Instrumenting an audit trail retroactively is painful; getting it from day one is nearly free when the platform does it natively. OBTO's pricing is structured so the Glass Receipt is on by default, not a paid add-on you bolt in after your first audit request. If you want to watch per-action receipts land on a real workflow, the getting-started guide takes about ten minutes, and the free Builder tier includes Glass Box tracing.
Agents earn a place in production the way any system does: when what they do is visible, provable, and hard to fake. Build the record so it can't be skipped, and the harder conversations — with auditors, customers, and yourself — get a lot shorter.