Article 12 of the EU AI Act is short, and most of the engineering work sits in the gaps between its sentences. This post reads it the way a team has to: as a specification for a logging subsystem, with a build-or-buy decision at the end. It is engineering analysis, not legal advice; whether your system is high-risk, and what your obligations are, is a question for counsel.
What the text requires#
Article 12 of Regulation (EU) 2024/1689 applies to high-risk AI systems. It says three things that matter to an engineer:
- The system must technically allow for the automatic recording of events (logs) over its lifetime. Automatic means the logging is part of the system, not something an operator remembers to do.
- The logging capability must enable traceability appropriate to the system's purpose. Specifically, it must record events relevant to identifying situations that may result in risk or a substantial modification, to facilitating post-market monitoring, and to monitoring the system's operation by the deployer.
- For some categories, such as remote biometric identification, the article lists minimum fields. We do not cover those here.
Retention is in two other places. Article 19 says providers keep the automatically generated logs, to the extent they are under their control, for a period appropriate to the intended purpose and at least six months, unless other Union or national law, data protection law in particular, says otherwise. Article 26(6) puts the same six-month floor on deployers for logs under their control.
Application dates, and the "digital omnibus" proposals that would move some high-risk deadlines, were still changing as of October 2026. Check the current status before you plan a schedule around any date; we are not asserting one.
The article names no format, schema, signature scheme or storage medium. Your conformity assessment, not this post, decides what "appropriate to the intended purpose" means for your system.
What "automatic recording" means for an agent#
For a classifier behind an API, an event is a request and a response. For an agentic system, one user-visible outcome is a tree: several model calls, tool calls chosen by the model, retries, and sometimes a human approval in the middle. The unit of traceability is therefore the run, and the log has to let you reconstruct it.
Three consequences follow.
Log at the boundary, not in the prompt. Recording happens in code that wraps the model client and the tool dispatcher. If the model is asked to "log what you did", you have a log of what the model said it did.
Fail loudly. A system that continues to act when the logger is down has a gap you will not see later. Decide, per action class, whether a failed write blocks the action. For anything with side effects in the world, we would block.
Log refusals and errors too. The call a guardrail blocked and the timeout that triggered a retry are events relevant to risk. A log of only successes describes a system that does not exist.
What to log per call#
The article does not give a schema, so this one is ours. It is a starting point to argue with, not a compliance checklist.
| Field | LLM call | Tool call |
|---|---|---|
runId, seq | yes | yes |
parentSeq (which step caused this) | yes | yes |
at (your clock, UTC) | yes | yes |
actor (agent id and version) | yes | yes |
| Model identifier and provider | yes | no |
| System prompt / policy version | yes | yes |
inputSha256, outputSha256 | prompt, completion | request body, response body |
| Token counts, latency | yes | latency only |
| Destination, method, status | no | yes |
| Declared purpose | optional | yes |
Outcome (ok, error, blocked, timeout) | yes | yes |
| Human involvement (who approved, when) | if any | if any |
Two fields deserve a comment. parentSeq is what turns a flat list into a trace: without it you can see that a refund was issued and that a model call happened, but not that one caused the other. The policy or prompt version is what lets you answer, months later, which rules the system was operating under when it made a decision; a hash of the exact system prompt is better than a name.
As JSON, one tool-call event looks like this:
{
"runId": "run_01JBX",
"seq": 7,
"parentSeq": 6,
"at": "2026-10-24T09:15:02.481Z",
"actor": "claims-triage-agent@4.2.0",
"kind": "tool.call",
"policySha256": "3b1c…",
"destination": "https://payments.example.com/v1/refunds",
"method": "POST",
"requestSha256": "9f2a…",
"responseSha256": "c07e…",
"status": 201,
"durationMs": 412,
"purpose": "refund under refund-policy-v7",
"outcome": "ok"
}Note what is absent: the request body, the response body and any personal data. That is deliberate, and the next sections explain why.
Why self-written logs are weak evidence#
A log written by the party that runs the system is evidence of what that party now says happened. Anyone with write access to the log store can edit a row, delete one or backdate one, and an ordinary database shows no sign of it. That includes you, and an auditor or a counterparty in a dispute has no way to tell which of you did it.
For agents the disputes are about actions: who authorized this refund, which prompt led to this email. The question is not "do you have logs" but "why should I believe them".
What tamper-evident means technically#
"Tamper-evident" is used loosely. It breaks into four properties, and each closes a different attack.
Signed. Each record carries a signature by a key the log writer cannot use to rewrite history afterwards. This stops editing a record in place. It does not stop deleting one.
Hash-chained. Each record includes the hash of the previous record. Editing, removing or reordering a record in the middle breaks every record after it. It does not stop truncating the tail, because a shorter chain still verifies. You close that by publishing or signing the chain head periodically and noting the expected count.
Externally timestamped. A time that comes from the log writer's own clock proves nothing about when. A timestamp from a party you do not control, covering the chain head, bounds how far back the log can have been rewritten. An RFC 3161 time-stamp authority is the classical way to get this.
Independently held. The signed material, or at least its head, sits somewhere the system operator cannot alter. If the only copy is in the same account as the system, then an administrator of that account can replace everything.
None of this proves completeness. A code path that never calls the logger leaves no trace, and no cryptography changes that. Completeness comes from the architecture: one choke point through which every model and tool call must pass, and an expected-event count you can compare with.
Retention versus erasure#
Article 19 and Article 26(6) set a floor of six months. The GDPR says you may not keep personal data longer than you need it. Both can be true at once if you design for it.
The approach that works in practice is to separate integrity evidence from content:
- The tamper-evident record holds hashes and non-personal metadata. A SHA-256 of a prompt identifies the exact bytes without revealing them.
- The content lives in a store you control, addressed by hash, with its own retention and deletion rules.
- When a data subject's content is erased, the hash stays in the record. The record still proves that an event of that shape occurred; it can no longer be used to reproduce the text.
There is a caveat, and it is easy to miss. A hash of low-entropy input, such as a short answer, a name or a date of birth, can be brute-forced by anyone who can guess candidates. Salt such values per subject, or avoid hashing them at all. Also, free-text metadata fields such as labels and purposes are not hashed, and if you write a person's name into one, it is now in an append-only record. Keep identifiers out of them. We wrote about this design more fully in Why we sign hashes, not your data.
Whether a given hash is personal data is a legal question. The engineering point is that you should not have to choose between a log you can show and a deletion you can perform.
Where signed receipts fit#
Trustvice receipts are Ed25519 signatures over RFC 8785 canonical JSON that anyone can verify offline against Trustvice's published public keys, at /verify or in their own code. In Trustvice 360, TrustActor checks agent runs against declared rules and keeps a per-workspace hash chain with replay and diff, and snapshots of the audit chain are signed with Ed25519 and anchored so they can be verified publicly. The receipt format is described in Inside the receipt format.
Against the four properties above:
- Signed: yes, with a key your own operators cannot use.
- Hash-chained: TrustActor keeps a per-workspace hash chain over agent runs. For logs you write yourself, you build the chain.
- Externally timestamped: partly.
issuedAtis set by Trustvice when it signs, not by you, which is a different clock from yours. A single receipt is not an RFC 3161 token; the transparency chain's hourly seal is anchored with OpenTimestamps. If you need a qualified timestamp, add one. - Independently held: the receipt is verifiable by anyone who holds a copy, but retention on our side follows your plan and is not a substitute for your own archive. Export what you need to keep.
What receipts do not do#
This is the part to take to your assessor.
They prove an event was recorded as stated, not that the system complied. A receipt says these facts were presented to, or observed by, Trustvice by issuedAt. It says nothing about whether the model's output was correct, whether the decision was lawful or whether your risk management worked.
They do not prove completeness. A missing receipt is invisible. Only your architecture and an expected-event count can show that nothing was left out.
For model calls, they do not prove the model said it. A receipt over hashes you report proves that you reported them. The provider is not a party.
They do not satisfy Article 12 by themselves. Article 12 is a property of the high-risk system: the capability to log, over its lifetime, with the traceability its purpose requires. Receipts are one way to make the resulting records hard to dispute. The capture code, the schema, the retention policy and the review process remain yours.
The practical takeaway#
Treat Article 12 as three separate problems and do not buy one tool for all of them. First, capture: a single choke point that records every model and tool call, including refusals, with a run id and a parent link, and that blocks side effects when it cannot write. Second, retention: hashes and metadata in the evidence record, content in a store you can erase from, and a retention period that is at least the legal floor and no longer than you can justify. Third, dispute resistance: signatures, a chain and a clock you do not control, so that the record holds up against someone who has reason to doubt you.
The third is the only part you should not write yourself. The first two you cannot buy.
To see how Trustvice 360 covers agent runs, start with TrustActor and its documentation.