Skip to content

CLI

claude_conversation_extractor.cli

Command-line interface for Claude conversation extractor.

cli

cli()

Extract Claude conversations from JSON exports and convert to markdown.

Source code in src/claude_conversation_extractor/cli.py
17
18
19
20
21
@click.group()
@click.version_option()
def cli() -> None:
    """Extract Claude conversations from JSON exports and convert to markdown."""
    pass

extract

extract(uuid, input, output, verbose)

Extract a conversation by UUID and convert to markdown.

Source code in src/claude_conversation_extractor/cli.py
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
@cli.command()
@click.option("--uuid", "-u", required=True, help="UUID of the conversation to extract")
@click.option(
    "--input",
    "-i",
    required=True,
    type=click.Path(exists=True, path_type=Path),
    help="Path to the Claude export JSON file",
)
@click.option(
    "--output",
    "-o",
    type=click.Path(path_type=Path),
    help="Output markdown file path (default: <uuid>.md)",
)
@click.option("--verbose", "-v", is_flag=True, help="Enable verbose output")
def extract(uuid: str, input: Path, output: Path | None, verbose: bool) -> None:
    """Extract a conversation by UUID and convert to markdown."""
    try:
        if verbose:
            console.print(f"🔍 Loading export file: {input}")

        # Initialize extractor
        extractor = ConversationExtractor(input)

        if verbose:
            console.print(f"🎯 Searching for conversation: {uuid}")

        # Extract conversation using streaming
        conversation = extractor.extract_conversation(uuid)

        if conversation is None:
            console.print(f"❌ Conversation with UUID '{uuid}' not found", style="red")
            sys.exit(1)

        if verbose:
            console.print(f"✅ Found conversation: {conversation.name or 'Untitled'}")
            console.print("📝 Converting to markdown...")

        # Convert to markdown
        converter = MarkdownConverter(conversation)

        # Determine output path
        if output is None:
            output = Path(f"{uuid}.md")

        # Save to file
        converter.save_to_file(str(output))

        # Success message
        success_text = Text()
        success_text.append("✅ ", style="green")
        success_text.append("Conversation extracted successfully!\n")
        success_text.append(f"📁 Output: {output}\n")
        success_text.append(f"💬 Messages: {len(conversation.chat_messages)}")

        console.print(Panel(success_text, title="Success", border_style="green"))

    except FileNotFoundError as e:
        console.print(f"❌ File not found: {e}", style="red")
        sys.exit(1)
    except Exception as e:
        console.print(f"❌ Error: {e}", style="red")
        if verbose:
            console.print_exception()
        sys.exit(1)

list_conversations

list_conversations(input, limit)

List available conversations in the export file.

Source code in src/claude_conversation_extractor/cli.py
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
@cli.command()
@click.option(
    "--input",
    "-i",
    required=True,
    type=click.Path(exists=True, path_type=Path),
    help="Path to the Claude export JSON file",
)
@click.option(
    "-l",
    "--limit",
    default=10,
    help="Maximum number of conversations to list (default: 10)",
)
def list_conversations(input: Path, limit: int) -> None:
    """List available conversations in the export file."""
    try:
        console.print(f"🔍 Loading export file: {input}")

        extractor = ConversationExtractor(input)

        # Get conversations using streaming
        conversations = extractor.list_conversations(limit)

        if not conversations:
            console.print("📭 No conversations found in the export file")
            return

        # Get total count for display
        total_count = extractor.get_conversation_count()
        console.print(f"\n📋 Found {total_count} conversations")
        console.print(f"Showing first {len(conversations)}:\n")

        for i, conv in enumerate(conversations, 1):
            # Create conversation info
            info = Text()
            info.append(f"{i}. ", style="bold blue")
            info.append(conv.name or "Untitled", style="bold")
            info.append(f" ({conv.uuid})", style="dim")
            info.append(f"\n   📅 {conv.created_at.strftime('%Y-%m-%d %H:%M:%S')}")
            info.append(f" | 💬 {len(conv.chat_messages)} messages")

            console.print(info)
            console.print()

        if total_count > limit:
            console.print(f"... and {total_count - limit} more conversations")

    except Exception as e:
        console.print(f"❌ Error: {e}", style="red")
        sys.exit(1)

main

main()

Main entry point for the CLI.

Source code in src/claude_conversation_extractor/cli.py
145
146
147
def main() -> None:
    """Main entry point for the CLI."""
    cli()