Workflow Monitor for Claude Code
Watch Claude Code workflow runs while they happen — phases, agents, token usage, retries — in a
sidebar tree and a charted dashboard.
Unofficial. Not affiliated with, endorsed by, or supported by Anthropic. "Claude" and
"Claude Code" are trademarks of Anthropic. This extension only reads files Claude Code has
already written to your own disk; it sends nothing anywhere and needs no API key.
Claude Code's CLI has /workflows for live progress. Its VS Code extension does not, and workflow
progress isn't exposed as an Agent SDK event either. This reads the same on-disk state /workflows
is backed by, so it needs no patching and no hooks.
What you get
Runs tree — every workflow run across all projects and sessions, newest first, grouped by phase.
Live runs show a spinner in the status bar. Click an agent for its full result; right-click for its
raw transcript.
Dashboard — a KPI row, a timeline of when each agent ran, peak context per agent, and a
per-agent drill-down into real token usage parsed from that agent's transcript.
The dashboard follows live runs by default: leave it open and it retargets when a workflow
starts. Pin it from the tab toolbar to hold on a run you're reading.
Requirements
Claude Code, with at least one workflow run on disk. Nothing else — no build step, no dependencies,
no configuration.
Two things it is careful about
These are the two places a naive reading of the data gives the wrong answer, and they shaped the UI.
Peak context is not token spend
The run files record a per-agent tokens figure. It is the agent's final context size — a
level, not a running total. Measured against transcripts it equals the last request's
input + cache_creation + cache_read to within 0.07%.
Actual tokens processed is a different, much larger number, because cache reads replay the context
on every call. One real agent: 162,831 peak context, 3,809,475 cache-read tokens across 39
requests. The dashboard labels the two separately and never adds them together.
The journal is a resume ledger, not an agent roster
journal.jsonl records one started per attempt, tagged with a key that is a content hash of
the agent's prompt and options. A retried agent emits several started records under one key, each
with a different agent id — so counting agent ids over-reports, and treating start-without-result as
"running" invents hung agents on a finished run.
Distinct keys track the roster exactly. One real run: 50 starts, 25 results, 17 keys —
sixteen of its seventeen agents ran three times each. That now surfaces as retried ×3 rather than
as phantom agents.
Live runs
The run-state file is written only when a workflow finishes, so mid-run there is no label, phase
or token data. Transcripts do exist while agents run, so the monitor recovers what it can from them:
| Field |
Live source |
| Label |
first line of the agent's prompt |
| Model |
message.model on assistant records |
| Peak context |
last request's input + cache_creation + cache_read |
| Tool calls |
tool_use blocks |
| Timing, requests |
record timestamps and count |
Phase grouping and retry attempts stay blank until the run completes — they exist nowhere else on
disk.
Two models, not one
The line under the run title is the orchestrator — the model that ran the workflow script, which
is often not what the agents ran on. Per-agent model appears in its own KPI tile (with the mix on a
mixed-model run), both chart tooltips, the table view, and the agent detail.
Everything this extension reads is undocumented Claude Code internals and can change without
notice. Rather than rendering confident numbers off a shape that no longer means what it used to,
the monitor checks what it parses and shows an "Unrecognised run format" banner listing exactly what
stopped matching. If you see it, the figures below it are suspect — please open an issue.
The agent detail additionally cross-checks peak context against the transcript and warns if they
diverge by more than 5%.
Settings
| Setting |
Default |
|
claudeWorkflows.projectsRoot |
~/.claude/projects |
Override the scan root |
claudeWorkflows.pollIntervalMs |
2000 |
Re-scan cadence |
claudeWorkflows.maxRuns |
25 |
How many runs to list |
claudeWorkflows.liveWindowSeconds |
90 |
Journal staleness before a run stops counting as live |
claudeWorkflows.groupByPhase |
true |
Off gives a flat agent list |
Polling, not file watching: ~/.claude sits outside the workspace, so VS Code's FileSystemWatcher
doesn't apply. Run files are re-stat'd every 2s and only re-parsed when an mtime or size actually
changes — a full scan of 9 runs / 293 agents is ~50 ms, and a no-change re-scan is ~2 ms.
Known limits
failed-state rendering is untested. No run on the author's disk has ever failed. States are
classified by substring; anything unrecognised falls through to a neutral icon rather than being
guessed as success.
- Nothing here is a stable contract. See "When the format changes" above.
Privacy
Reads only from your Claude projects directory. No network calls, no telemetry, no API key. Agent
prompts and results are shown to you and never leave your machine.
Development
No build step. Clone, open in VS Code, press F5.
All tests run under plain Node with a stubbed vscode — no Extension Host needed:
| Command |
Covers |
node chart-math-test.js |
61 assertions on chart geometry, formatting and model-id shortening, including degenerate inputs that would silently drop an SVG mark |
node format-guard-test.js |
Six shape-drift scenarios; asserts the guard fires on each and stays silent on a healthy run |
node follow-test.js |
Activates against fakes, drops a live run onto disk mid-test, drives the real poll tick |
node live-test.js |
Reproduces mid-run conditions by withholding a run-state file; asserts recovery from transcripts |
node scan-test.js |
Scanner against real runs on disk |
node ui-test.js |
Tree provider, click payloads, detail document |
node make-preview.js [run] [--dark] writes preview.html — the dashboard with real run data baked
in, openable in any browser. It embeds your own run labels and is gitignored; don't commit or
publish it. node make-icon.js regenerates the Marketplace icon.
License
MIT