Agent Timeline
ProA chart of the work your agents did over time, wired to a board of what came out of it. Point at a moment and its cards light up; select a stretch and the board shows only that stretch.
October close, overnight run
- finished
- 216
- for your sign-off
- 4
- stopped
- 2
| hour | Finished | Waiting on you | Stopped |
|---|---|---|---|
| 19:00 | 22 | 0 | 0 |
| 20:00 | 31 | 0 | 0 |
| 21:00 | 27 | 0 | 0 |
| 22:00 | 18 | 0 | 0 |
| 23:00 | 24 | 0 | 0 |
| 00:00 | 12 | 0 | 1 |
| 01:00 | 9 | 1 | 0 |
| 02:00 | 6 | 0 | 1 |
| 03:00 | 8 | 1 | 0 |
| 04:00 | 11 | 0 | 0 |
| 05:00 | 15 | 1 | 0 |
| 06:00 | 19 | 1 | 0 |
| 07:00 | 14 | 0 | 0 |
Your sign-off4
Post the hosting accrual
Ledger agent · 01:10 · €12,400
Write off a €38 rounding gap on the EU account
Reconciliation agent · 03:25
Release the supplier payment run
Payables agent · 05:40 · 27 payments
Nothing left to sign off.
Stuck2
Match the October card statement
Reconciliation agent · 00:20
The bank feed stopped at 28 October. Three pulls came back empty.
Revalue the USD balances
Ledger agent · 02:45
No rate published for 31 October yet. Nothing was posted.
Nothing stuck in this window.
Closed out216
212 bank lines matched to the ledger
48 invoices coded to cost centres
9 intercompany balances agreed
31 late receipts chased by email
Nothing closed out in this window.
Installation#
Usage#
Give the root one row per time bucket and give each card the buckets it belongs to. The rest follows: the chart and the board point at each other, a selected stretch filters the board, and the figures add up over that stretch. When the reader acts on a card, remove it and move its bucket from one series to the other, and the chart, the counts and the board change together. It fetches nothing, so it fits any agent product, from a support desk to a release pipeline.
The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.
Have a license? Unlock it here
Anatomy#
import {
AgentTimeline,
AgentTimelineHeader,
AgentTimelineHeading,
AgentTimelineTitle,
AgentTimelineWindow,
AgentTimelineCounts,
AgentTimelineCount,
AgentTimelineChart,
AgentTimelineRange,
AgentTimelineBoard,
AgentTimelineColumn,
AgentTimelineColumnHeader,
AgentTimelineList,
AgentTimelineItem,
AgentTimelineItemTitle,
AgentTimelineItemCount,
AgentTimelineItemMeta,
AgentTimelineItemDetail,
AgentTimelineItemActions,
AgentTimelineRevert,
AgentTimelineEmpty,
} from "@/components/ui/agent-timeline"Chart and board#
A column and its band on the chart share one tone. Point at a card and the chart dims everything but the moments it happened; point at a bar and the cards from other moments step back. Drag across the chart to keep only that stretch: cards outside it fold away and the counts add up again. This release night opens on the stretch around midnight.
| slot | Finished | Stopped |
|---|---|---|
| 22:00 | 4 | 0 |
| 22:30 | 7 | 0 |
| 23:00 | 5 | 2 |
| 23:30 | 9 | 0 |
| 00:00 | 12 | 0 |
| 00:30 | 6 | 1 |
| 01:00 | 3 | 0 |
| 01:30 | 2 | 0 |
Rolled back3
Search service, eu-west
Health checks failed twice
Billing worker, us-east
Migration lock held for 10 min
Image resizer, ap-south
Memory over the limit
No rollbacks in this window.
Shipped32
16 web services
21 background workers
11 edge functions
Nothing shipped in this window.
Long columns#
Finished work reads best summarised, one line per kind of task with its count. Past limit the lines fold behind a button and unfold one after another in place.
Closed out216
212 bank lines matched to the ledger
48 invoices coded to cost centres
Empty columns#
An empty column can say so with AgentTimelineEmpty, or step out of the board with hideWhenEmpty. Nothing got stuck here, so that column is gone and the other two share the row.
Your sign-off0
Nothing left to sign off.
Stuck0
Closed out216
212 bank lines matched to the ledger
48 invoices coded to cost centres
Narrow containers#
The timeline reads its own width, not the window's. In a side panel the counts wrap, the columns stack and the actions drop below the text, with density="compact" for tighter rows.
October close
- finished
- 216
- for your sign-off
- 4
| hour | Finished | Waiting on you | Stopped |
|---|---|---|---|
| 19:00 | 22 | 0 | 0 |
| 20:00 | 31 | 0 | 0 |
| 21:00 | 27 | 0 | 0 |
| 22:00 | 18 | 0 | 0 |
| 23:00 | 24 | 0 | 0 |
| 00:00 | 12 | 0 | 1 |
| 01:00 | 9 | 1 | 0 |
| 02:00 | 6 | 0 | 1 |
| 03:00 | 8 | 1 | 0 |
| 04:00 | 11 | 0 | 0 |
| 05:00 | 15 | 1 | 0 |
| 06:00 | 19 | 1 | 0 |
| 07:00 | 14 | 0 | 0 |
Your sign-off4
Post the hosting accrual
Ledger agent · 01:10 · €12,400
Closed out216
212 bank lines matched to the ledger
48 invoices coded to cost centres
API reference#
AgentTimeline
Holds the series, the selected stretch and the link between the chart and the board. It is a size container: the columns sit side by side when it is wide and stack when it is narrow. Every part accepts className, merged last.
| Prop | Type | Default | Description |
|---|---|---|---|
| data* | ChartDatum[] | - | One row per time bucket, such as { hour: "02:00", done: 6, failed: 1 }. Keys named after a status take its tone. |
| index* | string | - | The key that names each bucket. |
| config | ChartConfig | - | Labels and colours per series, merged over the status tones. |
| range | readonly [number, number] | null | - | The selected stretch, as first and last bucket, when you control it. |
| defaultRange | readonly [number, number] | null | null | The stretch selected on the first render. |
| onRangeChange | (range) => void | - | The reader selected a stretch, or cleared it. |
| variant | "card" | "plain" | "card" | A framed surface, or no chrome for a full page. |
| density | "comfortable" | "compact" | - | Padding and row spacing. Reads DensityProvider when unset. |
| Data attribute | Description |
|---|---|
| data-ranged | Present while a stretch is selected. |
AgentTimelineWindow
The time the timeline covers, as "18:40 yesterday to 07:40 · 13 h". It formats on the client, in the reader's time zone. Children replace the text.
| Prop | Type | Default | Description |
|---|---|---|---|
| from | Date | number | - | Where the window starts. |
| to | Date | number | - | Where it ends. Now, when unset. |
| locale | string | "en-US" | Formats the times and the day word. |
| joiner | string | "to" | The word between the two times. Use it to translate. |
| formatSpan | (ms: number) => string | - | Writes the length: 45 min, 13 h or 3 d by default. |
AgentTimelineCount
One figure in AgentTimelineCounts. Without count it adds up its series over the selected stretch, so it follows the chart. Pointing at it brings its band forward on the chart.
| Prop | Type | Default | Description |
|---|---|---|---|
| status* | "working" | "waiting" | "idle" | "done" | "failed" | - | Sets the dot and the default label. |
| series | string | - | The data key it adds up. The status, when unset. |
| count | number | - | A figure of your own, in place of the sum. |
AgentTimelineChart
Stacked bars on Koala's Chart, one band per series in the tone of its column. Drag across it, or click a bar, to select a stretch; from the keyboard, focus it, move with the arrows, press Enter to select, Shift and Enter to widen and Escape to clear. Extra children render inside the Chart.
| Prop | Type | Default | Description |
|---|---|---|---|
| markers | readonly AgentTimelineMarker[] | [] | { at, title, description?, label?, status? }, pinned above a bucket. Hover a marker or its bar to read it. |
| selectable | boolean | true | Turns selecting a stretch off. |
| plotClassName | string | "h-28" | Sizes the chart itself. |
| tickFormatter | (value, index) => string | - | Writes the bucket names on the axis. |
| valueFormatter | (value: number) => string | - | Writes the values in the tooltip. |
| totalLabel | string | "All" | Names the total row of the tooltip. |
| label | string | - | The chart's accessible name, with the keys it takes. |
| Data attribute | Description |
|---|---|
| data-selecting | Present while the reader drags a stretch. |
AgentTimelineRange
Says which stretch is selected, with a button that shows everything again. Renders nothing while no stretch is selected.
| Prop | Type | Default | Description |
|---|---|---|---|
| children | (from: string, to: string) => ReactNode | - | Writes the line from the first and last bucket names. |
| clearLabel | ReactNode | "Show all" | The button's label. |
AgentTimelineColumn
One column of the board. Its items that fall outside the selected stretch fold away, and AgentTimelineEmpty inside it shows only when none are left.
| Prop | Type | Default | Description |
|---|---|---|---|
| status* | "working" | "waiting" | "idle" | "done" | "failed" | - | Sets the tone of the column and the default title. |
| series | string | - | The chart series the column stands for. The status, when unset. |
| hideWhenEmpty | boolean | false | Hides the column while it has nothing to show. |
AgentTimelineColumnHeader
The column's dot, title and count. Pointing at it brings its band forward on the chart. Children replace the default title.
| Prop | Type | Default | Description |
|---|---|---|---|
| count | number | null | - | The figure at the end. The column's series summed over the stretch, when unset; null hides it. |
AgentTimelineList
The items of a column. Give each a stable key: an item that leaves collapses out while the others close the gap, and one that comes back grows into its old place.
| Prop | Type | Default | Description |
|---|---|---|---|
| limit | number | - | Folds the items past this many behind a button. |
| defaultExpanded | boolean | false | Opens the fold on the first render. |
| expanded | boolean | - | Whether the fold is open, when you control it. |
| onExpandedChange | (expanded: boolean) => void | - | The reader opened or closed the fold. |
| foldLabel | (hidden: number, expanded: boolean) => string | - | Writes the fold button. Use it to translate. |
AgentTimelineItem
One card of the board: a thing that waits on the reader, a stop, or a summary of many finished things. Pointing at it, or focusing inside it, lights the moments it happened on the chart.
| Prop | Type | Default | Description |
|---|---|---|---|
| at | number | string | readonly (number | string)[] | - | The buckets the item belongs to, by index or name. An item without one is never filtered. |
| Data attribute | Description |
|---|---|
| data-entering | Present on an item that arrived after the first render. |
| data-leaving | Present while the item collapses out. |
| data-filtered | Present while the item falls outside the selected stretch. |
| data-dimmed | Present while the reader points at a bucket the item is not in. |
| data-folded | Present while the item is folded past the limit. |
AgentTimelineItemCount
The leading figure of a summary line.
| Prop | Type | Default | Description |
|---|---|---|---|
| value* | number | - | The figure, in tabular numerals. |
AgentTimelineItemActions
The item's buttons, at the end of the row. Two or more drop below the text in a narrow column; a single one stays beside it. Use xs buttons.
AgentTimelineRevert
A quiet button that takes an action back. You handle the click: put the thing back in your state and the board returns it.
| Prop | Type | Default | Description |
|---|---|---|---|
| size | "xs" | "sm" | "xs" | The button size. |
useAgentTimeline
Reads the timeline from any part inside it: range, setRange, the bucket being pointed at, and inRange(bucket), to work out figures of your own for the stretch.