See exactly where your Claude Code context budget goes — and why.
A tiny local web app that reads your Claude Code, Cowork, and Codex CLI session files and breaks down every token in the context window — system prompts, tool calls, tool results, framework injections, the hidden prologue, and more.
Quickstart · Features · Configuration · Privacy · Changelog
Long AI sessions drift toward their context limit silently. It usually isn't
your prompts — it's an oversized Read, a 33KB skill manifest injected on
every turn, an unused CLAUDE.md, or cache-read tokens ballooning because the
model keeps re-reading the same 60K of prologue. This tool makes that
visible, measurable, and actionable.
You won't find another viewer that tells you the model saw a 2KB preview of a 369KB tool result the JSONL didn't bother to log, that your framework overhead is 35.9% of total, or that turn 28 cost you $0.15 while the median turn cost $0.02.
- $ cost per session with full Anthropic / OpenAI prompt-caching math (Opus, Sonnet, Haiku, GPT-5.x, GPT-4.1, o-series)
- Per-turn cost badges on assistant rows so you can spot the 3 turns that dominated your bill
- Context overhead panel itemizing the explicit system prompt, skill manifest, MCP instructions, tool catalog, harness envelopes, and the inferred hidden Claude Code prologue
- Compaction timeline on the growth chart — dashed markers with
pre → posttokens and duration - Turn latency panel (median / p95 / max) from Claude Code's
turn_durationevents - Cumulative-fill mini-bars on every Detailed row, scaled to your active context window (200K / 400K / 1M / custom)
- Heaviest-blocks table — click to jump straight to the offender
- Token math uses real tiktoken throughout (no chars/4 estimates)
type:"attachment"subtypes: skill listings, MCP instructions, tool catalog, plan-mode, hook success/additional-context, todo reminders, date changes, nested memory, IDE selection, file attachments, compact file referencestype:"system"subtypes:compact_boundary,turn_duration,away_summary,local_command- Persisted-output offload — oversized tool results are loaded from disk on demand (full
.txtfile, not the 2KB preview the model saw) - Sub-agent file grouping —
subagents/files are collapsed under their parent session instead of polluting the sidebar - Tool-use ↔ tool-result linking via
sourceToolAssistantUUID(↑ / ↓ jump chips) - Permission-mode badges on user rows (plan / bypassPermissions / acceptEdits)
- Compact-file-reference rows are dimmed with a "(purged by /compact)" suffix
- Session-context chips in the header: entrypoint, version, git branch, cwd, slug
- AI-generated titles (
ai-titleevents) preferred over heuristic title peeking
- Dark mode with OS
prefers-color-schemeand persisted preference - Keyboard shortcuts —
j/ksession nav,/focus search,g s/g dswitch tabs,[/]collapse/expand,ttheme,?overlay,Escclear - URL deep links —
#session=...&tab=detailed&path=...; share a link to any block - Global content search across every session with regex + case toggles
- Live updates via file watching + Server-Sent Events — new turns appear as Claude Code writes them
- Markdown + code rendering for assistant text, ANSI colours for terminal output
- Tool-specific rendering cards for
Bash,Read,Edit/MultiEdit,Write,Glob,Grep,WebFetch,WebSearch,Task,TodoWrite,NotebookEdit - Copy block text and export session as Markdown, JSON, or standalone HTML
- Rich per-turn hover tooltip on the growth chart
pip install -r requirements.txt
python3 server.pyThat's it. The viewer opens http://127.0.0.1:8765 automatically and auto-detects the standard session directories on your OS. If you have any Claude Code, Cowork, or Codex CLI sessions on your machine, they'll appear in the sidebar.
Requirements: Python 3.9+ and tiktoken (the only dependency).
Works on macOS, Linux, and Windows (use py instead of python3 on Windows).
Auto-detected per OS:
| OS | Claude Code | Claude desktop / Cowork | Codex CLI |
|---|---|---|---|
| macOS | ~/.claude/projects |
~/Library/Application Support/Claude/local-agent-mode-sessions |
~/.codex/sessions, ~/.codex/archived_sessions |
| Linux | ~/.claude/projects |
~/.config/Claude/local-agent-mode-sessions |
~/.codex/sessions, ~/.codex/archived_sessions |
| Windows | %USERPROFILE%\.claude\projects |
%APPDATA%\Claude\local-agent-mode-sessions |
%USERPROFILE%\.codex\sessions, ...\archived_sessions |
Missing directories are skipped silently.
All three of these work. Order of precedence: CLI flag → env var → .env → built-in default.
cp .env.example .env# macOS / Linux — ':' separates multiple paths
CLAUDE_SESSIONS_PATH=~/.claude/projects:~/work/claude-archive
CODEX_SESSIONS_PATH=~/.codex/sessions
PORT=9000
HOST=127.0.0.1On Windows, use ; instead of : for multiple paths.
python3 server.py --claude /path/to/sessions # add a Claude root (repeatable)
python3 server.py --codex /path/to/sessions # add a Codex root (repeatable)
python3 server.py --port 9000
python3 server.py --host 0.0.0.0 # bind to all interfaces (careful!)
python3 server.py --no-browser # don't auto-openOn startup the server prints which .env it loaded and which directories exist, so misconfigured paths surface immediately.
JSONL session file ──► parser normalises events into a unified Block tree
│
▼
aggregates by kind, computes $, infers hidden overhead
│
▼
ThreadingHTTPServer serves index.html + JSON APIs
│
▼
vanilla-JS client renders Simple / Detailed views
Every event — user messages, assistant turns, tool calls, attachments,
system subtypes, sub-agent runs, compactions — becomes a typed Block with
kind, label, text, children, meta. The client aggregates
by kind for the Simple view and walks the tree for the Detailed view. Token
counts use tiktoken's cl100k_base encoding server-side; prices come from
a current (checked 2026-04) model → $ table.
Two files carry the whole app: server.py (~1.7K LoC) and
index.html (~3.1K LoC).
Nothing leaves your machine. The server binds to 127.0.0.1 by default,
every file read happens in the same process that serves the page, and there
are no telemetry calls, no cloud sync, no outbound network of any kind.
The only time the viewer reads a file outside your session directories is
when you click "Load full file" on a persisted tool-result — and even then
it's the file Claude Code itself wrote to your ~/.claude/... folder.
"No conversations found."
The default directories don't exist or are empty. Check with ls (or dir
on Windows) and point the viewer at the right path via .env or
--claude / --codex.
Sessions don't appear after a refresh.
Reload the page — the sidebar is cached on the server. Killing and
restarting server.py also clears it. With live updates on (the default),
new sessions should appear within ~2s of being written by Claude Code.
Very large session feels slow. The viewer caps at 20,000 events per file to stay responsive. A yellow banner in the Simple view tells you if a file got truncated.
"Output too large" on a tool_result.
That's Claude Code's own message — it persisted the real output to
<session-dir>/tool-results/<id>.txt. Expand the tool_result and click
Load full file (N KB) to read it.
Codex rollout shows a lot of meta blocks.
Codex logs include session metadata and turn boundaries alongside actual
context events. Only message, function_call, function_call_output, and
reasoning become first-class nodes; the rest collapse under meta so
nothing is silently dropped.
context-viewer/
├── server.py # HTTP server, JSONL parser, pricing, watcher, SSE
├── index.html # single-file UI (vanilla JS, CSS, dark/light themes)
├── requirements.txt # tiktoken
├── .env.example # copy to .env to override paths / host / port
└── README.md
No build step. No npm. No frameworks.
Analysis & visualization
- Estimated $ cost KPI per session with prompt-caching-aware billing (Opus / Sonnet / Haiku / GPT-5.x / GPT-4.1 / o-series)
- Per-turn cost badges on assistant rows in the Detailed view (red pill when ≥ $0.05)
- Context overhead panel itemizing explicit system prompt, framework injections (skill manifest, MCP instructions, tool catalog, harness envelopes), and the inferred hidden Claude Code prologue
- Compaction timeline markers on the growth chart with before/after token counts and duration
- Turn latency panel showing per-turn duration with median / p95 / max stats
- Rich per-turn hover tooltip on the growth chart (per-kind breakdown, cumulative, duration, compaction note)
- Cumulative-fill mini-bars on every Detailed row, scaled to the active context window
- Heaviest-blocks table is clickable — jumps straight to the block
Richer Claude Code parsing
- Parses
type:"attachment"events (skill listings, MCP instructions, tool catalog, plan-mode, hooks, todo reminders, date changes, nested memory, IDE selection, file attachments) - Parses
type:"system"subtypes:compact_boundary,turn_duration,away_summary,local_command - Handles Claude Code's persisted-output offload — oversized tool results load from disk on demand
- Sub-agent JSONL files grouped with their parent session instead of polluting the sidebar
- New
frameworkblock kind distinguishes harness-injected content from real user input - Tool-use ↔ tool-result linking via
sourceToolAssistantUUID - Permission-mode badges on user rows (plan / bypassPermissions / acceptEdits)
- Compact-file-reference rows dimmed with "(purged by /compact)" suffix
- Session-context snapshot (entrypoint, cwd, git branch, version, slug) shown as chips in the header
- AI-generated titles (
ai-titleevents) preferred over heuristic peeking - Switched to real tiktoken counts everywhere client-side (no more chars/4 estimates)
Browsing & UX
- Dark mode with OS
prefers-color-schemedetection and persisted preference - Keyboard navigation:
j/k///g s·g d/[·]/t/?/Esc - URL deep links for session / tab / specific block path
- Global content search across all sessions with regex + case toggles, debounced
- Live updates: server watches session roots and pushes events over SSE
- Copy button on every expanded block body
- Export session as Markdown, JSON, or self-contained HTML
- Context-window picker available in both Simple and Detailed views
- Markdown + inline code rendering, ANSI colours in tool results
- Tool-specific rendering cards for Bash, Read, Edit/MultiEdit, Write, Glob, Grep, WebFetch, WebSearch, Task, TodoWrite, NotebookEdit
Quality
- Hardened JSONL parser against non-string
textfields - Filters out framework-only user events (IDE file-open, interrupt markers) from turn counting
- Minimum 1px bar segment so small turns remain visible on the growth chart
- Zero-dependency local web app (Python stdlib +
tiktoken) that reads Claude Code / Cowork / Codex CLI.jsonlfiles - Normalizes wildly different event shapes into a single expandable block tree
- Simple KPI + detailed tree views with growth-over-turns chart and heaviest-block detection
- Auto-detects sessions per OS; overridable via CLI flags, env vars, or
.env
MIT. Do whatever you want with it.