Skip to content

feat: Add multi-provider session viewer support (Codex, Gemini, OpenCode, agy)#225

Open
iansherr wants to merge 1 commit into
daaain:mainfrom
iansherr:main
Open

feat: Add multi-provider session viewer support (Codex, Gemini, OpenCode, agy)#225
iansherr wants to merge 1 commit into
daaain:mainfrom
iansherr:main

Conversation

@iansherr

@iansherr iansherr commented Jun 20, 2026

Copy link
Copy Markdown

Summary

This PR extends claude-code-log from a Claude Code-only viewer into a multi-provider session viewer that supports 5 AI coding tools: Claude Code, Codex CLI, Gemini CLI, OpenCode, and Antigravity CLI (agy).

What Changed

Provider Abstraction Layer

  • New providers/base.py — abstract BaseProvider with discover_sessions() and load_session() interfaces
  • New providers/registry.py — auto-discovery and management of providers based on ~/. directories
  • 5 concrete adapters: claude.py, codex.py, gemini.py, opencode.py, agy.py

CLI & TUI

  • --provider <name> — filter to a specific provider
  • --list-providers — show which providers are available
  • --all-providers — generate unified cross-provider index
  • TUI provider filter (f key cycles through providers)

All-Providers Unified Index

  • Generates a single index.html across all providers with session counts, provider badges
  • Full-text search across all sessions (content previews loaded via max_messages=10)
  • Clicking a search result navigates to the individual session HTML file with auto-search triggered via #search= URL hash
  • Session cards link directly to individual HTML files

Bug Fixes

  • Fixed search next/prev buttons on index page (was trying to scroll to non-existent highlights)
  • Fixed navigateToMatch to handle index page context correctly
  • Fixed provider badge CSS for all-providers layout

