Tuo Lei · · 7 min read

Claude Code's Source Leaked. We Read It and Shipped 5 Features in a Day.

513,000 lines of TypeScript, extracted from a source map left in the npm package. We found undocumented JSONL fields, hidden metadata, and MCP tool naming conventions — then turned them into product improvements.

On March 31, 2026, security researcher Chaofan Shou discovered that Anthropic had shipped a source map file inside the published @anthropic-ai/claude-code npm package. The cli.js.map file contained the sourcesContent of every original TypeScript file — 1,987 files, 513,000 lines of code, trivially extractable.

Within hours, multiple GitHub repositories had the full source. Anthropic acknowledged it and subsequently made the code publicly available.

We build vibe-replay, a tool that parses Claude Code’s JSONL session files and turns them into interactive replays. We’d been reverse-engineering the JSONL format from observed data for months. Now we had the actual source of truth.

We cloned the repo, read the code, and started shipping. Here’s what we found and what we built.


What the source revealed

Claude Code’s session format is far richer than what you see in the terminal. Every line in a .jsonl file is a typed Entry — and there are over 20 distinct entry types, most undocumented.

Before the leak, we knew about the obvious ones: user, assistant, system, progress, custom-title, pr-link. After reading src/types/logs.ts, we discovered entries like attribution-snapshot, marble-origami-commit (an obfuscated name for context collapse), speculation-accept, worktree-state, agent-setting, and more.

But the most useful discoveries weren’t new entry types — they were undocumented fields on existing messages that we’d been ignoring.


Discovery 1: isCompactSummary — a flag we were guessing at

When Claude Code runs out of context, it compacts the conversation into a summary. The compaction summary is a user-role message that starts with “This session is being continued from a previous conversation…”

We’d been detecting this with a string prefix match. Fragile — if Anthropic ever changed the wording, our detection would silently break.

The source revealed that every compaction summary message carries isCompactSummary: true as a top-level field. A reliable, future-proof flag that was sitting in the data all along.

We now use the flag as the primary detection, with the string prefix as a fallback for older sessions.


Discovery 2: isMeta — invisible messages that were leaking into replays

This was a bug we didn’t know we had.

Claude Code injects system messages into the conversation that are invisible in the terminal UI. These isMeta: true messages include skill injections (“Base directory for this skill: …”), local command caveats, and slash command outputs.

Our parser was treating them as regular user turns. In replays, they’d show up as mysterious user prompts with XML tags or skill configuration text that the user never actually typed.

After reading the source, we understood the taxonomy (counts from one developer machine, 129 sessions):

isMeta patternFrequencyValue
<local-command-caveat>108Low — just a wrapper telling the model to ignore
Skill injection (Base directory for this skill:)14High — shows which skills were activated
/insights output1High — slash command data
Image injection metadata6Medium

We now classify each isMeta message and handle them differently:

  • Skill injections become context-injection scenes with a specific label like “Skill: playwright-cli” — visible in the replay with blue styling, distinct from user prompts
  • Slash command outputs get labeled “Command: /insights”
  • Low-value caveats (local-command wrappers) are filtered out entirely — they added noise without insight

We also extract the skill names into a skillsUsed metadata field. In the dashboard, sessions now show skill badges:

[claude-opus-4-6] [cli] [playwright-cli]

Discovery 3: stop_reason — detecting truncated responses

Every assistant message in the JSONL carries a stop_reason field: end_turn, tool_use, or max_tokens. This is a standard Anthropic API field — we just hadn’t wired it up.

max_tokens means Claude’s response was cut off mid-sentence — important context that was invisible in replays.

We now track this per-message and surface it:

  • ParsedTurn gets a stopReason: "max_tokens" field
  • Text response scenes get an isTruncated flag
  • The viewer shows a small “Response truncated (max_tokens reached)” indicator
  • Session metadata includes truncatedResponses count

Across all sessions on one test machine, we found 211 truncated responses — far more than we expected.


Discovery 4: MCP tool naming convention

This one came from reading src/services/mcp/mcpStringUtils.ts. MCP (Model Context Protocol) tools follow a strict naming convention:

mcp__<server_name>__<tool_name>

For example: mcp__claude-in-chrome__tabs_context_mcp, mcp__playwright__navigate.

Before the leak, these names rendered verbatim in replays — long, ugly, and hard to parse visually. Now we:

  1. Detect MCP tools by the mcp__ prefix
  2. Extract server names into mcpServersUsed metadata (shown as purple badges in the dashboard)
  3. Format display names as server · tool (e.g., “claude-in-chrome · navigate”)
  4. Use a plug icon instead of the generic gear for MCP tools

On one test machine, 21 sessions used MCP tools across over 1,000 total calls — primarily claude-in-chrome (454 calls) and playwright (16 calls).


Discovery 5: service_tier and pricing validation

The usage object on assistant messages includes a service_tier field (e.g., "standard") that we’d been ignoring. We now extract it as session metadata.

More importantly, the source at src/utils/modelCost.ts contains the exact pricing tiers:

ModelInputOutputCache writeCache read
Opus 4.6/4.5$5/Mtok$25/Mtok$6.25/Mtok$0.50/Mtok
Opus 4/4.1$15/Mtok$75/Mtok$18.75/Mtok$1.50/Mtok
Sonnet 4/4.5/4.6$3/Mtok$15/Mtok$3.75/Mtok$0.30/Mtok
Haiku 4.5$1/Mtok$5/Mtok$1.25/Mtok$0.10/Mtok
Opus 4.6 fast mode$30/Mtok$150/Mtok$37.50/Mtok$3.00/Mtok

We validated our cost estimation against these exact numbers. The Sonnet 4 (non-4.5/4.6) model had been falling through to a generic rate — we added an explicit entry matching Claude Code’s COST_TIER_3_15.


What’s left to explore

The source revealed far more than we could ship in a day. Here’s what we documented for future work:

Data that exists but we haven’t seen in the wild yet:

  • api_metrics system messages with TTFT (time to first token) and tokens/sec
  • attribution-snapshot entries with character-level AI contribution tracking per file
  • speculation-accept entries showing time saved by speculative execution
  • worktree-state entries for git worktree isolation sessions
  • marble-origami-commit (context collapse) events

Viewer features that need larger work:

  • Context window utilization curve overlaid on the timeline (the data is already in turnStats.contextTokens)
  • Conversation tree visualization using parentUuid chains
  • Coordinator/worker multi-agent visualization for CLAUDE_CODE_COORDINATOR_MODE sessions

The meta observation

We’ve been parsing Claude Code’s JSONL output for months, treating it as an opaque format that we reverse-engineered from observed data. The source leak let us validate every assumption — and found several wrong ones.

The isMeta bug is a good example: we’d never noticed the skill injection messages leaking into replays because they were rare and looked vaguely plausible. Without the source telling us that isMeta: true marks system-injected content, we might never have caught it.

The full implementation is across two PRs: #116 (parser improvements, context-injection scenes, skill detection) and #119 (MCP server detection, tool name display). Both are merged.

If you want to see these improvements in action, install vibe-replay and run vibe-replay -d to open the dashboard — sessions with skills and MCP tools will now show the new badges and labels.

npx vibe-replay -d