Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ cython_debug/

.examples
test_output
claude-code-log-output/
.DS_Store
test/test_data/*.html
.claude-trace
Expand Down
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,28 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## [Unreleased]

### Added

- **Multi-provider session support** — Now supports sessions from 5 AI coding assistants:
- Claude Code (original)
- Codex CLI (OpenAI)
- Gemini CLI (Google)
- OpenCode
- Antigravity CLI (agy)
- **Provider abstraction layer** — Clean provider interface for adding new session sources
- **Unified session discovery** — Auto-detects sessions across all providers
- **Provider filtering in TUI** — Press `f` to cycle through providers (All → claude → codex → gemini → opencode → agy)
- **Provider badges** — Session rows show `[CLAUDE]`, `[CODEX]`, `[GEMINI]`, `[OPENCODE]`, `[AGY]` badges
- **New CLI options** — `--provider` flag (claude|codex|gemini|opencode|agy|all) and `--list-providers`
- **HTML/Markdown rendering** — Works for all providers using existing renderers

### Fixed

- **Type field on TranscriptEntry** — All entries now have required `type="user"` or `type="assistant"` field
- **Gemini parser** — Now correctly handles individual-message-per-line format (not `messages` array)

## [1.4.0] - 2026-06-03

### Changed
Expand Down
89 changes: 60 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Claude Code Log

A Python CLI tool that converts Claude Code transcript JSONL files into readable HTML and Markdown formats.
A Python CLI tool that converts AI coding assistant transcripts into readable HTML and Markdown formats.

**Supported providers:** Claude Code, Codex CLI, Gemini CLI, OpenCode, Antigravity CLI (agy)

Browser log demo:

Expand All @@ -14,28 +16,30 @@ TUI demo:

📋 **[View Changelog](CHANGELOG.md)** - See what's new in each release

This tool generates clean, minimalist HTML pages showing user prompts and assistant responses chronologically. It's designed to create a readable log of your Claude Code interactions with support for both individual files and entire project hierarchies.
This tool generates clean, minimalist HTML pages showing user prompts and assistant responses chronologically. It's designed to create a readable log of your AI coding assistant interactions with support for multiple providers (Claude Code, Codex CLI, Gemini CLI, OpenCode, Antigravity CLI) and both individual files and entire project hierarchies.

📄 **[View Example HTML Output](https://daaain.github.io/claude-code-log/example/)** - A real example generated from a sample of this project's development, regenerated on every docs build

## Quickstart

TL;DR: run the command below and browse the pages generated from your entire Claude Code archives:
TL;DR: run the command below and browse the pages generated from all your AI coding assistant archives:

```sh
uvx claude-code-log@latest --open-browser
```

## Key Features

- **Interactive TUI (Terminal User Interface)**: Browse and manage Claude Code sessions with real-time navigation, summaries, and quick actions for HTML export and session resuming
- **Project Hierarchy Processing**: Process entire `~/.claude/projects/` directory with linked index page
- **Multi-Provider Support**: Works with Claude Code, Codex CLI, Gemini CLI, OpenCode, and Antigravity CLI (agy) sessions
- **Interactive TUI (Terminal User Interface)**: Browse and manage sessions across all providers with real-time navigation, summaries, and quick actions for HTML export and session resuming
- **Provider Filtering**: Filter sessions by provider in the TUI (press `f` to cycle)
- **Project Hierarchy Processing**: Process entire project directories with linked index page
- **Individual Session Files**: Generate separate HTML files for each session with navigation links
- **Single File or Directory Processing**: Convert individual JSONL files or specific directories
- **Session Navigation**: Interactive table of contents with session summaries and quick navigation
- **Token Usage Tracking**: Display token consumption for individual messages and session totals
- **Runtime Message Filtering**: JavaScript-powered filtering to show/hide message types (user, assistant, system, tool use, etc.)
- **Chronological Ordering**: All messages sorted by timestamp across sessions
- **Chronological Ordering**: All messages sorted by timestamp across sessions and providers
- **Interactive timeline**: Generate an interactive, zoomable timeline grouped by message times to navigate conversations visually
- **Cross-Session Summary Matching**: Properly match async-generated summaries to their original sessions
- **Date Range Filtering**: Filter messages by date range using natural language (e.g., "today", "yesterday", "last week")
Expand All @@ -50,21 +54,21 @@ uvx claude-code-log@latest --open-browser

This tool helps you answer questions like:

- **"How can I review all my Claude Code conversations?"**
- **"What did I work on with Claude yesterday/last week?"**
- **"How much are my Claude Code sessions costing?"**
- **"How can I search through my entire Claude Code history?"**
- **"What tools did Claude use in this project?"**
- **"How can I share my Claude Code conversation with others?"**
- **"How can I review all my AI coding assistant conversations?"**
- **"What did I work on with [Claude/Codex/Gemini/agy] yesterday/last week?"**
- **"How much are my coding assistant sessions costing?"**
- **"How can I search through my entire coding history across all tools?"**
- **"What tools did my assistant use in this project?"**
- **"How can I share my coding conversation with others?"**
- **"What's the timeline of my project development?"**
- **"How can I analyse patterns in my Claude Code usage?"**
- **"How can I analyse patterns in my coding assistant usage?"**
- **"How can I feed a past session back to an LLM for analysis or experience building?"**

## Usage

### Interactive TUI (Terminal User Interface)

The TUI provides an interactive interface for browsing and managing Claude Code sessions with real-time navigation, session summaries, and quick actions.
The TUI provides an interactive interface for browsing and managing sessions across all supported providers with real-time navigation, session summaries, and quick actions.

```bash
# Launch TUI for all projects (default behavior)
Expand All @@ -73,36 +77,41 @@ claude-code-log --tui
# Launch TUI for specific project directory
claude-code-log /path/to/project --tui

# Launch TUI for specific Claude project
claude-code-log my-project --tui # Automatically converts to ~/.claude/projects/-path-to-my-project
# Launch TUI for specific project (auto-resolves ~/.claude/projects/ path)
claude-code-log my-project --tui
```

**TUI Features:**

- **Session Listing**: Interactive table showing session IDs, summaries, timestamps, message counts, and token usage
- **Smart Summaries**: Prioritizes Claude-generated summaries over first user messages for better session identification
- **Multi-Provider Session Listing**: Interactive table showing session IDs, provider badges, summaries, timestamps, message counts, and token usage
- **Provider Filter**: Press `f` to cycle through providers (All → Claude → Codex → Gemini → OpenCode → agy)
- **Smart Summaries**: Prioritizes assistant-generated summaries over first user messages for better session identification
- **Working Directory Matching**: Automatically finds and opens projects matching your current working directory
- **Quick Actions**:
- `h`: Generate and open session HTML in browser
- `m`: Generate and open session Markdown in browser
- `v`: View session Markdown in embedded viewer (with table of contents)
- `c`: Resume session in Claude Code with `claude -r <sessionId>`
- `c`: Resume session in its native CLI (where supported)
- `r`: Reload session data from files
- `p`: Switch to project selector view
- `H`/`M`/`V`: Force regenerate HTML/Markdown (hidden shortcuts for development)
- **Project Statistics**: Real-time display of total sessions, messages, tokens, and date range
- **Cache Integration**: Leverages existing cache system for fast loading with automatic cache validation
- **Keyboard Navigation**: Arrow keys to navigate, Enter to expand row details, `q` to quit
- **Keyboard Navigation**: Arrow keys to navigate, Enter to expand row details, `q to quit
- **Row Expansion**: Press Enter to expand selected row showing full summary, first user message, working directory, and detailed token usage

### Default Behavior (Process All Projects)

```bash
# Process all projects in ~/.claude/projects/ (default behavior)
# Process all projects across all providers (default behavior)
claude-code-log

# Explicitly process all projects
claude-code-log --all-projects
# Process all projects from a specific provider
claude-code-log --provider claude
claude-code-log --provider codex
claude-code-log --provider gemini
claude-code-log --provider opencode
claude-code-log --provider agy

# Process all projects and open in browser
claude-code-log --open-browser
Expand All @@ -113,6 +122,9 @@ claude-code-log --from-date "last week"

# Skip individual session files (only create combined transcripts)
claude-code-log --no-individual-sessions

# List available providers
claude-code-log --list-providers
```

This creates:
Expand Down Expand Up @@ -181,20 +193,39 @@ Placeholders: `{host}`, `{path}`, `{sha}`. The template fires only when the stat

## Project Hierarchy Output

When processing all projects, the tool generates:
When processing all projects, the tool generates output under each provider's data directory:

```sh
# Claude Code
~/.claude/projects/
├── index.html # Master index with project cards
├── project1/
│ ├── combined_transcripts.html # Combined project page
│ ├── session-{session-id}.html # Individual session pages
│ ├── session-{session-id}.md # Markdown version (on-demand via TUI)
│ └── session-{session-id2}.html # More session pages...
├── project2/
│ ├── combined_transcripts.html
│ └── session-{session-id}.html
└── ...

# Codex CLI
~/.codex/sessions/YYYY/MM/DD/
└── rollout-*.jsonl # Session rollout files

# Gemini CLI
~/.gemini/tmp/<project-hash>/chats/
└── session-*.jsonl # Session files

# OpenCode
~/.local/share/opencode/storage/
├── session/ # Session metadata
├── message/ # Messages per session
└── part/ # Message parts

# Antigravity CLI (agy)
~/.gemini/antigravity-cli/
├── conversations/ # SQLite databases
├── brain/<uuid>/.system_generated/logs/
│ └── transcript.jsonl # Human-readable transcript
└── history.jsonl # User input history
```

### Index Page Features
Expand All @@ -209,12 +240,12 @@ When processing all projects, the tool generates:
## Message Types Supported

- **User Messages**: Regular user inputs and prompts
- **Assistant Messages**: Claude's responses with token usage display
- **Assistant Messages**: AI responses with token usage display
- **Summary Messages**: Session summaries with cross-session matching
- **System Commands**: Commands like `init` shown in expandable details with structured parsing
- **Tool Use**: Tool invocations with collapsible details and special TodoWrite rendering
- **Tool Results**: Tool execution results with error handling
- **Thinking Content**: Claude's internal reasoning processes
- **Thinking Content**: AI's internal reasoning processes (where available)
- **Images**: Pasted images and screenshots

## HTML Output Features
Expand Down
97 changes: 95 additions & 2 deletions claude_code_log/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
get_file_extension,
get_index_filename,
process_projects_hierarchy,
generate_all_providers_index,
)
from .cache import (
CacheManager,
Expand Down Expand Up @@ -582,6 +583,11 @@ def _validate_git_link_template(template: str) -> None:
is_flag=True,
help="Process all projects in ~/.claude/projects/ hierarchy and create linked HTML files",
)
@click.option(
"--all-providers",
is_flag=True,
help="Discover sessions from ALL providers (Claude, Codex, Gemini, OpenCode, agy) and generate a unified index page",
)
@click.option(
"--no-individual-sessions",
is_flag=True,
Expand Down Expand Up @@ -716,6 +722,22 @@ def _validate_git_link_template(template: str) -> None:
"redundancy at --detail minimal."
),
)
@click.option(
"--provider",
type=click.Choice(
["claude", "codex", "gemini", "opencode", "agy", "all"], case_sensitive=False
),
default=None,
help=(
"Session provider to use. Default: auto-detect based on available ~/. directories. "
"Use 'all' to discover sessions from all providers."
),
)
@click.option(
"--list-providers",
is_flag=True,
help="List available session providers and exit.",
)
@click.option(
"--debug",
is_flag=True,
Expand All @@ -732,6 +754,7 @@ def main(
from_date: Optional[str],
to_date: Optional[str],
all_projects: bool,
all_providers: bool,
no_individual_sessions: bool,
no_cache: bool,
clear_cache: bool,
Expand All @@ -747,16 +770,31 @@ def main(
git_link: Optional[str],
no_timestamps: bool,
no_recaps: bool,
provider: Optional[str],
list_providers: bool,
debug: bool,
) -> None:
"""Convert Claude transcript JSONL files to HTML or Markdown.
"""Convert AI coding assistant transcripts to HTML or Markdown.

INPUT_PATH: Path to a Claude transcript JSONL file, directory containing JSONL files, or project path to convert. If not provided, defaults to ~/.claude/projects/ and --all-projects is used.
INPUT_PATH: Path to a transcript JSONL file, directory containing session files,
or project path to convert. If not provided, auto-discovers sessions from all
available providers (Claude Code, Codex CLI, Gemini CLI, OpenCode, agy).
Use --provider to limit to a specific provider.
"""
# Install signal-based stack dumper before any heavy work, so a hang
# can be diagnosed with `kill -USR1 <pid>` without root or restart.
_install_stack_dump_signal()

if list_providers:
from .providers import discover_providers

registry = discover_providers()
click.echo("Available session providers:")
for name in registry.get_all_providers():
status = "✓" if name in registry.get_available_providers() else "✗"
click.echo(f" {status} {name}")
return

# Custom-forge URL template: validate eagerly with a loud error,
# then pin to the env var so the resolver (which reads the env at
# render time) picks it up. Doing this at env-var level keeps the
Expand Down Expand Up @@ -1023,6 +1061,61 @@ def main(
click.launch(str(output_path))
return

# Handle --all-providers: discover from all providers and generate unified index
if all_providers:
from .providers import discover_providers

registry = discover_providers()

# Get available providers
available = registry.get_available_providers()
if not available:
click.echo(
"No providers found. Make sure at least one AI assistant is installed."
)
return

click.echo(f"Discovering sessions from providers: {', '.join(available)}")

# Collect sessions from all providers
all_sessions = []
for name in available:
provider = registry.get_provider(name)
try:
sessions = list(provider.discover_sessions())
for s in sessions:
all_sessions.append((name, s))
except Exception as e:
click.echo(f"Warning: Failed to discover {name} sessions: {e}")

if not all_sessions:
click.echo("No sessions found across any provider.")
return

click.echo(
f"Found {len(all_sessions)} total sessions across {len(available)} providers"
)

# Generate unified index
output_path = generate_all_providers_index(
all_sessions,
output_format,
output,
from_date,
to_date,
detail_level,
compact,
no_timestamps,
no_recaps,
image_export_mode,
)

click.echo(f"Successfully created unified index at {output_path}")

if open_browser:
click.launch(str(output_path))
return

# Handle default case - process all projects hierarchy if no input path and --all-projects flag
if input_path is None:
input_path = projects_dir or get_default_projects_dir()
Expand Down
Loading