Interactive demo · synthetic dataEvery record on this page is fabricated.

Agent Session Observability

Scrub a fabricated Claude Code session and watch the state machine, estimator and cost split decide what to show.

The production code behind this demo is my own work — design, build contract, implementation, directing AI coding agents.

Read the case study

ONE SESSION, ELEVEN MOMENTS

01:02 · working

The ordinary case. Something was written a second ago, so rule 6 fires and the activity line names the tool call the session is inside.

THE ROW THE DASHBOARD WOULD DRAW

Working

working

running npx vitest run src/ledger

ACTIVITY
Bash · npx vitest run src/ledger
ETA
~27–82 min · medium confidence
PLAN
no todo list yet
CONTEXT
196k of 1.0M
CHILD PROCESSES
none
EQUIVALENT API COST
$0.90 · 15 records

THE RULE STACK, IN THE ORDER IT IS WALKED

The first rule that matches decides the state, so every rule below it is never evaluated. The registry writes its own status field; it is consulted eleventh, because only sessions launched from the CLI write it at all.

  1. · 1the process is not alive→ donepid verified alive
  2. · 2an unresolved API error inside the last 2 min→ errorno errors recorded
  3. · 3a pending AskUserQuestion or ExitPlanMode→ waiting_inputno question or plan waiting on you
  4. · 4a pending tool call WITH live child processes→ working1 pending, but no live children
  5. · 5a pending tool call older than 10s, no children→ blocked_permissionno tool call has been pending longer than 10s
  6. ▸ 6the transcript was written to under 120s ago→ workinglast write 1s ago, inside the 120s window
  7. · 7background agents are still writing→ workingnot reached
  8. · 8the user has spoken since the assistant stopped→ workingnot reached
  9. · 9the last assistant message ended its turn→ waiting_inputnot reached
  10. · 10nothing written for over 15 min→ stallednot reached
  11. · 11the registry says idle (CLI sessions only)→ idlenot reached
  12. · 12a live session with no transcript records at all→ idlenot reached
  13. · 13nothing above matched→ idlenot reached

THREE SIGNALS, AND WHAT EACH ONE ALONE WOULD SAY

Every row below is the same estimator, run with only that one signal available. The last row is what the dashboard actually shows.

The ETA estimator run with each signal in isolation, and then with all of them
SIGNALESTIMATECONFIDENCEBASIS
Todo burn-downunknownnonenone
Background agentsunknownnonenone
Project history~27–82 minmediumhistorical
All three~27–82 minmediumhistorical

Point estimate 45m 18s, shown as a band because it is a guess. It is never rendered as a single number.

EQUIVALENT API COST, BY MODEL AND BY RATE CLASS

Nobody was charged this. The machine it runs on is on a flat subscription, so the figure is what the same tokens would have cost on API pricing — and the label says so, everywhere it appears.

  • cache reads 855k · 94.3%
  • cache writes (1h) 42k · 4.6%
  • input 6.4k · 0.7%
  • output 3.5k · 0.4%
Cost and tokens per model
MODEL ID ON THE WIREPRICED ASIN / OUTUSD
claude-opus-5[1m]claude-opus-5 · $5/$25 per 1M5.0k / 2.8k$0.86
claude-sonnet-5claude-sonnet-5 · $2/$10 per 1M · intro rate1.4k / 740$0.04

One blended rate across those rows would be a different number, and it would look just as authoritative. The model id also arrives with a suffix — a variant tag or a date — so it is resolved by the longest matching table key rather than by an exact lookup, and an id the table has never seen is priced on the fallback and flagged, not dropped.

NAMING A BACKGROUND AGENT

A fan-out spawns agents from one template, so the first line of every prompt is the same shared preamble. Reading line one gives a panel of identical rows at exactly the moment it matters most. The heuristic scans the whole head for what actually distinguishes this agent: a role declaration, then a lane or phase marker, then a markdown heading, and only then line one.

No agent is running at the moment selected above. These three are shown anyway, because the heuristic is the point rather than the timing.

  • AGENT 1 — POSTING RULE AUDITOR

    agent-1f4a · reading ledger/posting.ts · running 7m

    ROLE

  • LANE 2 — PERIOD BOUNDARY REGRESSION SWEEP

    agent-93b7 · running npx vitest run src/ledger/period · running 5m

    MARKER

  • Currency rounding on multi-leg reversals

    agent-c052 · editing ledger/rounding.test.ts · running 11m

    HEADING

What is real, and what is simulated

Runs in your browser

  • deriveState — seven states, thirteen rules, evaluated in priority order until one matches
  • estimateEta — the three bases, the 0.7/0.3 blend, the confidence ladder and the six-hour cap
  • priceFor and costOfUsage — per model, per rate class, with suffix resolution and dated rates
  • The background-agent task-line heuristic, and the naive first-line read it replaced

Ported from cost.js, activity.js, progress.js, eta.js and the task heuristic in agents.js — five modules whose logic has no imports outside the core, which is why this project earned a running demo rather than a diagram. 74 tests assert the rule order, both documented refinements to it, all three ETA bases and the pricing edge cases.

Simulated

  • File watching, the byte-offset streaming digest, SSE, the process table and the Electron shell. There is no file here — the digest is folded from a fabricated event list into the same shape.
  • Everything the engines read: about 150 invented transcript records, a fake session registry, a fake ps snapshot and three fabricated subagent prompts, for an imaginary project called atlas-ledger.
  • The streaming performance is quoted as a measurement, not demonstrated: a 46 MB transcript digests cold in ~94 ms and incrementally in ~0 ms on the author's machine.