Agent tracing is recording an agent run as a structured sequence of steps, typically nested spans covering model calls, tool calls and their timing. A trace shows the path an agent took through a task.
An agent’s work on a single task rarely happens in one place. The harness calls a model provider, dispatches tools to local processes and remote servers, hands part of the task to a subagent, waits for a person to approve something, and leaves follow-up work in a queue. Each of those participants keeps its own clock and its own records. Afterward, someone has to reconstruct what the run actually did. Tracing is how that reconstruction is done: it ties the separate operations together so they can be read as one execution. How reliable the result is, as an account of the agent’s work, depends on five things: what was instrumented, whether context propagated across every boundary, what was sampled, what was captured, and whether the work stayed continuous or was broken up in time.
The entry on agent observability covers what traces are used for. This entry covers how the reconstruction works and where it can fall short.
Spans: the unit of reconstruction
A trace is a tree of spans that share one trace identifier. Each span represents one operation with a start and an end, and records:
- Its identity and its parent. A span with no parent is the root, usually the whole agent invocation. Every other span names the span it ran inside.
- Timing. When it started and how long it took.
- Attributes. Key-value facts about the operation: the model, the tool name, token counts, and, where capture is enabled, inputs and outputs.
- Events. Timestamped points inside the span, such as a retry or an exception.
- Links. Optional references to spans in other traces, used when related work is not a direct child, such as a job queued by the run.
- Status. In OpenTelemetry, one of three values. Unset, the default, means the operation completed without an error being recorded. Error means an error was recorded. Ok is an explicit mark set by a developer. None of them describes an effect on another system.
For an agent, the tree mirrors the agent loop: the invocation at the root, model calls beneath it, the tool calls the model requested beside or beneath those, and subagents as nested invocations with their own children.
The names for these operations are still settling. OpenTelemetry’s semantic conventions for generative AI, marked as in development, define operations for creating and invoking an agent, invoking a workflow, planning, calling a model and executing a tool. Frameworks ship their own vocabularies: the OpenAI Agents SDK creates spans for agent runs, model generations, function tool calls, guardrails and handoffs, and Claude Code’s documentation describes spans linking each prompt to the API requests and tool executions it triggers, as a beta feature that is off by default. Two tracing systems may describe the same run with different names and different nesting, so comparing traces across frameworks takes some mapping.
Context propagation: what holds the reconstruction together
Spans only form one trace if each participant knows which trace it belongs to. The caller passes the trace identifier and its own span identifier to the callee, which starts a child span under that parent. The widely used format is W3C Trace Context, a W3C Recommendation, carried in a traceparent value. Protocols have made room for it: the Model Context Protocol, in its 2026-07-28 revision, reserves traceparent, tracestate and baggage in a request’s metadata, so a tool server that participates can place its spans under the client’s.
Propagation breaks in predictable places:
- A participant that does not propagate. A tool server, a model gateway or a subagent that ignores the incoming context starts its own trace or none.
- Work that runs later. A queued job that starts after the run has finished is usually recorded as a separate trace. A link can connect the two, if someone adds one.
- Separate processes without the context. Instrumentation that runs as a fresh process per event, without being handed the trace context, cannot attach to the trace.
- Human pauses. An approval that takes an hour splits naturally into separate traces unless the context is stored and restored.
What makes these breaks consequential is that they often do not show. A participant that fails to propagate does not attach a broken branch to the caller’s tree; it starts a new trace of its own, or records nothing, so the caller’s tree keeps no dangling reference and no error. (A tree can still contain an orphaned span, one whose parent is missing because it was sampled out or lost in collection, and an orphan does at least signal a gap. A participant that never joined leaves no such signal.) The root span’s duration covers only the time until the root operation ended. It says nothing about asynchronous work the run started that continues after that point. A well-formed span tree can be an incomplete representation of the task, and nothing in the tree says so. The clues are indirect: time inside a span that no child accounts for, a remote call with no server span beneath it, a result that implies work the trace never shows. In a multi-agent system, where work passes between agents built by different teams, a broken hop is the ordinary case unless it is designed against.
Five conditions on the account
| Condition | What it decides | What a gap looks like |
|---|---|---|
| Instrumentation | Which operations produce spans at all | Nothing: an uninstrumented operation leaves no trace |
| Propagation | Whether spans from different participants join one trace | Work recorded in a separate, unconnected trace, or not recorded |
| Sampling | Whether a given run’s trace is kept | The run is missing from the store, or kept only if it matched a rule |
| Capture | Whether inputs, outputs and arguments are recorded | A span that says a call happened but not what it carried |
| Continuity | Whether work separated in time stays connected | Follow-up work in a later trace, linked only if someone added a link |
Sampling. High-volume systems rarely keep every trace. Head sampling decides at the start of a trace; tail sampling decides after the spans are complete, which allows rules such as keeping every trace that contains an error. OpenTelemetry’s guidance is that a sample should be representative, and it notes that circumstances such as regulation can rule out dropping data. A sampled store is a statistical view of behavior, not an account of every run.
Capture. Defaults vary. OpenTelemetry’s generative AI conventions make message content opt-in and warn that it is likely to contain sensitive information. The OpenAI Agents SDK records model and function inputs and outputs by default, with a setting to leave them out. Claude Code’s traces redact prompts and tool content by default, with settings to include them. Content makes a trace far more useful for reconstruction and far more sensitive to keep.
An example: a complete-looking trace
The following is illustrative. It was written for this entry, uses OpenTelemetry’s generative AI operation names, and does not record a real run; identifiers and timings are invented.
A research agent is asked to summarize recent incidents for a service and file a ticket for the on-call engineer. Its harness is instrumented and propagates context. It delegates the search to a subagent. The ticketing tool is an MCP server that participates in tracing. The runbook tool is an MCP server that does not. Creating a ticket queues a job that pages the on-call engineer.
This is the trace the harness produced:
trace 4bf92f35 invoke_agent research-agent 48.2s Unset
├─ plan 2.1s Unset
│ └─ chat model 2.0s Unset
├─ invoke_agent search-subagent 31.5s Unset
│ ├─ chat model 1.8s Unset
│ ├─ execute_tool web_search 6.4s Unset
│ ├─ execute_tool web_search 0.3s Error (rate limited)
│ ├─ execute_tool web_search 5.9s Unset
│ └─ chat model 3.2s Unset
├─ execute_tool runbook.get_page 0.8s Unset
├─ chat model 4.1s Unset
├─ execute_tool tickets.update_ticket 0.9s Unset
│ └─ (server) tools/call update_ticket 0.8s Unset
└─ execute_tool tickets.create_ticket 1.2s Unset
└─ (server) tools/call create_ticket 1.1s Unset
Read on its own, it looks complete. Every span has its parent, the one recorded error was followed by a retry that recorded none, and the root ended with no error recorded. The create_ticket call completed without a recorded error on the client or the server; the trace does not show that a ticket now exists with the intended content, or that the task as a whole succeeded. Two other traces exist, and nothing in this one points to either:
trace 91c3a6b2 (runbook server) tools/call get_page 0.7s Unset
└─ query runbook_store 0.5s Unset
trace 7d1e04aa notify-oncall (queued job, started 3 min after the run ended)
└─ page provider request 0.4s Error (rejected: no escalation policy)
The first is the runbook server’s work, in its own trace because it did not propagate. In the harness’s trace it appears only as a client span with nothing beneath it, which is also what a purely local tool call looks like. The second is the asynchronous continuation of the task, and it failed. It started after the root span had ended, so no part of the root’s 48.2 seconds covers it, and because nobody added a span link from the ticket call to the queued job, the harness’s trace records no error while the engineer the ticket was meant for was never paged.
The harness’s trace is accurate. It is not complete execution evidence. Getting from one to the other took knowledge the trace did not carry: which servers propagate, which calls queue work, and where to look for the rest.
What a trace establishes, and where it stops
Within what was instrumented, propagated, sampled and captured, a trace is strong evidence of the path: what ran, in what order, nested inside what, for how long, and where errors were recorded. It is weaker evidence in four ways.
- Nesting is not reasoning. A span being a child of another says it ran inside it, not why the agent chose it.
- Status is not an effect. A tool span with status Unset means the call completed without an error being recorded. It does not independently confirm that the intended effect occurred: whether the ticket exists with the right content, or the page reached anyone, is known to those systems. A trace can carry evidence of effects when the systems acted on are separately instrumented, for example a span or event recording that a write was committed, but that evidence comes from the target’s instrumentation, not from the tool call’s status.
- Absence is not evidence of absence. A missing span can mean the operation did not happen, or that it happened somewhere uninstrumented, in a trace sampled out, or in a trace that lost its context.
- Accurate is not appropriate. A trace records the path. Whether each step belonged to the task is a separate question.
The example shows the last point concretely. The trace records tickets.update_ticket exactly: when it ran, inside which invocation, that the server received it, that no error was recorded, and, with capture on, that it raised the priority of an existing ticket owned by another team. Every one of those facts is correct. None of them says whether reprioritizing someone else’s ticket was part of “summarize recent incidents and file a ticket”. Answering that needs a reference the trace does not normally carry: the objective the agent was given, the scope of systems the task was meant to touch, and the applicable policy. Even with that reference, a structural comparison would find both ticket calls within a scope that includes the ticketing system; distinguishing filing a ticket from reprioritizing another team’s takes a judgment about the objective.
Tracing and governance
That question belongs to governance. A trace answers “what path did this run take?”. Governance evidence answers “how did each step compare with what was declared, under which policy, and where does certainty end?”. The two are complementary: a trace can carry governance information as span attributes, and a governance record can be correlated with a trace when both record a shared identifier for the same action.
Sentience Governor is one implementation on the governance side, and it is not a tracer. The Sentience Agent Execution Record its current implementation writes is an ordered sequence of events for one session, with sequence numbers, predecessor links and timestamps: it has no parent and child spans, no durations, and no OpenTelemetry output. What it adds is a reference, a declared intent and scope, and an evaluation of each attempted action against it at the execution boundary. Its evaluation is structural. In the example it would compare each ticket call’s target system with the declared scope, and it would not, by itself, tell filing from reprioritizing. In the Claude Code integration, each action event carries the identifier Claude Code assigns to the tool call, a natural join point with other telemetry that records the same identifier.
Often confused with
Logging. A log is a record of discrete events. A span looks much like a structured log entry, and OpenTelemetry’s documentation says as much, but it adds what makes reconstruction possible: a start and an end, a parent, and a shared trace identifier.
Agent observability. The broader capability of understanding agent execution. Tracing is one of the mechanisms that serves it, alongside metrics and logs.
Agent monitoring. Watching live behavior against thresholds and alerting. Monitoring often reads from traces; tracing records whether or not anyone is watching.
An audit trail. An AI audit trail is kept to account for actions later, usually completely and often in a tamper-evident store. Traces are usually sampled, may be truncated, and are kept for engineering, not accountability. A trace can feed an audit trail; it is rarely one by itself.
A governance record. Organized around a declared reference and findings; a trace is organized around the path and its timing.
Where the concept stops
Agent tracing reconstructs how a run unfolded across the operations and boundaries it can see. Within what is instrumented, propagated, sampled and captured, and while the work stays connected, it is a detailed account of the path and its timing. Outside those conditions it goes quiet without saying so, and a trace that looks complete can leave out part of the task. A tool-call span does not by itself confirm an effect, since it ends when the call returns; evidence of effects appears only where the systems acted on are instrumented to record it. And a trace does not judge whether a step belonged to the task, which takes a statement of what the task was.