CodeGraph
tree-sitter → SQLite + FTS5 · CLI + MCP · no model
One index, three front doors. tree-sitter parses a repository into a project-level index of symbols, calls and dependencies, then answers structural questions against it: who calls this, what does this reach, what does changing it touch. Those answers come out of a full syntax-tree parse — not a text match that happened to line up, and not a model.
There is no model inside it, which is why the bytes are reproducible
This is not a feature that was left out — it is the premise the whole thing rests on. The binary carries no embeddings, no vector index and no LLM call, so the same repository and the same question return byte-identical output on your laptop, on a colleague’s machine and on a CI runner. Reproducibility is what makes the next three things possible:
- Handed to a coding agent, it is a fact rather than a sample. Asking twice in one session cannot produce two different answers.
- It can be diffed in CI. A changed impact radius means the code structure changed, not that the weights felt different today.
- It can be reproduced when it is wrong. A deterministic pipeline gives a bug exactly one path to walk back down.
The problem it solves
grep cannot answer "what does changing this function touch". grep matches characters, not call relationships: same-named methods, re-exported symbols, calls dispatched through a trait or an interface — it sees none of them, and it will always hand you the matches inside comments and string literals as well. So you fall back to opening files and walking callers upward until you feel you have got them all — and that feeling is where regressions come from. CodeGraph computes that structure ahead of time, persists it, and answers the question in one query.
People editing an unfamiliar repository
You inherit a few hundred thousand lines and need to know, before touching anything, who depends on this symbol and how far a change reaches. Read the radius first, then decide how to change it.
Coding agents
One structural query returns the relevant symbols’ source plus the call paths between them, replacing dozens of grep-and-read round-trips — more accurate context, fewer tokens, shorter loops. That is what the MCP door exists for.
Editors and IDEs
Reach the same index over local HTTP instead of each reimplementing cross-file resolution. For remote development, HTTP is also the only transport that reliably works.
CI and code review
The blast radius of a change can be computed, diffed and quoted in a review. Deterministic output is what turns "this change reaches three more modules than the last one" into a verifiable sentence.
How it works
Four stages. None of them needs a network, and none of them sends your code anywhere. The index is written into the repository’s own .codegraph/ directory.
Parse
tree-sitter builds a syntax tree per file with a per-language grammar, extracting symbol definitions, call sites and file-to-file dependencies, then resolves symbols across files. This stage sets the ceiling on how precise every later answer can be.
Persist
Results go into a per-project SQLite database, with full-text search handled by FTS5. SQLite is compiled into the binary, so the host needs no system library installed.
Query
Symbol search, callers, callees, dependencies, change-impact radius, and a whole-graph export ranked by PageRank centrality. Queries read the index — sub-millisecond, not a fresh walk of the repository.
Follow
A background daemon watches for file changes on a 2-second debounce and updates the index incrementally, lagging writes by about a second. Every client on one project — terminal tabs, agents, editors — shares that single daemon; it exits once they all disconnect and the idle timeout elapses.
Three front doors, one index
The index is built once. People, agents and editors each come in through whichever door suits them and see the same data — there is no case where the CLI answer and the agent answer disagree.
CLI
for you
$ codegraph query "<symbol>" -p .A Clap subcommand set: init, index, sync, query, files, status, callers, callees, impact, affected, check, export, unlock — plus completion installers for bash, zsh, fish, powershell and elvish.
MCP over stdio
for coding agents
$ codegraph serve --mcpA standard MCP stdio server. codegraph install --yes detects the agents and IDEs you already have and writes their config; codegraph skill install additionally drops the usage guide into each one’s skill directory.
MCP over HTTP
for editors and remote work
$ codegraph serve --httpBinds 127.0.0.1:8111 by default and is not exposed off the host. codegraph http list shows what is running; codegraph http stop <addr> ends one of them. This is the recommended transport for SSH remote development.
What you can ask it
The command line and the MCP tools sit on one implementation, so the answers match.
| Question | Command line | MCP tool |
|---|---|---|
| Where is this symbol defined? | codegraph query | codegraph_search |
| How does this area work? | codegraph export | codegraph_explore |
| Give me its source and its call trail | codegraph query --json | codegraph_node |
| Who calls it? | codegraph callers | codegraph_callers |
| What does it call? | codegraph callees | codegraph_callees |
| What does changing it touch? | codegraph impact | codegraph_impact |
| Which files did this change affect? | codegraph affected | — |
| Is the index ready? | codegraph status | codegraph_status |
impact returns the transitive closure, not one layer of callers — which is the main thing it does that walking the call chain by hand does not. export can order the whole graph by PageRank centrality, which is how you find the real hubs in a repository you have never seen.
Install and first run
The one-liner detects your platform, downloads the matching prebuilt binary and puts it on your PATH — no Rust toolchain, no compile wait. It is not published to crates.io, so the registry path of a plain cargo install will not find it; with a Rust toolchain, use the --git form below.
# Linux and macOS
$ curl -fsSL https://raw.githubusercontent.com/sunerpy/codegraph-rust/main/scripts/install.sh | sh# Windows (PowerShell 5.1+)
$ irm https://raw.githubusercontent.com/sunerpy/codegraph-rust/main/scripts/install.ps1 | iex# or from source — not published to crates.io
$ cargo install --git https://github.com/sunerpy/codegraph-rust codegraph-rs# build the index into ./.codegraph/
$ codegraph init && codegraph index# look a symbol up
$ codegraph query "GraphTraverser" -p .# see what changing it would reach
$ codegraph impact GraphTraverser# wire the MCP server into installed agents
$ codegraph install --yesSet CODEGRAPH_VERSION to pin a release instead of taking the latest. In CI, CODEGRAPH_NO_DAEMON=1 forces foreground mode; pass --no-watch to skip file watching. Exclude patterns live in .codegraph/config.toml under [indexing] exclude, custom extension mappings in .codegraph/codegraph.json.
Language support
38 languages are parsed, but not to the same depth — and the depth is the number that matters. The three tiers below are graded by extraction depth; do not collapse them into "supports 38 languages".
- 29Full symbol extraction
- TypeScript · TSX · JavaScript · JSX · ArkTS · Python · Go · Rust · Java · C · C++ · C# · PHP · Ruby · Swift · Kotlin · Dart · Scala · Lua · Luau · Objective-C · R · Solidity · Nix · Terraform · Erlang · CFML · GDScript · Pascal
- 6Embedded / template extraction
- Vue · Svelte · Astro · Razor (.cshtml) · Liquid · XML / MyBatis mapper
- 3File level only
- YAML · Twig · Properties
In tier 2, symbols come from the scripts and template markup embedded in a host file, so the granularity depends on how that file was written. Tier 3 records files and the relationships between them, with no symbol-level call graph. The language set is fixed and there is no heuristic fallback — a file is either in the table or it is not in the graph.
Platforms
Six prebuilt targets, published as codegraph-<version>-<target>.<ext>. Linux builds are statically linked against musl — no glibc dependency and no system SQLite.
| Platform | Arch | Target triple | Format |
|---|---|---|---|
| Linux | x86_64 (musl, static) | x86_64-unknown-linux-musl | .tar.gz |
| Linux | aarch64 (musl, static) | aarch64-unknown-linux-musl | .tar.gz |
| macOS | x86_64 | x86_64-apple-darwin | .tar.gz |
| macOS | aarch64 (Apple Silicon) | aarch64-apple-darwin | .tar.gz |
| Windows | x86_64 | x86_64-pc-windows-msvc | .zip |
| Windows | aarch64 (ARM64) | aarch64-pc-windows-msvc | .zip |
You can also download an archive straight off the releases page, extract it, and put codegraph on your PATH.
Stack and storage
Every choice here serves the same goal: one binary, no external dependency, reproducible output.
- Rust, Edition 2024. Shipped as a single executable with no runtime.
- tree-sitter, one grammar per language, plus cross-file symbol resolution.
- Per-project SQLite with FTS5 for full-text search. SQLite is statically linked, so nothing needs installing on the host.
- .codegraph/ inside the repository — codegraph.db and its WAL, config.toml, codegraph.json, and the daemon’s pid, socket and log.
- Clap subcommands, with completion scripts for five shells shipped in the binary.
- A per-project shared daemon over a Unix socket, watching files and updating the index incrementally; it exits once all clients disconnect and the idle timeout elapses.
- Indexing and querying are entirely offline. The HTTP transport binds 127.0.0.1 by default.
- MIT.
What it does not do
Stating the boundary is worth more than listing another feature — especially for a tool this easy to mistake for something else.
No similarity retrieval
No embeddings, no vector store, no turning a question into a vector and looking for near neighbours. It answers structural questions using edges that genuinely exist in the syntax tree. If you want to find code by "roughly what it means", this is the wrong tool.
No judgement
It tells you the call relationships and the blast radius, not whether the code is any good or whether it has a bug. Types stay the compiler’s job, style the linter’s, correctness the test suite’s.
Cross-file resolution is best effort
Cross-file symbol resolution is name-based, so an ambiguous call returns several candidates. Dynamic dispatch, reflection and calls assembled at runtime are invisible to static parsing.
The index is not instantaneous
The daemon lags file writes by roughly a second. Query immediately after an edit and you may read the previous version; tool responses flag which files are pending re-index.
The language set is fixed
A language outside those 38 is not heuristically "parsed as best we can" — it simply does not enter the graph. That is a deliberate trade: better to under-collect than to emit edges nothing supports.
Run init once in any repository
Prebuilt binaries, the one-line installer and a source build are all below. It is an MIT-licensed personal project; issues and pull requests live in the same repository.