Skip to main content

codegraph

Graph-based code understanding for LLM agents. Parses a repo once with tree-sitter (no LLM, no cost), stores symbols and relations in SQLite, and serves compact, token-budgeted answers over MCP.

Instead of reading whole files, the agent asks the graph.

Install

pip install codegraph-network              # provides the `codegraph` command
pip install "codegraph-network[embed]"     # optional: semantic search, see "Hybrid search"

From a checkout:

pip install -e ".[dev]"     # drop [dev] if you don't need pytest/ruff
pip install -e ".[embed]"   # optional: semantic search (fastembed + numpy), see "Hybrid search"

Use with Claude Code

claude mcp add codegraph -- codegraph -r /path/to/repo serve

Or in any MCP client config:

{"mcpServers": {"codegraph": {"command": "codegraph", "args": ["-r", "/path/to/repo", "serve"]}}}

The index lives in <repo>/.codegraph/graph.db and updates incrementally on every server start; reindex re-scans after edits made outside the session. .gitignore it.

Explore visually

codegraph -r /path/to/repo ui

Opens an interactive map of the repo in your browser (served from 127.0.0.1 only, nothing leaves your machine). You start from the file-level network: lines are calls and imports between files, colour is community (or folder). Drag nodes to rearrange and pin them, scroll to zoom, drag the background to pan. Double-click a file to open it into its functions and classes; double-click a symbol to pull in everything it calls and everything that calls it. The side panel shows the source, callers and callees (click to jump), and Show impact highlights the transitive callers, i.e. what breaks if the symbol changes. Press / to search.

Tools

Tool Use it to
repo_map PageRank-ranked overview within a token budget; focus= personalizes it to what you're working on
search Find symbols by name, words (camel/snake split) or docstring; with the embed extra also by meaning, each hit tagged [lexical] / [semantic] / [both]
context Best first call: source + signatures it uses + who uses it, in one reply
source Exact source of one symbol
outline Symbol tree of a file, without code
callers / callees Walk the call/inherit graph (depth N)
impact Blast radius of a change, grouped by file
related Closest symbols to one symbol (direct + multi-hop), ranked by personalized PageRank; each line says how it is related (uses, used by, tested by, tests, key, similar)
similar Symbols that mean the same thing as this one even with no call between them (needs the embed extra)
file_deps What a file imports and what imports it
stats Index size, edges by confidence, communities
report Key symbols, communities, surprising connections; writes .codegraph/GRAPH_REPORT.md and a browsable graph.html
review (prs) What the git diff touches: blast radius per changed symbol, missing tests, files that usually change with it
reindex Re-scan after big external edits

The MCP server and the CLI are both generated from one tool registry (src/codegraph/tools.py), so they cannot drift apart. The CLI mirrors the tools: codegraph map, codegraph context Store.resolve, codegraph impact parse, ...

Languages

Python, TypeScript/TSX, JavaScript, Go, Rust, C/C++.

Beyond code, also parsed statically (no LLM): Markdown (headings become section symbols; `code spans` link to the symbols they name, relative links count as imports), SQL (CREATE TABLE/VIEW/FUNCTION/PROCEDURE, with FROM/JOIN/REFERENCES links), and PDF pages (pip install -e ".[pdf]"). Prose and SQL mentions link only when the name is unambiguous.

Edge confidence

Every edge records how it was resolved: extracted (one target named by the source itself: same file, an import, self.x()), inferred (a name match by proximity) or ambiguous (several equally plausible targets). callers, callees and context tag anything that is not extracted; impact marks it with ?. Treat tagged edges as upper bounds.

Scripting and ignoring

