claudegrep
grep, but semantic, for your Claude Code conversation history. Local-first, private, fast.
Every Claude Code session vanishes the moment you close it. claudegrep indexes
your ~/.claude/projects/ JSONL files into a single SQLite database and
gives you a fast CLI (recall) to find any past turn — hybrid BM25 + vector
search with optional cross-encoder reranking.
$ recall search "sqlite vec hybrid"
1. 2026-04-29 claude-recall score=-18.4
how should we store the chunk vectors — sqlite-vec or lancedb?
[assistant] for <10M vectors sqlite-vec wins on ops simplicity…
2. 2026-04-22 gstack score=-14.1
…
Status
Week 5 / 6 — recall serve is live: a local FastAPI + HTMX web UI at
http://127.0.0.1:7777 with hybrid search, inline filters, session viewer,
and one-click "copy turn" to clipboard. v0.3.0 ships it.
See PLAN.md.
Install
# CLI only (~120 MB with embedder model)
uv tool install claudegrep
# or:
pipx install claudegrep
# CLI + local web UI
uv tool install 'claudegrep[serve]'
# first run
recall index
recall search "your query"
recall serve # opens http://127.0.0.1:7777
Dev install:
git clone https://github.com/lbbstarry/claudegrep
cd claudegrep
uv sync
uv run recall index
Commands
| Command | What it does |
|---|---|
recall index |
Scan ~/.claude/projects/ and index + embed new/changed sessions (incremental via mtime + sha256). --no-embed for BM25-only. |
recall search <q> |
Hybrid BM25 + vector search by default. --mode bm25|vector|hybrid, --rerank, --limit N, --project NAME. Inline filters: project:foo since:7d role:user tool:Bash. |
recall show <session> |
Render a session as Markdown. Accepts an 8+ char prefix; use --turn N to view one turn. |
recall inject <chunk> |
Copy a chunk's text to your clipboard so you can paste it into a new Claude session. |
recall export <session> -o file.md |
Export a session to disk as Markdown. |
recall watch |
Re-index in the background as JSONL files change (debounced; uses polling on WSL2). |
recall serve |
Local web UI on 127.0.0.1:7777 (FastAPI + HTMX). Requires [serve] extras. |
recall stats |
Index size, vector count, DB path. |
python -m claude_recall.eval.run |
Run the labeled eval set, print Recall@10 / MRR / nDCG@10, write benchmarks/eval_results.md. |
Coming in Week 6+:
- bge-m3 + query expansion (planned biggest single eval bump)
- Pro tier: encrypted cross-machine sync, voyage-3-lite embedder
- v1.0 + Product Hunt launch
Architecture
~/.claude/projects/*.jsonl
│
▼
parsers/claude_code.py typed Message records
│
▼
ingest/chunker.py per-turn chunks (one user msg + following assistant)
│
▼
embed/local.py sentence-transformers (bge-small-zh) + disk cache
│
▼
store/ SQLite + FTS5 + sqlite-vec (vec0 virtual table)
│
▼
search/ bm25 · vector (KNN) · hybrid (RRF) · rerank (cross-encoder)
│
▼
cli.py Typer app
Why per-turn chunks? Per-message loses Q-A pairing; sliding-window inflates
the index 3-5×. A turn averages ~1.2k tokens — perfect for bge-m3's 8k
context, no truncation needed.
Why SQLite + FTS5 + (later) sqlite-vec? Single file, zero ops, ships with the wheel, hybrid search is a JOIN away. Beats Chroma at this scale.
Eval
51 hand-labeled (query, relevant_chunk_id) pairs from real developer
sessions in tests/fixtures/queries.jsonl. Index size: 6,593 chunks across
127 sessions / 6 projects. Reproduce with python -m claude_recall.eval.run.
| Method | Recall@10 | MRR | nDCG@10 | p95 ms |
|---|---|---|---|---|
| BM25 (FTS5) | 0.216 | 0.125 | 0.148 | 2 |
Vector (bge-small-zh-v1.5, 512d) |
0.353 | 0.175 | 0.217 | 13 |
| Hybrid (RRF) | 0.392 | 0.175 | 0.228 | 16 |
Hybrid + rerank (bge-reranker-base) |
0.471 | 0.230 | 0.289 | 214 |
Hybrid + rerank gives +118% Recall@10 and +95% nDCG@10 over BM25.
Reranker latency is dominated by CPU cross-encoder inference; GPU or
bge-reranker-v2-m3-onnx will reduce it. Numbers are CPU-only on a WSL2
Ryzen laptop.
Why the absolute numbers look modest: the eval queries are deliberately
short (median 5 chars) and developer-domain-specific, e.g. prefab,
figma示例. That is the realistic distribution for "I vaguely remember
talking about this last month" — and the gap between methods, not the
absolute floor, is what matters. Query expansion and bge-m3 (8k context,
multilingual) are next.
Roadmap
- Week 1 — Typer CLI, SQLite + FTS5, incremental ingest, BM25 search
- Week 2 — bge-small-zh embeddings, sqlite-vec, RRF hybrid, reranker, 51-query eval
- Week 3 —
show/inject/export,watchdaemon, filter DSL,--rerankflag - Week 4 — v0.2 on PyPI, eval blog post drafts (EN + ZH)
- Week 5 —
recall serve(FastAPI + HTMX local UI), v0.3 - Week 6 — v1.0, Pro tier (cloud sync, Voyage embedder), Product Hunt
Privacy
Everything stays on your machine. The index is a single SQLite file under your
OS's user data dir (~/.local/share/claude-recall/recall.db on Linux). No
network calls are made by the OSS build.
License
Apache-2.0
Metadata
Release files for claudegrep 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| claudegrep-0.3.0.tar.gz | 166.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| claudegrep-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 199.8 kB
Release files / claudegrep-0.3.0.tar.gz
| Download URL | claudegrep-0.3.0.tar.gz |
|---|---|
| Size | 166.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
505f37c0f56251dcf4f2e32bb6310c776de6de3735031a40d7aa07482c08b335
|
|
BLAKE2b-256 checksum How to use checksums |
6b8c3b9299ad7a9aabe1bd87aa24a334a7f5b3424d7aac3abbebdd1b15a2425b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / claudegrep-0.3.0-py3-none-any.whl
| Download URL | claudegrep-0.3.0-py3-none-any.whl |
|---|---|
| Size | 33.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
565302643c744d1bd1475dd556656d64188a64ddaf3d61b0bd9e82f6dbd36f14
|
|
BLAKE2b-256 checksum How to use checksums |
382ba6f94dcc2328ebac81c87bf7fee51d0ae0686d77145024e96423a66a6c6e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|