Go to file
Mathias Beaulieu-Duncan 780ef9378f feat: custom native file picker showing hidden files/folders
Replaced file_picker's Load/Browse with a custom NativePickerRegistrar
Swift plugin that opens NSOpenPanel with showsHiddenFiles = true.
The file_picker package hardcodes this to false, making hidden folders
like ~/.claude invisible in its dialogs.

Changes:
- New NativePickerRegistrar.swift: custom NSOpenPanel with hidden files
- New NativePicker Dart service using method channel
- Browse: only shows folders (canChooseFiles=false), hidden visible
- Load: only shows .jsonl files, hidden folders visible
- Registered via AppDelegate.applicationDidFinishLaunching
- Removed file_picker dependency from home_screen imports
- Fixed all info-level lint issues (super params, null-aware, doc comment)
- Signed, notarized, stapled DMG
2026-04-07 14:32:06 -04:00
lib feat: custom native file picker showing hidden files/folders 2026-04-07 14:32:06 -04:00
macos feat: custom native file picker showing hidden files/folders 2026-04-07 14:32:06 -04:00
test Rename to Claude Session Analysis and prepare for Mac App Store 2026-03-12 16:57:20 -04:00
.gitignore Initial commit: Claude Code session viewer (Flutter macOS) 2026-03-10 16:17:23 -04:00
.metadata Initial commit: Claude Code session viewer (Flutter macOS) 2026-03-10 16:17:23 -04:00
analysis_options.yaml Initial commit: Claude Code session viewer (Flutter macOS) 2026-03-10 16:17:23 -04:00
LICENSE docs: add README and CC BY-NC 4.0 license 2026-04-07 13:34:42 -04:00
pubspec.lock Rename to Claude Session Analysis and prepare for Mac App Store 2026-03-12 16:57:20 -04:00
pubspec.yaml Rename to Claude Session Analysis and prepare for Mac App Store 2026-03-12 16:57:20 -04:00
README.md docs: add README and CC BY-NC 4.0 license 2026-04-07 13:34:42 -04:00

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+ Free


For Everyone

What It Does

If you use Claude 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 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<ParseError>)
→ SessionProvider caches filteredEntries
→ Screens consume via context.select<SessionProvider, T>()

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+

# 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:

# 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.

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.