TL;DR
A span is one unit of work in a trace — it carries a kind (model call, tool call, retrieval, run wrapper), a duration (start to end), a parent (what it ran inside), and attributes (model, tokens, inputs, outputs). Understanding one span is how you read the whole tree.
What's inside a span
Every span, whatever its kind, carries the same four things:
- Kind — what type of work it was (model call, tool call, retrieval, the run wrapper). This drives its colour in the timeline.
- Duration — its start and end timestamps. The difference is the bar length you see in the timeline.
- Parent — the span it ran inside. The root has no parent; everything else points up to whatever triggered it. This is what assembles the tree.
- Attributes — the details: which model, how many input/output tokens, the exact inputs it received and outputs it produced, and whether it errored.
The parent link is the important one for structure; the attributes are the important ones for debugging (you'll lean on tokens in the cost lesson, and inputs/outputs in the debugging lesson).
The tree, drawn
The run wraps everything; a model call, a tool call, and a second model call nest under it; the tool's retrieval nests under the tool. Indentation = nesting; bar length = duration.
That nesting answers the checkpoint directly: a retrieval inside tool.execute
inside runner.execute means the run invoked the tool, and the tool
performed the retrieval. Read top-down, the tree is a chain of "who called whom."
Span kinds you'll see
Four kinds cover almost every agent run:
| Kind | Looks like | What it is |
|---|---|---|
| Run | runner.execute | The wrapper around the whole run; its bar spans everything else. |
| LLM | llm.complete | A call to the model. Usually the slowest span and the only one that costs money. |
| Tool | tool.execute | The agent calling a tool — an account lookup, an MCP tools/call, an HTTP request. |
| Retrieval | retrieval | A knowledge-base search specifically — finding relevant chunks (Module 4). |
Analogy
A span is a single line on a project's org chart and its calendar at once: the indentation says who it reports to (parent), and the bar says how long its task ran (duration). One glance gives you both the structure and the schedule.
Common mistake
Reading spans left-to-right as if order alone tells the story, and ignoring indentation. Two spans can start one after another yet have totally different parents — one part of the run, one nested inside a tool. Miss the nesting and you'll misattribute work (blaming the run for time a tool's retrieval actually spent).
Key takeaways
Key takeaways
- A span carries a kind, a duration, a parent link, and attributes.
- The parent link builds the tree; attributes (tokens, I/O) drive debugging.
- Four kinds cover most runs:
runner.execute,llm.complete,tool.execute,retrieval. - Nesting reads as "who called whom" — top-down through the tree.
Go deeper: attributes are where the answers hide
The tree shape tells you structure; the span attributes tell you why. The ones you'll reach for most:
model— which model ran (an unexpectedly large model on a cheap step is an easy cost win).input_tokens/output_tokens— the size of what went in and came out. The cost lesson shows input tokens dominate the bill.input/output— the literal prompt and completion (or tool args and result). The debugging lesson uses these to catch a tool that returned junk or a retrieval that returned the wrong chunk.status/error— whether the span failed. A failed tool span with a successful run is the classic "silent failure" signature.
A good trace viewer lets you click any span and read these. The skill is knowing which attribute answers the question you have — duration for "why slow," tokens for "why expensive," input/output for "why wrong." The rest of this module is one attribute family per lesson.
