Skip to content

feat: add --session-id flag for exporting a single #103

Open
chloelee767 wants to merge 7 commits intodaaain:mainfrom
chloelee767:claude/add-conversation-export-cli-deIod
Open

feat: add --session-id flag for exporting a single #103
chloelee767 wants to merge 7 commits intodaaain:mainfrom
chloelee767:claude/add-conversation-export-cli-deIod

Conversation

@chloelee767
Copy link

@chloelee767 chloelee767 commented Mar 13, 2026

Hello, this is a PR to propose adding a --session-id flag to allow exporting a single conversation by session ID.

Sample usage:

claude-code-log ~/.claude/projects/-path-to-project -o conversation.md -f md --session-id 73158d47-d83c-4f61-bca4-d62532664301

# just using the prefix is also supported
claude-code-log ~/.claude/projects/-path-to-project -o conversation.md -f md --session-id 73158d47

Summary by CodeRabbit

  • New Features

    • New --session-id CLI option to export a single session (supports short-prefix matching) and optionally open the result in your browser.
    • Improved session title generation for clearer filenames and headings.
  • Bug Fixes / Robustness

    • Better handling of invalid inputs and clearer error responses for session lookup and export.
  • Tests

    • Added comprehensive tests for single-session export, session ID resolution, output paths, formats, and error cases.

claude and others added 4 commits March 12, 2026 02:04
Adds a new `--session-id` option to the CLI that exports a single
conversation to HTML or Markdown without launching the TUI. Supports
full session IDs and 8-char short prefixes, including archived sessions.

https://claude.ai/code/session_01S99zF7j4LnfKCqbvyCXJV5
Tests cover input validation, session ID resolution (exact/prefix/ambiguous),
output path logic, no-cache mode, and session title generation from cache metadata.

https://claude.ai/code/session_01Gbx7zBdyjKkQq8frBfcP5M
@coderabbitai
Copy link

coderabbitai bot commented Mar 13, 2026

📝 Walkthrough

Walkthrough

Adds a session-based export flow: a new --session-id CLI option routes to generate_single_session_file, which resolves session IDs (exact or prefix), derives session titles, renders a single-session output file, writes it to disk, and returns early from the multi-project export path. Tests added.

Changes

Cohort / File(s) Summary
CLI Session Export Integration
claude_code_log/cli.py
Added --session-id option to main, validate/normalize input_path, import and invoke generate_single_session_file, print result and optionally open browser, and return early to skip multi-project flow.
Session Export Core Logic
claude_code_log/converter.py
Added build_session_title helper and generate_single_session_file (appears duplicated in patch). Handles cache init, loading transcripts, session ID resolution (exact or unique prefix), archived session loading, title derivation (summary / preview / fallback), rendering, and writing output.
TUI Title Centralization
claude_code_log/tui.py
Replaced inline per-session title derivation with centralized build_session_title import and call.
CLI Tests
test/test_cli.py
Added tests for --session-id behavior (missing path, full ID, short-prefix resolution, non-existent IDs, output path) and extended error-handling tests (invalid format, empty project, malformed JSONL).
Session Export Unit Tests
test/test_session_export.py
New comprehensive tests for generate_single_session_file: input validation, exact/short/ambiguous ID resolution, output path defaults/overrides and format extension handling, no-cache generation, session title derivation cases, and supporting test fixtures/utilities using isolated project dirs and cache env var.

Sequence Diagram(s)

sequenceDiagram
    participant User as User/CLI
    participant CLI as claude_code_log/cli.py
    participant Converter as claude_code_log/converter.py
    participant Cache as Cache System
    participant FS as File System
    participant Renderer as Renderer

    User->>CLI: Invoke CLI with --session-id
    CLI->>CLI: Validate/normalize input_path
    CLI->>Converter: generate_single_session_file(format, input_path, session_id, output, use_cache, image_mode)
    Converter->>FS: Load project transcripts (JSONL)
    Converter->>Converter: Resolve session_id (exact or prefix)
    alt use_cache
        Converter->>Cache: Load archived session metadata
        Cache-->>Converter: Session cache/meta
    end
    Converter->>Converter: build_session_title(project_title, session_id, session_cache)
    Converter->>Renderer: Render session content to format
    Renderer-->>Converter: Rendered bytes/text
    Converter->>FS: Write output file
    FS-->>Converter: Output path
    Converter-->>CLI: Return output path
    CLI->>User: Print success message (and optionally open browser)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped through logs to find one thread,
