CLI + API + Web UI that indexes any codebase with tree-sitter, stores semantic chunks in pgvector, reranks with Cohere, and answers engineering questions with full file and git-history context.
ContextCraft turns any codebase into a searchable knowledge base that understands code structure — not just text.
- Parses source with tree-sitter — functions, classes, and modules as semantic chunks, never mid-function splits.
- Builds a dependency graph — resolves Python imports and class inheritance into
chunk_edgesfor context expansion across file boundaries. - Enriches every chunk with
git blameauthor metadata and per-file commit history. - Embeds chunks (default: Gemini
gemini-embedding-2) and stores vectors in PostgreSQL + pgvector with an HNSW index. - Searches with hybrid Reciprocal Rank Fusion — vector cosine similarity and PostgreSQL full-text search merged without raw score normalization. Supports simultaneous multi-repo queries with per-repo RRF normalization to prevent large codebases from drowning out smaller ones.
- Reranks with Cohere
rerank-english-v3.0when an API key is configured — fetches 20 candidates, reranks to top 10. - Answers via Gemini, OpenAI, Anthropic, or local Ollama, grounded in retrieved code with file paths, line numbers, and git author context.
- Streams responses over SSE to both the CLI and the Next.js web UI.
Evaluated against ContextCraft's own codebase (v0.3.0), 10 hand-curated questions, 3 iterations each. Full methodology and per-question breakdown: BENCHMARK.md.
| Configuration | Source Hit Rate | Faithful Answers | P50 Latency |
|---|---|---|---|
| RRF only | 80.0% | 73.3% | 3,876ms |
| RRF + Reranker | 75.0% | 60.0% | 5,121ms |
| RRF + Reranker + Deps | 75.0% | 53.3% | 4,993ms |
Source Hit Rate: target file appeared in retrieved context (position-agnostic). Latency is retrieval only; LLM generation adds 2–15s depending on model.
pip install contextcraft-pygit clone https://github.com/AneeshVRao/ContextCraft.git
cd ContextCraft
python -m venv .venv
source .venv/bin/activate # Windows: .\.venv\Scripts\Activate.ps1
pip install -e ".[dev]"| Requirement | Purpose |
|---|---|
| Python 3.11+ | CLI, API, indexing |
| Docker | PostgreSQL 16 + pgvector |
| Git | Blame and history during index |
| Gemini API key | Default embeddings + LLM (free tier) |
| Cohere API key | Optional — enables reranking |
| Node.js 18+ | Web UI only |
docker compose -f docker/docker-compose.yml up -d postgrescp .env.example .envSet at minimum:
CONTEXTCRAFT_GEMINI_API_KEY=your_key_here
# Optional — enables Cohere reranking
# CONTEXTCRAFT_COHERE_API_KEY=your_key_herecontextcraft index ./path/to/your/project
contextcraft status
contextcraft ask "How does authentication work?"Terminal 1 — API server
uvicorn contextcraft.api.main:app --reload --host 0.0.0.0 --port 8000Startup verifies Postgres, pgvector, and configured provider keys.
Health check: GET http://localhost:8000/health
Terminal 2 — Web UI
cd web
npm install
npm run devOpen http://localhost:3000.
Parse → git metadata → embed → store. Rejects sensitive paths (~/.ssh, /etc)
and symlink escapes outside the repo root.
contextcraft index ./my-project
contextcraft index ./my-project --incremental # only changed files
contextcraft index ./my-project --skip-git # skip blame/history
contextcraft index ./my-project --skip-embeddings # parse and store onlyStreams an answer to the terminal. Queries are sanitized (max 500 characters, control characters stripped).
contextcraft ask "Where is authentication handled?"
contextcraft ask "Explain the DB pool" --all-repos
contextcraft ask "Caching layer" --repos repo-a,repo-b
contextcraft ask "Database client setup" --with-deps # expand 1-hop imports
contextcraft ask "Quick lookup" --no-rerank # skip Cohere, lower latencyLists indexed repositories, languages, chunk counts, and last index time.
| Method | Path | Description |
|---|---|---|
GET |
/health |
{"status":"ok","version":"…"} |
GET |
/repos |
List indexed repositories |
POST |
/index |
Start background indexing |
POST |
/ask |
SSE stream: token, sources, done events |
POST /ask is rate-limited to 10 requests/minute per IP.
curl http://localhost:8000/healthAll settings use the CONTEXTCRAFT_ prefix. Full list in .env.example.
| Variable | Default | Description |
|---|---|---|
CONTEXTCRAFT_DATABASE_URL |
postgresql://contextcraft:…@localhost:5432/contextcraft |
Postgres connection string |
CONTEXTCRAFT_GEMINI_API_KEY |
— | Gemini embeddings + LLM (default provider) |
CONTEXTCRAFT_GEMINI_MODEL |
gemini-3.1-flash-lite |
Gemini LLM model |
CONTEXTCRAFT_EMBEDDING_PROVIDER |
gemini |
gemini or openai |
CONTEXTCRAFT_LLM_PROVIDER |
gemini |
gemini, openai, anthropic, ollama |
CONTEXTCRAFT_OPENAI_API_KEY |
— | Required when using OpenAI provider |
CONTEXTCRAFT_COHERE_API_KEY |
— | Enables Cohere reranking |
CONTEXTCRAFT_RERANK_ENABLED |
true |
Toggle reranker on/off |
CONTEXTCRAFT_OLLAMA_BASE_URL |
http://localhost:11434 |
Local Ollama endpoint |
CONTEXTCRAFT_OLLAMA_MODEL |
qwen2.5-coder:7b |
Ollama model for local inference |
CONTEXTCRAFT_OLLAMA_ALLOW_REMOTE |
false |
Allow non-localhost Ollama URLs |
CONTEXTCRAFT_ALLOWED_ORIGINS |
http://localhost:3000,http://127.0.0.1:3000 |
CORS origins (comma-separated) |
CONTEXTCRAFT_SEARCH_TOP_K |
10 |
Chunks returned after search/rerank |
CONTEXTCRAFT_API_PORT |
8000 |
API listen port |
OpenAI (embeddings + LLM):
CONTEXTCRAFT_EMBEDDING_PROVIDER=openai
CONTEXTCRAFT_LLM_PROVIDER=openai
CONTEXTCRAFT_OPENAI_API_KEY=sk-...Ollama (fully local, no API keys):
ollama serve
ollama pull qwen2.5-coder:7bCONTEXTCRAFT_LLM_PROVIDER=ollama
CONTEXTCRAFT_OLLAMA_MODEL=qwen2.5-coder:7bOllama is restricted to localhost by default. Set
CONTEXTCRAFT_OLLAMA_ALLOW_REMOTE=true only if you understand the SSRF risk.
┌──────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ tree-sitter │────▶│ CodeChunks │────▶│ pgvector │
│ AST parse │ │ + git blame │ │ PostgreSQL │
└──────────────┘ └────────┬─────────┘ └────────┬────────┘
│ │
┌────────▼─────────┐ │
│ chunk_edges │ │
│ (imports / │ │
│ inherits) │ │
└────────┬─────────┘ │
│ │
┌────────▼─────────┐ ┌─────────▼───────┐
│ Hybrid RRF │◀───│ Vector + BM25 │
│ (per-repo norm) │ └─────────────────┘
└────────┬─────────┘
│
┌────────▼─────────┐
│ Cohere rerank │ (optional)
└────────┬─────────┘
│
┌────────▼─────────┐ ┌──────────────┐
│ Context + LLM │────▶│ Next.js UI │
│ (SSE stream) │ │ CLI │
└──────────────────┘ └──────────────┘
Design decisions
- AST chunking at function and class boundaries preserves semantic units — the LLM never receives partial functions or broken syntax.
- Single PostgreSQL instance serves metadata, vectors (pgvector), and full-text search (tsvector) — no separate vector database service required.
- Per-repo RRF normalization prevents large codebases from crowding out smaller ones in multi-repo queries.
- Git blame runs once per file (not per chunk) via async subprocess — blame metadata adds negligible indexing overhead.
- Dependency expansion uses a single batched SQL query with a visited-set cycle guard — safe on codebases with circular imports.
| Language | Extensions |
|---|---|
| Python | .py |
| JavaScript | .js, .jsx |
| TypeScript | .ts, .tsx |
| Go | .go |
ContextCraft pins tree-sitter<0.22.0 for compatibility with tree-sitter-languages.
Additional languages can be added via the LanguageAdapter interface in
src/contextcraft/parser/ast_parser.py.
python eval/run_eval.py --runs 3
python eval/run_eval.py --rerank --runs 3
python eval/run_eval.py --rerank --deps --runs 3Measures source hit rate (does the right file appear?), faithfulness (does the answer cover the ground truth?), and retrieval latency (P50/P95). Full results and methodology: BENCHMARK.md.
CI requires all four checks to pass before merge:
ruff format --check src/ tests/
ruff check src/ tests/
mypy src/contextcraft/ --strict
pytest tests/ -v --tb=shortTo auto-fix formatting and lint:
ruff format src/ tests/
ruff check --fix src/ tests/contextcraft/
├── src/contextcraft/
│ ├── cli/main.py # Typer CLI — index, ask, status
│ ├── api/main.py # FastAPI + SSE + rate limiting
│ ├── parser/ast_parser.py # tree-sitter → CodeChunk
│ ├── graph/ # Import resolver + 1-hop expander
│ ├── embeddings/ # Gemini, OpenAI, Ollama embedders
│ ├── git/ # Async blame + commit history
│ ├── db/ # asyncpg pool + SQL migrations
│ ├── search/ # Vector, BM25, hybrid RRF
│ ├── reranker/ # Cohere cross-encoder
│ ├── llm/ # Gemini, OpenAI, Anthropic, Ollama
│ ├── security.py # Path traversal + query sanitization
│ └── startup.py # API startup health checks
├── web/ # Next.js 14 UI (App Router + SSE)
├── eval/ # RAG evaluation harness + test cases
├── tests/ # pytest unit tests
├── docker/
│ ├── Dockerfile # Production image (non-root user)
│ └── docker-compose.yml # PostgreSQL 16 + pgvector
├── railway.toml # Railway deployment config
├── pyproject.toml
├── BENCHMARK.md # Measured retrieval quality and latency
├── CHANGELOG.md
└── .env.example
railway.toml is included. Set the following environment variables in the
Railway dashboard:
DATABASE_URL
CONTEXTCRAFT_GEMINI_API_KEY
CONTEXTCRAFT_COHERE_API_KEY # optional
CONTEXTCRAFT_ALLOWED_ORIGINS # set to your frontend URL
PORT # Railway sets this automatically
docker build -f docker/Dockerfile -t contextcraft .
docker run -p 8000:8000 --env-file .env contextcraftThe production image runs as a non-root user and reads the port from $PORT.
Note: A public hosted demo is not maintained to avoid uncontrolled API costs. The full stack runs locally with a free Gemini key — see Quick Start above.
- Phase 1: Core pipeline — tree-sitter parser, pgvector, hybrid RRF search
- Phase 2: Cohere reranker, eval harness, Next.js web UI
- Phase 3: Dependency graph, multi-repo search with per-repo RRF normalization
- Phase 4: Eval benchmarks, PyPI publish (
pip install contextcraft-py), Railway deploy - Phase 5: File watcher for live re-indexing on save
- Phase 6: VS Code extension
MIT