Skip to main content

repo2graph

AST-driven code graphs & zero-dependency GraphRAG for AI coding agents and humans

English · 简体中文 · 日本語 · Français · Español · Deutsch

📦  Package 🩺  Health 🗂️  Listed on
PyPI version
Python versions
License: MIT
CI status
Dependency audit status
Provenance and licence compliance status
Glama MCP server score
Listed on mcpservers.org
Listed in the MCP Registry
repo2graph on AI Agents Listing

GitHub stars

repo2graph building a map of a repository, then answering a question about it, in a terminal

What is it · Quickstart · MCP setup · Compare · 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 code graph of a project mapped by repo2graph

Interactive canvas, zoomed Filter & inspector controls
Zoomed into the map: named functions, files and libraries joined by arrows Side panel with search box, node kinds and relationship kinds

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.

🚀 Four ways to run repo2graph

Same graph, same chunk format, same .r2g output — pick the interface for where you're standing right now.

🐍  Python / CLI ⚙️  GitHub Action 🔌  MCP server 🐳  Docker

Local dev, scripting, ad-hoc questions from a terminal.

Jump in ↓

A fresh graph committed next to your code on every push, zero Python setup.

Jump in ↓

Give Claude, Cursor or any MCP client live, cited access to the codebase.

Jump in ↓

Enterprise-ready, read-only, non-root container deployment.

Jump in ↓

🐍 1. Python / CLI

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

A terminal running repo2graph build on a repository; a JSON summary appears counting files, functions, classes, CALLS, IMPORTS and CO_CHANGE edges, nodes, edges and chunks

One pass over this repository — 195 files, 2,552 nodes, 11,118 edges — takes about three seconds and needs no configuration file, no language server and no API key. Ask it something, and the answer comes back as source you can check, not a summary you have to trust:

A terminal running repo2graph rag with a question; a repo map scrolls past and then cited code blocks appear, each headed with a cite marker naming the file and line range, listing the callers and callees of the function shown

Full flag tables, budget accounting and the Python API: docs/cli.md · docs/python-api.md.

⚙️ 2. GitHub Action

Published on the GitHub Marketplace — one step, no Python setup on the runner:

- uses: actions/checkout@v4
  with: { fetch-depth: 0 }   # full history, so CO_CHANGE edges are meaningful

- uses: Srinivasan-78/repo2graph@v2
  with:
    path: .                  # or: repo: some-org/other-repo
    git-history: "500"       # commits scanned for CO_CHANGE edges (0 = skip)
    artifact-name: repo-graph

@v2 follows every 2.x release; pin an exact tag (@v2.1.0) to upgrade by hand instead. It never calls an LLM — --answer is deliberately not exposed — and it writes a job-summary table (hub files, CO_CHANGE hotspots, the graph delta since the last build) straight from the artifacts, so the shape of the map shows up in the run without downloading anything.

Also pack a cited context for a fixed question, and push the map to a browsable branch:

- uses: Srinivasan-78/repo2graph@v2
  with:
    query: "how does auth middleware validate a token"
    commit-branch: graph     # force-pushed; this repo's own /graph branch is built this way

All inputs/outputs, private-repo tokens and the vector-embedding step: docs/github-action.md.

🔌 3. MCP server

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.

An MCP repo_neighbours call on one function id; the reply lists its defining class, its inner function, the two callers and the two callees, each with a file and line number

That is the hop grep cannot do: one symbol in, and its definer, its callers and its callees come back with file and line — the relationship, not a text match that happens to contain the name.

🐳 4. Docker

For enterprise and shared deployments, an official Dockerfile is provided. It's a multi-stage build running as a non-root user (10000:10000), fully compatible with a read-only root filesystem and dropped capabilities.

docker build -t repo2graph .
docker run --rm \
  --read-only \
  --cap-drop=ALL \
  --security-opt=no-new-privileges \
  --network=none \
  -v /path/to/repo:/repo:ro \
  -v repo2graph-index:/repo/.r2g \
  repo2graph build /repo -o /repo/.r2g

See docs/ENTERPRISE_DEPLOYMENT.md for full container hardening and HTTP server instructions.

✨ 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.
17 grammars, full treatment Python, JS, TS, TSX, Go, Rust, Java, Ruby, C, C++, C#, PHP, Kotlin, Swift, Scala, Bash and Lua get functions/classes/calls — 29 file extensions in all. 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.

🆚 How it compares

Several tools build a graph out of a codebase. The thing that separates them is what comes back when you ask a question — a picture, a subgraph, or the code itself.

repo2graph Graphify Code Graph (Obsidian) grep / embedding RAG
What a query returns the source, packed — every block headed [cite: path:start-end] a scoped subgraph, a path, or a concept explanation to traverse a force-directed picture to read matching lines, or nearest-neighbour chunks
How hits are ranked BM25 seeds, then k-hop graph expansion; optional dense fusion graph traversal (explicitly not a vector index) n/a — it is a view lexical only, or vectors only
Token budget hard cap on the whole pack, re-measured before returning (12k ceiling over MCP) not a packing layer n/a usually unbounded
Edges from git history CO_CHANGE, from --git-history
Runs with no assistant, no model, no account yes — CLI, MCP, or the GitHub Action code pass is local; the docs/media pass uses a model needs Obsidian desktop 1.7.2+ varies
Corpus code in 16 parsed grammars, every other file as text code in ~40 languages, plus docs, PDFs, images, video TS/TSX/JS/Python parsed, imports-only for 8 more anything

