The reason I know exactly what to log when an AI agent acts on your behalf is this. I once ran a job whose only record of having fired was an untracked file and a broken connection. Seventy minutes of unattended writing. A complete draft. And no evidence anywhere else that the run had ever started. If you'd asked me the next morning whether the agent had done what it was told to, I couldn't have answered honestly. The only artefact I could point to was the one produced by the agent itself. And the one produced by the agent itself is exactly the one you can't trust.
This post is the operating manual that came out of that morning. It isn't the compliance guide the platform vendors are writing. It's the honest small-shop version. The minimum log you need if you've decided to hand a machine the authority to write to your git repository, push to your live site, send an email under your name, or move money in your account. Everything below is from having run agents that do at least the first two of those things, on this website, unattended.
The morning that made me write logs
The first autonomous publishing run on this site was supposed to write three posts overnight and commit them. It died at seventy minutes. The connection that carried the agent's session to my machine dropped. The process on the far side terminated. And the local environment had exactly what a local environment has when a process dies. An untracked file, no commit, no log entry, no evidence that the job had ever started.
I found this out the next morning by looking at git status. There was a file. There was no cover for it. There were no internal links from any older post to it. There was no line in a run log saying "at 21:04 the agent picked topic X". Nothing except a Markdown file with a plausible slug and 3,141 words of prose that could have been written any time in the previous six hours.
The failure wasn't the connection. The failure was that the entire evidence chain for whether the agent had done its job lived inside the agent's own process. When that process died, so did the evidence. I could see that a thing had been written. I couldn't see why it had been written, when, what topic it had rejected on the way, or whether any of the three posts it was supposed to write had actually been attempted. I had to reconstruct all of that from the file itself. Which is the equivalent of asking a defendant to write their own witness statement.
The very next thing I did that day was change the procedure so the run log opened at the start of the run, not at the end. Every step in this post is a scar left by that morning.
Two categories: intent and effect
There are two kinds of thing you have to log when an agent acts on your behalf. Confusing them is where most audit trails go wrong.
Intent is what the agent chose to do. Which action it decided on. Why. What other actions it considered and rejected. And the field almost every vendor logging framework leaves out: what it explicitly refused to do.
Effect is what actually happened as a result. The commit sha. The API response. The file that landed on disk. The row that was inserted. The money that moved.
Intent without effect is a plan. Effect without intent is a mystery. You need both. And you need them cross-referenced by a stable identifier that survives whether the agent finished, crashed, got killed by the operator, or was rate-limited by an upstream API.
The distinction matters because one day, in the middle of the night, you'll get exactly one job that only produced half of these things. When that happens, you need to look at the log and answer, in under a minute, three questions. Did the agent get as far as deciding what to do but crash before doing it (safe, retry)? Did it decide what to do and do some of it (dangerous, investigate)? Or did it do the thing but never get to record that it had done it (worst, because the next run will probably do it again)?
The one artefact you cannot trust
The agent's own summary of its run is unreliable. For three reasons that stack.
First, the summary is written by the same actor whose behaviour it describes. This is a category of evidence a court would exclude. And there's no reason to hold your own audit trail to a lower standard than the one you'd demand of a witness in a room.
Second, the summary is written from inside the process it summarises. If the process died before the summary got written, there is no summary. If the process died after the summary got written but before the effect landed, the summary reports an effect that didn't happen. The only summary you can trust is one you would still have if the process were killed at any point in its execution. The summary written by the process itself isn't one of those.
Third, and this is the failure mode most people underestimate. The summary is optimised. The model has been trained to produce a coherent narrative of what it did. Which means it will fill in gaps to make the narrative hang together. It isn't deliberately lying. It's doing the thing it was trained to do, which is produce fluent explanation. If you rely on the agent's own after-action report as your evidence chain, you're relying on a fluent explanation. That's exactly the wrong thing to rely on when you need to know what really happened.
The rule that comes out of these three. Log the effects from outside the agent. Log the intents from inside the agent. Never let the agent be the only witness to its own actions.
The minimum log
The compliance guides are proposing thirteen-field logs with policy pointers, tenant IDs, GDPR retention markers, and a five-layer taxonomy. If you work at a bank, follow the compliance guides. If you're a founder who's given an agent access to your git repository and your Cloudflare account, you need something considerably shorter. Considerably more honest. And considerably more likely to actually get written every time. Here it is.
1. Run ID. A UUID or a timestamp-slug generated at the start of the run and written to disk before the agent does anything else. Every subsequent log line, every commit message the agent writes, every file it creates references this ID. If the process dies at second three, this file is your evidence that the run happened. If the process dies at second thirty and produces an orphan file with the run ID in its filename, you know at a glance which run to look at when reconstructing.
2. Started-at, ended-at, exit reason. Stored outside the agent's own process, in a file the wrapping script owns. The exit reason is the honest one. "Clean exit". "Operator killed". "Connection dropped". "Hit iteration cap". "Raised exception". "Completed successfully" isn't an exit reason. It's a summary, and it belongs elsewhere.
3. Inputs. The prompt the agent was given, the configuration file it read, the environment variables that were set. And critically, the versions of any tools or models it used. If the agent picks up a slightly different model tomorrow because you upgraded the endpoint, the log for today needs to say which model ran today. Because next week when you compare outputs you won't remember.
4. Intent-per-step. For each decision the agent makes, record the choice, the alternatives that were considered, and the reason the chosen one won. Pick a topic. Choose a category. Decide to refresh vs write new. Decide to commit. This is where the "the agent's own summary" concern applies most. Keep this log line short and factual, not narrative. "Chose X over Y because Y failed the four-part test" is auditable. "Considered several options and settled on X after careful thought" is prose.
5. Effects, from outside. Every write the agent commits gets recorded by the wrapping script or the platform, not by the agent itself. A git commit sha. An API call and its HTTP status. A file created on disk with its byte size. An email queued with its message ID. The record survives the agent dying. And it can't be embellished by the same process that produced it.
6. Declines. The single most useful field, and the one nobody writes. Every time the agent explicitly decided not to do something, log it, with the reason. Rejected a topic as failing a safety rule. Refused to publish a draft under the word-count floor. Backed off a commit because the build gate failed. When you audit an agent's behaviour six weeks later, the declines tell you as much about whether the safety constraints are working as the actions do.
7. Retries and failures inside the run. Not just the final exit. Every attempt that failed and was retried. A run that hit the API three times before succeeding is a different animal from a run that succeeded first go. If you never log the difference, you won't spot the day an upstream provider quietly starts failing.
Seven fields. Compliance vendors will tell you to log fifty. If you can write seven honestly, every time, the seven you write will be worth more than fifty that get logged once and skipped whenever the run is under time pressure.
Where to store it so it survives the run dying
The one lesson from the morning that started this post. The log has to live outside the process it describes. That means:
- The run ID gets written to disk in the first thirty seconds of the run, before the agent does any real work, in a file whose name contains the run ID.
- Every log line is flushed to disk as it's written, not buffered. Buffered logs are lost logs when the process dies.
- The exit is recorded by the wrapping script, not by the agent. If the agent is the one recording that it exited cleanly, the case where the agent lied about that is exactly the case you can't detect.
- Wherever practical, log to two places. A local file and something the operator can inspect from another device. On this site, that means a Markdown run log in the repo and, for the failures that matter, an issue in the repo's own issue tracker. If the machine that ran the job isn't reachable, the issue on GitHub is.
The two-places rule is the small-shop equivalent of what large systems call "log shipping" or "immutable audit sinks". You don't need Kafka. You need any two places that aren't both going to be down at the same time as the process that generated the log.
What "reconstruct why the agent did X" actually looks like
The test of whether your log is working isn't whether it has the right fields. It's whether, six weeks after a run, you can pick a specific action and answer the question: why did the agent do this? Without asking the agent.
Concretely, for this site. Pick any published post. Now, using only the log, answer four things. Which topic ID did it come from? Why was that topic chosen over the others in the same category on that day? Which alternatives were rejected during research? What commit sha carried the file to main? If any of these four can't be answered from the log without opening the post itself, the log is missing something.
For a customer-facing agent, the test is: pick any message the agent sent to a customer. Which conversation context produced it? Which policy check ran on it before it was sent? Which alternative responses were generated and rejected? Which message ID did the outgoing channel return? Same test, different verbs.
If you can't pass the test, add fields until you can. If you can pass the test easily, resist the temptation to add more fields "just in case". The fields you never use are the fields your successor won't write when the log system gets ported to a new stack in eighteen months.
Retention: shorter than you think, longer than you want
The compliance frameworks give retention numbers, and they're worth citing because they're the floor. SOC 2 evidence typically covers twelve months. The EU AI Act guidance for high-risk systems points to at least six months of decision logs unless another law extends the window. If you're anywhere near either regime, meet the floor.
Under the floor, be honest about what you're trying to answer. For a solo operator running agents against their own systems, the useful retention is "long enough that any pattern of behaviour that would concern you has had time to become visible". In my experience that's roughly one to three months of full logs plus a summarised long tail. Longer than that and the logs stop being read. Shorter and you can't see the drift.
Whatever you settle on, write it into the procedure. An unstated retention rule becomes "as long as the disk lasts" by default. And disks are neither compliant nor useful.
The specific traps that catch small teams
Six things that have caught me or someone I know running agent workflows on their own infrastructure. Fix them once and never think about them again.
Trap one: logging into the same file the agent is writing. The log line and the agent's output land in the same file. The log line is what gets truncated when the agent crashes mid-write. Separate the log file from the artefact file. Always.
Trap two: logging via the same network call that's failing. A remote logging endpoint is fine until the day the network is the thing that broke. At which point the log of the network failure is the log line that couldn't be written because the network was broken. Log to disk first, ship to remote later.
Trap three: logging only in the happy path. The try block logs "action succeeded". The except block logs nothing because the developer assumed the exception itself was the log. The exception isn't the log. The exception is the reason for the log line that also needs to say what the agent was trying to do when the exception fired.
Trap four: logging the agent's chain-of-thought verbatim. Model chain-of-thought can be enormous, unstable across model versions, and often contains material that shouldn't be persisted. Customer data quoted back to the model. Tokens. Error messages containing secrets. Log the intent as a short structured field. The decision, the alternatives, the reason. Not the whole reasoning trace.
Trap five: logging without a run ID that links intent to effect. If your intent log lives in one file and your effect log lives in another and they share no identifier, you have two logs, not one audit trail. Every log line, everywhere, carries the run ID.
Trap six: assuming the model's summary of the run is the log. It isn't. The model's summary is a piece of evidence produced by the actor being audited. It's useful. It's not sufficient. Read it and then read the log the wrapping script wrote. If the two disagree, believe the log.
The five-minute test for any agent you run today
If you already run agents on your own systems, do this. Pick a run from any time in the last week. Pick one action inside that run. One commit. One email. One API call. Now, without opening the agent's output, answer four questions from your logs.
- Which run did this action belong to?
- What was the agent trying to do at that moment?
- What did it consider doing instead, and why did it choose this?
- Did the action succeed, and what was the effect on the outside world?
If you can answer all four in under two minutes, you have a log. If you can't, you have hope. And hope doesn't stand up in a review.
Fix the missing field this week. Not next quarter. The next agent run is either going to prove the log works or expose that it doesn't. It's far cheaper to be the one who discovers the gap than the one whose customer discovered it first.
Where this fits with the rest of the work
The reason to log at all is that the space of failures an agent can produce is larger than the space of failures a human can. A human who forgets to send an email leaves an inbox. An agent that forgets to send an email leaves a log line that isn't written. Which is a different, and easier to miss, kind of evidence. The specific case where the workflow reports success and does nothing is covered in The automation failure nobody catches: the workflow that runs green and does nothing.
If your problem is upstream of "what do I log", you haven't yet decided which tasks to hand to an agent at all. Start with How to automate your work with AI, which frames the choice.
If your interest is broader, where the whole direction of unattended AI systems is heading, and what that means for jobs and organisations built around human sign-off, the further-out picture is in AI is heading toward autonomy: what dark factories tell us about what's next.
Logging is one half of running unattended agents. The other is deciding what they're allowed to touch at all. The audit trail lets you reconstruct why the agent did what it did. The permissions boundary is what limits what it could have done in the first place. The two are designed together. That decision framework, blast-radius classification, standing vs just-in-time tokens, and the three artefacts every Class 2+ permission needs, is in deciding what an AI agent is allowed to touch.
FAQ
How long should I keep agent logs before deleting them?
If you're under SOC 2 or the EU AI Act, meet the floor those regimes set. Twelve months for SOC 2 evidence and at least six months for high-risk system decision logs. For a solo operator running agents on their own systems, one to three months of full logs plus a summarised long tail is usually enough to see drift without the logs going unread.
What if the agent crashes before it writes any log at all?
That's the case the run ID is designed to catch. Write the run ID to disk in the first thirty seconds, before the agent does any real work. Even a three-second crash leaves an evidence file behind. If you can't see a run ID file, the wrapping script didn't start properly. Which is a different bug from an agent failure and worth fixing separately.
Should I log the model's full chain-of-thought or just the decision it made?
Just the decision, the alternatives it considered, and the reason. As a short structured field. Chain-of-thought traces are enormous, unstable across model versions, and often contain material that shouldn't be persisted. Storing them creates more risk than value for a small-team audit trail.
How many log fields do I actually need to start with?
Seven. Run ID, timestamps and exit reason, inputs, intent-per-step, effects captured from outside, declines, and retries. Compliance vendors will push fifty. Seven you write honestly every run is worth more than fifty that get skipped whenever a job is under time pressure.
What if I already run agents and have no logs at all, where do I start?
Add the run ID and the wrapping-script exit reason first. Those two survive the process dying and unlock everything else. Then run the five-minute test on a recent action and add whichever field you needed to answer the four questions but couldn't.
Should I use a remote logging service or just write to a local file?
Write to a local file first and ship to remote later. A remote-only setup fails exactly when you need it most. The day the network is the thing that broke is the day the log line about the network breaking can't be written.
What if the agent's summary and the wrapping-script log disagree?
Believe the log. The agent's summary is written by the actor being audited from inside the process being described. Any conflict with an outside-observed log is resolved in favour of the outside observer. Same standard you'd apply to any other witness.
The one-sentence version
Log intent from inside the agent, log effect from outside the agent, cross-reference both by a run ID that survives the process dying, and treat the agent's own summary of its run as evidence to be checked against the log rather than as the log itself. Everything else is variation on those four rules. The day you skip any of the four is the day you find out which one you skipped.
Top comments (0)