Provider Notes

  • agy: Reads brain/<uuid>/.system_generated/logs/transcript.jsonl (not protobuf SQLite) — binary blobs in conversations/*.db are not human-readable
  • OpenCode: Reads sharded JSON format (session/*.json, message/{id}/*.json)
  • Gemini: Extracts from logs/*.ndjson with CLI command extraction
  • All providers support max_messages for preview loading

Default Output Directory

  • Changed default output from ./claude-code-log-output to ~/.local/agent_log_viewer/
  • Keeps generated files out of project directories, follows XDG convention
  • --output flag still works as before

Testing

  • 2059 unit tests passing
  • 8 snapshot tests updated (search template changes)
  • Format/lint clean (ruff)
  • Pyright: 274 pre-existing errors (no regressions)

Scope Note

This is a substantial feature addition. I started with a fork of daaain/claude-code-log (MIT licensed) and extended it with the provider abstraction. The original Claude Code functionality is fully preserved — new providers are additive.

I'm happy to continue working on this (there are more polish items I'd like to address), but wanted to share the progress in case you'd like to review or have preferences on direction.

The output directory change is included here as a separate commit for easy extraction if you'd prefer it as a standalone PR.

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 156 files, which is 6 over the limit of 150.

To get a review, narrow the scope:
• coderabbit review --type committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

Upgrade to a paid plan to raise the limit.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1a3f8a6c-12b7-45e0-ad25-fd27527a5a14

📥 Commits

Reviewing files that changed from the base of the PR and between f4f743d and f0d148a.

📒 Files selected for processing (156)
  • .gitignore
  • CHANGELOG.md
  • README.md
  • claude_code_log/cli.py
  • claude_code_log/converter.py
  • claude_code_log/discovery.py
  • claude_code_log/html/templates/all_providers_index.html
  • claude_code_log/html/templates/components/search.html
  • claude_code_log/providers/__init__.py
  • claude_code_log/providers/agy.py
  • claude_code_log/providers/base.py
  • claude_code_log/providers/claude.py
  • claude_code_log/providers/codex.py
  • claude_code_log/providers/gemini.py
  • claude_code_log/providers/opencode.py
  • claude_code_log/providers/registry.py
  • claude_code_log/tui.py
  • docs/changelog.md
  • docs/changelog.md
  • docs/contributing.md
  • docs/contributing.md
  • docs/development
  • docs/development/agents.md
  • docs/development/application_model.md
  • docs/development/css-classes.md
  • docs/development/dag.md
  • docs/development/implementing-a-tool-renderer.md
  • docs/development/message-hierarchy.md
  • docs/development/messages.md
  • docs/development/messages/assistant/assistant.json
  • docs/development/messages/assistant/assistant.jsonl
  • docs/development/messages/assistant/assistant_sidechain.json
  • docs/development/messages/assistant/assistant_sidechain.jsonl
  • docs/development/messages/assistant/thinking.json
  • docs/development/messages/assistant/thinking.jsonl
  • docs/development/messages/system/file_history_snapshot.json
  • docs/development/messages/system/file_history_snapshot.jsonl
  • docs/development/messages/system/queue_operation.json
  • docs/development/messages/system/queue_operation.jsonl
  • docs/development/messages/system/summary.json
  • docs/development/messages/system/summary.jsonl
  • docs/development/messages/system/system_info.json
  • docs/development/messages/system/system_info.jsonl
  • docs/development/messages/tools/AskUserQuestion-tool_result.json
  • docs/development/messages/tools/AskUserQuestion-tool_result.jsonl
  • docs/development/messages/tools/AskUserQuestion-tool_result_error.json
  • docs/development/messages/tools/AskUserQuestion-tool_result_error.jsonl
  • docs/development/messages/tools/AskUserQuestion-tool_use.json
  • docs/development/messages/tools/AskUserQuestion-tool_use.jsonl
  • docs/development/messages/tools/Bash-tool_result.json
  • docs/development/messages/tools/Bash-tool_result.jsonl
  • docs/development/messages/tools/Bash-tool_result_error.json
  • docs/development/messages/tools/Bash-tool_result_error.jsonl
  • docs/development/messages/tools/Bash-tool_use.json
  • docs/development/messages/tools/Bash-tool_use.jsonl
  • docs/development/messages/tools/BashOutput-tool_result.json
  • docs/development/messages/tools/BashOutput-tool_result.jsonl
  • docs/development/messages/tools/BashOutput-tool_use.json
  • docs/development/messages/tools/BashOutput-tool_use.jsonl
  • docs/development/messages/tools/Edit-tool_result.json
  • docs/development/messages/tools/Edit-tool_result.jsonl
  • docs/development/messages/tools/Edit-tool_result_error.json
  • docs/development/messages/tools/Edit-tool_result_error.jsonl
  • docs/development/messages/tools/Edit-tool_use.json
  • docs/development/messages/tools/Edit-tool_use.jsonl
  • docs/development/messages/tools/ExitPlanMode-tool_result.json
  • docs/development/messages/tools/ExitPlanMode-tool_result.jsonl
  • docs/development/messages/tools/ExitPlanMode-tool_result_error.json
  • docs/development/messages/tools/ExitPlanMode-tool_result_error.jsonl
  • docs/development/messages/tools/ExitPlanMode-tool_use.json
  • docs/development/messages/tools/ExitPlanMode-tool_use.jsonl
  • docs/development/messages/tools/Glob-tool_result.json
  • docs/development/messages/tools/Glob-tool_result.jsonl
  • docs/development/messages/tools/Glob-tool_use.json
  • docs/development/messages/tools/Glob-tool_use.jsonl
  • docs/development/messages/tools/Grep-tool_result.json
  • docs/development/messages/tools/Grep-tool_result.jsonl
  • docs/development/messages/tools/Grep-tool_use.json
  • docs/development/messages/tools/Grep-tool_use.jsonl
  • docs/development/messages/tools/KillShell-tool_result.json
  • docs/development/messages/tools/KillShell-tool_result.jsonl
  • docs/development/messages/tools/KillShell-tool_result_error.json
  • docs/development/messages/tools/KillShell-tool_result_error.jsonl
  • docs/development/messages/tools/KillShell-tool_use.json
  • docs/development/messages/tools/KillShell-tool_use.jsonl
  • docs/development/messages/tools/LS-tool_result.json
  • docs/development/messages/tools/LS-tool_result.jsonl
  • docs/development/messages/tools/LS-tool_use.json
  • docs/development/messages/tools/LS-tool_use.jsonl
  • docs/development/messages/tools/MultiEdit-tool_result.json
  • docs/development/messages/tools/MultiEdit-tool_result.jsonl
  • docs/development/messages/tools/MultiEdit-tool_result_error.json
  • docs/development/messages/tools/MultiEdit-tool_result_error.jsonl
  • docs/development/messages/tools/MultiEdit-tool_use.json
  • docs/development/messages/tools/MultiEdit-tool_use.jsonl
  • docs/development/messages/tools/Read-tool_result.json
  • docs/development/messages/tools/Read-tool_result.jsonl
  • docs/development/messages/tools/Read-tool_result_error.json
  • docs/development/messages/tools/Read-tool_result_error.jsonl
  • docs/development/messages/tools/Read-tool_use.json
  • docs/development/messages/tools/Read-tool_use.jsonl
  • docs/development/messages/tools/Task-tool_result.json
  • docs/development/messages/tools/Task-tool_result.jsonl
  • docs/development/messages/tools/Task-tool_use.json
  • docs/development/messages/tools/Task-tool_use.jsonl
  • docs/development/messages/tools/TodoWrite-tool_result.json
  • docs/development/messages/tools/TodoWrite-tool_result.jsonl
  • docs/development/messages/tools/TodoWrite-tool_use.json
  • docs/development/messages/tools/TodoWrite-tool_use.jsonl
  • docs/development/messages/tools/WebFetch-tool_result.json
  • docs/development/messages/tools/WebFetch-tool_result.jsonl
  • docs/development/messages/tools/WebFetch-tool_use.json
  • docs/development/messages/tools/WebFetch-tool_use.jsonl
  • docs/development/messages/tools/WebSearch-tool_result.json
  • docs/development/messages/tools/WebSearch-tool_result.jsonl
  • docs/development/messages/tools/WebSearch-tool_use.json
  • docs/development/messages/tools/WebSearch-tool_use.jsonl
  • docs/development/messages/tools/Write-tool_result.json
  • docs/development/messages/tools/Write-tool_result.jsonl
  • docs/development/messages/tools/Write-tool_result_error.json
  • docs/development/messages/tools/Write-tool_result_error.jsonl
  • docs/development/messages/tools/Write-tool_use.json
  • docs/development/messages/tools/Write-tool_use.jsonl
  • docs/development/messages/tools/exit_plan_mode-tool_result.json
  • docs/development/messages/tools/exit_plan_mode-tool_result.jsonl
  • docs/development/messages/tools/exit_plan_mode-tool_use.json
  • docs/development/messages/tools/exit_plan_mode-tool_use.jsonl
  • docs/development/messages/user/bash_input.json
  • docs/development/messages/user/bash_input.jsonl
  • docs/development/messages/user/bash_output.json
  • docs/development/messages/user/bash_output.jsonl
  • docs/development/messages/user/command_output.json
  • docs/development/messages/user/command_output.jsonl
  • docs/development/messages/user/image.json
  • docs/development/messages/user/image.jsonl
  • docs/development/messages/user/user.json
  • docs/development/messages/user/user.jsonl
  • docs/development/messages/user/user_command.json
  • docs/development/messages/user/user_command.jsonl
  • docs/development/messages/user/user_sidechain.json
  • docs/development/messages/user/user_sidechain.jsonl
  • docs/development/messages/user/user_slash_command.json
  • docs/development/messages/user/user_slash_command.jsonl
  • docs/development/plugins.md
  • docs/development/rendering-architecture.md
  • docs/development/teammates.md
  • docs/development/workflows.md
  • test/__snapshots__/test_snapshot_html.ambr
  • test/fixtures/codex/sample-session.jsonl
  • test/fixtures/gemini/session-sample.jsonl
  • test/fixtures/opencode/message/test-session/msg-001.json
  • test/fixtures/opencode/message/test-session/msg-002.json
  • test/fixtures/opencode/part/msg-001/part-001.json
  • test/fixtures/opencode/part/msg-002/part-002.json
  • test/fixtures/opencode/session/test-project/test-session.json
  • test/test_providers.py

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Extend claude-code-log from a Claude Code-only viewer into a
multi-provider session viewer supporting 5 AI coding tools:
Claude Code, Codex CLI, Gemini CLI, OpenCode, and Antigravity CLI (agy).

Provider abstraction:
- BaseProvider ABC with discover_sessions() and load_session()
- ProviderRegistry for auto-discovery based on ~/. directories
- 5 concrete adapters with max_messages support for previews

CLI & TUI:
- --provider <name> to filter to a specific provider
- --list-providers to show available providers
- --all-providers to generate unified cross-provider index
- TUI provider filter (f key cycles through providers)

All-providers unified index:
- Single index.html across all providers with session counts/badges
- Full-text search across all 883 sessions via hidden data div
- Click search result → navigate to session HTML with #search= hash
- Individual session HTML files generated during index build

Bug fixes:
- Search next/prev buttons on index page (navigateToMatch)
- Provider badge CSS for all-providers layout

Default output directory:
- Changed from ./claude-code-log-output to ~/.local/agent_log_viewer/
- Keeps generated files out of project directories (XDG convention)
@daaain

daaain commented Jun 21, 2026

Copy link
Copy Markdown
Owner

Wow, this is incredible, thanks a lot for taking the time implementing and submitting!

I opened an issue to discuss on a higher level, would appreciate your insights having already done this implementation: #226

@iansherr

Copy link
Copy Markdown
Author

Thanks! Happy to see you're excited. Just responded in the issue discussion. Meantime, I'm going to keep tinkering with the fork, just because there are some other elements I've been itching for, like parallel processing from your todo list. I'll keep them as separate worktrees as much as possible so it's easy to pick and choose merges however you move forward.

@cboos

cboos commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Hello Ian, this looks indeed promising. However, it seems your branch had some trouble with the symlink in the docs (docs/development), bringing in a lot of unrelated (and outdated?) changes in. As a result, CodeRabbit went back to its burrow... Can you try to tidy this up a bit, so that only the relevant changes are included?

Also: Pyright: 274 pre-existing errors - this is also concerning... I wonder why, as main is "clean" in that respect.

@cboos

cboos commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

(Claude) Thanks for this — it's an ambitious contribution and the multi-provider direction is compelling. The core abstraction is well-placed: BaseProvider adapting each format into the existing TranscriptEntry model means the whole downstream pipeline (DAG, factories, rendering) is reused unchanged. A few things would need addressing before this can land, plus a fidelity question.

Type checking — fails the pyright CI gate

uv run pyright reports 274 errors, all in the new/changed code (≈223 across the provider adapters, 40 in the new generate_all_providers_index functions, ~10 in the CLI block); the pre-existing code is clean. They're mostly loose typing — untyped JSON access (entry.get(...) into bare dict/list), tool_calls: list without an element type, and one reportPrivateUsage (registry._provider_classes accessed outside the class). just ci runs pyright as a gate, so this currently makes CI red. The tests do pass, but the type gate doesn't.

Docs symlinks got replaced with copies

docs/development, docs/changelog.md, and docs/contributing.md are symlinks in the repo (to dev-docs/, CHANGELOG.md, CONTRIBUTING.md). This PR replaces them with ~5000 lines of copied files, which will silently drift from their sources. This looks like a checkout artifact (e.g. a Windows clone materializing symlinks) rather than an intentional change — worth restoring the symlinks.

Shared index template

The all-providers search support modifies the shared index-page JavaScript rather than isolating it, so the standard (Claude-only) index now carries the extra code too. Behavior is preserved (the new branches are inert without provider data), but it's worth being aware the change isn't fully isolated.

Real-data test of the agy adapter

Tested against a real Antigravity CLI session. It renders and reads coherently — good. Two fidelity gaps surfaced:

  1. Flat DAG. Every entry is created with parentUuid=None, so the DAG builder logs N roots found (N-1 unexpected), walking all from earliest and renders a flat list — none of the structured rendering (tool cards, threading, nesting) engages. Threading entries sequentially (each entry's parentUuid = the previous one's uuid) would let the existing renderer do much more.

  2. Dropped entry types. _parse_entry only handles USER_INPUT, PLANNER_RESPONSE, CHECKPOINT, and LIST_DIRECTORY. GENERIC, RUN_COMMAND, VIEW_FILE, and CODE_ACTION fall through and are silently skipped — in one real ~47-entry session that dropped 19 entries (~40%), including all command output, file views, and code edits. You see the planner's narration and tool-call invocations, but not the tool results. Either mapping these to tool_use/tool_result pairs or at least emitting them as text would preserve the content; a warning on unrecognized types would also help.

Suggestion

The abstraction is the right shape, but with 5 adapters at once (each a flat, lossy MVP) this is a lot to land and verify together. It might be smoother to land the abstraction plus one fully-realized provider — properly typed, threading entries, and modeling tool calls/results — as the quality bar, then add the others incrementally against that template.

@cboos

cboos commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

(Claude) One more, found while testing the CLI end-to-end: the --provider <name> option is a no-op. It's declared (a click.Choice of claude/codex/gemini/opencode/agy/all) and documented ("Use --provider to limit to a specific provider"), but main() never branches on the provider argument — only --list-providers and --all-providers are actually wired. So --provider agy (or any single-provider value) is silently ignored and falls through to the default Claude path. Either wire it to a single-provider discover+render, or drop the option so it isn't an advertised flag that does nothing.

(Minor, and likely not worth chasing given the data is old: on a real multi-provider system the codex and gemini adapters report as available — is_available() only checks that the top-level dir exists — but discover zero sessions, silently, because their assumed on-disk layout doesn't match the real one, e.g. codex walks sessions/<year>/<month>/<day>/rollout-*.jsonl while an actual session can sit flat in sessions/. A discovery that finds nothing under an "available" provider could at least warn.)

@cboos

cboos commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

(Claude) Related gap: --all-providers / --provider should compose with the path-output flags (--expand-paths / --filter-path, i.e. "Obsidian mode") the way --all-projects does — currently they don't. generate_all_providers_index doesn't accept those params, so they're silently ignored under --all-providers; and passing --all-providers --all-projects together doesn't help because the all_providers branch returns before the all_projects one. (Worth deciding what path-filtering means for non-Claude providers, whose sessions aren't organized by project path.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants