An agent that can write its own audit row can write a plausible one. Four properties keep the trail out of reach: the row is written on the far side of the tool boundary, storage is append-only, the actor is a reference, and recording never fails the operation.
An audit trail is evidence only when the thing being audited cannot author its own entry. For an AI agent driving a marketing stack, that means the agent's tool surface offers no way to write a row, no way to edit one, and no way to read the trail back. The rows are written by the services on the far side of the tool boundary, as a side effect of the operation they describe. In this product's MCP server, no registered tool takes an audit entry as an argument and no tool returns the trail.
124 toolsTools registered on this product's MCP server. None of them writes or reads an audit row.
Why does it matter who writes the row?
An audit row is worth reading because it was produced by a different party than the actor it describes. If the agent supplies the action name, the resource and the result, the record says whatever the agent decided the record should say, and a plausible one is as easy to produce as a true one. Moving the write behind the tool boundary means the caller supplies the request and the service supplies the record of it: who, when, which app, what was touched, and whether it succeeded.
Reading is a separate question from writing, and it has a separate answer. The audit trail's readers are people investigating an incident, and its shape is a decision about retention and evidence rather than a feature an assistant needs mid-task. Leaving it out of the tool surface entirely costs the agent nothing it uses and removes a whole class of behaviour — an agent that tidies its own history as part of finishing a job — without needing a rule against it.
Which four properties put the log out of reach?
The row is written on the far side of the boundary. A tool calls a service, and the service records the entry. The caller never names the action, the result or the actor, because it never touches the record at all.
Storage is append-only. The collection carries a creation timestamp and deliberately no update timestamp, so there is no supported path that rewrites a row after it lands.
The actor is stored as a nullable reference. A user id or an API key id, either of which may later be deleted, and the row survives that deletion. A trail that disappears with its actor is a trail an actor can clear by removing itself.
Recording never fails the operation. An audit write that throws is logged and swallowed, because a failing trail must not break the business operation it describes. The exception is deliberate: an entry that must share the fate of a database transaction is written inside it, so no row survives describing a change that was rolled back.
The server is the same in both. What differs is which layers the client implements: how it connects, how it discovers the authorisation server, which of the three capabilities it lists, and whether it reads the hints on each tool.
Write once. Ship it everywhere.
Market4 turns one release note into a changelog page, a blog post, a mail-out and a week of social posts — and then tells you which of them brought anyone back.
No card to start. Cancel from the settings screen, not from an email.
What does each property actually prevent?
Each property answers one specific way a log stops being evidence.
Property
What it prevents
The service writes the row, not the caller
An actor composing its own account of what it did
Append-only storage, creation timestamp only
A record edited afterwards to match a better story
Actor held as a nullable reference
A trail that vanishes when the user or the key is deleted
No tool reads or writes the trail
An agent tidying its own history as part of a task
Recording is best-effort and never fatal
An audit outage turning into a product outage
A fixed retention window
A trail quietly pruned to whatever somebody found convenient
How long should the trail live?
Retention for an audit trail is a compliance-shaped decision rather than a disk-space one, which makes it different from every other retention window in a product. Incident investigations routinely reach back months, the documents are small, and the cost of keeping them is far lower than the cost of discovering the window closed the week before the question arrived. This product keeps a full year by default and reads the window from an environment variable, so an operator who needs longer changes one setting rather than a schema.
365 daysDefault retention for the audit trail, set by an environment variable.
What does one row have to carry?
A useful audit row names the organisation, the app, the actor, where the request came from, a dotted action name such as app.create or approval.approve, the resource type and its identifier, the result, and a free-form metadata field. Two details in that list are easy to get wrong. The resource identifier is stored as a plain string rather than a database id, because the trail also records things with no document of their own — a slug, a provider-side identifier. And the metadata field must never carry a secret, because it is the field everybody reaches for when they want more context and nobody re-reads a year later.
What an audit trail does not give you
An audit trail is not a control. It records what happened; it stops nothing. If the honest answer to "could the agent do this?" is "yes, and we would see it afterwards", then the thing you wanted was an approval step or a spend cap, and a log is a consolation prize. Decide which actions need a gate in front of them first, and treat the trail as the record of everything that passed the gate rather than as the gate.
Should an AI agent be able to read its own audit log?
It rarely needs to. The trail's readers are people investigating something after the fact, and an agent that wants to know what it did already has its own transcript of the session. Leaving the trail out of the tool surface removes a category of behaviour without needing a policy about it, and it keeps the retention and evidence decisions with the people who are accountable for them.
Does append-only mean rows are never deleted?
No, it means no row is ever rewritten and no request names a row for removal. Rows leave by age, when the retention window expires and the storage engine removes everything past it. That is deletion by policy applied uniformly, which is a different thing from an actor removing a specific record, and it is the difference that matters when someone asks whether the trail can be edited.
What belongs in the metadata field of an audit row?
Enough context to reconstruct the decision, and nothing that would be a problem to find in a year-old record. Identifiers, counts, the settings that were in force, the reason a guardrail refused. Never a token, an API key, a password or a customer's raw text. The metadata field is where secrets end up when nobody wrote down that they must not, so write it down.
What should happen when the audit write itself fails?
Log it and carry on. An audit write that can fail a publish, a payment or a deletion hands a logging outage the power to take the product down, and the operation it was describing has already happened by then anyway. The exception is an entry that must share the fate of a transaction: write that one inside the transaction, so a rolled-back change leaves no row claiming it succeeded.
Both can hand a model a block of JSON, so the choice looks cosmetic. It is not. A tool call is a decision the model makes with arguments it invents; a resource read is a fetch the client performs against an address it already holds.