@graphpilot-oss/graphpilot 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +72 -126
- package/README.md +290 -102
- package/dist/cli.js +41 -1
- package/dist/cli.js.map +1 -1
- package/dist/edges.js +22 -11
- package/dist/edges.js.map +1 -1
- package/dist/indexer.js +3 -3
- package/dist/indexer.js.map +1 -1
- package/dist/init.d.ts +28 -0
- package/dist/init.js +112 -0
- package/dist/init.js.map +1 -0
- package/dist/interactions.d.ts +5 -4
- package/dist/interactions.js +0 -0
- package/dist/interactions.js.map +1 -1
- package/dist/mcp.js +119 -90
- package/dist/mcp.js.map +1 -1
- package/dist/repo-resolve.d.ts +47 -0
- package/dist/repo-resolve.js +195 -0
- package/dist/repo-resolve.js.map +1 -0
- package/dist/storage.js +10 -1
- package/dist/storage.js.map +1 -1
- package/dist/symbols.js +26 -2
- package/dist/symbols.js.map +1 -1
- package/dist/validation.js +30 -4
- package/dist/validation.js.map +1 -1
- package/dist/validators.d.ts +1 -5
- package/dist/validators.js +0 -11
- package/dist/validators.js.map +1 -1
- package/dist/watcher.d.ts +10 -0
- package/dist/watcher.js +70 -7
- package/dist/watcher.js.map +1 -1
- package/examples/README.md +105 -0
- package/examples/claude-code/README.md +125 -0
- package/examples/claude-code/claude-routing.md +102 -0
- package/examples/claude-code/claude_config.json +8 -0
- package/examples/cline/.clinerules +39 -0
- package/examples/cline/README.md +104 -0
- package/examples/cline/cline_mcp_settings.json +10 -0
- package/examples/continue/.continuerules +39 -0
- package/examples/continue/README.md +98 -0
- package/examples/continue/config.json +13 -0
- package/examples/cursor/.cursorrules +39 -0
- package/examples/cursor/README.md +98 -0
- package/examples/cursor/mcp.json +11 -0
- package/examples/windsurf/.windsurfrules +39 -0
- package/examples/windsurf/README.md +85 -0
- package/examples/windsurf/mcp_config.json +8 -0
- package/package.json +14 -4
- package/.editorconfig +0 -15
- package/.github/CODEOWNERS +0 -22
- package/.github/FUNDING.yml +0 -1
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -33
- package/.github/ISSUE_TEMPLATE/config.yml +0 -5
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -23
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -19
- package/.github/dependabot.yml +0 -15
- package/.github/workflows/ci.yml +0 -62
- package/.github/workflows/release.yml +0 -50
- package/.prettierignore +0 -19
- package/.prettierrc.json +0 -20
- package/CODE_OF_CONDUCT.md +0 -83
- package/CONTRIBUTING.md +0 -111
- package/bench/README.md +0 -544
- package/bench/results/agent-tier-2026-05-22.md +0 -28
- package/bench/results/agent-tier-summary.md +0 -44
- package/bench/results/baseline-tier-2026-05-22.md +0 -23
- package/bench/results/baseline.json +0 -810
- package/bench/results/baseline.md +0 -28
- package/bench/run-agent-tier-automated.ts +0 -234
- package/bench/run-agent-tier.md +0 -125
- package/bench/run-baseline-tier.ts +0 -200
- package/bench/run.ts +0 -210
- package/bench/runner-baseline.ts +0 -177
- package/bench/runner-graphpilot.ts +0 -131
- package/bench/score-agent-tier.ts +0 -191
- package/bench/score.ts +0 -59
- package/bench/tasks.ts +0 -236
- package/dist/provenance.d.ts +0 -74
- package/dist/provenance.js +0 -95
- package/dist/provenance.js.map +0 -1
- package/docs/architecture.md +0 -311
- package/docs/limitations.md +0 -156
- package/docs/mcp-setup.md +0 -231
- package/docs/quickstart.md +0 -202
- package/eslint.config.js +0 -148
- package/lefthook.yml +0 -81
- package/pnpm-workspace.yaml +0 -6
- package/scripts/smoke-stdio.mjs +0 -97
- package/src/cli.ts +0 -171
- package/src/edges.ts +0 -202
- package/src/git.ts +0 -255
- package/src/graph-schema.ts +0 -229
- package/src/impact.ts +0 -218
- package/src/indexer.ts +0 -152
- package/src/interactions.ts +0 -0
- package/src/mcp.ts +0 -652
- package/src/parser.ts +0 -138
- package/src/provenance.ts +0 -115
- package/src/query.ts +0 -148
- package/src/redact.ts +0 -122
- package/src/storage.ts +0 -115
- package/src/symbols.ts +0 -173
- package/src/validation.ts +0 -69
- package/src/validators.ts +0 -253
- package/src/watcher.ts +0 -383
- package/tests/edges.test.ts +0 -175
- package/tests/fixtures/sample.ts +0 -32
- package/tests/git.test.ts +0 -303
- package/tests/graph-schema.test.ts +0 -321
- package/tests/impact.test.ts +0 -454
- package/tests/interactions.test.ts +0 -180
- package/tests/lint-policy.test.ts +0 -106
- package/tests/mcp-stdio.test.ts +0 -171
- package/tests/mcp.test.ts +0 -335
- package/tests/parser.test.ts +0 -31
- package/tests/provenance.test.ts +0 -132
- package/tests/query.test.ts +0 -160
- package/tests/redact.test.ts +0 -167
- package/tests/security.test.ts +0 -144
- package/tests/symbols.test.ts +0 -78
- package/tests/validators.test.ts +0 -193
- package/tests/watcher.test.ts +0 -250
- package/tsconfig.json +0 -18
package/README.md
CHANGED
|
@@ -4,129 +4,317 @@
|
|
|
4
4
|
|
|
5
5
|
<h1 align="center">GraphPilot</h1>
|
|
6
6
|
|
|
7
|
-
>
|
|
8
|
-
>
|
|
9
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Structural memory for coding agents.</strong><br />
|
|
9
|
+
A refactor-safe, branch-aware, evidence-backed code graph that runs entirely on your machine.
|
|
10
|
+
</p>
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/License-Apache_2.0-blue.svg" alt="License: Apache 2.0" /></a>
|
|
14
|
+
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg" alt="Node ≥20" /></a>
|
|
15
|
+
<img src="https://img.shields.io/badge/version-0.1.0-blue.svg" alt="v0.1.0" />
|
|
16
|
+
<img src="https://img.shields.io/badge/status-alpha-orange.svg" alt="alpha" />
|
|
17
|
+
<img src="https://img.shields.io/badge/tests-239%20passing-brightgreen.svg" alt="239 tests" />
|
|
18
|
+
</p>
|
|
14
19
|
|
|
15
|
-
|
|
20
|
+
<p align="center">
|
|
21
|
+
<a href="#quickstart">Quickstart</a> ·
|
|
22
|
+
<a href="#the-four-tools">Tools</a> ·
|
|
23
|
+
<a href="#how-it-works">How it works</a> ·
|
|
24
|
+
<a href="#editor-setup">Editor setup</a> ·
|
|
25
|
+
<a href="docs/limitations.md">Limitations</a> ·
|
|
26
|
+
<a href="bench/README.md">Benchmarks</a>
|
|
27
|
+
</p>
|
|
16
28
|
|
|
17
|
-
|
|
18
|
-
GraphPilot
|
|
19
|
-
|
|
20
|
-
conclusion. [Reproduce in 30 s →](bench/README.md)
|
|
29
|
+
<p align="center">
|
|
30
|
+
<img src="docs/press/hero.gif" alt="GraphPilot demo — install, index, and query a real TypeScript repo in under 30 seconds" width="900" />
|
|
31
|
+
</p>
|
|
21
32
|
|
|
22
33
|
---
|
|
23
34
|
|
|
24
|
-
##
|
|
35
|
+
## What it is
|
|
36
|
+
|
|
37
|
+
GraphPilot is a local CLI + MCP server that indexes your TypeScript/JavaScript repo into a structural graph (symbols, callers, callees, blast radius) and exposes it to coding agents — Claude Code, Cursor, Cline, Windsurf, Continue — so they stop re-`grep`ping the same files every conversation.
|
|
38
|
+
|
|
39
|
+
The problem it solves: agents burn tokens, hallucinate function names, and miss structural relationships ("what calls this?", "what breaks if I rename it?") because each session starts from zero. GraphPilot is the persistent structural memory in between.
|
|
40
|
+
|
|
41
|
+
**Token cost drops. Hallucinations drop. Refactors get safer.**
|
|
42
|
+
|
|
43
|
+
Put a real coding agent (claude-sonnet-4-5) on **40 structural questions about fastify** — a ~300-file Node.js framework — and give it nothing but file reads. Then hand it GraphPilot's four tools and ask the same 40. The agent with GraphPilot uses **61 % fewer tokens**, costs **$3.68 instead of $8.88 — $5.20 saved per session** — and gets **more** of them right, not fewer (37 correct vs 33). Same model, same questions, same repo; the only change is whether the structural index is there. [Reproduce it →](benchmark/README.md)
|
|
44
|
+
|
|
45
|
+
A separate correctness benchmark backs the savings with precision: on 10 standardized structural queries GraphPilot scores **F1 0.89 vs grep's 0.42** while reading **99.9 % fewer bytes** (721 B vs 528 KB), and the byte-cost win holds at scale — indexing **microsoft/TypeScript** (601 files, 17 k symbols, 70 k call edges in 10 s) gives **sub-millisecond queries** and a **99.99 % bytes-read reduction**. [Full methodology →](bench/README.md)
|
|
46
|
+
|
|
47
|
+
## One binary, two modes
|
|
48
|
+
|
|
49
|
+
GraphPilot ships as a single npm package (`@graphpilot-oss/graphpilot`) with two runtime modes — most users run both.
|
|
50
|
+
|
|
51
|
+
| Mode | Command | What it does |
|
|
52
|
+
| -------------- | -------------------------- | ---------------------------------------------------------------------------- |
|
|
53
|
+
| **CLI** | `graphpilot index <path>` | Walks your repo, builds the structural graph, writes it to `~/.graphpilot/` |
|
|
54
|
+
| | `graphpilot watch <path>` | Keeps the graph fresh (~10 ms per file save) |
|
|
55
|
+
| | `graphpilot status <path>` | Health probe — when the graph was last refreshed, file/symbol/edge counts |
|
|
56
|
+
| **MCP server** | `graphpilot mcp` | Speaks MCP over stdio — your coding agent calls into this to query the graph |
|
|
57
|
+
|
|
58
|
+
**The flow:** the **CLI** builds the index once (and `watch` keeps it warm). The **MCP server** is what your coding agent talks to — you never invoke it yourself, you just point your agent's MCP config at `graphpilot mcp` once and the agent spawns it on every session.
|
|
59
|
+
|
|
60
|
+
<p align="center">
|
|
61
|
+
<img src="docs/diagrams/data-flow.svg" alt="GraphPilot data flow: you run index/watch to build ~/.graphpilot/<repo>/graph.json; the read-only graphpilot mcp server reads it and serves your coding agent over stdio JSON-RPC" width="720" />
|
|
62
|
+
</p>
|
|
63
|
+
|
|
64
|
+
If you only want CLI access to your code graph (no agent), run `graphpilot index` and then `graphpilot stats` / inspect `graph.json` directly. If you only want the agent integration, you still need to run `graphpilot index` once — the MCP server is read-only against the on-disk graph.
|
|
65
|
+
|
|
66
|
+
## What makes it different
|
|
67
|
+
|
|
68
|
+
Other code-graph tools treat your repo as a static blob: index once, query forever, no branch awareness, no proof of where an answer came from. GraphPilot is built around three properties none of them ship:
|
|
69
|
+
|
|
70
|
+
- 🔍 **Evidence anchors.** Every tool response carries `file:line @ sha` on every symbol and call site. The agent can quote the anchor verbatim and you can verify it instantly — hallucinations get exposed the moment you jump to the line.
|
|
71
|
+
- 🌿 **Differential impact.** Pass `since: <commit|branch>` to `gp_impact` and the result is filtered to files your branch actually touches. PR-scoped refactor analysis in one call instead of `git diff | xargs grep`.
|
|
72
|
+
- 🪵 **Worktree-aware by default.** Two `git worktree add`-ed branches naturally produce two separate indexes — no manual config. Run `graphpilot index ./src/feature` from a subdir and it transparently re-roots to the worktree top. Opt out with `--no-worktree`.
|
|
73
|
+
|
|
74
|
+
Add to that: **local-first** (no telemetry, no remote calls, enforced by an ESLint policy on `src/` itself), **deterministic** (same repo → same graph), **sub-second incremental** updates via watch mode.
|
|
75
|
+
|
|
76
|
+
## Quickstart
|
|
77
|
+
|
|
78
|
+
**Prerequisites**
|
|
25
79
|
|
|
26
|
-
|
|
80
|
+
- Node.js ≥ 20 (`node --version` to check)
|
|
81
|
+
- An MCP-capable coding agent (Claude Code, Cursor, Cline, Windsurf, or Continue)
|
|
82
|
+
- A TypeScript or JavaScript repo to index
|
|
27
83
|
|
|
28
|
-
|
|
84
|
+
End-to-end time: ~3 minutes.
|
|
85
|
+
|
|
86
|
+
**1. Install the CLI**
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npm install -g @graphpilot-oss/graphpilot
|
|
90
|
+
# or: pnpm add -g @graphpilot-oss/graphpilot
|
|
91
|
+
# or one-shot, no install: npx @graphpilot-oss/graphpilot <command>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Verify it landed on your `PATH`:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
graphpilot --version
|
|
98
|
+
# → 0.1.0
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
If you see `command not found: graphpilot`, your global npm bin is not on `PATH`. Run `npm config get prefix` and add `<prefix>/bin` to your shell's `PATH`, or use the `npx` form above.
|
|
102
|
+
|
|
103
|
+
**2. Build the structural index for your repo**
|
|
104
|
+
|
|
105
|
+
Run this once per project. It walks your source tree, parses each TS/JS file with tree-sitter, extracts symbols + call edges, and writes the graph to `~/.graphpilot/<repo-id>/graph.json`.
|
|
29
106
|
|
|
30
107
|
```bash
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
108
|
+
graphpilot index ~/code/my-app
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Expect a one-line summary like `indexed 412 files · 3,981 symbols · 7,204 edges · 1.8s`.
|
|
35
112
|
|
|
36
|
-
|
|
37
|
-
node dist/cli.js index /path/to/your/repo
|
|
113
|
+
**3. Wire it into your coding agent**
|
|
38
114
|
|
|
39
|
-
|
|
40
|
-
node dist/cli.js status /path/to/your/repo
|
|
115
|
+
GraphPilot speaks MCP over stdio. Add this server entry to your agent's MCP config — every supported client uses the same two-line shape:
|
|
41
116
|
|
|
42
|
-
|
|
43
|
-
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"mcpServers": {
|
|
120
|
+
"graphpilot": {
|
|
121
|
+
"command": "graphpilot",
|
|
122
|
+
"args": ["mcp"]
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
44
126
|
```
|
|
45
127
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
128
|
+
Where this file lives depends on the client (`~/.cursor/mcp.json`, `~/.claude.json`, Cline's settings panel, etc.). Pre-made configs with the exact file path for each agent are in [`examples/`](examples/) — copy the one for your client.
|
|
129
|
+
|
|
130
|
+
Restart the agent. It now has four new tools: `gp_recall`, `gp_callers`, `gp_impact`, `gp_index` — see [The four tools](#the-four-tools) below for what each one does and when the agent should reach for it.
|
|
131
|
+
|
|
132
|
+
**4. Try it**
|
|
133
|
+
|
|
134
|
+
Ask your agent a structural question instead of letting it grep:
|
|
135
|
+
|
|
136
|
+
> _"Use gp_impact to show me everything that breaks if I rename `parseToken`."_
|
|
137
|
+
|
|
138
|
+
You should see a response with `file:line @ sha` anchors you can click straight to. If the agent doesn't reach for the tool, prompt explicitly: "use the `gp_` MCP tools." If it can't see them at all, the MCP config wasn't picked up — restart the agent and re-check the config path for your client in [`examples/`](examples/).
|
|
139
|
+
|
|
140
|
+
**5. Keep the index fresh as you edit (optional but recommended)**
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
graphpilot watch ~/code/my-app
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Sub-10 ms incremental updates on each file save. Leave it running in a terminal tab.
|
|
147
|
+
|
|
148
|
+
**6. Drop per-editor routing rules into your repo (optional)**
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
graphpilot init
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Auto-detects which editors you have installed (Cursor, Claude Code, Cline, Windsurf, Continue) and writes the matching rules file (`.cursorrules`, `CLAUDE.md`, etc.) to the current directory. The rules teach the agent to reach for `gp_*` tools before grep.
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
graphpilot init --all # write rules for every supported editor
|
|
158
|
+
graphpilot init --client cursor # one editor only
|
|
159
|
+
graphpilot init --dry-run # preview without writing
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Full 5-minute walkthrough with screenshots: [`docs/quickstart.md`](docs/quickstart.md).
|
|
163
|
+
|
|
164
|
+
## The four tools
|
|
165
|
+
|
|
166
|
+
GraphPilot exposes four MCP tools. Each one answers a structural question your agent would otherwise solve by grepping and reading files.
|
|
167
|
+
|
|
168
|
+
### `gp_recall` — find a symbol by name
|
|
169
|
+
|
|
170
|
+
Use this when the agent asks "where is X defined?" or needs to locate a function before reasoning about it.
|
|
171
|
+
|
|
172
|
+
- **Input:** `{ query, limit?, substring?, path? }`
|
|
173
|
+
- **Returns:** symbols matching the name (exact case-insensitive by default; `substring: true` for partial matches), each with `file:line @ sha`.
|
|
174
|
+
- **Replaces:** `grep -rn "function X"` plus reading each hit to find the real definition.
|
|
175
|
+
|
|
176
|
+
```text
|
|
177
|
+
Agent: gp_recall({ query: "parseToken" })
|
|
178
|
+
→ parseToken (function) — src/auth.ts:42 @ a1b2c3d
|
|
179
|
+
export function parseToken(raw: string): Token | null
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### `gp_callers` — list callers (or callees)
|
|
183
|
+
|
|
184
|
+
Use this when the agent needs to know "who calls X?" or "what does X call?" — the two fundamental questions of refactoring.
|
|
185
|
+
|
|
186
|
+
- **Input:** `{ symbol, direction?: 'callers' | 'callees', limit?, includeUnresolved?, path? }`
|
|
187
|
+
- **Returns:** every call edge where the symbol is target (callers) or source (callees), with anchors.
|
|
188
|
+
- **Replaces:** `grep -rn "X("` followed by manual filtering of comments, strings, and renamed shadows.
|
|
189
|
+
|
|
190
|
+
```text
|
|
191
|
+
Agent: gp_callers({ symbol: "authenticate", direction: "callers" })
|
|
192
|
+
→ login → authenticate — src/routes/login.ts:18 @ a1b2c3d
|
|
193
|
+
→ refreshSession → authenticate — src/session.ts:64 @ a1b2c3d
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### `gp_impact` — blast radius in one call
|
|
197
|
+
|
|
198
|
+
Use this when the agent asks "what breaks if I rename X?" or "what depends on this?" — the single most expensive question an agent normally solves.
|
|
199
|
+
|
|
200
|
+
- **Input:** `{ symbol, depth? (1–5, default 3), since?, path? }`
|
|
201
|
+
- **Returns:** direct callers, transitive callers grouped by BFS depth, tests likely affected, public-API flag, summary stats.
|
|
202
|
+
- **Killer feature:** pass `since: 'main'` and the result is scoped to files your branch actually touches — PR-scoped refactor review without `git diff` gymnastics.
|
|
203
|
+
|
|
204
|
+
```text
|
|
205
|
+
Agent: gp_impact({ symbol: "extractSymbols", depth: 2, since: "main" })
|
|
206
|
+
→ Direct callers (2): indexDirectory, applyUpdate
|
|
207
|
+
→ Depth-2 callers (1): cmdIndex
|
|
208
|
+
→ Tests affected (3): tests/indexer.test.ts, tests/symbols.test.ts, tests/cli.test.ts
|
|
209
|
+
→ Public API: no
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### `gp_index` — refresh from inside the agent
|
|
213
|
+
|
|
214
|
+
Use this after the agent (or the user) has made a batch of structural edits and wants the graph to reflect them without dropping to a shell.
|
|
215
|
+
|
|
216
|
+
- **Input:** `{ path? }`
|
|
217
|
+
- **Returns:** re-indexes the repo and invalidates the per-path query cache.
|
|
218
|
+
- **Pairs with:** `graphpilot watch` for sub-10 ms incremental updates between explicit re-indexes.
|
|
219
|
+
|
|
220
|
+
## How it works
|
|
221
|
+
|
|
222
|
+
<p align="center">
|
|
223
|
+
<img src="docs/diagrams/how-it-works.svg" alt="How GraphPilot works, in two phases. Build time (CLI index/watch): your repo flows through indexer.ts, parser.ts, and symbols.ts + edges.ts, which storage.ts writes to graph.json at ~/.graphpilot/<repo-id>/ (mode 0600). Serve time (read-only MCP server): query.ts reads graph.json, mcp.ts exposes 4 tools over stdio JSON-RPC with evidence anchors, served to Claude Code, Cursor, Cline, Windsurf, and Continue." width="760" />
|
|
224
|
+
</p>
|
|
225
|
+
|
|
226
|
+
Data flow is one-way: source → tree → symbols + edges → JSON → query → agent. GraphPilot never modifies your code.
|
|
227
|
+
|
|
228
|
+
Full pipeline writeup with file references: [`docs/architecture.md`](docs/architecture.md).
|
|
229
|
+
|
|
230
|
+
## When to use which tool
|
|
231
|
+
|
|
232
|
+
| If the agent is about to… | Reach for… | Why |
|
|
233
|
+
| --------------------------------------- | ------------------------------ | ----------------------------------------------------- |
|
|
234
|
+
| `grep` for a function by name | `gp_recall` | One call, no false positives from comments or strings |
|
|
235
|
+
| Read 20 files looking for "who calls X" | `gp_callers` | Pre-computed reverse index, sub-millisecond |
|
|
236
|
+
| Plan a rename or signature change | `gp_impact` | Direct + transitive + tests + public-API in one call |
|
|
237
|
+
| Review a PR's structural blast radius | `gp_impact({ since: 'main' })` | Differential — only callers your branch touches |
|
|
238
|
+
| Re-grep after editing several files | `gp_index` | Incremental: lets the next call see your edits |
|
|
239
|
+
|
|
240
|
+
For string literals, error messages, config values, or anything in a language other than TS/JS: **stay with grep.** GraphPilot indexes code structure, not text.
|
|
241
|
+
|
|
242
|
+
## Editor setup
|
|
243
|
+
|
|
244
|
+
GraphPilot speaks MCP over stdio, so it works with any MCP-capable client. Ready-to-paste configs live in `examples/`:
|
|
245
|
+
|
|
246
|
+
| Client | Folder |
|
|
247
|
+
| ----------------------------- | ------------------------------------------------ |
|
|
248
|
+
| **Claude Code** (Anthropic) | [`examples/claude-code/`](examples/claude-code/) |
|
|
249
|
+
| **Cursor** | [`examples/cursor/`](examples/cursor/) |
|
|
250
|
+
| **Cline** (VS Code extension) | [`examples/cline/`](examples/cline/) |
|
|
251
|
+
| **Windsurf** (Codeium) | [`examples/windsurf/`](examples/windsurf/) |
|
|
252
|
+
| **Continue.dev** | [`examples/continue/`](examples/continue/) |
|
|
253
|
+
| Any other MCP client | See [`docs/mcp-setup.md`](docs/mcp-setup.md) |
|
|
254
|
+
|
|
255
|
+
Each folder contains: a `README.md` walkthrough, a sample config file with the exact JSON to paste, and (where the client supports it) a routing template so the agent automatically reaches for GraphPilot on structural questions.
|
|
256
|
+
|
|
257
|
+
## Privacy & security
|
|
258
|
+
|
|
259
|
+
GraphPilot is **local-first by promise and by build gate**.
|
|
260
|
+
|
|
261
|
+
- **No telemetry, no remote calls, ever.** Verifiable: `src/` has zero `http`, `fetch`, `axios`, or analytics imports — enforced by an ESLint rule plus a meta-test that proves the rule fires on every banned import.
|
|
262
|
+
- **No `child_process`, no `exec`, no `spawn`.** Git facts are read directly from `.git/` via pure-JS helpers.
|
|
263
|
+
- **Source code never leaves your machine.** Only structural metadata (names, locations, signatures, call relationships) lives in `~/.graphpilot/`.
|
|
264
|
+
- **Signatures are redacted** for common secret patterns (OpenAI/Anthropic `sk-`, GitHub `ghp_`/`ghs_`, AWS `AKIA`, JWTs, PEM headers, Slack/Stripe tokens) before they're written to disk.
|
|
265
|
+
- **Strict file permissions:** dir `0o700`, files `0o600`.
|
|
266
|
+
- **Schema validation on load:** tampered or corrupt `graph.json` falls back to "no index" rather than poisoning the agent.
|
|
267
|
+
- **Hand-rolled input validators** on every MCP tool — unknown fields are rejected, every field type-checked, numbers range-checked, strings length-capped.
|
|
268
|
+
|
|
269
|
+
Threat model and per-defence test references live in [`docs/architecture.md`](docs/architecture.md). Report security issues per [`SECURITY.md`](SECURITY.md).
|
|
270
|
+
|
|
271
|
+
## Limitations
|
|
272
|
+
|
|
273
|
+
GraphPilot v0.1 makes deliberate trade-offs to ship small and sharp:
|
|
274
|
+
|
|
275
|
+
- **TS/JS only.** Python, Rust, Go, Java are out of scope for v1. Python is demand-gated for v0.2 / v0.3.
|
|
276
|
+
- **Name-based resolver** (no import-path tracking, no type-based method dispatch). Expected resolution rate: ~25–35 % of edges resolve to in-repo symbols; the rest are stdlib / third-party. That's enough because the questions agents actually ask (_"who calls X in my repo?"_) are the ones the dumb resolver answers correctly.
|
|
277
|
+
- **No semantic search.** `gp_recall` is name-only. "Find code similar to this snippet" is deferred until 30+ users ask for it.
|
|
278
|
+
- **No `.graphpilotignore`** yet (defaults skip `node_modules`, `dist`, `build`, `.git`, `coverage`, `.next`, `.nuxt`, `.cache`, `out`, `*.d.ts`).
|
|
279
|
+
- **Single repo per query.** Workspace abstraction is on the v1.x roadmap.
|
|
280
|
+
|
|
281
|
+
Full list with mitigations: [`docs/limitations.md`](docs/limitations.md).
|
|
282
|
+
|
|
283
|
+
## FAQ
|
|
284
|
+
|
|
285
|
+
**Does it send my code anywhere?**
|
|
286
|
+
No. There is no network code in `src/`, no telemetry, no update check. An ESLint rule blocks adding any of those at the build gate.
|
|
287
|
+
|
|
288
|
+
**Will it slow down my editor?**
|
|
289
|
+
The MCP server is idle until your agent calls a tool. Tool calls are sub-millisecond after the first lazy load. Watch mode adds ~3–10 ms per file save.
|
|
290
|
+
|
|
291
|
+
**What happens to the graph when I switch branches?**
|
|
292
|
+
If you use `git worktree`, you automatically get a separate graph per worktree. On a single working copy that you switch with `git checkout`, the graph reflects the last `gp_index` (or watch-mode updates). Run `gp_index` after a branch switch to refresh.
|
|
293
|
+
|
|
294
|
+
**Do I need to re-index every session?**
|
|
295
|
+
No. The graph persists at `~/.graphpilot/<repo-id>/graph.json`. Re-index after sweeping changes; otherwise, watch mode keeps it fresh incrementally.
|
|
296
|
+
|
|
297
|
+
**Why TypeScript/JavaScript first?**
|
|
298
|
+
That's where the maintainer's pain was, and tree-sitter-typescript covers TS, TSX, JSX, and JS in a single grammar. Python is the next likely addition; vote with a GitHub Discussion.
|
|
299
|
+
|
|
300
|
+
**How does this compare to LSP?**
|
|
301
|
+
LSPs are scoped to one editor and one buffer at a time, and they re-compute on each query. GraphPilot is editor-agnostic, persists across sessions, and answers structural questions (who-calls, blast-radius) that LSPs don't expose uniformly.
|
|
116
302
|
|
|
117
303
|
## Documentation
|
|
118
304
|
|
|
119
|
-
- [docs/quickstart.md](docs/quickstart.md) — 5-minute walkthrough
|
|
120
|
-
- [docs/mcp-setup.md](docs/mcp-setup.md) — per-client config
|
|
121
|
-
- [docs/architecture.md](docs/architecture.md) —
|
|
122
|
-
- [docs/limitations.md](docs/limitations.md) — v1 caveats (read this)
|
|
123
|
-
- [bench/README.md](bench/README.md) — benchmark methodology + results
|
|
305
|
+
- [`docs/quickstart.md`](docs/quickstart.md) — 5-minute walkthrough
|
|
306
|
+
- [`docs/mcp-setup.md`](docs/mcp-setup.md) — per-client config reference
|
|
307
|
+
- [`docs/architecture.md`](docs/architecture.md) — pipeline writeup with file refs
|
|
308
|
+
- [`docs/limitations.md`](docs/limitations.md) — v1 caveats (read this)
|
|
309
|
+
- [`bench/README.md`](bench/README.md) — benchmark methodology + results
|
|
310
|
+
- [`examples/`](examples/) — ready-to-paste configs for every supported client
|
|
124
311
|
|
|
125
312
|
## Contributing
|
|
126
313
|
|
|
127
|
-
|
|
128
|
-
|
|
314
|
+
GraphPilot is small, opinionated, and accepting contributions. Start with [`CONTRIBUTING.md`](CONTRIBUTING.md) — especially the _"What we are NOT doing in v1"_ section before you propose a feature.
|
|
315
|
+
|
|
316
|
+
Found a security issue? Please follow [`SECURITY.md`](SECURITY.md) instead of opening a public issue.
|
|
129
317
|
|
|
130
318
|
## License
|
|
131
319
|
|
|
132
|
-
[Apache-2.0](LICENSE). Copyright 2026 Akshay Sharma.
|
|
320
|
+
[Apache-2.0](LICENSE). Copyright 2026 Akshay Sharma — [codewithakki@gmail.com](mailto:codewithakki@gmail.com)
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { resolve } from 'node:path';
|
|
2
|
+
import { resolve, dirname, join } from 'node:path';
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
3
5
|
import { indexDirectory } from './indexer.js';
|
|
4
6
|
import { saveGraph, loadGraph, graphPath, repoIdFor } from './storage.js';
|
|
5
7
|
import { validateRootPath } from './validation.js';
|
|
@@ -13,6 +15,8 @@ Usage:
|
|
|
13
15
|
graphpilot status <path> Show info about an indexed repo
|
|
14
16
|
graphpilot watch <path> Watch the repo and update the index on save
|
|
15
17
|
graphpilot mcp Start the MCP server (stdio)
|
|
18
|
+
graphpilot init Drop routing-rules files for detected editors
|
|
19
|
+
graphpilot version Print the installed version
|
|
16
20
|
graphpilot help Show this help
|
|
17
21
|
|
|
18
22
|
Examples:
|
|
@@ -20,6 +24,10 @@ Examples:
|
|
|
20
24
|
graphpilot status .
|
|
21
25
|
graphpilot watch . # keeps the index fresh as you edit
|
|
22
26
|
graphpilot mcp # used by MCP clients (Claude Code, Cursor, ...)
|
|
27
|
+
graphpilot init # auto-detect editors and write routing rules
|
|
28
|
+
graphpilot init --all # write rules for all supported editors
|
|
29
|
+
graphpilot init --client cursor --path /my/repo
|
|
30
|
+
graphpilot init --dry-run # preview what would be written
|
|
23
31
|
`;
|
|
24
32
|
async function cmdIndex(pathArg, opts = {}) {
|
|
25
33
|
const requested = resolve(pathArg);
|
|
@@ -99,9 +107,26 @@ function cmdStatus(pathArg) {
|
|
|
99
107
|
`Graph file: ${graphPath(absRoot)}\n`);
|
|
100
108
|
return 0;
|
|
101
109
|
}
|
|
110
|
+
function getVersion() {
|
|
111
|
+
// dist/cli.js and src/cli.ts both sit one level under the package root,
|
|
112
|
+
// so ../package.json resolves in both the built and dev layouts.
|
|
113
|
+
try {
|
|
114
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
115
|
+
const pkg = JSON.parse(readFileSync(join(here, '..', 'package.json'), 'utf8'));
|
|
116
|
+
return pkg.version ?? 'unknown';
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return 'unknown';
|
|
120
|
+
}
|
|
121
|
+
}
|
|
102
122
|
async function main() {
|
|
103
123
|
const [, , cmd, ...rest] = process.argv;
|
|
104
124
|
switch (cmd) {
|
|
125
|
+
case 'version':
|
|
126
|
+
case '--version':
|
|
127
|
+
case '-v':
|
|
128
|
+
process.stdout.write(`${getVersion()}\n`);
|
|
129
|
+
return 0;
|
|
105
130
|
case 'index': {
|
|
106
131
|
const noWorktree = rest.includes('--no-worktree');
|
|
107
132
|
const path = rest.find((a) => !a.startsWith('--')) ?? '.';
|
|
@@ -144,6 +169,21 @@ async function main() {
|
|
|
144
169
|
await watcher.stop();
|
|
145
170
|
return 0;
|
|
146
171
|
}
|
|
172
|
+
case 'init': {
|
|
173
|
+
const { runInit } = await import('./init.js');
|
|
174
|
+
const allFlag = rest.includes('--all');
|
|
175
|
+
const dryRun = rest.includes('--dry-run');
|
|
176
|
+
const pathIdx = rest.indexOf('--path');
|
|
177
|
+
const pathArg = pathIdx !== -1 ? rest[pathIdx + 1] : undefined;
|
|
178
|
+
const clientIdx = rest.indexOf('--client');
|
|
179
|
+
const clientArg = clientIdx !== -1 ? rest[clientIdx + 1] : undefined;
|
|
180
|
+
const repoPath = resolve(pathArg ?? '.');
|
|
181
|
+
const clients = clientArg
|
|
182
|
+
? [clientArg]
|
|
183
|
+
: undefined;
|
|
184
|
+
await runInit({ repoPath, clients, all: allFlag, dryRun });
|
|
185
|
+
return 0;
|
|
186
|
+
}
|
|
147
187
|
case 'help':
|
|
148
188
|
case '--help':
|
|
149
189
|
case '-h':
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/edges.js
CHANGED
|
@@ -7,17 +7,22 @@ const FUNCTION_NODE_TYPES = new Set([
|
|
|
7
7
|
'method_definition',
|
|
8
8
|
]);
|
|
9
9
|
/**
|
|
10
|
-
* Walk a function body,
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* Walk a function body, stopping at nested functions that are themselves named
|
|
11
|
+
* symbols (they'll be walked separately). Anonymous callbacks — arrow functions
|
|
12
|
+
* or function expressions passed directly as arguments — are walked through and
|
|
13
|
+
* their calls are attributed to the enclosing named function. This ensures that
|
|
14
|
+
* calls made inside `this.after(() => { foo() })` are attributed to the outer
|
|
15
|
+
* named function rather than silently lost.
|
|
14
16
|
*/
|
|
15
|
-
function* walkBodyExcludingNestedFns(rootNode) {
|
|
17
|
+
function* walkBodyExcludingNestedFns(rootNode, symByKey) {
|
|
16
18
|
const stack = [{ node: rootNode, isRoot: true }];
|
|
17
19
|
while (stack.length > 0) {
|
|
18
20
|
const { node, isRoot } = stack.pop();
|
|
19
|
-
if (!isRoot && FUNCTION_NODE_TYPES.has(node.type))
|
|
20
|
-
|
|
21
|
+
if (!isRoot && FUNCTION_NODE_TYPES.has(node.type)) {
|
|
22
|
+
const key = nodeMatchKey(node);
|
|
23
|
+
if (key && symByKey.has(key))
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
21
26
|
yield node;
|
|
22
27
|
for (let i = node.childCount - 1; i >= 0; i--) {
|
|
23
28
|
const child = node.child(i);
|
|
@@ -70,16 +75,22 @@ function nodeMatchKey(node) {
|
|
|
70
75
|
return `${node.startPosition.row + 1}:${name}`;
|
|
71
76
|
}
|
|
72
77
|
if (node.type === 'arrow_function' || node.type === 'function_expression') {
|
|
73
|
-
// We stored these under their variable name; the variable_declarator is
|
|
74
|
-
// the parent we need. The declarator's startLine matches the SymbolRecord
|
|
75
|
-
// line (we record the declarator, not the value).
|
|
76
78
|
const parent = node.parent;
|
|
77
79
|
if (parent?.type === 'variable_declarator') {
|
|
80
|
+
// `const foo = () => {}` — stored under the variable declarator's line.
|
|
78
81
|
const name = parent.childForFieldName('name')?.text;
|
|
79
82
|
if (!name)
|
|
80
83
|
return null;
|
|
81
84
|
return `${parent.startPosition.row + 1}:${name}`;
|
|
82
85
|
}
|
|
86
|
+
if (node.type === 'function_expression') {
|
|
87
|
+
// `module.exports = function foo() {}` — named function expression not
|
|
88
|
+
// assigned via variable_declarator; stored under its own name + line.
|
|
89
|
+
const name = node.childForFieldName('name')?.text;
|
|
90
|
+
if (!name)
|
|
91
|
+
return null;
|
|
92
|
+
return `${node.startPosition.row + 1}:${name}`;
|
|
93
|
+
}
|
|
83
94
|
}
|
|
84
95
|
return null;
|
|
85
96
|
}
|
|
@@ -108,7 +119,7 @@ export function extractRawCalls(parsed, fileSymbols) {
|
|
|
108
119
|
const body = node.childForFieldName('body');
|
|
109
120
|
if (!body)
|
|
110
121
|
continue;
|
|
111
|
-
for (const sub of walkBodyExcludingNestedFns(body)) {
|
|
122
|
+
for (const sub of walkBodyExcludingNestedFns(body, symByKey)) {
|
|
112
123
|
if (sub.type !== 'call_expression' && sub.type !== 'new_expression') {
|
|
113
124
|
continue;
|
|
114
125
|
}
|
package/dist/edges.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"edges.js","sourceRoot":"","sources":["../src/edges.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAmB,MAAM,aAAa,CAAC;AAgCpD,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,sBAAsB;IACtB,gCAAgC;IAChC,qBAAqB;IACrB,gBAAgB;IAChB,mBAAmB;CACpB,CAAC,CAAC;AAEH
|
|
1
|
+
{"version":3,"file":"edges.js","sourceRoot":"","sources":["../src/edges.ts"],"names":[],"mappings":"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"}
|