9.8 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
LEANN is a lightweight vector database and RAG (Retrieval-Augmented Generation) system that achieves 97% storage reduction compared to traditional vector databases through graph-based selective recomputation. It enables semantic search across various data sources (emails, browser history, chat history, code, documents) on a single laptop without cloud dependencies.
Build & Development Commands
Quick install (pip)
pip install leann
Development setup (from source)
# Install uv first (required package manager)
curl -LsSf https://astral.sh/uv/install.sh | sh
git submodule update --init --recursive
# macOS
brew install libomp boost protobuf zeromq pkgconf
uv sync
# Ubuntu/Debian
sudo apt-get install libomp-dev libboost-all-dev protobuf-compiler \
libabsl-dev libmkl-full-dev libaio-dev libzmq3-dev
uv sync
# Windows (requires VS 2022 Build Tools with C++ workload, vcpkg, chocolatey)
choco install cmake swig pkgconfiglite nuget.commandline -y
vcpkg install zeromq:x64-windows openblas:x64-windows lapack:x64-windows boost-program-options:x64-windows protobuf:x64-windows
# Set CMAKE_PREFIX_PATH, PKG_CONFIG_PATH, OPENBLAS_LIB to vcpkg paths (see README)
uv sync --extra diskann
# Install lint tools
uv sync --group lint
# Install test tools
uv sync --group test
Code Quality
# Format code
ruff format
# Lint with auto-fix
ruff check --fix
# Pre-commit hooks (install once)
pre-commit install
# Run pre-commit manually
uv run pre-commit run --all-files
Architecture
Core API Layer (packages/leann-core/src/leann/)
api.py: Main APIs -LeannBuilder,LeannSearcher,LeannChatreact_agent.py:ReActAgentfor multi-turn reasoningcli.py: CLI implementation (leann build,leann search,leann ask)chat.py: LLM provider integrations (OpenAI, Ollama, HuggingFace, Anthropic)embedding_compute.py: Embedding computation (sentence-transformers, MLX, OpenAI)metadata_filter.py: Search result filtering by metadata
Backend Layer (packages/)
leann-backend-hnsw/: Default backend using FAISS HNSW for fast in-memory searchleann-backend-ivf/: IVF backend (FAISS IndexIVFFlat + DirectMap.Hashtable) supporting in-place add/remove without rebuildleann-backend-diskann/: DiskANN backend for larger-than-memory datasetsleann-mcp/: MCP server for Claude Code integration
Backends are auto-discovered via leann-backend-* naming convention and registered in registry.py.
RAG Applications (apps/)
Example applications demonstrating RAG on various data sources:
document_rag.py: PDF/TXT/MD documentsemail_rag.py: Apple Mailbrowser_rag.py: Chrome browser historywechat_rag.py,imessage_rag.py: Chat historycode_rag.py: Codebase search with AST-aware chunkingslack_rag.py,twitter_rag.py: MCP-based live data
Key Design Patterns
Incremental Update (IVF backend)
The IVF backend supports in-place updates and deletes without rebuilding the entire index:
add_vectors(index_path, embeddings, passage_ids): Append new vectors to an existing index.remove_ids(index_path, passage_ids): Remove vectors by passage ID using FAISS DirectMap.Hashtable.LeannBuilder.update_index(): High-level API that orchestrates remove-then-add for changed files, compactspassages.jsonl, and updates the offset map.
leann build is idempotent — re-running it on an existing index automatically performs an incremental update instead of a full rebuild. It detects new, modified, and removed files and applies the minimal set of changes:
- IVF: Supports add, remove, and modify incrementally (remove old chunks then re-insert).
- HNSW (non-compact): Supports add-only incremental updates; modified/removed files trigger a full rebuild.
- Use
--force/-fto force a full rebuild regardless.
Index Structure
A LEANN index consists of:
<name>.meta.json: Metadata (backend, embedding model, dimensions)<name>.passages.jsonl: Raw text chunks with metadata<name>.passages.idx: Offset map for fast passage lookup<name>.index: Backend-specific vector index
Embedding Recomputation
The core storage optimization: instead of storing embeddings, LEANN stores a pruned graph and recomputes embeddings on-demand during search via ZMQ server communication.
CLI Usage
# Build index
leann build my-docs --docs ./documents/
# Search
leann search my-docs "query"
# Interactive chat
leann ask my-docs --interactive
# List indexes
leann list
# Remove index
leann remove my-docs
Common Development Tasks
Running example RAG applications:
# Document RAG (easiest to test)
python -m apps.document_rag --query "What is LEANN?"
# Code RAG
python -m apps.code_rag --repo-dir ./src --query "How does search work?"
Python Version
Requires Python 3.10+ (uses PEP 604 union syntax X | Y).
Agent Coding Guidelines
General
- Voice input may contain typos — interpret intent, not literal text.
- When you encounter a problem, fix it immediately and keep going until there are no more problems.
- Do not ask about ordering or sequencing — figure it out. If something is unclear, note it and skip it; only escalate when all paths are blocked.
- Obvious bugs: fix silently without reporting.
- No fallbacks or compatibility shims. One correct implementation per feature — no redundancy.
Roadmap
- Public roadmap:
docs/roadmap.md— tracks P0/P1 priorities, completed milestones, and timeline. - Long-term vision:
docs/ultimate_goal.md— the north star for where LEANN is headed. - Keep in sync with GitHub issue #237.
- Welcome everyone to add more, and the craziest feature you want to put here! If people want some feature, all put there.
Changelog (for contributors)
- Maintain
docs/CHANGELOG.md— append-only log of major changes (new features, breaking changes, important fixes). - Format:
## YYYY-MM-DD: <short summary>followed by bullet points. - Update the changelog when merging significant PRs or completing notable work.
- See
docs/CONTRIBUTING.mdfor full contributor workflow (conventional commits, PR process, CI).
Personal Dev Notes (gitignored)
docs/dev/is gitignored for personal development notes (TODO, progress, experiments).- Use
docs/dev/TODO.mdfor in-progress tasks,docs/dev/PROGRESS.mdfor completed work. - These are private scratch space — but must follow the Self-Contained Principle below.
Documentation — Self-Contained Principle
All dev docs (PROGRESS.md, STATES.md, EXPERIMENTS.md, TODO.md) must be fully understandable from the document alone, with no reliance on conversation context or implied knowledge.
Requirements:
- Every technique/approach must be explained on first use. Not "switched to IVF backend" — write "switched to IVF backend (FAISS IndexIVFFlat + DirectMap.Hashtable, supports in-place add/remove without full index rebuild)."
- Never assume the reader knows any abbreviation. On first use: full name + one-sentence explanation. E.g., "HNSW (Hierarchical Navigable Small World — a graph-based ANN index used as LEANN's default backend)."
- Benchmark results must include full context. Not "recall improved to 0.95" — write "recall@10 improved from 0.91 to 0.95 after switching from flat chunking (512 tokens, no overlap) to AST-aware chunking (function-level splits with 64-token overlap)."
- Numbers must have reference points. Not "build time: 12s" — write "build time: 12s (vs. 45s before incremental update support, on 10k-document corpus)."
- Include the causal chain — not just conclusions. Not "duplicate chunks appeared after incremental build" — write "Duplicate chunks appeared after incremental build because
passages.jsonlwas appended without first removing stale entries for modified files. The IVF index had correct vectors (remove-then-add), but the passage store was append-only, causing the same text to appear at multiple offsets." docs/dev/STATES.mdtop section maintains a glossary of all key terms (backends, index files, chunking strategies, embedding models). Other docs reference it at the top.
Bad examples (forbidden):
- "Fixed the chunking bug" → Which bug? What was the symptom? What was the root cause?
- "Improved search quality" → By what metric? From what baseline? What change caused it?
- "Used nprobe=32" → What is nprobe? Why 32? What was it before and what effect did the change have?
Doc Maintenance
- Maintain
docs/dev/PROGRESS.md— completed work only (with key script/log/config paths). No plans. - Maintain
docs/dev/TODO.md— incomplete/in-progress/next-steps only (aim for one-command reproducibility). When done: remove from TODO, write result to PROGRESS, update STATES/EXPERIMENTS if needed. - Both files: append-only, chronological order (oldest first). Use
tail -n 80 docs/dev/PROGRESS.mdto read recent entries; increase range or grep by date/keyword if needed. - Keep TODO clean — either do items or remove them. Ask the user when unsure how to handle a TODO item.
- Maintain
docs/dev/STATES.md— tracks all currently useful state (index configs, backend choices, known limitations); does NOT grow indefinitely (delete stale entries). - Maintain
docs/dev/EXPERIMENTS.md— benchmarks, A/B comparisons, parameter sweeps (recall@k, latency, storage size). Experimental content goes here, not in STATES.md.
Commits
Commit when: (1) a complete feature is finished and tested, or (2) a destructive change is unavoidable.
git add <specific files>
git commit -m “feat: ...” # follow conventional commits
- When correcting errors: fix directly with no trace of the error.
- If you write a correct new version of a file, delete the wrong version. No duplicate implementations.