A prefix, a title, a file to be fed.
Cache and renderer, a tidy small run,
Tests hold my paws steady — export is done.
🎉🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main feature being added: a new --session-id flag for exporting a single session, which is the primary change across all modified files.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
claude_code_log/cli.py (1)

548-690: ⚠️ Potential issue | 🟡 Minor

Add explicit conflict checks for --session-id combinations.

--session-id can be silently ignored when combined with --tui (and is ambiguous with --all-projects). Fail fast with a clear CLI error.

Suggested fix
     try:
+        if session_id is not None and tui:
+            click.echo("Error: --session-id cannot be used with --tui", err=True)
+            sys.exit(1)
+        if session_id is not None and all_projects:
+            click.echo("Error: --session-id cannot be used with --all-projects", err=True)
+            sys.exit(1)
+
         # Handle TUI mode
         if tui:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@claude_code_log/cli.py` around lines 548 - 690, The CLI currently allows
--session-id to be combined with conflicting flags (tui, all_projects) and may
silently ignore session_id; add an explicit conflict check early in the command
handler: if session_id is not None and tui is True or session_id is not None and
all_projects is True, raise a clear click.UsageError or echo an error and
sys.exit(1) so the command fails fast; update the top of the TUI/argument
handling (near variables session_id, tui, all_projects) to validate these
combinations before any project discovery/convert_project_path_to_claude_dir or
generate_single_session_file calls, listing the conflicting flags in the
message.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@claude_code_log/converter.py`:
- Around line 1680-1733: Single-session export currently passes raw
session_messages to renderer.generate_session and skips the deduplication step
used by the main export flow; locate the deduplication helper used elsewhere in
the codebase (e.g., dedupe_session_entries / deduplicate_messages / similar) and
apply it to session_messages (or via cache_manager if that provides dedupe)
before calling renderer.generate_session so duplicates/stutter are removed while
preserving existing use of session_messages, matched_id, session_title and
cache_manager.
- Around line 1640-1643: The code currently constructs cache_manager =
CacheManager(input_path, get_library_version()) when use_cache is true, but that
will raise and abort the export if CacheManager initialization fails (DB
lock/corruption/permission); wrap the CacheManager(...) call in a try/except
that catches Exception, logs the error (include exception details) and falls
back to disabling cache by setting cache_manager = None (and optionally set
use_cache = False) so the export proceeds without cache; reference the
CacheManager constructor call and the cache_manager variable when making this
change.

---

Outside diff comments:
In `@claude_code_log/cli.py`:
- Around line 548-690: The CLI currently allows --session-id to be combined with
conflicting flags (tui, all_projects) and may silently ignore session_id; add an
explicit conflict check early in the command handler: if session_id is not None
and tui is True or session_id is not None and all_projects is True, raise a
clear click.UsageError or echo an error and sys.exit(1) so the command fails
fast; update the top of the TUI/argument handling (near variables session_id,
tui, all_projects) to validate these combinations before any project
discovery/convert_project_path_to_claude_dir or generate_single_session_file
calls, listing the conflicting flags in the message.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1fba01b5-3cbf-465f-8e15-9df030ddff46

📥 Commits

Reviewing files that changed from the base of the PR and between 5d1cf46 and 142112b.

📒 Files selected for processing (4)
  • claude_code_log/cli.py
  • claude_code_log/converter.py
  • test/test_cli.py
  • test/test_session_export.py

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
claude_code_log/converter.py (1)

1472-1486: Consider adding a docstring and tightening the type hint.

