repo2graph
AST-driven code graphs & zero-dependency GraphRAG for AI coding agents and humans
English · 简体中文 · 日本語 · Français · Español · Deutsch
What is it · Quickstart · MCP setup · Benchmarks · Architecture · Docs · Contributing
⚡ What is repo2graph?
When an AI coding agent searches a codebase with grep or plain keyword matching, it either dumps whole matching files into context — burning the token budget and losing structure — or misses the implementation entirely because it used different words than the search query.
repo2graph parses source with tree-sitter into a
graph of real code relationships — CALLS, IMPORTS, INHERITS, DEFINES, CO_CHANGE — and
serves that graph to agents over the Model Context Protocol, or packs it into a budget-bounded
markdown context for any LLM. Every returned block carries an exact [cite: path:start-end]
anchor, so answers are traceable back to source instead of paraphrased from a guess.
flowchart LR
A[your code] --> B[tree-sitter<br/>reads the code]
B --> C[graph<br/>dots + arrows]
C --> D[graph.html<br/>the picture]
C --> E[chunks.jsonl<br/>pieces for an AI]
C -->|MCP stdio| F[Claude / Cursor /<br/>any MCP client]
No project setup, no language server, no build step — point it at a folder and it works.
| Interactive canvas, zoomed | Filter & inspector controls |
|---|---|
graph.html is one self-contained file — no server, no internet, drag to pan, scroll to zoom,
click a node to inspect its code and neighbours.
🚀 Quickstart (under 30 seconds)
Requires Python 3.10+. Run via uv, no install step:
uvx repo2graph build . -o .r2g && open .r2g/human/graph.html
Or install it properly:
pip install repo2graph
repo2graph build /path/to/project -o .r2g --git-history 200
repo2graph query "how does routing match a path" -o .r2g
🔌 MCP client configuration
repo2graph-mcp is a stdio MCP server. It builds its own index on the first call if one doesn't
exist yet — nothing to run ahead of time.
Claude Code
claude mcp add repo2graph -- uvx --from "repo2graph[mcp]" repo2graph-mcp /path/to/project
Claude Desktop (claude_desktop_config.json) and Cursor (.cursor/mcp.json) — same block:
{
"mcpServers": {
"repo2graph": {
"command": "uvx",
"args": ["--from", "repo2graph[mcp]", "repo2graph-mcp", "/path/to/project"]
}
}
}
Any other stdio-based MCP client (Windsurf, Zed, generic clients) takes the same command/args
pair — see docs/mcp.md for config file locations per platform and client.
✨ Key features
| Deterministic graph, not embeddings-only search | Callers, callees, imports and class hierarchies resolved from the actual AST — not a nearest-neighbour guess. |
| Hybrid retrieval | BM25 + graph-neighbour expansion by default; optional dense vector fusion (repo2graph embed) with zero required extra dependencies. |
| Hard token ceilings, enforced twice | pack_context()'s budget bounds the entire rendered markdown, not just chunk text — and the MCP server clamps and re-measures before returning. |
| 15 languages, full treatment | Python, JS/TS/TSX, Go, Rust, Java, Ruby, C, C++, C#, PHP, Kotlin, Swift, Scala, Bash get functions/classes/calls. Everything else still appears as files on the map. |
| CI-native | Published as a GitHub Action — commit a fresh graph next to your code on every push. |
| Local by default | build, query, rag, and the MCP server make zero network calls. The one opt-in exception (rag --answer) prints the provider + hostname before sending anything. |
| Export to real graph tooling | graph.graphml (yEd, Gephi, NetworkX) and graph.cypher (Neo4j, Memgraph) come out of every build, no extra step. |
🛠️ MCP tools exposed
| Tool | Arguments | What comes back |
|---|---|---|
repo_map |
none | Languages, hub files, and top entry points. Stable across calls — read this first. |
repo_search |
query, optional k (default 8, max 50), hops (default 1, max 4), budget_tokens (default 6000, max 12000) |
Seed chunks plus graph neighbours, each block headed [cite: path:start-end]. |
repo_neighbours |
node_id, optional hops (max 4), limit (default 20, max 50) |
One graph hop from a symbol/file/dir id: callers, callees, base classes, defining file. |
Secrets are excluded unconditionally on every tool call — no flag turns that off. Full contract,
including the two diagnostic tools (repo_cache_stats, repo_build_status) added for long-running
server deployments: docs/mcp.md.
📐 Architecture & token economics
- Nodes:
repo,dir,file,symbol(function/method/class/struct/trait/interface/type),module(external dependency),external(an unresolved call target). - Edges:
CONTAINS,DEFINES,IMPORTS,CALLS(carriescount+confidence),CALLS_EXTERNAL,INHERITS,CO_CHANGE(from--git-history, requires 3+ co-edits). - Call resolution is name-based, not type-based — a deliberate trade-off that keeps repo2graph
language-agnostic and setup-free. Ambiguous calls fan out to up to 5 candidate edges at
confidence = 1/n; filter toconfidence == 1.0when you need certainty over recall. - Two budget models, on purpose:
Index.retrieve()'sbudget_charsbounds only the chunks' own text (a back-compat surface);Index.pack_context()'sbudget_charsbounds the entire rendered markdown — citation headers, separators, everything. New retrieval code should be built onpack_context(). - Chunking: roughly one chunk per function/class, cut at ~4000 characters with 8 lines of overlap so nothing is lost at a seam; each chunk's header names its callers and callees, which is what makes graph-expanded retrieval better than plain top-k text search.
Full breakdown of every node/edge kind and the chunk schema: docs/reference.md. The pipeline, the Python API, and where the graph guesses (and why): TECHNICAL.md.
📊 See it on real repositories
Not a toy demo — five real, large, public repositories, each indexed at a pinned commit, with the
generated graph committed and the exact reproduction command recorded. Every number is measured,
from benchmarks/results.json, not estimated.
| Repository | Language(s) | Scope | Nodes | Edges |
|---|---|---|---|---|
| Kubernetes | Go | scoped (controllers, scheduler, API server) | 14,197 | 83,525 |
| TensorFlow | C++ / Python | scoped (Python/C++ boundary) | 20,641 | 96,013 |
| Django | Python | full repository | 54,544 | 228,461 |
| VS Code | TypeScript | scoped (src/vs/) |
113,115 | 431,453 |
| Linux kernel | C | scoped (extreme-scale) | 136,182 | 257,655 |
See examples/README.md for the full index and reproduction commands, docs/benchmarks.md for methodology, and docs/limitations.md for what running against five real repositories actually surfaced (parse-error rates on macro-heavy C/C++, call-name ambiguity, cross-language resolution limits).
📖 CLI & server reference
| Command | Does |
|---|---|
repo2graph build <path> -o .r2g [--git-history N] |
Parse a local repo into a graph + chunks. |
repo2graph github <owner/repo> -o <dir> |
Fetch, build, and clean up — no local clone needed. |
repo2graph query "<question>" -o .r2g |
Lexical search + one-hop graph expansion. |
repo2graph rag "<question>" -o .r2g [--vectors] [--answer] |
Budget-bounded GraphRAG pack; --answer sends it to an LLM (opt-in, network). |
repo2graph embed -o .r2g [--verify-rag] |
Compute/verify dense vectors for hybrid search. |
repo2graph map -o .r2g [--viz-nodes N] |
Regenerate graph.html with a different node cap. |
repo2graph stats -o .r2g |
Node/edge/function counts for an existing index. |
repo2graph-mcp <path> [--no-auto-build] [--async-build] |
stdio MCP server over .r2g. |
Environment variables (only read by rag --answer, in this precedence order):
GEMINI_API_KEY → OPENAI_API_KEY → ANTHROPIC_API_KEY → OLLAMA_HOST. No other command makes a
network call or reads these. Full flag tables and budget accounting: docs/cli.md.
🔐 Security
build, query, rag, and the MCP server make no network calls. rag --answer is the one
opt-in exception — it sends the assembled pack to an LLM provider and prints the provider +
hostname before doing so. The MCP server excludes credential-shaped files unconditionally, with no
flag to turn that off. Details: SECURITY.md.
🤝 Contributing & community
git clone https://github.com/Srinivasan-78/repo2graph
cd repo2graph
python3 -m venv .venv && .venv/bin/pip install -e ".[dev]"
make lint test # or: ruff check . && pytest
- .github/CONTRIBUTING.md — full local dev setup, code style, and the registry/Glama release process.
- docs/BACKLOG.md — deliberately deferred work and why; the closest thing to a roadmap, plus a "good first issues" section.
- AGENTS.md — this codebase's non-obvious conventions (Windows encoding, text
slicing, the two budget models) before editing
repo2graph/. - CODE_OF_CONDUCT.md — Contributor Covenant v2.1.
- Found a bug or have a feature idea? Open an issue.
License
MIT. See LICENSE.
Found repo2graph useful? Star the repo — it's the easiest way to help other people find it.
Release files for repo2graph 1.5.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| repo2graph-1.5.2.tar.gz | 222.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| repo2graph-1.5.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 346.0 kB
Release files / repo2graph-1.5.2.tar.gz
| Download URL | repo2graph-1.5.2.tar.gz |
|---|---|
| Size | 222.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a43f74e6438c7518ae3c60bf7793dceeb432be8780687cdcae6201885adc77e2
|
|
BLAKE2b-256 checksum How to use checksums |
bba635ffa1de6458c57683e0402576c2e17bae76a5aa0aa4443163000210bac2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency logRelease files / repo2graph-1.5.2-py3-none-any.whl
| Download URL | repo2graph-1.5.2-py3-none-any.whl |
|---|---|
| Size | 123.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dad357c4e846ab2009e8214e5b4ea31cabec3ab569af6b60854c5a062d835eb7
|
|
BLAKE2b-256 checksum How to use checksums |
e686f8a64980d0f2a5718de9c5426c11477304afb6eea08415a9185da0503f96
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency log