# Codegraph

> Source: <https://github.com/colbymchenry/codegraph>
> Published: 2026-07-26 04:19:41+00:00

Already installed? Run `codegraph upgrade`

Follow [@getcodegraph](https://x.com/getcodegraph) on X for updates.

### Supercharge Claude Code, Cursor, Codex, OpenCode, Hermes Agent, Gemini, Antigravity, and Kiro with Semantic Code Intelligence

**The fastest complete code graph · surgical context · built for how agents actually work · 100% local**

**The CodeGraph platform is coming** — for every PR, know exactly what to test, what could break, which flows are affected, and whether business logic is compromised.

Get early beta access to the hosted product · getcodegraph.com

[Get Started](#get-started)[Language Support](#language-support)[Why CodeGraph?](#why-codegraph)[Key Features](#key-features)[Framework-aware Routes](#framework-aware-routes)[Mixed iOS / React Native / Expo bridging](#mixed-ios--react-native--expo-bridging)[Quick Start](#quick-start)[How It Works](#how-it-works)[CLI Reference](#cli-reference)[MCP Tools](#mcp-tools)[Library Usage](#library-usage)[Configuration](#configuration)[Telemetry](#telemetry)[Verified releases](#verified-releases)[Supported Platforms](#supported-platforms)[Supported Agents](#supported-agents)[Supported Languages](#supported-languages)[Measured cross-file coverage](#measured-cross-file-coverage)[Troubleshooting](#troubleshooting)[License](#license)

**No Node.js required** — one command grabs the right build for your OS:

```
# macOS / Linux
curl -fsSL https://raw.githubusercontent.com/colbymchenry/codegraph/main/install.sh | sh

# Windows (PowerShell)
irm https://raw.githubusercontent.com/colbymchenry/codegraph/main/install.ps1 | iex
```

**Already have Node? Use npm instead (works on any version)**

```
npm i -g @colbymchenry/codegraph
```

CodeGraph bundles its own runtime — nothing to compile, no native build, works the same everywhere. The installer puts codegraph on your PATH but doesn't change your current shell — open a new terminal before the next step so the command resolves.

**Upgrade any time** with `codegraph upgrade`

— it detects how you installed (bundle, npm, or npx) and updates in place. Add `--check`

to see if an update is available, or `codegraph upgrade <version>`

to pin one.

In a **new terminal**, run the installer to connect CodeGraph to the agents you use:

```
codegraph install
```

Detects and auto-configures Claude Code, Cursor, Codex CLI, opencode, Hermes Agent, Gemini CLI, Antigravity IDE, and Kiro — wiring the CodeGraph MCP server into each. This is the step that connects CodeGraph to your agent; installing the CLI in step 1 does not do it on its own. It only wires up your agent — it does not index any code; building each project's graph is the separate

`codegraph init`

in step 3. (Shortcut: `npx @colbymchenry/codegraph`

downloads and runs this in one go.)

```
cd your-project
codegraph init
```

`codegraph init`

creates the local `.codegraph/`

directory and builds the full graph in the same step — one command, done.

Auto-sync is enabled by default. CodeGraph watches the project and updates the graph on every file change — while your agent edits code, or you add, modify, or delete files. **The index is never stale, and there is nothing to re-run.**

Changed your mind? One command removes CodeGraph from every agent it configured **and** the CLI itself — every install it finds (standalone bundle, npm global package, launcher link), shown to you before anything is deleted:

```
codegraph uninstall
```

Pass `--keep-cli`

to remove only the agent configurations and keep the CLI installed.

Reverses the installer — strips CodeGraph's MCP server config, instructions, and permissions from each configured agent. Your project indexes ( .codegraph/) are left untouched; remove those per-project with codegraph uninit. Use --target to remove from specific agents, or --yes to run non-interactively.

Every language below gets the same treatment — full structural extraction and cross-file resolution into one graph, no per-language setup:

Per-language details — extensions, frameworks, and what exactly gets extracted — in Supported Languages.

When an AI agent needs to understand code — to answer a question or make a change — it discovers structure the slow way: grep, glob, and Read, one file at a time, rebuilding call paths and dependencies by hand. That's a pile of tool calls and round-trips before it even starts the real work.

**CodeGraph hands the agent the exact code it needs in one call.** It's a pre-built knowledge graph of every symbol, call edge, and dependency in your codebase — so instead of crawling files, the agent asks one question and gets back the relevant source, the call paths between those symbols (including dynamic-dispatch hops grep can't follow), and the blast radius of a change. **Surgical context, not a file-by-file search** — which means fewer tool calls and faster answers on every codebase, large or small.

A note on cost:CodeGraph's win oneverycodebase is precision — the agent stops crawling files and answers from the graph. On current models that precision is also a large direct saving: the 2026-07 re-validation measured60% lower cost and 69% fewer tokens on averageacross the seven benchmark repos, because a strong modelwithoutthe graph burns millions of tokens re-deriving structure. The savings scale with repo size and tangle — dramatic on VS-Code-class trees, modest on a 100-file project — and compound across a team's daily agent usage.

Tested across **7 real-world open-source codebases** spanning 7 languages, comparing an agent (Claude Code, headless) answering one architecture question **with** and **without** CodeGraph, at the **median of 4 runs per arm**. *Re-validated 2026-07-21 on Claude Opus 4.8 against the current build — the Rust kernel plus this cycle's resolution overhaul.*

The universal win — every repo, every size: 89% fewer tool calls · 60% cheaper · 69% fewer tokens · file reads cut to zero on all seven repos.

With the index available, the agent answers from a couple of `codegraph_explore`

calls and stops. Without it, the agent burns its budget on discovery — up to **57 tool calls and 4.3M tokens** re-deriving what the graph already knew. The **Time** column averages 20% faster but is the noisiest metric: on two small repos a strong model's raw grep loop finishes the wall-clock race sooner while still spending 5–10× the tokens and money — noted per-row below.

| Codebase | Language | Tool calls | Time | File reads | Tokens | Cost |
|---|---|---|---|---|---|---|
VS Code |
TypeScript · ~11k files | 2 vs 40 |
5× faster (41s vs 3m 24s) |
0 vs 17 |
83% fewer | 75% cheaper |
Excalidraw |
TypeScript · ~640 | 3 vs 55 | 36s vs 23s¹ | 0 vs 24 |
89% fewer | 78% cheaper |
Django |
Python · ~3k | 2 vs 29 |
38% faster | 0 vs 16 |
78% fewer | 69% cheaper |
Tokio |
Rust · ~790 | 3 vs 57 | 65% faster | 0 vs 15 |
91% fewer | 86% cheaper |
OkHttp |
Java · ~645 | 1 vs 5 | 10% faster | 0 vs 1 |
33% fewer | ~even² |
Gin |
Go · ~110 | 3 vs 10 | 57% faster | 0 vs 4 |
18% fewer | 41% cheaper |
Alamofire |
Swift · ~110 | 3 vs 53 | 49s vs 31s¹ | 0 vs 18 |
90% fewer | 86% cheaper |

¹ The small-repo floor effect: Opus 4.8 greps small trees fast enough to win wall-clock while spending ~5–10× the tokens and ~4–7× the cost — the with-arm still answers from zero file reads. ² OkHttp's without-arm got lucky in 5 calls; the with-arm answered in 1 call for ~$0.03 more. File reads = median files opened — the surgical-context win in one column: the agent never reads a file on any of the seven repos when CodeGraph is present.

**Per-repo breakdown — WITH vs WITHOUT (median of 4)**

| Codebase | Metric | WITH cg | WITHOUT cg |
|---|---|---|---|
VS Code |
Time / Tools / Tokens / Cost | 41s / 2 / 265k / $0.36 | 3m 24s / 40 / 1.5M / $1.41 |
Excalidraw |
Time / Tools / Tokens / Cost | 36s / 3 / 324k / $0.40 | 23s / 55 / 2.9M / $1.81 |
Django |
Time / Tools / Tokens / Cost | 42s / 2 / 254k / $0.35 | 1m 8s / 29 / 1.2M / $1.13 |
Tokio |
Time / Tools / Tokens / Cost | 46s / 3 / 386k / $0.44 | 2m 11s / 57 / 4.3M / $3.04 |
OkHttp |
Time / Tools / Tokens / Cost | 27s / 1 / 156k / $0.23 | 30s / 5 / 233k / $0.20 |
Gin |
Time / Tools / Tokens / Cost | 30s / 3 / 246k / $0.27 | 1m 10s / 10 / 300k / $0.46 |
Alamofire |
Time / Tools / Tokens / Cost | 49s / 3 / 316k / $0.35 | 31s / 53 / 3.1M / $2.51 |

**Full benchmark details**

**Methodology.** Each arm is `claude -p`

(Claude Opus 4.8) run headlessly against the repo with `--strict-mcp-config`

: **WITH** = CodeGraph's MCP server enabled, **WITHOUT** = an empty MCP config. Built-in Read/Grep/Bash stay available to both. Same question per repo, **4 runs per arm, median reported**. Cost = the run's `total_cost_usd`

; Tokens = total tokens processed (input incl. cached + output); Time = wall-clock; Tool calls = every tool invocation, including those inside any sub-agents the model spawns. Repos cloned at `--depth 1`

and indexed by the same CodeGraph build that served them. Re-validated 2026-07-21 on the current build (native Rust kernel, adaptive parallel resolution, scoped sync).

**Queries:**

| Codebase | Query |
|---|---|
| VS Code | "How does the extension host communicate with the main process?" |
| Excalidraw | "How does Excalidraw render and update canvas elements?" |
| Django | "How does Django's ORM build and execute a query from a QuerySet?" |
| Tokio | "How does tokio schedule and run async tasks on its runtime?" |
| OkHttp | "How does OkHttp process a request through its interceptor chain?" |
| Gin | "How does gin route requests through its middleware chain?" |
| Alamofire | "How does Alamofire build, send, and validate a request?" |

**Why CodeGraph wins:** with the index available, the agent answers directly — usually one `codegraph_explore`

returns the relevant source — and stops, with zero file reads on every benchmark repo. Without it, the agent spends most of its budget on discovery (find/ls/grep) before reading the right code. CodeGraph only helps when queried *directly*, so its instructions steer agents to answer directly rather than delegate exploration to file-reading sub-agents — otherwise a sub-agent reads files regardless and CodeGraph becomes overhead.

CodeGraph's parsing engine is a **native Rust kernel**: 20 languages — TypeScript, JavaScript, Java, Python, Go, C, C++, Rust, C#, Ruby, PHP, Swift, Kotlin, Scala, Dart, R, Lua, Luau (Metal and CUDA ride the C++ path) — parse in compiled code with one boundary crossing per file. Every language shipped only after its graphs proved **byte-for-byte identical** to the reference engine on real repositories, from small libraries up to the Linux kernel; platforms without a prebuilt binary and files with syntax errors fall back per-file automatically, same graph either way.

**And it scales itself to the machine it's on.** Worker pools, parallel resolution, and analysis caches are sized from what the system actually has — real core counts (container/cgroup-aware, so a VPS that grants 2 cores gets sized for 2, not the host's 64), honestly-measured available RAM on macOS and Linux, and the measured cost of *your* project's resolution work:

