How to prove what your AI agent did: a tamper-evident audit log
· By the Shotoku team
Short answer: record every decision in an append-only log where each entry includes the hash of the one before it, then sign a snapshot of the log and keep it somewhere else. The hash chain shows that a past record was changed. The signed snapshot catches what a chain misses, such as deleted entries at the end.
Why isn’t a normal log enough?
A plain log file can be edited, and nothing shows it was. That matters when you need to answer questions after the fact: what did the agent try to do, who approved it, and which rules applied at the time? If a record can change without trace, you are trusting the file, not checking it.
What should an agent audit log record?
| Field | Why it matters |
|---|---|
| Who | Which agent made the request |
| What | The action, the resource and the amount |
| Decision | Approved, denied or pending |
| Reasons | Which rule or limit produced that result |
| Human answer | The approval or denial, as a new entry that leaves the original untouched |
| Refused attempts | Denied requests often tell you more than approved ones |
What gets caught? We tried to tamper with one
We recorded three decisions with the current npm release, signed a snapshot, then changed the files:
| Change | shotoku history | shotoku snapshot verify |
|---|---|---|
| None | Works | Verified |
| Edited the amount in record 2 | Error: ledger corrupt at line 2 | Failed: ledger corrupt at line 2 |
| Deleted the last record | Not noticed | Failed: head hash and record count don't match |
| Raised a limit in the policy | Not checked | Failed: policy hash doesn't match |
The deleted record is the one to remember. A hash chain links each record to the one before it, so nothing after the last record can vouch for it. Removing entries from the end leaves a valid, shorter chain. You need a signed record of how long the log was.
How do you set this up?
Every decision Shotoku makes already goes into a hash-chained JSONL file, one record per line, that you can read in any editor. To add snapshots, set a secret and create one:
Check the current files against it later:
Take snapshots on a schedule, such as daily, and keep them with the secret away from the machine the agent runs on. Anything recorded after your last snapshot isn’t covered yet.
What doesn’t a tamper-evident log prove?
- It is evidence, not prevention. It doesn’t stop someone editing a file. It shows that they did.
- The chain alone can be rebuilt. Someone with file access could recompute every hash. That’s why the signed snapshot, and keeping its secret elsewhere, matter.
- It records decisions, not outcomes. An approved entry shows the action was allowed, not that the payment or call then succeeded.
- It only covers what passes through it. Calls that skip the check leave no entry.
- It isn’t a compliance certification. It can support an audit, but you still need to confirm what your own requirements ask for.
Common questions
Do I need a blockchain for this?
No. A hash chain borrows one idea from them, and a local file plus a signed snapshot stored elsewhere covers the cases above.
Where is the log stored?
On your machine, by default in data/decisions.jsonl. Run shotoku where to see which files a directory uses.
Can I read it without Shotoku?
Yes. It is plain JSON, one object per line, so standard tools can read it. Use shotoku history for filters and integrity checks.
More in the snapshots guide.