8fddd501935ac7b43ff0395b582d708b4d48bfb6
Rewrite session discovery to be filesystem-first, addressing the widespread bug where Claude Code's sessions-index.json files are unreliable (87 MB of unindexed sessions, 17% loss rate across all projects). Architecture: Three-tier metadata lookup Tier 1 - Index validation (instant): - Parse sessions-index.json into Map<sessionId, IndexEntry> - Validate entry.modified against actual file stat.mtimeMs - Use 1s tolerance to account for ISO string → filesystem mtime rounding - Trust content fields only (messageCount, summary, firstPrompt) - Timestamps always come from fs.stat, never from index Tier 2 - Persistent cache hit (instant): - Check MetadataCache by (filePath, mtimeMs, size) - If match, use cached metadata - Survives server restarts Tier 3 - Full JSONL parse (~5-50ms/file): - Call extractSessionMetadata() with shared parser helpers - Cache result for future lookups Key correctness guarantees: - All .jsonl files appear regardless of index state - SessionEntry timestamps always from fs.stat (list ordering never stale) - Message counts exact (shared helpers ensure parser parity) - Duration computed from JSONL timestamps, not index Performance: - Bounded concurrency: 32 concurrent operations per project - mapWithLimit() prevents file handle exhaustion - Warm start <1s (stat all files, in-memory lookups) - Cold start ~3-5s for 3,103 files (stat + parse phases) TOCTOU handling: - Files that disappear between readdir and stat: silently skipped - Files that disappear between stat and read: silently skipped - File actively being written: partial parse handled gracefully Include PRD document that drove this implementation with detailed requirements, edge cases, and verification plan. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Session Viewer
Browse, filter, redact, and export Claude Code sessions as self-contained HTML files.
Session Viewer reads session data from ~/.claude/projects/ and presents it in a dark-themed web interface with full-text search, message filtering, sensitive data redaction, and one-click HTML export.
Quick Start
# Install dependencies
npm install
# Run in development mode (starts both server and client with hot reload)
npm run dev
# Or run from the CLI entry point (opens browser automatically)
node bin/session-viewer.js
The API server runs on http://localhost:3848 and the Vite dev server on http://localhost:3847 (proxying API requests to the backend).
Features
Session Navigation
- Project grouping -- Sessions are organized by their originating project directory.
- Session metadata -- Each session displays its summary, first prompt, message count, duration, and last-modified date.
- Sorted by recency -- Most recently modified sessions appear first.
Message Display
- Nine message categories --
user_message,assistant_text,thinking,tool_call,tool_result,system_message,hook_progress,file_snapshot, andsummary, each with a distinct color indicator. - Collapsible sections -- Thinking blocks, tool calls, and tool results collapse by default to reduce noise.
- Diff rendering -- Git-style diffs are auto-detected and rendered with line-level syntax coloring.
- Code blocks -- Fenced code blocks display a language label and a copy-to-clipboard button.
- Time gap indicators -- Gaps of more than five minutes between messages are shown as labeled dividers.
- Hash anchor links -- Each message has a copyable anchor link (
#msg-{uuid}) for deep linking.
Search
- Full-text search across message content and tool input.
- Match cycling -- Navigate between matches with
Enter/Shift+EnterorCtrl+G/Ctrl+Shift+G. - Match counter -- Displays current position and total matches (e.g., "3/12").
- Minimap -- A scrollbar overlay shows match positions as yellow ticks with a viewport indicator. Click a tick to jump to that match.
- Dimming -- Non-matching messages are visually dimmed while search is active.
- Keyboard shortcut -- Press
/to focus the search bar;Escapeto clear and blur.
Filtering
- Category toggles -- Show or hide any of the nine message categories. Thinking and hook progress are hidden by default.
- Filters compose with search -- Category filters and search operate independently.
Redaction
- Manual redaction -- Click the eye icon on any message to select it, then confirm to redact. Redacted messages are replaced by a visual divider.
- Auto-redaction -- Toggle automatic detection of sensitive data (API keys, tokens, secrets, PII) using 37 regex patterns derived from gitleaks. Matching content is replaced with
[REDACTED]inline. - Export-aware -- Both manual and auto-redaction states are respected during export.
Export
- Self-contained HTML -- Export the current session view as a standalone HTML file with embedded CSS and syntax highlighting.
- Respects filters -- The export includes only visible messages and applies the current redaction state.
- Clean filenames -- Output files are named
session-{id}.htmlwith sanitized IDs.
Architecture
src/
client/ React + Vite frontend
components/ UI components (SessionList, SessionViewer, MessageBubble, etc.)
hooks/ useSession, useFilters
lib/ Markdown rendering, sensitive redactor, types, utilities
styles/ CSS custom properties, Tailwind, design tokens
server/ Express backend
routes/ /api/sessions, /api/export
services/ Session discovery, JSONL parser, HTML exporter
shared/ Types shared between client and server
bin/ CLI entry point
tests/
unit/ Vitest unit tests
e2e/ Playwright end-to-end tests
fixtures/ Test data
Tech Stack
| Layer | Technology |
|---|---|
| Frontend | React 18, Tailwind CSS, Vite |
| Backend | Express 4, Node.js |
| Markdown | marked + marked-highlight + highlight.js |
| Testing | Vitest (unit), Playwright (e2e) |
| Language | TypeScript (strict mode) |
API Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /api/health |
Health check |
| GET | /api/sessions |
List all sessions (30s server cache) |
| GET | /api/sessions/:id |
Get session detail with parsed messages |
| POST | /api/export |
Generate self-contained HTML export |
Scripts
| Script | Description |
|---|---|
npm run dev |
Start server + client with hot reload |
npm run build |
TypeScript compile + Vite production build |
npm run test |
Run unit tests (Vitest) |
npm run test:e2e |
Run end-to-end tests (Playwright) |
npm run typecheck |
TypeScript type checking |
npm run lint |
ESLint |
Configuration
| Variable | Default | Description |
|---|---|---|
PORT |
3848 |
API server port |
SESSION_VIEWER_OPEN_BROWSER |
unset | Set to 1 to auto-open browser on start |
Security
- Path traversal protection -- Session discovery validates all paths stay within
~/.claude/projects/. - HTML escaping -- All user content is escaped before interpolation in exports.
- Filename sanitization -- Export filenames strip non-alphanumeric characters.
- Localhost binding -- Both the API server and Vite dev server bind to
127.0.0.1only.
Description
Languages
TypeScript
84.7%
HTML
8.8%
CSS
5%
JavaScript
1.5%