**On a workstation:** the full parallel pipeline — native parse workers, a multi-worker resolver pool that engages the moment it pays for itself, memory-gated analysis caches. The Swift compiler repository (27k files of Swift and C++) fresh-indexes in about 100 seconds; a one-file edit re-syncs in ~4.**On a 2-core / 6GB VPS:** the same graph, from a pipeline tuned to*finish*— the Linux kernel (70k files, 2M symbols, 6.4M relationships) indexes to completion in under 12 minutes where RAM-first designs run out of memory before reaching 1%.**Every day after day one:** saving a file updates the graph in well under a second — the watcher fires 300ms after a lone save and syncs exactly what changed (~0.3s of work on a 4,400-file project, ~0.4s on the 27,000-file Swift compiler repo), never re-scanning the tree. Measured against the fastest competing indexer's re-index-on-change: 2–7× faster on medium and larger repos across a 31-repo, 30-language benchmark — and the gap widens with repo size, because their cost grows with the repository and ours grows with the change.

Native Rust Kernel |
Parsing and extraction run in a compiled Rust engine for 20 languages — with graphs verified byte-for-byte identical to the reference engine, and automatic per-file fallback so nothing ever breaks |
Adapts to Your Machine |
Sizes its worker pools and caches from what the system actually has — real core counts (container-aware), honest available RAM, measured per-project cost. A workstation gets the full parallel pipeline; a 2-core VPS gets one tuned to finish reliably |
Surgical Context |
One tool call returns entry points, related symbols, and code snippets — no slow file-by-file exploration |
Full-Text Search |
Find code by name instantly across your entire codebase, powered by FTS5 |
Impact Analysis |
Trace callers, callees, and the full impact radius of any symbol before making changes |
Always Fresh |
File watcher uses native OS events (FSEvents/inotify/ReadDirectoryChangesW) with debounced auto-sync — the graph stays current as you code, zero config |
20+ Languages |
TypeScript, JavaScript, ArkTS, Python, Go, Rust, Java, C#, VB.NET, PHP, Ruby, C, C++, CUDA, Objective-C, Metal, Swift, Kotlin, Scala, Dart, Lua, Luau, R, Nix, Erlang, CFML, COBOL, Solidity, Terraform/OpenTofu, Svelte, Vue, Astro, Liquid, Pascal/Delphi |
Framework-aware Routes |
Recognizes web-framework routing files and links URL patterns to their handlers across 17 frameworks |
Mixed iOS / React Native / Expo |
Closes cross-language flows that static parsing misses: Swift ↔ ObjC bridging, React Native legacy bridge + TurboModules + Fabric view components, native → JS event emitters, Expo Modules |
100% Local |
No data leaves your machine. No API keys. No external services. SQLite database only |