codegraph <tool> exits 0 on an answer, 3 when a name matches several symbols, 4 when it matches none. .codegraphignore (gitignore-style: # comments, dir/, /anchored, *.glob, !negation) excludes paths from the index, on top of the built-in skips (node_modules, venv, dist, hidden directories, ...).

Installing into assistants and git

codegraph install [claude|cursor|gemini|agents|all]   # skill, MCP config, guidance block; --uninstall to undo
codegraph hook install                                # re-index after commit, checkout, merge, rebase

install is idempotent and merges into existing files (guidance lives between <!-- codegraph:start/end --> markers; JSON configs keep their other entries). For Claude Code it also adds a Glob|Grep hint hook (--no-hooks to skip). Git hooks are appended to existing ones and run the indexer in the background.

How it works

Indexing is incremental in two layers. Files are re-parsed only when their hash changes, and edge resolution is scoped: a change re-resolves only the raw references whose name, or whose source file, is affected. Parsing runs across processes and writes are batched; PageRank and community detection warm-start from the previous run. On a 3,091-file / 59k-symbol / 79k-edge corpus (8 cores) a full index takes ~7.6s (was ~22s single-process), changing one file ~2s, and a no-op reindex ~0.3s. PageRank is the one step that always walks the whole graph; whether it converged is reported by codegraph index rather than assumed.

Edge resolution is name-based, using the strongest evidence available:

  • self.x() / this.x() link only to methods of the enclosing class, its bases and its subclasses (no match => inherited from an external base => no edge).
  • obj.x() links only if a candidate is in the same file, an imported file or the same directory.
  • bare x() prefers same file, then imported files, then same directory, then anywhere.
  • a bare call to a Python builtin, or to a name imported from a module outside the repo (from typing import cast), links to nothing — otherwise isinstance(...) would attach thousands of phantom edges to whatever repo method happens to share the name.
  • Targets defined in more than 4 places are dropped as too ambiguous.

Everything above is exact and structural. A second layer adds recall for relationships that are not spelled out in code. It never touches callers / callees / impact or global PageRank: those stay structural. Soft links live in their own tables (links, file_links) and enter the personalized PageRank behind context / related / repo_map(focus=) at a lower weight than a call edge (LINK_WEIGHT in queries.py).

Link Source Needs
tests test_foo.py / foo.test.ts / foo_test.go -> the file named after it, and test_bar -> bar inside that pair; test callers are labelled tested by nothing
key the same string literal used in matching roles in different files: route path (@app.get("/x") vs requests.get("/x"), express vs fetch), event name (emit vs on), config key (getenv, config.get). Table-driven: add a row to PATTERNS in keys.py. Keys shared by more than 8 symbols and generic events (error, data, ...) are ignored nothing
co-change git log --name-only (last 1000 commits, commits over 30 files ignored, pairs need 3+ co-changes); shown by deps and used by repo_map's ranking. No git or no history: no edges git
similar top-5 nearest neighbours by embedding cosine >= 0.85, skipping pairs already linked by a call/inheritance, overloads, and test-to-test pairs embed extra

Semantic search is optional: pip install codegraph[embed] (fastembed + numpy). Each function / method / class / type is embedded from its name as words, qualified name, signature and doc line with a small local ONNX model (BAAI/bge-small-en-v1.5); there is no network access at query time, the model files are downloaded once at the first index. Vectors are cached in SQLite by content hash, so only changed symbols are ever re-embedded and a no-change reindex stays near-instant. search fuses FTS5 and vector rankings with reciprocal rank fusion (semantic hits in test files count half). Without the extra, or with CODEGRAPH_EMBED=off, nothing changes: the output is the plain lexical search, byte for byte.

Providers are pluggable: CODEGRAPH_EMBED=package.module:factory loads any object with a name, embed_passages(list[str]) and embed_query(str) returning L2-normalised float32 vectors (see tests/fake_embed.py); CODEGRAPH_EMBED_MODEL picks another fastembed model.

Measured (fastembed bge-small, Apple silicon, CPU)

Flask (Python) ky (TypeScript)
files / symbols 88 / 1,723 100 / 11,427
cold index, no embeddings 0.4 s 0.9 s
first-time embedding (one-off, then cached) 27 s / 1,624 symbols 58 s / 7,389 symbols
no-change reindex 0.06 s 0.04 s
edges (structural) 1,011 calls, 74 inherits 2,915 calls, 8 inherits
soft links 70 tests, 52 key, 353 similar, 39 co-change 3 key, 1,261 similar, 40 co-change

codegraph bench tasks.yaml replays your own (task, expected symbols) list and reports, per task and in total, recall@k of lexical-only vs hybrid search and the tokens an agent reads through the graph vs reading the files that contain the expected symbols (pip install codegraph[bench] for YAML; JSON works without). On 7 Flask and 5 ky natural-language tasks written for this README: hybrid recall 8/9 and 3/5, lexical-only 1/9 and 1/5. The lexical baseline is the existing search, which needs every query word to match, so it scores ~0 on questions phrased unlike the code by construction. Treat the gap as "what the semantic layer adds for descriptive queries", not as a general accuracy figure.

The similarity threshold (0.85) was set on codegraph's own code: bge-small cosines are high in general (median nearest-neighbour 0.80 here); real near-duplicates (make_repo in two test files, pagerank vs personalized_pagerank) start around 0.85, and below it the pairs are mostly generically similar test names.

Tests

pytest              # 232 tests
pytest tests/test_edges.py -rA      # per-language edge precision/recall report

tests/fixtures/<lang>/expected.json holds hand-verified edges per language. Each fixture lists true edges (must all be found) and known_ambiguous ones (accepted false positives from not tracking receiver types, each with a stated reason). Anything the tool emits that is in neither list fails the test, so a new kind of false positive cannot slip in unnoticed.

Known limits

  • Remaining false positives: obj.x() where obj's type is unknown and an imported file defines a method called x (e.g. Path(p).resolve() vs your own resolve). Type-aware indexers (SCIP) fix this.
  • Dynamic dispatch, reflection and macros are mostly invisible.
  • Semantic search is as good as a small local model: it can miss (jsonify for "turn python objects into a json response" in Flask) and it ranks by meaning of the name/signature/doc line, not of the body. Variables and TypeScript interface fields are not embedded.
  • String keys match on identical literals only (no /users/{id} vs /users/1), and only for Python and JS/TS call shapes listed in keys.py. os.environ["X"] and process.env.X are not recognised yet.
  • Co-change uses the last 1000 commits and treats renames as new files.
  • Object-literal properties in JS/TS ({ json: body }) are indexed as methods by the parser, which inflates TypeScript indexes (ky: 11k symbols for 100 files) and puts noise in semantic results.
  • Go/Rust/C++ import resolution is heuristic. Notably a stdlib import can collide with a local directory of the same name: net/http matches an internal/http directory, because there is no go.mod to tell the module prefix apart. Python imports are exact (see py_lookup in store.py).

Next steps

  • Type-aware resolution via SCIP/LSIF indexers for exact call edges
  • Optional one-line LLM summaries per symbol, generated once at index time
  • Git-aware ranking by recency (co-change is in; "recently changed" is not)

Metadata

Release files for codegraph-network 0.2.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 codegraph-network 0.2.0
File Size Uploaded
codegraph_network-0.2.0.tar.gz 102.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for codegraph-network 0.2.0
File Interpreter ABI Platform
codegraph_network-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 185.4 kB

Release files / codegraph_network-0.2.0.tar.gz

Download URL codegraph_network-0.2.0.tar.gz
Size 102.4 kB
Tags Source
SHA-256 checksum
How to use checksums
cd98f273b768c862a506b0e782f2b7ea3ffd8b66336ad0f96a9ef605e6a6538d
BLAKE2b-256 checksum
How to use checksums
6151a6188a633ad1003585d13643258b3fa9fc40ecba6ee276be33855d3b58e9
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 Oct 19, 2026.

Transparency log

Release files / codegraph_network-0.2.0-py3-none-any.whl

Download URL codegraph_network-0.2.0-py3-none-any.whl
Size 83.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
297e530d2ee5c4f71d70e7a9c6c9c26cba7bedf5fc0c3d99381026394a74ea4e
BLAKE2b-256 checksum
How to use checksums
25b55f44e7ca71078b7d065ea1ad7d1aa57ec0f697dae186e50c5cf82c122838
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 Oct 19, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.0

2 release files

This release

0.2.0 This release

2 release files

0.1.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