High-performance CLI for searching Claude session JSONL files with an interactive TUI mode.
- 🚀 Blazing Fast: SIMD-accelerated JSON parsing with parallel file processing
- 🔍 Powerful Query Syntax: Boolean operators (AND/OR/NOT), regex, and quoted literals
- 🎯 Smart Filtering: Filter by role, session ID, timestamp ranges, and project paths
- 💻 Interactive Mode: fzf-like TUI with Search and Session List tabs
- 📊 Statistics Mode: Comprehensive search statistics with
--statsflag - 📋 Session Browser: Browse and search all sessions with full-text search
- 🎨 Beautiful Output: Colored terminal output with match highlighting
- 📄 Multiple Output Formats: Text, JSON, or JSONL with customizable formatting
- 🔧 Robust Testing: Comprehensive test suite with cargo-nextest support
- 🚀 Shell Completion: Auto-completion support for bash, zsh, and fish shells
# Install directly from GitHub
cargo install --git https://github.com/mkusaka/ccms
# Or install a specific version/tag
cargo install --git https://github.com/mkusaka/ccms --tag v0.0.1# Clone the repository
git clone https://github.com/mkusaka/ccms.git
cd ccms
# Build and install
cargo install --path .# Build release version
cargo build --release
# Copy to your PATH
cp target/release/ccms ~/.local/bin/
# or
sudo cp target/release/ccms /usr/local/bin/CCMS supports shell completion for bash, zsh, and fish. To enable it:
# Generate completion script to file
ccms --completion bash > ~/.bash_completion.d/ccms
# Or add to .bashrc for persistent completion
echo 'source <(ccms --completion bash)' >> ~/.bashrc
# Or enable completion immediately in current shell
source <(ccms --completion bash)# Generate completion script to file
ccms --completion zsh > ~/.zsh/completions/_ccms
# Or add to .zshrc for persistent completion
echo 'source <(ccms --completion zsh)' >> ~/.zshrc
# Or enable completion immediately in current shell
source <(ccms --completion zsh)# Generate completion script
ccms --completion fish > ~/.config/fish/completions/ccms.fishAfter installation, restart your shell or source your configuration file to enable completions.
# Launch interactive mode (no arguments needed)
ccms
# Search for "error" in all Claude sessions
ccms "error"
# Search in specific files
ccms -p "~/.claude/projects/myproject/*.jsonl" "bug"
# Filter by role
ccms -r user "how to"
ccms -r assistant "I can help"
# Filter by current project directory (default behavior)
ccms "TODO" # Searches in current directory by default
# Explicitly specify project directory
ccms --project "/path/to/project" "TODO"
# Search all projects (bypass default filter)
ccms --project "/" "TODO"
# Show statistics only (no message content)
ccms --stats "" # Stats for all messages
ccms --stats "error" # Stats for messages containing "error"
ccms --stats --role user "question" # Stats with filtersLaunch an interactive search interface similar to fzf. Interactive mode starts automatically when no query is provided:
# Interactive search (default when no query provided)
ccms
# Interactive search in specific directory
ccms -p "~/my-project/*.jsonl"
# Interactive search with filters
ccms --project $(pwd) # Current project only
ccms --since "1 day ago" # Recent messages only
ccms -r user # Pre-filter by role
ccms --project $(pwd) --since "2 hours ago" # Combine filters
# All standard filters are supported
ccms -s "session-id" # Filter by session
ccms --after "2024-01-01T00:00:00Z" # Time range filters
ccms -n 100 # Adjust result limitInteractive Mode Controls:
- Type to search in real-time
↑/↓- Navigate resultsCtrl+u/d- Half-page scrolling (up/down)Enter- View full messageCtrl+S- Jump directly to session viewerTab- Cycle role filters (all → user → assistant → system → summary)Shift+Tab- Switch between Search and Session List tabsCtrl+R- Clear cache and reload filesCtrl+T- Toggle message truncation (Truncated/Full Text)Alt+←- Navigate back through historyAlt+→- Navigate forward through historyCtrl+C (2x)- Exit (press twice within 1 second)Esc- Go back to previous screen (does not exit from search screen)
Session List Tab:
- View all available sessions in a browsable list
- Real-time search through all messages in all sessions
- Shows session ID, message count, timestamp, and first message preview
p- Toggle first message preview on/offEnter- Open session in Session Viewer- Search highlights matching text in yellow
Note on Filters in Interactive Mode:
- All command-line filters (
--project,--since,--after,--before,-s, etc.) are applied as base filters - The
-rflag sets the initial role filter, but you can still cycle through roles with Tab - Filters persist throughout the interactive session
- Results are loaded incrementally - initially 100 items, then automatically loads more as you scroll
- Interactive mode ignores the
-nflag to allow viewing all available results
Result Actions:
Enter- View message detailsCtrl+S- Jump directly to session viewerTab- Toggle role filter (all → user → assistant → system)Ctrl+O- Toggle sort order (newest/oldest first)Ctrl+T- Toggle message truncation
Message Detail & Session Viewer Copy Operations (Unified):
c- Copy content/textC- Copy as JSONi- Copy session IDf- Copy file pathp- Copy project pathv- Convert current session to Codex rollout and copy Codex session ID (Session Viewer only)
Session Viewer Controls:
↑/↓orCtrl+P/N- Navigate messagesCtrl+U/D- Half-page scrolling (up/down)Tab- Cycle role filters (all → user → assistant → system)/- Search within session (Tab works in search mode too)Ctrl+O- Toggle sort orderEnter- View message detailEsc- Return to previous screen
# AND operator
ccms "error AND connection"
# OR operator
ccms "warning OR error"
# NOT operator
ccms "response NOT error"
# Complex queries with parentheses
ccms "(error OR warning) AND NOT /test/i"
# Regular expressions
ccms "/failed.*connection/i"
ccms "/^Error:.*\d+/m"# Limit results
ccms -n 100 "search term"
# Filter by session ID
ccms -s "session-123" "query"
# Filter by timestamp
ccms --after "2024-01-01T00:00:00Z" "recent"
ccms --before "2024-12-31T23:59:59Z" "old"
# Filter using relative time or Unix timestamp
ccms --since "1 day ago" "recent activity"
ccms --since "2 hours ago" "latest changes"
ccms --since "yesterday" "yesterday's work"
ccms --since "last week" "weekly review"
ccms --since "3 days ago" "recent work"
ccms --since 1720000000 "since Unix timestamp"
# Filter by project path (defaults to current directory if not specified)
ccms --project "/Users/me/project" "bug"
# Search all projects (bypass default current directory filter)
ccms --project "/" "bug"
# Combine filters
ccms -r user -n 20 --after "2024-06-01T00:00:00Z" "question"
# Convert a Claude session to Codex rollout (resolve by session-id)
ccms convert claude-to-codex --session-id "session-123"
# Dry-run conversion (show destination only)
ccms convert claude-to-codex --session-id "session-123" --dry-run
# Output rollout JSONL to stdout
ccms convert claude-to-codex --session-id "session-123" --stdout# Default text output with colors
ccms "query"
# Disable colors
ccms --no-color "query"
# Show full message text
ccms --full-text "query"
# Show raw JSON of matched messages
ccms --raw "query"
# JSON output with detailed statistics
ccms -f json "query" > results.json
# JSONL output (one JSON per line)
ccms -f jsonl "query" > results.jsonl
# Verbose output with debug info
ccms -v "query"The JSON output format provides rich metadata about search results:
# Get detailed JSON output with session and file statistics
ccms -f json "error" --project "/" -n 100
# Extract summary information
ccms -f json "query" | jq '.summary'
# List all unique sessions with message counts
ccms -f json "query" | jq -r '.sessions[] | "\(.session_id): \(.message_count) messages"'
# List all unique files with message counts
ccms -f json "query" | jq -r '.files[] | "\(.message_count) messages: \(.path)"'JSON output structure includes:
results: Array of search results with full message detailssummary: Search statistics including duration, total/returned counts, unique sessions/filessessions: List of unique sessions with message countsfiles: List of unique files with message counts and associated session IDs
-p, --pattern <PATTERN>- File pattern to search (default:~/.claude/projects/**/*.jsonl)-n, --max-results <N>- Maximum number of results to return (default: 200)-f, --format <FORMAT>- Output format:text,json, orjsonl(default: text)-v, --verbose- Enable verbose output--no-color- Disable colored output--full-text- Show full message text without truncation--raw- Show raw JSON of matched messages--stats- Show only statistics without message content
-r, --role <ROLE>- Filter by message role:user,assistant,system, orsummary-s, --session-id <ID>- Filter by session ID--project <PATH>- Filter by project path (default: current directory; use/to search all projects)--before <TIMESTAMP>- Filter messages before this timestamp (RFC3339 format)--after <TIMESTAMP>- Filter messages after this timestamp (RFC3339 format)--since <TIME>- Filter messages since this time (relative time like "1 day ago" or Unix timestamp)
-i, --interactive- Launch interactive search mode (fzf-like TUI)- Note: Interactive mode starts automatically when no query is provided
--help-query- Show query syntax help--completion <SHELL>- Generate shell completion script for bash, zsh, or fish--profile <NAME>- Generate profiling report (requires --features profiling)-h, --help- Print help information-V, --version- Print version information
convert claude-to-codex --session-id <ID>- Convert one Claude session to Codex rollout format--codex-home <DIR>- Override destination root ($CODEX_HOMEor~/.codexby default)--dry-run- Resolve source and output path without writing--stdout- Print converted rollout JSONL to stdout
hello- Case-insensitive literal search"hello world"- Quoted literal (preserves spaces)'hello world'- Single-quoted literal/pattern/flags- Regular expression with optional flags
AND- Both terms must be presentOR- Either term must be presentNOT- Term must not be present()- Grouping for complex expressions
i- Case insensitivem- Multi-line modes- Dot matches newline
# Find errors in connection handling
error AND /failed.*connection/i
# Find user messages excluding tests
"user message" AND NOT test
# Find warnings or errors with timestamps
(warning OR error) AND timestamp
# Find specific error patterns
/^Error:.*\d+/m
# Complex nested query
(("connection failed" OR "timeout") AND error) NOT debugThe --stats flag displays comprehensive statistics about search results:
# Statistics for all messages
ccms --stats ""
# Statistics for error messages
ccms --stats "error"
# Statistics with filters
ccms --stats --role assistant --since "1 week ago" "code"Output includes:
- Total message count
- Messages by role with percentages
- Unique sessions, files, and projects
- Message type breakdown
- Time range (earliest to latest)
- Search execution time
- Rust 1.75 or later
- cargo-nextest (for enhanced testing)
- clippy (for linting)
# Clone the repository
git clone https://github.com/mkusaka/ccmeta.git
cd ccmeta/schema/ccms
# Install development tools
cargo install cargo-nextest --locked
rustup component add clippy
# Build the project
cargo build
# Run tests
cargo nextest run
# Run clippy (checks code quality and style)
cargo clippy -- -D warningsNote on Clipboard Tests: Some tests that verify clipboard functionality are marked with #[ignore] as they require clipboard utilities (pbcopy on macOS, xclip/xsel on Linux) that may not be available in CI environments. To run these tests locally:
# Run all tests including ignored ones
cargo test -- --ignored
# Run only the clipboard tests
cargo test clipboard -- --ignored# Run all tests with cargo-nextest
cargo nextest run
# Run specific test
cargo nextest run test_name
# Run tests with standard cargo
cargo test
# Run tests with output
cargo test -- --nocapture# Run benchmarks
cargo bench
# Run specific benchmark
cargo bench search_benchmark
# Profile with flamegraph (requires profiling feature)
cargo run --release --features profiling -- --profile baseline "query"ccms/
├── src/
│ ├── main.rs # CLI entry point
│ ├── lib.rs # Library exports
│ ├── interactive_ratatui/ # Interactive TUI mode (Clean Architecture)
│ │ ├── mod.rs # Main event loop
│ │ ├── domain/ # Domain layer (models, business rules)
│ │ ├── application/ # Application layer (services)
│ │ └── ui/ # UI layer (MVU pattern, components)
│ ├── query/ # Query parsing and evaluation
│ │ ├── parser.rs # Nom-based query parser
│ │ └── condition.rs # Query condition types
│ ├── schemas/ # Claude message schemas
│ │ ├── session_message.rs
│ │ └── tool_result.rs
│ ├── search/ # Search engine implementation
│ │ ├── engine.rs # Core search logic
│ │ ├── file_discovery.rs
│ │ └── async_engine.rs
│ ├── stats.rs # Statistics collection and formatting
│ └── profiling.rs # Performance profiling
├── benches/ # Benchmarks
├── tests/ # Integration tests
├── CLAUDE.md # Guidance for Claude Code
├── spec.md # Detailed interactive mode specification
└── PERFORMANCE.md # Performance characteristics and benchmarks
This tool is optimized for maximum performance:
- SIMD JSON Parsing: Uses sonic-rs for hardware-accelerated parsing
- Parallel Processing: Leverages all CPU cores with Rayon
- Zero-Copy Design: Minimizes allocations and string copies
- Smart Filtering: Early termination and efficient predicate evaluation
- Memory-Mapped I/O: Efficient handling of large files
By default, searches in ~/.claude/projects/**/*.jsonl
# Search in specific project
ccms -p "~/.claude/projects/myproject/*.jsonl" "query"
# Search in current directory
ccms -p "$(pwd)/**/*.jsonl" "query"
# Search single file
ccms -p "/path/to/specific/session.jsonl" "query"- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Run tests and ensure they pass (
cargo nextest run) - Run clippy and fix any warnings (
cargo clippy -- -D warnings) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow Rust standard style guidelines
- Use
cargo fmtbefore committing - Ensure
cargo clippypasses with no warnings - Add tests for new functionality
- Update documentation as needed
- Check file permissions on Claude session files
- Verify the search pattern matches existing files
- Use
-vflag for verbose output to debug file discovery
- Use
-nto limit results for large datasets - Consider using more specific search patterns
- Enable profiling with
--features profilingto identify bottlenecks
- Ensure terminal supports ANSI escape codes
- Check that required clipboard utilities are installed (pbcopy/xclip/xsel)
- Try running with
--no-colorif display issues occur
MIT License - see LICENSE file for details