**How auto-syncing works — and why you don't need to run **`codegraph sync`

manually

`codegraph sync`

manuallyWhen your agent (Claude Code, Cursor, Codex, opencode) launches `codegraph serve --mcp`

, three layers keep the index in step with your code — and make sure the agent never gets a silent wrong answer in the brief window between an edit and the next sync:

-
**File watcher with debounced auto-sync.** A native FSEvents / inotify / ReadDirectoryChangesW watcher captures every source-file create / modify / delete and triggers a re-index after a debounce window (default`2000ms`

, tunable via`CODEGRAPH_WATCH_DEBOUNCE_MS`

, clamped to`[100ms, 60s]`

). Bursts of edits collapse into a single sync. -
**Per-file staleness banner.** During the brief debounce window, MCP tool responses that would reference a still-pending file prepend a`⚠️`

banner naming it and telling the agent to`Read`

it directly. Pending files NOT referenced by the response surface as a small footer instead. Either way, the agent gets an explicit signal — validated with Claude Code, where the agent literally says "Reading the file directly for the live content" before opening it. -
**Connect-time catch-up.** When the MCP server (re)connects, codegraph runs a fast`(size, mtime)`

+ content-hash reconciliation against the working tree before answering the first query — so edits made while no MCP server was running (a`git pull`

from the terminal, edits from another editor, a previous agent session that exited) get absorbed on the next session's first tool call.

```
agent writes src/Widget.ts
  → watcher fires (<100ms)
  → debounce (default 2s)
  → sync; Widget.ts is in the index
  → next agent query sees it
```

**Verify any time** with `codegraph status`

(CLI). If anything is pending, you'll see a `### Pending sync:`

section naming the files and their edit age.

The handful of cases where manual `codegraph sync`

makes sense: the watcher is disabled (sandboxed environments, or `CODEGRAPH_NO_DAEMON=1`

), or you're scripting against the index outside an agent session and want a pre-flight sync at the start of your script.

