# Claude Session Viewer A macOS desktop app for browsing and analyzing your Claude AI conversation sessions. Explore your prompts, assistant responses, tool usage, token consumption, and subagent activity — all in a fast, searchable interface. ![macOS 13.0+](https://img.shields.io/badge/platform-macOS%2013%2B-black) ![Free](https://img.shields.io/badge/license-CC--BY--NC--4.0-green) --- ## For Everyone ### What It Does If you use [Claude](https://claude.ai) with the CLI (`claude`), every conversation is saved as a `.jsonl` file on your Mac. **Claude Session Viewer** lets you open those files and browse them with: - **Timeline view** — See your conversation as a visual tree with user prompts, assistant responses, and tool calls all laid out chronologically - **Search & filter** — Find specific messages, filter by type (user/assistant/system), or narrow down to a specific subagent - **Tool usage analytics** — See which tools were used, how often, and with what arguments - **Token tracking** — Break down token consumption by agent (input, output, cache hits) - **Subagent inspection** — Drill into subagent conversations that were spawned during a session ### Installation 1. Download the latest `Claude Session Viewer.dmg` from the [Releases](../../releases) page 2. Double-click the DMG 3. Drag **Claude Session Viewer** to your **Applications** folder 4. Launch it — no Gatekeeper warnings, the app is signed and notarized by Apple ### Quick Start 1. Open the app 2. It automatically scans `~/.claude/projects` for your session files 3. Pick a project → pick a session → browse the timeline 4. Or use **File → Open** to load any `.jsonl` file directly ### Tips - Use the **search bar** in the timeline to find specific messages or tool calls - Click the **type toggles** (User / Assistant / System) to filter what's shown - Use the **agent dropdown** to focus on a specific subagent's activity - Expand **tool use cards** to see arguments, results, and inline subagent conversations - Expand **Thinking** blocks to see Claude's reasoning (when available) --- ## For Developers ### Architecture ``` lib/ ├── main.dart # Entry point, Provider setup ├── models/ │ ├── agent_info.dart # AgentInfo + SessionLog aggregates │ ├── content_block.dart # ContentBlock hierarchy (Text, Thinking, ToolUse, ToolResult) │ ├── log_entry.dart # LogEntry hierarchy (User, Assistant, System, Progress, FileSnapshot) │ └── token_usage.dart # TokenUsage value type ├── providers/ │ └── session_provider.dart # ChangeNotifier with cached filtering + debounced search ├── services/ │ └── jsonl_parser.dart # Isolate-based JSONL parser + session builder ├── screens/ │ ├── home/ # Project/session browser (scans ~/.claude/projects) │ ├── timeline/ # Flat virtualized timeline with tree connectors │ ├── agents/ # Agent analytics cards │ ├── tokens/ # Token usage dashboard (pie chart + data table) │ └── toolbelt/ # Tool usage bar chart + per-tool details ├── theme/ │ └── app_theme.dart # Dark theme + color constants └── widgets/ ├── common/ # ExpandableCard (lazy expand), JsonTreeView └── navigation/ # AppShell (IndexedStack), Sidebar ``` ### Data Flow ``` FilePicker → SessionProvider.loadSession() → Isolate.run(JsonlParser._parseInIsolate) # CPU work off main thread → jsonDecode per line + LogEntry.fromJson → _linkToolResults() + _buildAgents() → ParseResult(SessionLog, List) → SessionProvider caches filteredEntries → Screens consume via context.select() ``` ### Key Design Decisions | Decision | Rationale | |----------|-----------| | **Single ChangeNotifier** | App has one data source (a session file). No need for Riverpod/Bloc complexity. | | **Isolate-based parsing** | 50K-line JSONL files parse in 2-4s — must not block the UI thread. | | **Flat virtualized timeline** | Flattened turns into `List<_TimelineItem>` so `ListView.builder` recycles every card independently. | | **Cached filter results** | `_FilterKey`-based invalidation avoids O(n) recomputation on every rebuild. | | **Lazy ExpandableCard** | `AnimatedCrossFade` builds both children eagerly. Replaced with `SizeTransition` + `_hasBeenExpanded` guard. | | **IndexedStack navigation** | Preserves scroll position and state across tab switches. | | **No code generation** | 17 source files, single-user tool — hand-written `fromJson` is fine. | ### Building from Source **Requirements:** Flutter 3.29+ / Dart 3.10+, macOS 13.0+, Xcode 16+ ```bash # Clone git clone https://github.com/your-org/claude_session_viewer.git cd claude_session_viewer # Install dependencies flutter pub get # Run in debug mode flutter run -d macos # Build release flutter build macos --release ``` ### Building a Signed & Notarized DMG The project is pre-configured for Developer ID distribution. Set your team ID in `macos/Runner.xcodeproj/project.pbxproj` and `macos/Runner/Configs/AppInfo.xcconfig`, then: ```bash # Build flutter build macos --release # Re-sign with hardened runtime (inside-out) APP="build/macos/Build/Products/Release/Claude Session Viewer.app" SIGN_ID="Developer ID Application: Your Name (TEAMID)" find "$APP/Contents/Frameworks" -name "*.framework" -maxdepth 1 | while read fw; do codesign --force --deep --sign "$SIGN_ID" --timestamp --options runtime \ --entitlements macos/Runner/Release.entitlements "$fw" done codesign --force --deep --sign "$SIGN_ID" --timestamp --options runtime \ --entitlements macos/Runner/Release.entitlements "$APP" # Create DMG hdiutil create -volname "Claude Session Viewer" \ -srcfolder "$APP" -ov -format UDZO \ "build/Claude Session Viewer.dmg" # Sign DMG codesign --sign "$SIGN_ID" --timestamp "build/Claude Session Viewer.dmg" # Notarize xcrun notarytool submit "build/Claude Session Viewer.dmg" \ --keychain-profile "notarytool" --wait # Staple ticket xcrun stapler staple "build/Claude Session Viewer.dmg" ``` ### Dependencies | Package | Purpose | |---------|---------| | `provider` | State management (ChangeNotifier) | | `file_picker` | Native file picker dialog | | `flutter_markdown` | Markdown rendering in assistant messages | | `fl_chart` | Pie chart (tokens) + bar chart (tool usage) | | `google_fonts` | Inter font family | | `intl` | Number/date formatting | ### Entitlements (macOS Sandbox) The release build runs in the macOS **App Sandbox** with: - `com.apple.security.app-sandbox` — enabled - `com.apple.security.files.user-selected.read-only` — open files via dialog - `com.apple.security.files.home-directory.read-only` — scan `~/.claude/projects` ### Contributing Contributions are welcome! Please: 1. Fork the repository 2. Create a feature branch (`git checkout -b feature/my-feature`) 3. Commit your changes 4. Open a pull request Note: This project is **non-commercial** — contributions must respect the CC BY-NC 4.0 license. --- ## License This project is licensed under [Creative Commons Attribution-NonCommercial 4.0 International](./LICENSE). You are free to use, modify, and distribute this software for personal and non-commercial purposes. Commercial use, resale, or monetization is not permitted without written permission. © 2026 Svrnty. All rights reserved.