Reach for Graphify when the graph itself is the product: community detection, shortest path between two concepts, and your PDFs and design docs in the same graph as the code. Reach for the Obsidian plugin when a human wants to read the graph beside their notes. Reach for repo2graph when an agent needs cited source inside a fixed token budget, when it has to run in CI with no model and no account, or when "which files keep changing together" is part of the answer.

Longer version, with the trade-offs each choice implies: docs/comparison.md.

🛠️ MCP tools exposed

Five tools. Three answer questions about the code; two report on the server itself.

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 (default 1, max 4), limit (default 20, max 50) One graph hop from a symbol/file/dir id: callers, callees, base classes, defining file.
repo_cache_stats none Result-cache counters: hits, misses, size, max_size, ttl_s, evictions, hit_rate. Never itself cached.
repo_build_status task_id Progress of a background --async-build: building, ready, failed or unknown, with progress_pct and eta_s.

The three content tools exclude secrets unconditionally — no flag turns that off — and every numeric argument is clamped in the handler, so a caller cannot widen a bound by asking. Full contract, argument ceilings and client configs: docs/mcp.md. Running it shared, over HTTP, with bearer or OIDC auth and an audit log: docs/ENTERPRISE_DEPLOYMENT.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 (carries count + 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 to confidence == 1.0 when you need certainty over recall.
  • Two budget models, on purpose: Index.retrieve()'s budget_chars bounds only the chunks' own text (a back-compat surface); Index.pack_context()'s budget_chars bounds the entire rendered markdown — citation headers, separators, everything. New retrieval code should be built on pack_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,451 110,246
TensorFlow C++ / Python scoped (Python/C++ boundary) 21,380 115,984
Django Python full repository 55,810 303,339
VS Code TypeScript scoped (src/vs/) 113,080 656,158
Linux kernel C scoped (extreme-scale) 136,219 256,413

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 [--format text] Node/edge/function counts for an existing index; --format text for a quality summary.
repo2graph doctor [path] Diagnose environment, dependencies, permissions, and index integrity.
repo2graph explain-path <path> [-r <repo>] Say whether a path would be indexed, and which precedence rule decided.
`repo2graph explain <edge node
repo2graph completion [shell] Print shell tab completion setup script (bash, zsh, fish).
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_KEYOPENAI_API_KEYANTHROPIC_API_KEYOLLAMA_HOST. --model overrides the provider's best-effort default. No other command makes a network call or reads these. Full flag tables and budget accounting: docs/cli.md.

🔐 Security

  • Secure-by-default secret exclusion: build, github, auto-building query/rag, GitHub Action, and MCP exclude credential files (.env*, private keys, certificates, tokens, .ssh, .aws, .gnupg) automatically. Use --include-secrets only if you explicitly choose to index them.
  • Content-aware secret scanning: Chunks are scanned for high-entropy tokens, cloud API keys (AWS, OpenAI, Google, Slack, GitHub), JWTs, DB URLs, and private keys. Inline matches undergo line-preserving redaction (--secret-policy redact-match|exclude-file|warn-only|off).
  • Sanitized logs and events: Audit logs and structured event sinks enforce cycle detection, container size limits, recursion depth ceilings, and scrub URL basic-auth credentials.
  • Local by default: 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. Details: .github/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 2.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for repo2graph 2.1.0
File Size Uploaded
repo2graph-2.1.0.tar.gz 429.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for repo2graph 2.1.0
File Interpreter ABI Platform
repo2graph-2.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 638.8 kB

Release files / repo2graph-2.1.0.tar.gz

Download URL repo2graph-2.1.0.tar.gz
Size 429.1 kB
Tags Source
SHA-256 checksum
How to use checksums
6a920393d28897c0ddf53674a93e529b8373b503424eb8c329a2fa12cab4d71f
BLAKE2b-256 checksum
How to use checksums
1a70d70d50363125483a172651abf77b0d06e191dd894c77b5b6cd9404e99ad6
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 24, 2026.

Transparency log

Release files / repo2graph-2.1.0-py3-none-any.whl

Download URL repo2graph-2.1.0-py3-none-any.whl
Size 209.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0e5ff9cd221aa03bd72429c38dba96267c4c79d83bbf8e6a3a0e1121c8412a1a
BLAKE2b-256 checksum
How to use checksums
aeb19144d00056696246d66bc2ea864b4c12e38a836fdd39c17648340dbc820c
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 24, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

2.1.0 This release

2 release files

2.0.0

2 release files

1.6.0

2 release files

1.5.4

2 release files

1.5.3

2 release files

1.5.2

2 release files

1.5.1

2 release files

1.5.0

2 release files

1.4.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page