Timeline
Shows when each step of a run started and how long it took, with the slow and failed ones marked.
Examples
| Step | Started at | Took | Status |
|---|---|---|---|
| plan | 0ms | 0.5s | OK |
| search_orders | 500ms | 2.1s | OK |
| attempt 1 | 500ms | 0.8s | Warning |
| attempt 2 | 1.3s | 1.3s | OK |
| issue_refund | 2.6s | 9.8s | OK |
| refund_charge | 11.7s | 0.7s | Failed |
| send_reply | 12.4s | 0.2s | Waiting on you |
| Step | Started at | Took | Status |
|---|---|---|---|
| plan | 0ms | 0.4s | OK |
| search_orders | 400ms | 1.5s | OK |
| draft_reply | 1.9s | 1.1s | Running |
Open: model-l
| Step | Started at | Took | Status |
|---|---|---|---|
| plan | 0ms | 0.5s | OK |
| model-l | 520ms | 2.1s | OK |
| search_orders | 2.6s | 1.7s | OK |
| attempt 1 | 2.6s | 0.8s | Warning |
| attempt 2 | 3.4s | 0.9s | OK |
| Step | Started at | Took | Status |
|---|---|---|---|
| prepare | 0ms | 0.8min | OK |
| evals | 48.0s | 1.4min | Warning |
| release 10% | 2.2min | 1.0min | OK |
| release 100% | 3.2min | 0.4min | Waiting on you |
Status
OK2.6s OK Step Started at Took Status search_orders 400ms 1.7s OK okdefault
Running1.8sRunning Running Step Started at Took Status search_orders 400ms 1.4s Running running
Warn2.1s Warn Step Started at Took Status search_orders 400ms 1.7s Warning warn
Fail2.1sFailed Fail Step Started at Took Status search_orders 400ms 1.7s Failed fail
Waiting2.6s Waiting Step Started at Took Status search_orders 400ms 2.2s Your review waiting
States
Loading Loading Step Started at Took Status loading
Empty Empty Step Started at Took Status empty
Usage
When to use it
- Use
- A person asks where the time in a run went: steps, tool calls and model calls laid out on one clock.
- Use
- A run failed and the person needs the step that broke, in its place among the others.
- Use
- A prompt release or an eval that ran, or is running, as stages in order.
- Not for
- Records to compare across columns. Use Table.
- Not for
- Planning work that has not happened yet.
Rules
7 rules
- Never
- Put a Timeline in a Panel or beside Panels; it is a working surface, white with one grey edge and a rule under its header. Because a surface that scrolls, streams or is read closely needs the white frame's edge to show where it ends, and a white frame in a grey Panel is a box in a box.
- Must
- Pass start and end in milliseconds and let the timeline pick one unit; never format durations yourself. Because mixed units put 950ms beside 1.2s, so the bigger-looking number is the shorter step.
- Must
- Set status on the span that owns it, never on its parents. Because a parent marked failed puts a second wash on the run, so two rows read as the root cause.
- Must
- Give a timeline that can pass 200 spans a maxHeight so its rows window. Because without it every span renders, and a long agent run stalls the page each second it ticks.
- Never
- Use a Timeline to plan work; it shows what happened. Because a bar here means time spent, so a planned bar reads as work already done.
- Should
- Write label as the run it shows, with its id: "Run run_8f2a91".
- Should
- Give a waiting span the wait in waitingLabel, one to three words.
Accessibility
5 checks
- The frame is a section named by label; the rows are a list, or a listbox with onSpanClick.
- Each row is named "{label}, started at 1.2s, took 0.8s, failed".
- With onSpanClick the rows are one tab stop: Up and Down move, Home and End jump, Enter opens.
- A screen-reader table carries step, start, duration and status; the bars and the axis are aria-hidden.
- Status is always a word; the wash and the bar colour never carry it alone. A narrow frame hides the status column, and the header and each row's name still say it.
Edge cases
8 edge cases
- Running span
- The bar has no end and grows to now, easing along between ticks of the clock.
- Waiting span
- A paper bar with an ink edge from the start to now and the waiting label, in the status column or after the bar when the frame is narrow.
- Span under 1% of the run
- Keeps a 4px bar so it stays visible.
- Deep nesting
- 16px per depth; the name truncates and meta shrinks first; under 448px the meta goes.
- 1,000 spans
- With maxHeight about 20 rows stay in the DOM.
- No spans
- "No steps yet." top-left in the body.
- Right to left
- Time runs from the right; names and the status column mirror.
- Forced colors
- Bars draw CanvasText; status stays a word.
API
9 props
labelstringdefaultrequiredspansTimelineSpan[]defaultrequirednownumberactiveId, onSpanClickstring, (span) => voidkindKindmaxHeightnumberbars'kind' | 'quiet'default'kind'footerReactNodeloadingbooleandefaultfalse
Tokens
17 tokens
--line-frame- oklch(var(--ink-c) / var(--line-frame-alpha))
--line-row- oklch(var(--ink-c) / 0.08)
--accent-mark- var(--ink)
--accent-line- var(--ink)
--accent-wash- var(--surface-selected)
--ink- oklch(var(--ink-c))
--surface-skeleton- color-mix(in oklch, oklch(var(--grey-c)), oklch(var(--ink-c)) var(--skeleton-step))
--type-label- 400 14px/16px var(--font-sans)
--type-label-sm- 400 12px/16px var(--font-sans)
--type-tag- var(--type-code-sm)
--text-2- oklch(var(--ink-c) / 0.80)
--text-3- oklch(var(--ink-c) / 0.66)
--status-column- 128px
--timeline-name- 200px
--timeline-name-min- 120px
--radius-inner- 4px
--radius-frame- 10px