#!/usr/bin/env bash # Search Claude Code conversation history # Usage: claude-search [--rebuild] set -euo pipefail CLAUDE_DIR="${HOME}/.claude" INDEX_FILE="${CLAUDE_DIR}/search-index.jsonl" build_index() { echo "Building index..." >&2 local tmp_index tmp_index=$(mktemp) for project_dir in "$CLAUDE_DIR"/projects/*/; do [[ -d "$project_dir" ]] || continue project_name=$(basename "$project_dir") for session_file in "$project_dir"/*.jsonl; do [[ -f "$session_file" ]] || continue [[ $(basename "$session_file") == agent-* ]] && continue uuid=$(basename "$session_file" .jsonl) # Extract summaries summaries=$(jq -rs '[.[] | select(.type == "summary") | .summary] | join(" | ")' "$session_file" 2>/dev/null || echo "") # Count messages msg_count=$(jq -s '[.[] | select(.type == "user" or .type == "assistant")] | length' "$session_file" 2>/dev/null || echo "0") # Get timestamps first_ts=$(jq -rs '[.[] | select(.timestamp) | .timestamp] | first // ""' "$session_file" 2>/dev/null || echo "") # Get first user message preview preview=$(jq -rs '[.[] | select(.type == "user") | .message.content][0] // ""' "$session_file" 2>/dev/null | head -c 100 || echo "") # Skip empty sessions [[ -z "$first_ts" ]] && continue # Output index entry (compact JSON, one per line) jq -cn \ --arg uuid "$uuid" \ --arg project "$project_name" \ --arg summaries "$summaries" \ --arg preview "$preview" \ --arg first_ts "$first_ts" \ --argjson msg_count "$msg_count" \ '{uuid: $uuid, project: $project, summaries: $summaries, preview: $preview, date: $first_ts, messages: $msg_count}' >> "$tmp_index" done done mv "$tmp_index" "$INDEX_FILE" echo "Index built: $(wc -l < "$INDEX_FILE") sessions" >&2 } search_index() { local query="$1" if [[ ! -f "$INDEX_FILE" ]]; then echo "Index not found. Building..." >&2 build_index fi # Search summaries and preview (case-insensitive) grep -i "$query" "$INDEX_FILE" 2>/dev/null | jq -r ' "\(.date | split("T")[0]) [\(.project | ltrimstr("-home-dan-proj-"))] \(.messages)msg" + "\n " + (if .summaries != "" then .summaries else .preview end) + "\n " + .uuid + "\n" ' | head -50 } case "${1:-}" in --rebuild) build_index ;; --help|-h) echo "Usage: claude-search [--rebuild]" echo "" echo "Search Claude Code conversation history" echo "" echo "Options:" echo " --rebuild Rebuild the search index" echo " --help Show this help" ;; "") echo "Usage: claude-search " >&2 exit 1 ;; *) search_index "$1" ;; esac