Capturing Claude's Autonomous Agent Mode: A Deep Dive into Dispatch
I let Claude plan a 6-hour Japan trip in Cowork mode. Then I tried to replay it — and vibe-replay couldn't see the session at all. Here's what it took to fix that.
I let Claude plan a Japan spring break trip in autonomous mode. 6 hours, 125 prompts, 364 tool calls — Gmail searches, browser sessions, calendar checks, all chained together while I went about my day. When I came back, I wanted to replay it.
vibe-replay couldn’t see the session.
It now can. This is what it took.
Two Claudes in one app
Claude Desktop is actually two AI experiences sharing a window. The Code tab is Claude Code in a managed wrapper — the same CLI, the same JSONL transcripts, the same tool calls you’d see in your terminal. The Cowork tab is something else entirely: an autonomous agent mode where Claude runs in an isolated sandbox VM, orchestrates multi-step plans on its own, and writes its transcript to a completely different place on disk.
Anthropic internally calls the orchestrator behind Cowork Dispatch — and the name fits. Each Cowork session spins up a sandboxed VM with a codename like hopeful-awesome-feynman or zealous-wonderful-meitner, mounts your real folders into a fake filesystem rooted at /sessions/{processName}/, and writes its full audit trail into:
~/Library/Application Support/Claude/local-agent-mode-sessions/.../audit.jsonl
That’s nowhere near ~/.claude/projects/, which is what vibe-replay had been scanning since day one.
That answered the surface question — why didn’t vibe-replay see the session? But once I actually opened those audit files, two deeper things mattered.
Discovery 1: Cowork transcripts are self-contained
Claude Code’s storage layout has a small but consequential split. Metadata lives in one place; the transcript lives in another, joined by an ID:
~/.claude/projects/{encoded-cwd}/{sessionId}.jsonl ← transcript
~/Library/.../claude-code-sessions/.../local_{id}.json ← metadata, with cliSessionId pointing back to the JSONL
To replay a Code-tab session, you read the metadata, follow the pointer, and find the JSONL — which means re-implementing Claude’s “encode cwd by replacing / with -” path scheme. Brittle, but solvable.
Cowork chose a different shape:
~/Library/.../local-agent-mode-sessions/{accountId}/{orgId}/
├── local_{id}.json ← metadata (title, model, initialMessage)
└── local_{id}/
└── audit.jsonl ← full transcript, right next door
No cross-references. No path encoding tricks. The transcript sits next to its metadata in a sibling directory. This is the kind of design choice that probably saved its authors a week of debugging — and it lets vibe-replay treat each Cowork session as a single self-contained unit, no matter what sandbox it ran in or what codename it got.
Discovery 2: the cliSessionId trap
Cowork sessions also carry a cliSessionId field. The name is suggestive — exactly the kind of thing you’d grab as a dedup key without thinking.
Don’t.
The cliSessionId in a Cowork session is the UUID of the inner Claude Code subprocess running inside the sandbox VM — a completely separate process from the one writing the audit trail you’re reading. It doesn’t appear anywhere on the outer audit records. Treat it as the session’s identity and you’ll permanently break replay-to-source linking: every time the sandbox restarts that inner CLI, the “same” session gets a new ID.
The right key is the metadata’s sessionId field (with the local_ prefix stripped). That’s the stable, outer-loop identity of the Cowork session itself.
I learned this the long way. Future me, reading this post, gets to skip that.
Three providers, one discovery pass
Once those two truths were in hand, the rest of the implementation practically wrote itself:
claude-codescans~/.claude/projects/for raw JSONL files. The original provider.claude-desktopreads metadata from the Code tab’s location, followscliSessionIdover to~/.claude/projects/, and overlays Desktop’s richer metadata (title, exact model, permission mode) on top.claude-coworkreads metadata from the autonomous-mode location and goes straight to the co-located audit.jsonl. No path resolution required — that’s discovery 1 paying off.
Running them in parallel introduces one collision: the same Code-tab JSONL gets found twice — once raw by claude-code, once dressed up by claude-desktop. Both correctly assign the same sessionId, so dedup just keeps the best-quality record:
claude-cowork → claude-desktop → claude-code → cursor
claude-desktop wins over claude-code because it has the title and model that the Desktop UI inferred. claude-cowork ranks first because its transcript is authoritative.
What replay looks like now
A Cowork session in the player:
Left panel: outline of every user prompt — useful when there are 125 of them. Center: the conversation, with tool-use tags inline (the parser normalizes Cowork’s mcp__workspace__* names into recognizable tags like gmail_read_message and Claude_in_Chrome).
Code-tab sessions running through Desktop pick up metadata the raw JSONL never sees — the human-readable title Desktop inferred, the permission mode, the git worktree branch:
(That session is literally the implementation of the Cowork provider itself. The first prompt: “Add support for Cowork (Dispatch) sessions to vibe-replay…” The dangerous mode badge and claude/crazy-ishizaka-06a286 branch name come from Desktop’s metadata.)
Try it
If you’ve used Cowork at all, you have audit files sitting on disk right now:
npx vibe-replay
Auto-discovery picks up everything — Code, Desktop, Cowork, Cursor. Pick a session, get a self-contained HTML file in ~/.vibe-replay/{sessionId}/index.html.
Or surface them all at once:
npx vibe-replay --dashboard
The foundation is in place. Every audit.jsonl Claude produces — Code, Desktop, Cowork — is now fair game.
vibe-replay is open source. The providers discussed here landed in PR #187.




