Skip to main content
Glama
mohansagark
by mohansagark
README.md
<div align="center">

<img src="docs/images/logo.svg" alt="claude-graph" width="120" />

# claude-graph

**A local knowledge graph for Claude Code — structural code intelligence with zero network calls.**

[![PyPI version](https://img.shields.io/pypi/v/claude-graph?style=flat-square&color=blue)](https://pypi.org/project/claude-graph/)
[![PyPI downloads](https://img.shields.io/pypi/dm/claude-graph?style=flat-square&color=blue)](https://pypi.org/project/claude-graph/)
[![CI](https://img.shields.io/github/actions/workflow/status/mohansagark/claude-graph/ci.yml?style=flat-square&label=CI)](https://github.com/mohansagark/claude-graph/actions/workflows/ci.yml)
[![Python](https://img.shields.io/badge/python-3.11%2B-blue?style=flat-square)](https://pypi.org/project/claude-graph/)
[![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux%20%7C%20Windows-lightgrey?style=flat-square)](#requirements)
[![License](https://img.shields.io/badge/license-MIT-green?style=flat-square)](LICENSE)
[![Network calls](https://img.shields.io/badge/network%20calls-zero-brightgreen?style=flat-square)](#zero-network-calls)

---

*Answer structural questions about your codebase in a single MCP tool call — without sending a single byte of code to the cloud.*

<!-- HERO GIF: record a short (~15s) screen capture of:
     1. running `claude-graph build` in a terminal
     2. the viz opening in the browser with nodes animating into place
     3. clicking a node to highlight its neighborhood
     Save as docs/images/demo.gif and replace this comment with:
     ![claude-graph demo](docs/images/demo.gif)
-->

</div>

---

## Why claude-graph?

Claude Code answers structural questions ("what calls this?", "what breaks if I change this file?") by reading source files into context. On any non-trivial codebase that means:

- **Hundreds of files** that may not fit in the context window
- **Thousands of tokens** spent on code Claude won't actually use
- **No answer at all** for repos larger than the context window

claude-graph solves this by building a persistent **call graph** (functions → calls → functions, files → imports → files, tests → tests_for → source) stored in a local SQLite database. Claude issues a single MCP tool call and gets back only the relevant nodes and edges — typically **7× to 236× fewer tokens** than reading the source files directly.

**Everything happens on your machine. No embeddings, no cloud API, no telemetry — ever.**

---

## Real benchmark — Django (3,040 files)

> Built with `claude-graph build` on a shallow clone of [Django](https://github.com/django/django) `main`.

```
Build time:  17 seconds
Files:       3,040
Nodes:       45,096   (functions + classes + modules)
Edges:       938,763  (calls + imports + tests_for)
```

| Query | Tokens — naive (send matching files) | Tokens — claude-graph | Reduction |
|---|---|---|---|
| `callers_of HttpResponse` | 112,991 | 15,455 | **7× less** |
| `callees_of dispatch` | 92,539 | 3,143 | **29× less** |
| `callers_of authenticate` | 46,032 | 5,278 | **8× less** |
| `search permission` | 155,915 | 659 | **236× less** |

> **Dumping the full Django source naively = 1,475,429 tokens — 7.4× Claude's 200k context window.**
> Claude cannot answer structural questions about Django at all without a tool like this.

---

## Quick start

```bash
# 1. Install
pip install claude-graph

# 2. Wire it into your project (writes .mcp.json + .claude/skills/)
cd /path/to/your/project
claude-graph install

# 3. Build the graph
claude-graph build
```

Restart Claude Code (or run `/mcp` to confirm `claude-graph` is connected), then ask:

> *"What calls `save()` in this repo?"*
> *"What breaks if I change `auth/middleware.py`?"*
> *"Is `parse_file` covered by tests?"*

<!-- TERMINAL SCREENSHOT: capture the output of `claude-graph status` after a build on a real project.
     Save as docs/images/status.png and replace this comment with:
     ![claude-graph status output](docs/images/status.png)
-->

---

## Features

### 🔍 Structural queries

Ask Claude things it couldn't answer without reading the entire repo:

| Query pattern | What it returns |
|---|---|
| `callers_of NAME` | Every function that calls `NAME` |
| `callees_of NAME` | Every function that `NAME` calls |
| `imports_of NAME` | Every file that imports `NAME` |
| `tests_for FILE` | Test files linked to `FILE` |
| `file_summary FILE` | All symbols defined in `FILE` |
| `search KEYWORD` | Fuzzy search over all function/class names |

### 📡 Impact radius

Changed a file? Get the blast radius instantly:

```bash
claude-graph query callers_of parse_file
# or let Claude Code call get_impact_radius_tool automatically
```

### 🗺️ Interactive visualization

```bash
claude-graph viz                        # whole graph (capped at 500 nodes)
claude-graph viz --symbol HttpResponse  # direct neighborhood of a symbol
claude-graph viz --impact db/models.py  # visual blast radius of a file
claude-graph viz --max-nodes 0          # uncapped (may be slow on large repos)
```

<!-- VIZ SCREENSHOT: open the graph in a browser, click a node to show the panel,
     take a screenshot. Save as docs/images/viz.png and replace this comment with:
     ![claude-graph visualization](docs/images/viz.png)
-->

The viz renders a **self-contained HTML file** — no server, works fully offline. Features:
- Force-directed D3 layout with drag, zoom, and pan
- Click any node to highlight its direct neighborhood + see file/line
- Filter panel to toggle node kinds (function / class / module) and edge kinds (calls / imports / tests_for) live
- Translucent **file-cluster hulls** grouping nodes that share a file
- Search box to find any node by name

### 👁️ File watcher

```bash
pip install "claude-graph[watch]"
claude-graph watch   # auto-rebuilds incrementally on every file change
```

### 🩺 Health check

```bash
claude-graph doctor
```

Verifies grammars, FTS5, git access, MCP wiring, and graph existence — with a pass/fail table and exit code.

---

## Zero network calls

Built for corporate and regulated environments with one hard requirement: **everything stays on your machine.**

- No embeddings, no vector index, no model downloads
- No cloud API calls — not even for tokenization
- No telemetry, no daemon, no background process
- No home-directory writes — everything lives inside your repo (`.claude-graph/`, `.mcp.json`, `.claude/skills/`)
- Nothing runs automatically — you or Claude Code call `build_or_update_graph` explicitly

See [`tests/test_no_network.py`](tests/test_no_network.py) for the automated proof: a full build + query + viz + MCP startup cycle with outbound sockets disabled.

---

## MCP tools (used by Claude Code automatically)

| Tool | What it does |
|---|---|
| `build_or_update_graph` | Full build if no graph exists, incremental update otherwise |
| `get_graph_stats` | Node / edge / file counts and detected languages |
| `query_graph_tool` | `callers_of` / `callees_of` / `imports_of` / `tests_for` / `file_summary` |
| `get_impact_radius_tool` | Blast radius of a set of changed files |
| `search_nodes_tool` | Keyword search over function/class names and signatures |
| `render_graph_tool` | Render the graph (or a scoped neighborhood) to a local HTML file |

---

## CLI reference

| Command | What it does |
|---|---|
| `claude-graph build` | Full parse of every git-tracked file |
| `claude-graph update` | Re-parses only files changed since the last build |
| `claude-graph status` | Node / edge / file counts (`--json` for machine-readable output) |
| `claude-graph install` | Writes `.mcp.json` and `.claude/skills/` for this repo |
| `claude-graph serve` | Starts the MCP server (stdio) — Claude Code launches this itself |
| `claude-graph viz` | Interactive HTML graph, opens in browser |
| `claude-graph watch` | Auto-rebuild on file change (requires `claude-graph[watch]`) |
| `claude-graph doctor` | Health check with pass/fail table |
| `claude-graph query PATTERN TARGET` | Run a structural query from the CLI |
| `claude-graph search QUERY` | Keyword search from the CLI |

Every command accepts `--repo PATH` to target a repo other than `$CWD`.  
`status`, `install`, `viz`, `doctor`, `query`, and `search` accept `--json`.

---

## Supported languages

**31 built in.** Powered by [tree-sitter-language-pack](https://github.com/xberg-io/tree-sitter-language-pack) which bundles **306 grammars** — add any of them with a single `.claude-graph/languages.toml` entry, no code change needed.

| | Language | Extensions |
|---|---|---|
| <img src="https://cdn.simpleicons.org/python/3776AB" width="16"/> | Python | `.py` |
| <img src="https://cdn.simpleicons.org/javascript/F7DF1E" width="16"/> | JavaScript | `.js` `.jsx` `.mjs` `.cjs` |
| <img src="https://cdn.simpleicons.org/typescript/3178C6" width="16"/> | TypeScript | `.ts` |
| <img src="https://cdn.simpleicons.org/react/61DAFB" width="16"/> | TSX | `.tsx` |
| <img src="https://cdn.simpleicons.org/go/00ADD8" width="16"/> | Go | `.go` |
| <img src="https://cdn.simpleicons.org/rust/000000" width="16"/> | Rust | `.rs` |
| <img src="https://cdn.simpleicons.org/openjdk/ED8B00" width="16"/> | Java | `.java` |
| <img src="https://cdn.simpleicons.org/csharp/239120" width="16"/> | C# | `.cs` |
| <img src="https://cdn.simpleicons.org/ruby/CC342D" width="16"/> | Ruby | `.rb` |
| <img src="https://cdn.simpleicons.org/c/A8B9CC" width="16"/> | C | `.c` `.h` |
| <img src="https://cdn.simpleicons.org/cplusplus/00599C" width="16"/> | C++ | `.cpp` `.cc` `.cxx` `.hpp` `.hh` |
| <img src="https://cdn.simpleicons.org/swift/F05138" width="16"/> | Swift | `.swift` |
| <img src="https://cdn.simpleicons.org/kotlin/7F52FF" width="16"/> | Kotlin | `.kt` `.kts` |
| <img src="https://cdn.simpleicons.org/scala/DC322F" width="16"/> | Scala | `.scala` `.sc` |
| <img src="https://cdn.simpleicons.org/php/777BB4" width="16"/> | PHP | `.php` `.phtml` |
| <img src="https://cdn.simpleicons.org/dart/0175C2" width="16"/> | Dart | `.dart` |
| <img src="https://cdn.simpleicons.org/elixir/4B275F" width="16"/> | Elixir | `.ex` `.exs` |
| <img src="https://cdn.simpleicons.org/gnubash/4EAA25" width="16"/> | Bash / Zsh | `.sh` `.bash` `.zsh` |
| <img src="https://cdn.simpleicons.org/lua/2C2D72" width="16"/> | Lua | `.lua` |
| <img src="https://cdn.simpleicons.org/zig/F7A41D" width="16"/> | Zig | `.zig` |
| <img src="https://cdn.simpleicons.org/docker/2496ED" width="16"/> | Dockerfile | `Dockerfile` `.dockerfile` |
| <img src="https://cdn.simpleicons.org/terraform/844FBA" width="16"/> | HCL / Terraform | `.tf` `.hcl` |
| <img src="https://cdn.simpleicons.org/nixos/5277C3" width="16"/> | Nix | `.nix` |
| <img src="https://cdn.simpleicons.org/cmake/064F8C" width="16"/> | CMake | `CMakeLists.txt` `.cmake` |
| <img src="https://cdn.simpleicons.org/solidity/363636" width="16"/> | Solidity | `.sol` |
| <img src="https://cdn.simpleicons.org/nvidia/76B900" width="16"/> | CUDA | `.cu` `.cuh` |
| <img src="https://cdn.simpleicons.org/r/276DC3" width="16"/> | R | `.r` `.R` |
| <img src="https://cdn.simpleicons.org/julia/9558B2" width="16"/> | Julia | `.jl` |
| <img src="https://cdn.simpleicons.org/gleam/FFAFF3" width="16"/> | Gleam | `.gleam` |
| <img src="https://cdn.simpleicons.org/cairo/000000" width="16"/> | Cairo | `.cairo` |

**Adding a language:** drop a `.claude-graph/languages.toml` into your repo. See [`claude_graph/default_languages.toml`](claude_graph/default_languages.toml) for the schema (extensions, grammar name, node types for functions/classes/imports/calls).

---

## Install options

### pip (recommended)

```bash
pip install claude-graph

# With file-watching support
pip install "claude-graph[watch]"
```

### Docker

```bash
docker pull ghcr.io/mohansagark/claude-graph:latest
docker run --rm -v "$PWD:/repo" ghcr.io/mohansagark/claude-graph build
docker run --rm -v "$PWD:/repo" ghcr.io/mohansagark/claude-graph viz --symbol MyClass
```

### From source

```bash
git clone https://github.com/mohansagark/claude-graph.git
cd claude-graph
pip install -e .
```

### From a release asset (no PyPI)

Each [GitHub Release](https://github.com/mohansagark/claude-graph/releases) ships a wheel as a downloadable asset:

```bash
pip install https://github.com/mohansagark/claude-graph/releases/download/v0.2.3/claude_graph-0.2.3-py3-none-any.whl
```

---

## Requirements

- Python 3.11+
- git
- macOS, Linux, or Windows

---

## How call resolution works

- A `calls` edge's **source** is always a function-kind node — only functions/methods make calls.
- A `calls` edge's **target** prefers a function match; if none exists, falls back to a class match (instantiation, e.g. `Foo()`).
- One edge per call site — if `bar()` is called twice, you get two edges. Call frequency is preserved.
- Cross-file resolution is name-based: a call to `save()` matches every function named `save` in the graph. This is a deliberate precision/recall trade-off — better to surface too many candidates for Claude to disambiguate than to miss a real caller.

---

## Known limitations

- **Name-based call resolution** — cross-file calls match by name only, not by scope. Highly common names (`save`, `get`, `run`) produce over-broad results on large repos.
- **`tests_for` linking** — naming convention + imports only (`test_foo.py` ↔ `foo.py`, `foo.spec.ts` ↔ `foo.ts`). Tests that don't follow a convention aren't linked.
- **Import resolution** — best-effort path matching, not real module resolution. Won't follow `tsconfig.json` path aliases or Python namespace packages.
- **Incremental edge re-linking** — `claude-graph update` only re-links edges for changed files. Moving a symbol to another file keeps stale cross-file edges until the next full `claude-graph build`.

---

## Contributing

```bash
git clone https://github.com/mohansagark/claude-graph.git
cd claude-graph
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest
```

---

## Releasing (maintainers)

Bump `version` in `pyproject.toml`, then cut a [GitHub Release](https://github.com/mohansagark/claude-graph/releases/new). Publishing the release triggers `.github/workflows/publish.yml` which uploads to PyPI via OIDC trusted publishing and pushes the Docker image to GHCR — no API tokens stored in this repo.

---

## License

[MIT](LICENSE) © [Mohansagar Killamsetty](https://github.com/mohansagark)

Maintenance

ActivitySlowing
ResponsivenessNo issues