→ Full deep-dive in [Guides → Indexing a Project](https://colbymchenry.github.io/codegraph/guides/indexing/#stay-fresh-automatically).

CodeGraph detects web-framework routing files and emits `route`

nodes linked by `references`

edges to their handler classes or functions. Querying callers of a view/controller now surfaces the URL pattern that binds it.

| Framework | Shapes recognized |
|---|---|
Django |
`path()` , `re_path()` , `url()` , `include()` in `urls.py` (CBV `.as_view()` , dotted paths) |
Flask |
`@app.route('/path', methods=[...])` , blueprint routes |
FastAPI |
`@app.get(...)` , `@router.post(...)` , all standard methods |
Express |
`app.get(...)` , `router.post(...)` with middleware chains |
NestJS |
`@Controller` + `@Get/@Post/...` , GraphQL `@Resolver` + `@Query/@Mutation` , `@MessagePattern` /`@EventPattern` , `@SubscribeMessage` |
Laravel |
`Route::get()` , `Route::resource()` , `Controller@action` , tuple syntax |
Drupal |
`*.routing.yml` routes (`_controller` , `_form` , entity handlers); `hook_*` implementations in `.module` /`.theme` /`.install` /`.inc` |
Rails |
`get '/x', to: 'users#index'` , hash-rocket `=>` syntax |
Spring |
`@GetMapping` , `@PostMapping` , `@RequestMapping` on methods |
Play |
`GET` /`POST` /… verb routes in `conf/routes` → `Controller.method` actions (Scala + Java) |
Gin / chi / gorilla / mux |
`r.GET(...)` , `router.HandleFunc(...)` |
Axum / actix / Rocket |
`.route("/x", get(handler))` |
ASP.NET |
`[HttpGet("/x")]` attributes on action methods |
Vapor |
`app.get("x", use: handler)` |
React Router / SvelteKit |
Route component nodes |
Vue Router / Nuxt |
`pages/` file-based routes, `server/api/` endpoints, route middleware |
Astro |
`src/pages/` file-based routes (`.astro` pages + `.ts` endpoints, `[param]` /`[...rest]` syntax) |

Real iOS and React Native codebases live across multiple languages — a Swift caller invokes an Objective-C selector that's been auto-bridged, a JS file calls into a native module via the React Native bridge, a JSX component delegates to a native view manager. Static tree-sitter extraction stops at each language boundary. CodeGraph bridges them so `codegraph_explore`

connects the flow end-to-end across the gap — call paths and blast radius cross the boundary instead of stopping at it.

| Boundary | JS / Swift side | Native side | How |
|---|---|---|---|
Swift → ObjC |
Swift `obj.foo(bar:)` |
ObjC selector `-fooWithBar:` |
`@objc` auto-bridging rules (including init/property/protocol forms) + Cocoa preposition prefixes (`With` /`For` /`By` /`In` /`On` /`At` /…) |
ObjC → Swift |
ObjC `[obj fooWithBar:]` |
Swift `@objc func foo(bar:)` |
Reverse-bridge name candidates; verifies `@objc` exposure from source |
React Native legacy bridge |
JS `NativeModules.X.fn(...)` |
ObjC `RCT_EXPORT_METHOD` / `RCT_REMAP_METHOD` · Java/Kotlin `@ReactMethod` |
Parses macro/annotation declarations to build a JS-name → native-method map |
React Native TurboModules |
JS `import M from './NativeM'; M.fn(...)` |
Native impl matching the Codegen spec | Treats the `Native<X>.ts` spec interface as ground truth |
RN native → JS events |
JS `new NativeEventEmitter(...).addListener('e', cb)` |
ObjC `[self sendEventWithName:@"e" body:...]` · Swift `sendEvent(withName: "e", ...)` · Java/Kotlin `.emit("e", ...)` |
Synthesized cross-language event channel keyed by literal event name |
Expo Modules |
JS `requireNativeModule('X').fn(...)` |
Swift / Kotlin `Module { Name("X"); AsyncFunction("fn") { ... } }` |
Parses the Expo DSL literals; synthetic method nodes resolve via existing name-match |
Fabric view components |
JSX `<MyView prop={v}/>` |
TS Codegen spec + native impl class | Spec → `component` node; convention-based name+suffix lookup (`View` /`ComponentView` /`Manager` /`ViewManager` ) bridges to native |
Legacy Paper view managers |
JSX `<MyView prop={v}/>` |
ObjC `RCT_EXPORT_VIEW_PROPERTY` · Java/Kotlin `@ReactProp` |
Same as Fabric — Paper-era declarations also produce `component` + `property` nodes |

**Validated on real codebases** (small + medium + large for each bridge):

| Bridge | Small | Medium | Large |
|---|---|---|---|
| Swift ↔ ObjC |
|

[realm-swift](https://github.com/realm/realm-swift)[Wikipedia-iOS](https://github.com/wikimedia/wikipedia-ios)[AsyncStorage](https://github.com/react-native-async-storage/async-storage)[react-native-svg](https://github.com/software-mansion/react-native-svg)[react-native-firebase](https://github.com/invertase/react-native-firebase)[RNGeolocation](https://github.com/Agontuk/react-native-geolocation-service)[react-native-segmented-control](https://github.com/react-native-segmented-control/segmented-control)[react-native-screens](https://github.com/software-mansion/react-native-screens)[react-native-skia](https://github.com/Shopify/react-native-skia)Each bridge emits edges tagged `provenance:'heuristic'`

with `metadata.synthesizedBy:`

set to a stable channel name (e.g. `swift-objc-bridge`

, `rn-event-channel`

, `fabric-native-impl`

, `expo-module-extract`

), so the agent can tell at a glance how a hop got into the graph.

```
npx @colbymchenry/codegraph
```

The installer will:

- Ask which agent(s) to configure — auto-detects installed ones from:
**Claude Code**,** Cursor**,** Codex CLI**,** opencode**,** Hermes Agent**,** Gemini CLI**,** Antigravity IDE**,** Kiro** - Prompt to install
`codegraph`

on your PATH (so agents can launch the MCP server) - Ask whether configs apply to all your projects or just this one
- Write each chosen agent's MCP server config, plus a small marker-fenced CodeGraph section in the agent's instructions file (
`CLAUDE.md`

/`AGENTS.md`

/`GEMINI.md`

) — that's how subagents and non-MCP agents learn the`codegraph explore`

command, since the MCP server's own guidance only reaches the main agent. Removed cleanly by`codegraph uninstall`

. - Set up auto-allow permissions when Claude Code is one of the targets

The installer **wires up your agents only — it does not index your code.** After it finishes, build each project's graph yourself with `codegraph init`

(step 3). One global `codegraph install`

covers every project; you run `codegraph init`

once per project.

**Non-interactive (scripting / CI):**

```
codegraph install --yes                              # auto-detect agents, install global
codegraph install --target=cursor,claude --yes       # explicit target list
codegraph install --target=auto --location=local     # detected agents, project-local
codegraph install --print-config codex               # print snippet, no file writes
```

| Flag | Values | Default |
|---|---|---|
`--target` |
`auto` , `all` , `none` , or csv (`claude,cursor,...` ) |
prompt |
`--location` |
`global` , `local` |
prompt |
`--yes` |
(boolean) | prompt every step |
`--no-permissions` |
(boolean) skip Claude auto-allow list | permissions on |
`--print-config <id>` |
dump snippet for one agent and exit | — |

Restart your agent (Claude Code / Cursor / Codex CLI / opencode / Hermes Agent / Gemini CLI / Antigravity IDE / Kiro) for the MCP server to load.

```
cd your-project
codegraph init
```

Builds the per-project knowledge graph index, which then auto-syncs on every file change. A single global `codegraph install`

works in every project you open — no need to re-run the installer per project.

That's it — your agent will use CodeGraph tools automatically when a `.codegraph/`

directory exists.

**Manual Setup (Alternative)**

**Install globally:**

```
npm install -g @colbymchenry/codegraph
```

**Add to ~/.claude.json:**

```
{
  "mcpServers": {
    "codegraph": {
      "type": "stdio",
      "command": "codegraph",
      "args": ["serve", "--mcp"]
    }
  }
}
```

**Add to ~/.claude/settings.json (optional, for auto-allow):**

```
{
  "permissions": {
    "allow": [
      "mcp__codegraph__*"
    ]
  }
}
```

One wildcard auto-approves every CodeGraph tool — codegraph_explore is the only one listed by default, but if you re-enable others via CODEGRAPH_MCP_TOOLS they're already permitted, no prompt.

**Agent Tool Guidance**

CodeGraph's MCP server delivers its usage guidance to your agent **automatically**, in the MCP `initialize`

response. In short, it tells the agent to:

**Answer structural questions directly with CodeGraph**— it*is*the pre-built index, so a grep/read loop just repeats work it already did. Treat the returned source as already read.**Reach for**— "how does X work", a flow/"how does X reach Y", or surveying an area. One call returns the relevant symbols' verbatim source grouped by file, the call paths between them (dynamic-dispatch hops included), and a blast-radius summary. Name a file or symbol in the query to read its current line-numbered source.`codegraph_explore`

for almost anything**Trust the results — don't re-verify with grep**, and check the staleness banner after edits.- Works
**per project**: query any project that has a`.codegraph/`

index by passing`projectPath`

— so a monorepo where only some services are indexed, or a second repo, works in one session. A path with no index returns clean guidance to use built-in tools; indexing stays your decision.

The exact text is `src/mcp/server-instructions.ts`

— the single source of truth for the main agent. Because subagents and non-MCP harnesses never see the MCP guidance, the installer also writes a short marker-fenced section into the agent's instructions file pointing at the `codegraph explore`

CLI equivalent.

```
┌───────────────────────────────────────────────────────────────────┐
│                            Claude Code                            │
│                                                                   │
│   "How does a request reach the database?"                        │
│       calls CodeGraph tools directly — no Explore sub-agent       │
│                                 │                                 │
└─────────────────────────────────┬─────────────────────────────────┘
                                  │
                                  ▼
┌───────────────────────────────────────────────────────────────────┐
│                        CodeGraph MCP Server                       │
│                                                                   │
│ explore  ·  one call → verbatim source + call flow + blast radius │
│                                 │                                 │
│                                 ▼                                 │
│                       SQLite knowledge graph                      │
│          symbols · edges · files · FTS5 full-text search          │
└───────────────────────────────────────────────────────────────────┘
```

-
**Extraction**— a native** Rust kernel**parses source with[tree-sitter](https://tree-sitter.github.io/)grammars compiled into it, extracting nodes (functions, classes, methods) and edges (calls, imports, extends, implements) for 20 languages; remaining languages and per-file fallbacks use the same extraction logic on the portable engine, producing identical graphs. -
**Storage**— Everything goes into a local SQLite database (`.codegraph/codegraph.db`

) with FTS5 full-text search. -
**Resolution**— After extraction, references are resolved: function calls → definitions, imports → source files, class inheritance, and framework-specific patterns. -
**Auto-Sync**— The MCP server watches your project using native OS file events. Changes are debounced (2-second quiet window), filtered to source files only, and incrementally synced. The graph stays fresh as you code — no configuration needed.

```
codegraph                         # Run interactive installer
codegraph install                 # Run installer (explicit)
codegraph uninstall               # Remove CodeGraph from your agents AND the CLI (--keep-cli for configs only)
codegraph init [path]             # Initialize a project + build its graph (one step)
codegraph uninit [path]           # Remove CodeGraph from a project (--force to skip prompt)
codegraph index [path]            # Full index (--force to re-index, --quiet for less output)
codegraph sync [path]             # Incremental update
codegraph status [path]           # Show statistics
codegraph unlock [path]           # Remove a stale lock file that's blocking indexing
codegraph query <search>          # Search symbols (--kind, --limit, --json)
codegraph explore <query>         # Relevant symbols' source + call paths in one shot (same output as the codegraph_explore MCP tool)
codegraph node <symbol|file>      # One symbol's source + callers, or read a file with line numbers (same output as codegraph_node)
codegraph files [path]            # Show file structure (--format, --filter, --max-depth, --json)
codegraph callers <symbol>        # Find what calls a function/method (--limit, --json)
codegraph callees <symbol>        # Find what a function/method calls (--limit, --json)
codegraph impact <symbol>         # Analyze what code is affected by changing a symbol (--depth, --json)
codegraph affected [files...]     # Find test files affected by changes (see below)
codegraph daemon                  # Manage background daemons — pick one to stop (alias: daemons)
codegraph telemetry [on|off]      # Show or change anonymous usage telemetry
codegraph upgrade [version]       # Update to the latest release (--check, --force)
codegraph version                 # Print the installed version (also -v, --version)
codegraph help [command]          # Show help, optionally for one command
```

Traces import dependencies transitively to find which test files are affected by changed source files.

```
codegraph affected src/utils.ts src/api.ts         # Pass files as arguments
git diff --name-only | codegraph affected --stdin   # Pipe from git diff
codegraph affected src/auth.ts --filter "e2e/*"     # Custom test file pattern
```

| Option | Description | Default |
|---|---|---|
`--stdin` |
Read file list from stdin | `false` |
`-d, --depth <n>` |
Max dependency traversal depth | `5` |
`-f, --filter <glob>` |
Custom glob to identify test files | auto-detect |
`-j, --json` |
Output as JSON | `false` |
`-q, --quiet` |
Output file paths only | `false` |

**CI/hook example:**

``` bash
#!/usr/bin/env bash
AFFECTED=$(git diff --name-only HEAD | codegraph affected --stdin --quiet)
if [ -n "$AFFECTED" ]; then
  npx vitest run $AFFECTED
fi
```

When running as an MCP server, CodeGraph exposes a **single tool** — `codegraph_explore`

. Measured agent behavior showed that one strong tool steers agents better than a menu of narrower ones — fewer mis-picks, and it saves context every session:

| Tool | Purpose |
|---|---|
`codegraph_explore` |
Answer almost any question in one call — "how does X work", a flow ("how does X reach Y"), or surveying an area — returning the relevant symbols' verbatim source grouped by file, plus the call paths between them and a blast-radius summary. Surfaces dynamic-dispatch hops (callbacks, React re-render, interface→impl) grep can't follow. Name a file or symbol in the query to read its current line-numbered source, the same shape the Read tool gives you. |

The other tools (`codegraph_node`

, `codegraph_search`

, `codegraph_callers`

, `codegraph_callees`

, `codegraph_impact`

, `codegraph_files`

, `codegraph_status`

) stay fully functional but **unlisted by default** — everything they return already arrives inline on `codegraph_explore`

(its blast-radius section, the relationship map, a symbol's body as its callee list). Re-enable any of them for the MCP surface with the `CODEGRAPH_MCP_TOOLS`

environment variable (e.g. `CODEGRAPH_MCP_TOOLS=explore,node,search,callers`

), or use their CLI equivalents (`codegraph node`

/ `query`

/ `callers`

/ `callees`

/ `impact`

/ `files`

/ `status`

).

Even when the server's own root has no `.codegraph/`

index, the tools stay available: pass `projectPath`

to query any indexed project — a sub-service in a monorepo, or a second repo — in the same session. A path that has no index returns clean guidance to use built-in tools instead, so nothing fails loudly, and indexing stays your decision.

CodeGraph can be embedded directly. The npm package re-exports its programmatic
API, so both `import`

and `require`

resolve the `CodeGraph`

class in your own
process — handy for embedding it in an app (e.g. an Electron main process).

``` python
import CodeGraph from '@colbymchenry/codegraph';
// CommonJS works too:
//   const { CodeGraph } = require('@colbymchenry/codegraph');

const cg = await CodeGraph.init('/path/to/project');
// Or: const cg = await CodeGraph.open('/path/to/project');

await cg.indexAll({
  onProgress: (p) => console.log(`${p.phase}: ${p.current}/${p.total}`)
});

const results = cg.searchNodes('UserService');
const callers = cg.getCallers(results[0].node.id);
const context = await cg.buildContext('fix login bug', { maxNodes: 20, includeCode: true, format: 'markdown' });
const impact = cg.getImpactRadius(results[0].node.id, 2);

cg.watch();   // auto-sync on file changes
cg.unwatch(); // stop watching
cg.close();
```

Lower-level building blocks are exported from the same entry point for callers
that drive the graph directly: `DatabaseConnection`

, `QueryBuilder`

,
`getDatabasePath`

, `initGrammars`

/ `loadGrammarsForLanguages`

, and `FileLock`

.

**Embedding requirements**

- Install from npm (
`npm i @colbymchenry/codegraph`

) so the matching per-platform package — which carries the compiled library and its dependencies — is fetched alongside the shim. - The API runs on
**your** runtime, so it needs**Node 22.5+** for the built-in`node:sqlite`

(Electron qualifies when its bundled Node is 22.5+). The CLI and MCP server are unaffected — they run on the self-contained bundled runtime. - TypeScript types ship with the package. As with any Node-targeting library,
keep
`@types/node`

available and`skipLibCheck: true`

(the common default).

Next to none — CodeGraph is **zero-config by default**, with nothing to write or
keep in sync to get started. Language support is automatic from the file
extension; there's nothing to wire up per language. The one optional file is for
mapping [custom file extensions](#custom-file-extensions).

What it skips out of the box:

**Dependency, build, and cache directories**—`node_modules`

,`vendor`

,`dist`

,`build`

,`target`

,`.venv`

,`Pods`

,`.next`

, and the like across every[supported stack](#supported-languages)— so the graph is your code, not third-party noise. This holds even with no`.gitignore`

.**Anything in your**— honored in git repos via git, and in non-git projects by reading`.gitignore`

`.gitignore`

directly (root and nested).**Files larger than 1 MB**— generated bundles, minified JS, vendored blobs.

To keep something else out, add it to `.gitignore`

. To pull a default-excluded
directory back **in** (say you really do want a vendored dependency indexed),
add a negation — `!vendor/`

. The defaults apply uniformly, so committing a
dependency or build directory doesn't force it into the graph; the `.gitignore`

negation is the explicit opt-in.

`.gitignore`

can't drop a directory you've **committed**, though. For a vendored
theme or SDK that's checked into the repo (e.g. a Metronic theme under
`static/`

), list it under `exclude`

in `codegraph.json`

— gitignore-style
patterns, matched against repo-root-relative paths, honored on index, sync, and
watch:

```
{
  "exclude": ["static/", "**/vendor/**"]
}
```

Conversely, when real source is gitignored on purpose — a project under a second
VCS (SVN, Perforce) that `.gitignore`

s its own source so it stays out of Git —
force it back in with `include`

(the opposite of `exclude`

; `includeIgnored`

only revives embedded git repos, not plain source):

```
{
  "include": ["Tools/", "Local/typescript/"]
}
```

CodeGraph discovers those files off disk, overriding `.gitignore`

, on index,
sync, and watch. An explicit `exclude`

still wins, and built-in skips
(`node_modules`

, `dist`

, `.git`

) are never re-included.

If your project uses a non-standard extension for a [supported
language](#supported-languages) — say `.dota_lua`

for Lua, or `.tpl`

for PHP —
those files are skipped by default, because the extension isn't one CodeGraph
recognizes. Map them with an optional ** codegraph.json** at your project root:

```
{
  "extensions": {
    ".dota_lua": "lua",
    ".tpl": "php"
  }
}
```

Each value is a supported language id. The mappings merge on top of the built-in
defaults and win on conflict, so you can also re-point a built-in (e.g.
`".h": "cpp"`

). Commit the file to share the mapping with your team. A typo'd
language or a malformed file is warned about and skipped — it never breaks
indexing — and a project with no `codegraph.json`

behaves exactly as before.
Re-index (`codegraph index`

) after adding or changing mappings.

CodeGraph collects **anonymous usage statistics** — which tools and commands get
used, which languages get indexed — to guide where language and agent support
work goes. **Never** any code, paths, file or symbol names, queries, or IP
addresses; usage is aggregated locally into daily totals before anything is
sent, and the ingest endpoint is [public code in this repo](/colbymchenry/codegraph/blob/main/telemetry-worker)
that enforces the documented field list. The installer asks up front; turn it
off any time:

```
codegraph telemetry off    # or: CODEGRAPH_TELEMETRY=0, or DO_NOT_TRACK=1
```

[ TELEMETRY.md](/colbymchenry/codegraph/blob/main/TELEMETRY.md) lists every field, with the off-switches and the
full data-handling story.

Every artifact is built and published by the public
[Release workflow](/colbymchenry/codegraph/blob/main/.github/workflows/release.yml) — never from a laptop — and
carries cryptographic proof of it:

-
**npm packages** are published via[trusted publishing](https://docs.npmjs.com/trusted-publishers)(OIDC — no long-lived npm tokens exist that could be stolen) with[provenance attestations](https://docs.npmjs.com/generating-provenance-statements)linking every version to the exact commit and workflow run that built it. Verify what's installed:

```
npm audit signatures
```

-
**GitHub Release bundles**(and`SHA256SUMS`

) carry signed[build attestations](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations)(SLSA v1.0 Build Level 2). Verify any downloaded bundle:

```
gh attestation verify codegraph-darwin-arm64.tar.gz -R colbymchenry/codegraph
```

Releases published before July 2026 predate this pipeline and don't carry attestations.

Every release ships a self-contained build (bundled Node runtime — nothing to compile) for all three desktop OSes, on both Intel/AMD (x64) and ARM (arm64):

| Platform | Architectures | Install |
|---|---|---|
| Windows | x64, arm64 | PowerShell installer or npm |
| macOS | x64, arm64 | shell installer or npm |
| Linux | x64, arm64 | shell installer or npm |

See [Get Started](#get-started) for the one-line install commands.

The interactive installer auto-detects and configures each of these — wiring up the MCP server (which delivers its own usage guidance, so no instructions file is written):

**Claude Code****Cursor****Codex CLI****opencode****Hermes Agent****Gemini CLI****Antigravity IDE****Kiro**

| Language | Extension | Status |
|---|---|---|
| TypeScript | `.ts` , `.tsx` |
Full support |
| JavaScript | `.js` , `.jsx` , `.mjs` |
Full support |
| ArkTS (HarmonyOS) | `.ets` |
Full support (everything TypeScript has, plus `@Component` /`@ComponentV2` structs with their ArkUI decorators (`@State` /`@Prop` /`@Link` /`@Local` /`@Builder` /…), `build()` view trees — parent→child component edges, chained-attribute links to `@Extend` /`@Styles` functions, `.onClick(this.handler)` event bindings — dynamic-dispatch bridges for state→`build()` re-renders, `@ohos.events.emitter` emit→subscriber pairs (static event keys only), and `router.pushUrl` literal urls → the target page struct; ohpm workspace modules resolve bare `import { X } from "data"` through `oh-package.json5` `file:` dependencies, honoring each module's `main` entry) |
| Python | `.py` |
Full support |
| Go | `.go` |
Full support |
| Rust | `.rs` |
Full support |
| Java | `.java` |
Full support |
| C# | `.cs` |
Full support |
| PHP | `.php` |
Full support |
| Ruby | `.rb` |
Full support |
| C | `.c` , `.h` |
Full support |
| C++ | `.cpp` , `.hpp` , `.cc` |
Full support |
| Objective-C | `.m` , `.mm` , `.h` |
Partial support (classes, protocols, methods, `@property` , `#import` , message sends; `.mm` ObjC++ may parse incompletely) |
| Metal | `.metal` |
Full support (vertex/fragment/kernel functions, structs, type aliases, call edges — MSL parses as C++, with `[[attribute]]` annotations handled) |
| CUDA | `.cu` , `.cuh` |
Full support (kernels and device/host functions, structs, classes, host→kernel call edges through `<<<grid, block>>>` launch syntax — templated launches, function-pointer launches (`auto kernel = &fn<...>` ), `dim3{...}` configs, and macro-defined kernels included; `__global__` /`__device__` /`__launch_bounds__` specifiers handled; CUDA in plain `.h` /`.hpp` headers recognized by content) |
| Swift | `.swift` |
Full support |
| Kotlin | `.kt` , `.kts` |
Full support |
| Scala | `.scala` , `.sc` |
Full support (classes, traits, methods, type aliases, Scala 3 enums) |
| Dart | `.dart` |
Full support |
| Svelte | `.svelte` |
Full support (script extraction, Svelte 5 runes, SvelteKit routes) |
| Vue | `.vue` |
Full support (script + script-setup extraction, Nuxt page/API/middleware routes) |
| Astro | `.astro` |
Full support (frontmatter + script extraction, template component/call references, `src/pages/` routes) |
| Liquid | `.liquid` |
Full support |
| Pascal / Delphi | `.pas` , `.dpr` , `.dpk` , `.lpr` |
Full support (classes, records, interfaces, enums, DFM/FMX form files) |
| Lua | `.lua` |
Full support (functions, methods with receivers, local variables, `require` imports, call edges) |
| R | `.R` `.r` |
Full support (functions in every assignment form, S4/R5/R6 classes with methods, `library` /`require` imports, `source()` file references, call edges) |
| Luau | `.luau` |
Full support (everything in Lua, plus `type` /`export type` aliases, typed signatures, and Roblox instance-path `require` ) |
| CFML | `.cfc` , `.cfm` , `.cfs` |
Full support (tag-based `<cfcomponent>` /`<cffunction>` and bare-script `component { ... }` styles, `extends` /`implements` , embedded `<cfscript>` delegation, call edges) |
| COBOL | `.cbl` , `.cob` , `.cpy` |
Full support (programs, sections/paragraphs with PERFORM/GO TO call edges, CALL 'literal' cross-program calls, COPY copybook imports — including standalone `.cpy` files — DATA DIVISION records/fields/88-levels, EXEC CICS LINK/XCTL and EXEC SQL INCLUDE targets; fixed and free format) |
| Visual Basic .NET | `.vb` |
Full support (classes, Modules, interfaces, structures, enums, properties, events, `Declare` P/Invoke, `Handles` /`WithEvents` , `Inherits` /`Implements` edges, call edges through VB's call/index paren ambiguity, `As New` instantiation, interpolated strings, LINQ, Unicode identifiers) |
| Erlang | `.erl` , `.hrl` , `.escript` , `.app.src` , `.app` |
Full support (functions with multi-clause/multi-arity grouping, `-spec` signatures, records with fields, `-type` /`-opaque` aliases, `-define` macros, `-include` /`-include_lib` /`-import` edges, local and `mod:fn` remote call edges, `fun name/arity` references, `spawn` /`apply` /`proc_lib` /`timer` /`rpc` MFA-argument call edges, `gen_server:call/cast(?MODULE)` → own `handle_call` /`handle_cast` links, `-behaviour` links, `-export` -based visibility) |
| Solidity | `.sol` |
Full support (contracts, libraries, interfaces, structs, enums, modifiers, events, errors, state variables, `import` /`using` directives, `emit` /`revert` calls) |
| Terraform / OpenTofu | `.tf` , `.tfvars` , `.tofu` |
Full support (resources, data sources, modules, variables, outputs, providers incl. aliases, `locals` ; `var.` /`local.` /`module.` /resource references with Terraform's per-directory scoping enforced; module calls bridged across the boundary — inputs to the child module's variables, `module.M.out` to the child's output, `source` to the module's files; cloudposse/atmos `remote-state` cross-component wiring when the component is statically named; `provider = aws.east` selections resolved up the module tree; `moved` /`import` /`removed` /`check` block references; `.tfvars` assignments linked to the variables they set) |
| Nix | `.nix` |
Full support (functions with simple/destructured/curried params, `let` /attrset bindings, `inherit` , `import ./path` file edges — `./dir` resolving through `default.nix` — plus NixOS module `imports = [ ./x.nix ]` lists and `callPackage ./pkg.nix` file edges; call edges; module-system option wiring — a config write like `launchd.user.agents.x = { ... }` links to the module declaring `options.launchd.user.agents` , so option flows trace across modules) |

Impact and blast-radius queries are only as good as the dependency graph behind them, so coverage is measured rather than asserted. **Fair coverage** = the share of symbol-bearing source files that have at least one *resolved cross-file dependent* — something that imports, calls, references, or (through a framework convention) routes to them — on a real-world benchmark repo per language. The residual is always a genuine static-analysis frontier (runtime dynamic dispatch, reflection / DI containers, framework-convention entry points, vendored third-party code), never hidden by gaming the denominator.

| Language | Benchmark repo | Coverage |
|---|---|---|
| TypeScript / JavaScript | this repo | 95.8% |
| Python | psf/requests | 100% |
| Go | gin-gonic/gin | 96.6% |
| Rust | BurntSushi/ripgrep | 86.7% |
| Java | google/gson | 93.3% |
| C# | jbogard/MediatR | 85.2% |
| PHP | guzzle/guzzle | 100% |
| Ruby | sidekiq/sidekiq | 100% |
| C | redis/redis | 92.2% |
| C++ | google/leveldb | 94.8% |
| Objective-C | SDWebImage | 91.6% |
| Swift | Alamofire | 95.3% |
| Kotlin | square/okhttp | 96.2% |
| Scala | gatling/gatling | 91.2% |
| Dart | flutter/packages | 92.4% |
| Svelte / SvelteKit | sveltejs/realworld | 100% |
| Vue / Nuxt | nuxt/movies | 93.5% |
| Astro | xingwangzhe/stalux | 93.0% |
| Lua | nvim-telescope/telescope.nvim | 84.2% |
| Luau | dphfox/Fusion | 92.2% |
| Liquid | Shopify/dawn | 73.8% |
| Pascal / Delphi | PascalCoin | 77.4% |

Framework routing is validated the same way, on a canonical app per framework: Express 100%, FastAPI 98%, Flask 100%, NestJS 96.8%, Gin 96.5%, Axum 100%, Rocket 93.8%, Vapor 100%, Laravel 92%, Rails 89.6%, React Router 100% — and the convention/reflection-heavy ones at their honest static-analysis ceiling: ASP.NET 83.9%, Spring 83.3%, Drupal 78.9%, Play 76.3%, Django 74.1%. SvelteKit, Vue/Nuxt, and Astro use file-based routing, so their page/endpoint coverage is the Svelte/SvelteKit (100%), Vue/Nuxt (93.5%), and Astro (93.0% — every `src/pages/`

file maps to a route node on the two validation repos) figures in the table above.

**"CodeGraph not initialized"** — Run `codegraph init`

in your project directory first.

**Indexing is slow** — Check that `node_modules`

and other large directories are excluded. Use `--quiet`

to reduce output overhead.

**MCP hits database is locked** — current builds shouldn't: CodeGraph bundles its own Node runtime and uses Node's built-in

`node:sqlite`

in WAL mode, where concurrent reads never block on a writer. If you still see it:**You're on an old (pre-0.9) install.** Reinstall to get the bundled runtime —`curl -fsSL https://raw.githubusercontent.com/colbymchenry/codegraph/main/install.sh | sh`

(macOS/Linux),`irm https://raw.githubusercontent.com/colbymchenry/codegraph/main/install.ps1 | iex`

(Windows), or`npm i -g @colbymchenry/codegraph@latest`

.— WAL couldn't be enabled on this filesystem (common on network shares and WSL2`codegraph status`

shows`Journal:`

other than`wal`

`/mnt`

), so reads can block on writes. Move the project (with its`.codegraph/`

folder) onto a local disk.

**MCP server not connecting** — Your agent starts the server itself, so you don't launch it by hand. Make sure the project is initialized and indexed (`codegraph status`

) and that the path in your MCP config is correct. If it still won't connect, re-run `codegraph install`

to rewrite the config.

**MCP tool calls fail with Transport closed while codegraph status/sync are healthy** — almost always WSL2 with the project on a Windows drive (a

`/mnt/c`

or `/mnt/d`

path), where the local socket CodeGraph uses to share one background server across sessions is unreliable. CodeGraph now falls back to serving the session in-process instead of dropping the connection, but if you still hit it, set `CODEGRAPH_NO_DAEMON=1`

in your MCP server's environment to skip the shared server entirely (each session runs in its own process). Moving the project onto the Linux-native filesystem (e.g. under `~/`

instead of `/mnt/`

) restores the shared server.**Missing symbols** — The MCP server auto-syncs on save (wait a couple seconds). Run `codegraph sync`

manually if needed. Check that the file's language is supported and isn't inside a `.gitignore`

d or default-excluded directory (e.g. `node_modules`

, `dist`

).

**Sharing one checkout between Windows and WSL** — Don't point both at the same `.codegraph/`

: the background-server lock and the SQLite index are tied to the OS that wrote them, and SQLite locking across the WSL2/Windows filesystem boundary is unreliable. Give each side its own index in the same tree by setting `CODEGRAPH_DIR`

to a distinct name on one of them — e.g. `CODEGRAPH_DIR=.codegraph-win`

on Windows, leaving WSL on the default `.codegraph`

. CodeGraph skips any sibling `.codegraph-*`

directory when indexing and watching, so the two never trip over each other.

MIT

**Made for AI coding agents — Claude Code, Cursor, Codex CLI, opencode, Hermes Agent, Gemini CLI, Antigravity IDE, and Kiro**