This is a public helper now imported by tui.py. A brief docstring would clarify its purpose. Additionally, Optional[Any] could be Optional[SessionCacheData] for better type safety.

📝 Suggested improvement
 def build_session_title(
     project_title: str,
     session_id: str,
-    session_cache: Optional[Any],
+    session_cache: Optional[SessionCacheData],
 ) -> str:
+    """Build a display title for a session.
+
+    Uses the session summary if available, otherwise the first user message
+    preview (truncated to 50 chars), falling back to "Session {id[:8]}".
+    """
     if session_cache:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@claude_code_log/converter.py` around lines 1472 - 1486, Add a short docstring
to build_session_title describing its purpose, parameters (project_title,
session_id, session_cache) and return value; tighten the type hint of
session_cache from Optional[Any] to Optional[SessionCacheData] (import or
forward-declare SessionCacheData if needed) and ensure any attribute access
(summary, first_user_message) aligns with that type. Keep the existing logic
intact and update the function signature and docstring accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@claude_code_log/converter.py`:
- Around line 1472-1486: Add a short docstring to build_session_title describing
its purpose, parameters (project_title, session_id, session_cache) and return
value; tighten the type hint of session_cache from Optional[Any] to
Optional[SessionCacheData] (import or forward-declare SessionCacheData if
needed) and ensure any attribute access (summary, first_user_message) aligns
with that type. Keep the existing logic intact and update the function signature
and docstring accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cff9a1a6-f1d3-44b6-b144-92588f7d143f

📥 Commits

Reviewing files that changed from the base of the PR and between 142112b and a2a67ac.

📒 Files selected for processing (2)
  • claude_code_log/converter.py
  • claude_code_log/tui.py

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
claude_code_log/converter.py (1)

1661-1696: Consider lazy loading for single-session export performance.

The function loads all messages from the directory (line 1661) before filtering to the target session (lines 1692-1696). For large projects, this is inefficient when exporting a single session.

This is acceptable for the current CLI use case, but if this becomes a hot path, consider:

  • Using cache metadata to resolve session IDs without loading all messages
  • Loading only the specific session's JSONL file when the full session ID is provided
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@claude_code_log/converter.py` around lines 1661 - 1696, The code currently
calls load_directory_transcripts(input_path, cache_manager) and loads all
messages into messages before resolving session_id; change this to resolve
matched_id using cache metadata first (use
cache_manager.get_cached_project_data() and project_cache.sessions) and only
call load_directory_transcripts when necessary (e.g., if session_id is ambiguous
or not found in cache), and if the provided session_id is a full ID, load just
that session's JSONL file instead of the whole directory; update the logic
around matched_id, messages, and session_messages (referencing
load_directory_transcripts, cache_manager, project_cache, session_id,
matched_id, messages, session_messages) so we lazily load transcripts for a
single-session export.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@claude_code_log/converter.py`:
- Around line 1661-1696: The code currently calls
load_directory_transcripts(input_path, cache_manager) and loads all messages
into messages before resolving session_id; change this to resolve matched_id
using cache metadata first (use cache_manager.get_cached_project_data() and
project_cache.sessions) and only call load_directory_transcripts when necessary
(e.g., if session_id is ambiguous or not found in cache), and if the provided
session_id is a full ID, load just that session's JSONL file instead of the
whole directory; update the logic around matched_id, messages, and
session_messages (referencing load_directory_transcripts, cache_manager,
project_cache, session_id, matched_id, messages, session_messages) so we lazily
load transcripts for a single-session export.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9bc4602d-c3ea-47d6-9bc1-dc188181ff88

📥 Commits

Reviewing files that changed from the base of the PR and between a2a67ac and 3b0c9f8.

📒 Files selected for processing (1)
  • claude_code_log/converter.py

@daaain
Copy link
Owner

daaain commented Mar 18, 2026

Hey, thanks a lot for this PR!

What do you think about dropping the input_path requirement?

Session ids should be globally unique and now we have a SQLite cache, so it's a simple lookup.

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