An audit log should preserve boundaries, not manufacture a transcript.
Agent systems often mix the human request, model output, authority checks, tool execution, and final summary into one timeline. Those records have different evidentiary strength. A model requesting a tool is not the same as the tool executing; an allowed action is not proof that it occurred; and a successful API response is not proof that the intended real-world outcome followed.
Record each boundary crossing as its own event. Link related events with trace and call identifiers. Preserve missing links and unverified outcomes as explicit unknowns.
The minimal event envelope.
Start with fields that let a reviewer answer who or what acted, under which authority, against which target, with what recorded result, and what still needs verification.
{
"event_id": "evt_01J...",
"occurred_at": "2026-08-30T00:14:07.412Z",
"event_type": "tool.execution.completed",
"actor": { "type": "agent", "id": "support-agent", "version": "2.4.1" },
"operation": "update_ticket",
"target": { "system": "helpdesk", "type": "ticket", "id": "redacted" },
"authority": { "decision": "allow", "policy_ref": "pol_support_write_v3" },
"outcome": { "status": "success", "effect": "update accepted" },
"correlation": {
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
"span_id": "00f067aa0ba902b7",
"tool_call_id": "call_7f2"
},
"source_ref": "protected://agent-ledger/evt_01J...",
"evidence": "observed",
"unknowns": ["final ticket state not independently read back"],
"next_human_decision": "verify ticket state before closing the incident"
}
The envelope is a review projection, not a demand to replace native logs. Keep the protected source record available under your normal access controls.
What each field is for.
- event identity and time: a unique event ID and UTC timestamp, with clock precision and ordering limitations documented;
- event type: a stable verb such as
agent.invoked,authority.decided,tool.execution.started,tool.execution.completed, oroutcome.verified; - actor: the agent, workflow, service, or human identity that initiated the recorded event—not an inferred owner;
- operation and target: a bounded action name and the least-sensitive target identity needed for review;
- authority: allow, deny, require approval, or unknown, with a policy or approval reference where one exists;
- outcome: success, failure, denial, timeout, partial, or unknown, plus a short effect that does not copy raw content;
- correlation: trace, span, workflow, tool-call, request, or receipt identifiers that support the join;
- evidence class: observed, governed, prevented, reported, inferred, or unknown;
- unknowns and next decision: the missing proof and the person-owned decision that remains.
Record a sequence, not a success flag.
- Intent. Record the human request or workflow objective by reference. If only the agent summary is available, label it reported.
- Authority. Record policy evaluation and approval separately. A denied action should remain visible even when no tool call follows.
- Execution. Pair each tool call with its result using a stable call ID. Preserve orphan calls, retries, and missing results.
- Effect. Record the downstream system response or changed target separately from the tool invocation.
- Verification. Record an independent read-back, test, receipt check, or human review. If none exists, state that explicitly.
Use trace context for correlation, not as proof of completeness.
W3C Trace Context standardises traceparent so a request can carry a trace ID, parent ID, and trace flags across service boundaries. OpenTelemetry semantic conventions add common meaning to operations and attributes, including GenAI operations such as invoke_agent and execute_tool.
A matching trace ID supports correlation. It does not prove every participating system sampled or retained every event. Preserve sampling, retention, clock, and instrumentation gaps as limitations.
Keep high-risk content out of the default projection.
OpenTelemetry warns that GenAI messages, tool arguments, and tool results may contain sensitive information. NIST audit guidance also recognises that audit trails can reveal personally identifiable information and that event-selection criteria should be coordinated with the organisations that need the evidence.
- do not record access tokens, secrets, cookies, raw credentials, or private reasoning;
- omit prompts, arguments, and results by default; retain a bounded operation, target, and outcome;
- prefer workload IDs or pseudonymous user IDs over names and email addresses;
- keep source references access-controlled and define retention separately from the review projection;
- version the schema and document unknown event types instead of silently dropping them.
A reviewable event fails loud.
- Can every tool result be paired with a call?
- Can every authority decision be distinguished from execution?
- Are downstream effects separate from agent-reported success?
- Are unrecognised event types counted and surfaced?
- Does the record end with an explicit human decision or verification gap?
If any answer is no, the handback should say review needed. Do not convert missing evidence into a clean status.
Official references.
- OpenTelemetry GenAI attributes and sensitive-content warnings
- OpenTelemetry trace semantic conventions
- W3C Trace Context Recommendation
- NIST SP 800-53 Rev. 5 audit and accountability controls
AI agent audit-log schema FAQ
What is the minimum useful AI agent audit record?
Record event identity and time, actor, operation, target, authority, outcome, correlation IDs, source reference, evidence class, unknowns, and the next human decision.
Should I store full prompts and tool results?
Not by default. They can carry secrets and personal information. Store a minimal review projection and retain protected native records only where authorised.
Does trace context make the audit trail complete?
No. It supports correlation across instrumented systems. Sampling, retention, clock, and instrumentation gaps can still leave evidence missing.
Can Traceplain collect these events?
No. Traceplain is a downstream browser-local reviewer and runner-local GitHub Action. It does not operate as a trace collector or audit-log store.