CLI Commands¶
Command-line interface built on the Echomine library.
Overview¶
The Echomine CLI provides a thin wrapper over the library API for terminal use. All CLI commands use the same library functions available programmatically.
See CLI Usage Guide for comprehensive command reference.
Architecture¶
The CLI follows the library-first architecture principle:
User Input (CLI)
↓
Typer Command Handler
↓
Library Function (OpenAIAdapter)
↓
Rich Formatter (Terminal Output)
↓
stdout/stderr
Key Points:
- CLI contains NO business logic
- All operations delegated to library
- Rich formatting for human-readable output
- JSON mode for programmatic use
Commands¶
list¶
List all conversations in an export file.
Usage:
Library Equivalent:
from echomine import OpenAIAdapter
adapter = OpenAIAdapter()
for conversation in adapter.stream_conversations(file_path):
print(f"{conversation.title}: {len(conversation.messages)} messages")
See: CLI Usage - list
search¶
Search conversations with keyword matching and relevance ranking.
Usage:
Library Equivalent:
from echomine import OpenAIAdapter, SearchQuery
adapter = OpenAIAdapter()
query = SearchQuery(keywords=["python"], limit=10)
for result in adapter.search(file_path, query):
print(f"[{result.score:.2f}] {result.conversation.title}")
See: CLI Usage - search
export¶
Export a specific conversation to markdown or JSON format.
Usage:
Options:
--output PATH: Output file path (if not specified, prints to stdout)--format TEXT: Export format:markdown(default) orjson
Library Equivalent:
from echomine import OpenAIAdapter
from echomine.exporters import MarkdownExporter, JSONExporter
adapter = OpenAIAdapter()
conversation = adapter.get_conversation_by_id(file_path, conversation_id)
if conversation:
# Markdown export (default)
markdown_exporter = MarkdownExporter()
markdown = markdown_exporter.export(conversation)
print(markdown)
# JSON export
json_exporter = JSONExporter()
json_output = json_exporter.export(conversation)
print(json_output)
See: CLI Usage - export
Output Formats¶
Human-Readable (Default)¶
Uses Rich library for formatted terminal output:
echomine list export.json
# Output:
# Conversations in export.json
#
# [2024-01-15] Python Async Best Practices
# Messages: 42
# ID: conv-abc123
# ...
JSON (--json flag)¶
Machine-readable JSON on stdout:
Exit Codes¶
Standard UNIX exit codes:
- 0: Success
- 1: Operational error (file not found, parsing error)
- 2: Usage error (invalid arguments)
Implementation¶
Typer Application¶
app
¶
Main CLI application entry point.
This module defines the Typer application and main() entry point for the echomine CLI tool.
Architecture
- Typer application with registered commands
- main() function as entry point (referenced in pyproject.toml)
- Minimal error handling (commands handle their own errors)
Constitution Compliance
- Principle I: Library-first (CLI delegates to library)
- CHK031: stdout/stderr separation
- CHK032: Exit codes 0/1/2
Entry Point Configuration (pyproject.toml): [project.scripts] echomine = "echomine.cli.app:main"
Usage
As installed script¶
$ echomine list export.json
As Python module (development)¶
$ python -m echomine.cli.app list export.json
callback
¶
callback(
ctx: Context,
version: Annotated[
bool,
Option("--version", "-v", help="Show version and exit", is_eager=True),
] = False,
) -> None
Echomine CLI - Library-first tool for parsing AI conversation exports.
Source code in src/echomine/cli/app.py
main
¶
Entry point for CLI application.
This function is referenced in pyproject.toml as the console script entry point. It invokes the Typer app and handles any uncaught exceptions (though commands should handle their own errors).
Exit Codes
0: Success 1: Error (user error, file not found, parse error, etc.) 2: Invalid arguments (Typer handles this)
Requirements
- CHK032: Consistent exit codes
- Entry point for installed script
Source code in src/echomine/cli/app.py
Command Handlers¶
Command handlers in echomine/cli/commands/:
list.py: List command handlersearch.py: Search command handlerexport.py: Export command handler
Formatters¶
Terminal formatters in echomine/cli/formatters.py:
format_conversation_list(): Format list outputformat_search_results(): Format search outputformat_conversation_export(): Format export output
Design Patterns¶
Library-First Pattern¶
# CLI command handler (thin wrapper)
def list_command(file_path: Path, limit: Optional[int] = None, json: bool = False):
# Delegate to library
adapter = OpenAIAdapter()
conversations = adapter.stream_conversations(file_path)
if limit:
conversations = itertools.islice(conversations, limit)
# Format output
if json:
print_json(conversations) # JSON formatter
else:
print_table(conversations) # Rich formatter
Stdout/Stderr Contract¶
import sys
# Results to stdout
print(json.dumps(results)) # stdout
# Progress to stderr
print("Processing...", file=sys.stderr) # stderr
# Errors to stderr
print(f"Error: {error}", file=sys.stderr) # stderr
sys.exit(1) # Exit code 1
Progress Reporting¶
from rich.progress import track
def list_command(file_path: Path):
adapter = OpenAIAdapter()
# Show progress bar (stderr)
conversations = list(adapter.stream_conversations(file_path))
for conv in track(conversations, description="Listing..."):
# Process
pass
Testing CLI¶
Contract Tests¶
CLI contract tests verify stdout/stderr behavior:
def test_list_command_json_output(tmp_export_file):
"""List command outputs valid JSON to stdout."""
result = subprocess.run(
["echomine", "list", str(tmp_export_file), "--json"],
capture_output=True,
text=True
)
assert result.returncode == 0
data = json.loads(result.stdout) # Validates JSON
assert "conversations" in data
Exit Code Tests¶
def test_list_command_file_not_found():
"""List command exits with code 1 on file not found."""
result = subprocess.run(
["echomine", "list", "nonexistent.json"],
capture_output=True
)
assert result.returncode == 1
assert "not found" in result.stderr.lower()
Related¶
- CLI Usage Guide: Complete CLI reference
- OpenAI Adapter: Library backend
- Library Usage: Programmatic usage