carto-md 2.0.6 → 2.0.8

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/README.md CHANGED
@@ -7,93 +7,147 @@
7
7
 
8
8
  **The structural intelligence layer for AI coding tools.**
9
9
 
10
+ Your AI coding tool sees files. Carto sees architecture — domains, blast radius, import graph, routes. Every AI tool you use stops guessing about your codebase and starts knowing it.
11
+
10
12
  ```bash
11
13
  npm install -g carto-md
12
14
  cd your-project
13
15
  carto init
14
16
  ```
15
17
 
16
- Carto indexes your codebase routes, models, import graph, blast radius, domain clusters and keeps it live via SQLite. Every AI tool you use gets accurate structural facts about your project instead of guessing.
18
+ That's it. Carto auto-wires itself into every AI tool you have installed. Restart your AI tool and it now knows your codebase architecturally.
19
+
20
+ **Works with:** Cursor · Claude Code · Codex · Kiro · Claude Desktop · Windsurf · VS Code Copilot · JetBrains · Zed
17
21
 
18
22
  ---
19
23
 
20
- ## Benchmarks
24
+ ## Use it with your AI tool
21
25
 
22
- Measured on real open-source repos. Apple M-series, 8 CPUs, 8GB RAM.
26
+ `carto init` auto-wires the MCP server into every AI tool it detects. If yours wasn't detected, here's the manual config — **one block, copy-paste, done.**
23
27
 
24
- | Repo | Language | Source Files | Indexed | First Run | Second Run | DB Size | Import Edges |
25
- |------|----------|-------------|---------|-----------|------------|---------|--------------|
26
- | [prisma/prisma](https://github.com/prisma/prisma) | TypeScript | 3,303 | 3,303 | **1.6s** | **178ms** | 2.2 MB | 3,590 |
27
- | [supabase/supabase](https://github.com/supabase/supabase) | TypeScript | 6,818 | 6,746 | **4.9s** | **725ms** | 4.3 MB | 5,754 |
28
- | [microsoft/vscode](https://github.com/microsoft/vscode) | TypeScript | 10,565 | 10,565 | **9.7s** | **1.2s** | 10.6 MB | 19,769 |
29
- | [zed-industries/zed](https://github.com/zed-industries/zed) | Rust | 1,837 | 1,837 | **2.7s** | **83ms** | 4.7 MB | 2,176 |
28
+ ### Cursor
30
29
 
31
- **Second run** = only changed files re-parsed. mtime+size checked before reading content — if nothing changed, nothing is re-parsed.
30
+ `carto init` writes this for you. Manual: `~/.cursor/mcp.json`
31
+ ```json
32
+ { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
33
+ ```
32
34
 
33
- **All MCP queries** (blast radius, routes, structure, domains): **<5ms** on all repos.
35
+ ### Claude Code (CLI)
34
36
 
35
- ### Domains detected
37
+ `carto init` writes `<project>/.mcp.json` for you when Claude Code is detected (`claude` binary on PATH or `~/.claude/` exists). Manual:
38
+ ```bash
39
+ claude mcp add carto -- carto serve
40
+ ```
41
+ Or create `.mcp.json` at the project root:
42
+ ```json
43
+ { "mcpServers": { "carto": { "command": "carto", "args": ["serve"] } } }
44
+ ```
36
45
 
37
- | Repo | Domains |
38
- |------|---------|
39
- | prisma | DATABASE · CORE · EVENTS · AUTH |
40
- | supabase | CORE · AUTH · DATABASE · PAYMENTS · EVENTS · NOTIFICATIONS · TRPC |
41
- | vscode | CORE · AUTH · EVENTS · DATABASE · NOTIFICATIONS |
42
- | zed (Rust) | CORE · DATABASE · AUTH · EVENTS · PAYMENTS · NOTIFICATIONS |
46
+ ### Codex (CLI)
47
+
48
+ `carto init` writes `~/.codex/config.toml` for you when Codex is detected (`codex` binary on PATH or `~/.codex/` exists). Manual:
49
+ ```bash
50
+ codex mcp add carto -- carto serve
51
+ ```
52
+ Or edit `~/.codex/config.toml`:
53
+ ```toml
54
+ [mcp_servers.carto]
55
+ command = "carto"
56
+ args = ["serve"]
57
+ cwd = "/your/project"
58
+ enabled = true
59
+ ```
43
60
 
44
- vscode at 10,565 files in under 10 seconds. Rust import graph working on zed (2,176 edges from `mod` declarations and `use crate::` paths).
61
+ ### Kiro
45
62
 
46
- ---
63
+ `carto init` writes this for you. Manual: `~/.kiro/settings/mcp.json`
64
+ ```json
65
+ { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
66
+ ```
47
67
 
48
- ## What it does
68
+ ### Claude Desktop
49
69
 
70
+ `carto init` writes this for you (cross-platform). Manual paths:
71
+ - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
72
+ - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
73
+ - Linux: `~/.config/Claude/claude_desktop_config.json` (community Linux builds)
74
+
75
+ ```json
76
+ { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
50
77
  ```
51
- carto init / carto sync
52
-
53
- Discovers all files (no cap — SQLite handles the volume)
54
- mtime+size checkskip unchanged files
55
- tree-sitter parse → imports + symbols (0.05–0.2ms/file)
56
- Babel deep parse routes + models (API handler files only)
57
- Leiden+CPM graph clustering → auto-detects domains
58
- Computes reverse deps → blast radius for every file
59
- Writes AGENTS.md + .carto/context/*.md (lazy, on-demand)
60
- Auto-wires MCP into Kiro, Cursor, Claude Desktop
61
-
62
- carto watch
63
-
64
- File saved → debounce 50ms → re-parse 1 file → SQLite write → <50ms
78
+
79
+ ### VS Code Copilot
80
+
81
+ `carto init` writes `<project>/.vscode/mcp.json` for you when the `code` binary is on PATH. Manual: `.vscode/mcp.json` in your project root, or Command Palette `MCP: Add Server`. Note: VS Code uses `servers` (not `mcpServers`) and requires `"type": "stdio"`.
82
+ ```json
83
+ { "servers": { "carto": { "type": "stdio", "command": "carto", "args": ["serve"] } } }
65
84
  ```
66
85
 
86
+ ### Windsurf
87
+
88
+ `carto init` writes this for you when Windsurf is detected. Manual: `~/.codeium/windsurf/mcp_config.json`
89
+ ```json
90
+ { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
91
+ ```
92
+
93
+ ### Zed / JetBrains / VS Code (full agent mode)
94
+
95
+ Carto also runs as a full **ACP agent** — not just a passive MCP server, but an active coding agent with architectural awareness. See [ACP Agent](#acp-agent-zed--jetbrains--vs-code) below.
96
+
67
97
  ---
68
98
 
69
- ## 16 MCP tools
99
+ ## What changes for your AI
70
100
 
71
- `carto serve` exposes a local MCP server. Kiro, Cursor, and Claude query it mid-task.
101
+ Without carto, your AI greps text and guesses. With carto, it queries structural facts:
72
102
 
73
- | Tool | What it returns |
74
- |------|----------------|
75
- | `get_architecture()` | 500-word project overview: domains, entry points, stack, key patterns. **Use this first.** |
76
- | `get_blast_radius(file)` | All files affected by changing a given file, with hop distance |
77
- | `get_context(file)` | Everything about a file: domain, blast radius, neighbors, routes, models |
78
- | `get_change_plan(intent)` | Given "add rate limiting to /api/users" → files to touch, domains affected, blast radius, similar patterns |
79
- | `get_file_summary(file)` | What a file does, its role, key deps and dependents |
80
- | `get_similar_patterns(file)` | Files with same domain, same route shape, or shared dependencies — find conventions before writing new code |
81
- | `get_routes()` | All API endpoints with file mapping |
82
- | `get_structure()` | Import graph, entry points, high-impact files, tech stack |
83
- | `get_domain(name)` | All routes, models, functions for a domain. Lazily regenerated when stale. |
84
- | `get_neighbors(file, hops)` | Import graph neighbors: nodes and edges |
85
- | `get_cross_domain()` | Import edges that cross domain boundaries |
86
- | `search_routes(query)` | Search API routes by path or method |
87
- | `get_models(domain?)` | All data models, optionally filtered by domain |
88
- | `get_high_impact_files(n)` | Top N files by blast radius |
89
- | `get_env_vars(domain?)` | All env vars with domain mapping |
90
- | `get_domains_list()` | All detected domains with file, route, model counts |
103
+ > *"Add rate limiting to /api/users"*
104
+
105
+ **Without carto:** AI grep-searches your codebase, finds 12 files mentioning "users", picks 3 at random, hopes for the best.
106
+
107
+ **With carto:** AI calls `get_change_plan("add rate limiting to /api/users")` and gets back:
108
+ - The exact route handler file
109
+ - All 7 files that import it (blast radius)
110
+ - The AUTH domain it lives in
111
+ - Similar middleware patterns already in the codebase
112
+ - Cross-domain dependencies that could break
113
+
114
+ Your AI's response goes from "here's a guess" to "here's the right change with the architectural context."
115
+
116
+ ### Catching bad changes before save
117
+
118
+ The harder problem isn't finding the right file it's stopping a confident-sounding AI from writing a refactor that breaks the rest of the repo. Carto exposes a diff-shaped query the AI can call before the user accepts a change:
119
+
120
+ > *AI proposes a 12-line patch to `packages/pg-meta/src/pg-format/index.ts`. Before showing the diff, it calls `validate_diff(patch)`.*
121
+
122
+ ```
123
+ # Diff Validation
124
+
125
+ **Risk:** 🔴 HIGH
126
+ **Files changed:** 1
127
+ **Union blast radius:** 83 transitive dependents
128
+
129
+ ## Violations (1)
130
+
131
+ | Severity | Kind | File | Detail |
132
+ |----------|-------------|----------------------------------------|-----------------------------------------------------------------|
133
+ | HIGH | high_blast | `packages/pg-meta/src/pg-format/index.ts` | Modifying this file affects 83 transitive dependents (>50). |
134
+ ```
135
+
136
+ The AI sees this *before* it proposes the diff. It revises its plan, splits the change, or asks the user. The bad refactor never makes it to the screen. Sub-millisecond on a 7,000-file repo — see the **Benchmarks** section below.
137
+
138
+ Every `validate_diff` call is also written to a local SQLite log, so a session that runs five hours later can ask `did_we_discuss_this("snake_case naming")` and get back the prior decision. The AI stops re-deciding settled questions.
139
+
140
+ ### In the wild
141
+
142
+ ![Claude Code reviewing the supabase repo through carto's MCP server](docs/screenshots/claude-code-supabase.png)
143
+
144
+ *Claude Code analyzing the [supabase](https://github.com/supabase/supabase) repo via carto. Real session, no editing — 5,974 files indexed in ~780ms, 86 routes, 4,839 import edges, 7 domains. The agent's own verdict at the bottom: "useful, especially for a large codebase like supabase. The blast radius + cross-domain tools are the most valuable."*
91
145
 
92
146
  ---
93
147
 
94
148
  ## Languages and frameworks
95
149
 
96
- ### Import graph + symbols (tree-sitter — works on any repo)
150
+ ### Import graph + symbols (any repo)
97
151
 
98
152
  | Language | Extensions |
99
153
  |----------|-----------|
@@ -106,16 +160,16 @@ File saved → debounce 50ms → re-parse 1 file → SQLite write → <50ms
106
160
  | C# | `.cs` |
107
161
  | Ruby | `.rb` |
108
162
 
109
- ### Route extraction (framework-specific)
163
+ ### Route extraction (framework-aware)
110
164
 
111
165
  | Framework | Language |
112
166
  |-----------|---------|
113
- | Express, Next.js (App + Pages Router), tRPC, React Router | TypeScript / JavaScript |
167
+ | Express, Next.js (App + Pages), tRPC, React Router | TypeScript / JavaScript |
114
168
  | FastAPI, Flask, Django | Python |
115
169
  | Gin, Echo, Chi, net/http | Go |
116
170
  | Actix-web, Axum, Rocket | Rust |
117
171
  | Spring MVC / Boot, JAX-RS | Java |
118
- | ASP.NET Core (attribute routing + minimal API) | C# |
172
+ | ASP.NET Core | C# |
119
173
  | Rails, Sinatra | Ruby |
120
174
 
121
175
  ### Model extraction
@@ -127,52 +181,18 @@ File saved → debounce 50ms → re-parse 1 file → SQLite write → <50ms
127
181
  | Go structs | Go |
128
182
  | Rust structs | Rust |
129
183
  | JPA `@Entity`, Java records | Java |
130
- | EF Core classes, C# records | C# |
184
+ | EF Core, C# records | C# |
131
185
  | ActiveRecord | Ruby |
132
186
 
133
187
  ### TypeScript path aliases
134
188
 
135
- Reads `tsconfig.json` / `jsconfig.json` for `paths` config. `@/components/Button` resolves to the actual file in the import graph — blast radius works correctly for Next.js and Vite projects.
136
-
137
- ---
138
-
139
- ## Domain detection
140
-
141
- Carto uses **Leiden+CPM graph clustering** — files that import each other heavily cluster together. Domain names are inferred from path tokens, with keyword hints for well-known patterns (AUTH, PAYMENTS, DATABASE, etc.).
142
-
143
- Works on any repo — not just SaaS apps. vscode gets AUTH/EVENTS/DATABASE. zed (Rust) gets DATABASE/AUTH/EVENTS. A game engine would get RENDERER/PHYSICS/AUDIO.
144
-
145
- Custom domains via `carto.config.json`:
146
-
147
- ```json
148
- {
149
- "domains": {
150
- "EDITOR": ["editor", "monaco", "text"],
151
- "WORKBENCH": ["workbench", "layout", "panel"]
152
- }
153
- }
154
- ```
155
-
156
- ---
157
-
158
- ## Commands
159
-
160
- | Command | What it does |
161
- |---------|-------------|
162
- | `carto init` | Detect project, index codebase, generate AGENTS.md, wire MCP |
163
- | `carto sync` | Full re-index (skips unchanged files via mtime+size cache) |
164
- | `carto watch` | Incremental live re-index on every file save (<50ms) |
165
- | `carto serve` | Start MCP server for Kiro / Cursor / Claude |
166
- | `carto agent` | Start ACP agent mode (for Zed / JetBrains / VS Code) |
167
- | `carto impact <file>` | Blast radius: risk level, affected files, routes at risk |
168
- | `carto check` | Cross-domain violations, high-risk uncommitted changes, domain health |
169
- | `carto remove` | Remove AGENTS.md and .carto/ from project |
189
+ Reads `tsconfig.json` / `jsconfig.json` `paths` config. `@/components/Button` resolves to the actual file in the import graph — blast radius works correctly for Next.js and Vite projects.
170
190
 
171
191
  ---
172
192
 
173
193
  ## ACP Agent (Zed / JetBrains / VS Code)
174
194
 
175
- Carto works as a full **ACP agent** — not just a passive tool server, but an active coding agent with architectural awareness.
195
+ Beyond MCP, Carto runs as a full **ACP agent** — an active coding agent with built-in architectural awareness.
176
196
 
177
197
  ```
178
198
  User: "Add rate limiting to /api/users"
@@ -189,20 +209,16 @@ Sends to LLM (your API key) → streams answer + diffs back to editor
189
209
 
190
210
  ### Setup in Zed
191
211
 
192
- Add to `~/.config/zed/settings.json`:
193
-
212
+ `~/.config/zed/settings.json`:
194
213
  ```json
195
214
  {
196
215
  "agent_servers": {
197
- "Carto": {
198
- "command": "carto",
199
- "args": ["agent"]
200
- }
216
+ "Carto": { "command": "carto", "args": ["agent"] }
201
217
  }
202
218
  }
203
219
  ```
204
220
 
205
- ### BYOK (Bring Your Own Key)
221
+ ### Bring Your Own Key
206
222
 
207
223
  Carto supports any LLM provider — configure in your editor:
208
224
 
@@ -217,53 +233,204 @@ Carto supports any LLM provider — configure in your editor:
217
233
  | Together AI | Open-source models |
218
234
  | Azure OpenAI | Enterprise deployments |
219
235
 
220
- ### What makes it different
236
+ ---
237
+
238
+ ## The 22 MCP tools
221
239
 
222
- Other agents are smart but blind. Carto sees the architecture:
223
- - Auto-indexes your project on first session (1-10s depending on size)
224
- - Injects structural context into every LLM call (blast radius, domains, routes)
225
- - 12 internal tools the LLM can call during reasoning
226
- - Zero cost to you beyond your own API key
240
+ Once carto is wired in, your AI tool can call any of these mid-task. You don't need to memorize them — your AI will pick the right ones.
241
+
242
+ | Tool | What it returns |
243
+ |------|----------------|
244
+ | `get_architecture()` | 500-word project overview: domains, entry points, stack, key patterns. **Use this first.** |
245
+ | `get_change_plan(intent)` | Given "add rate limiting to /api/users" → files to touch, domains affected, blast radius, similar patterns |
246
+ | `get_blast_radius(file)` | All files affected by changing a given file, with hop distance |
247
+ | `simulate_change_impact(files)` | Union of all files transitively affected by changing **multiple** files at once. Powered by the bitmap engine — sub-millisecond on 7K-file repos. |
248
+ | `validate_diff(diff)` | Given a unified diff: violations (cross-domain imports, high-blast files), blast radius per file, risk level (SAFE/LOW/MEDIUM/HIGH), suggestions. Each call is recorded in the **episodic memory** log so other tools can ask "did we discuss this?". Sub-15ms p99. |
249
+ | `get_context(file)` | Everything about a file: domain, blast radius, neighbors, routes, models |
250
+ | `get_file_summary(file)` | What a file does, its role, key deps and dependents |
251
+ | `get_similar_patterns(file)` | Files with same domain, route shape, or shared deps — find conventions before writing new code |
252
+ | `get_routes()` | All API endpoints with file mapping |
253
+ | `get_structure()` | Import graph, entry points, high-impact files, tech stack |
254
+ | `get_domain(name)` | All routes, models, functions for a domain. Lazily regenerated when stale. |
255
+ | `get_neighbors(file, hops)` | Import graph neighbors: nodes and edges |
256
+ | `get_cross_domain()` | Import edges that cross domain boundaries |
257
+ | `search_routes(query)` | Search API routes by path or method |
258
+ | `get_models(domain?)` | All data models, optionally filtered by domain |
259
+ | `get_high_impact_files(n)` | Top N files by blast radius |
260
+ | `get_env_vars(domain?)` | All env vars with domain mapping |
261
+ | `get_domains_list()` | All detected domains with file, route, model counts |
262
+ | `get_recent_decisions(time_range, kind?)` | Recent validation decisions and architectural choices the AI has made in this project |
263
+ | `get_session_context(session_id?)` | Full context for an AI session: every decision and intervention, ordered chronologically |
264
+ | `did_we_discuss_this(topic)` | Substring search over the episodic memory log — avoid re-deciding settled questions |
265
+ | `get_intervention_history(file?)` | Past Carto-issued violations and suggestions, optionally filtered by file |
266
+
267
+ **All MCP queries:** **<5ms** on every benchmarked repo.
268
+
269
+ ## Episodic Memory
270
+
271
+ Carto remembers every diff it validates. The `validate_diff` tool writes one row per call into a local SQLite log (`ai_sessions`/`decisions`/`interventions` tables) — so a session that runs five hours later can still ask `did_we_discuss_this("snake_case naming")` and get back the prior decision. The log lives next to the index in `.carto/carto.db` — never sent over the network, never shared between projects.
227
272
 
228
273
  ---
229
274
 
230
- ## MCP config (if auto-wire missed your IDE)
275
+ ## Domain detection
231
276
 
232
- `carto init` auto-wires into Kiro, Cursor, and Claude Desktop. If it missed yours, add manually:
277
+ Carto uses **Leiden+CPM graph clustering** files that import each other heavily cluster together. Domain names are inferred from path tokens, with keyword hints for well-known patterns (AUTH, PAYMENTS, DATABASE, etc.).
233
278
 
234
- **Kiro** `~/.kiro/settings/mcp.json`
235
- ```json
236
- { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
237
- ```
279
+ **Adaptive strategy:** Repos under 100 files use keyword-only clustering (avoids over-fragmentation). Larger repos with dense import graphs get graph-based clustering with a gamma that scales continuously with repo size.
238
280
 
239
- **Cursor**`~/.cursor/mcp.json`
240
- ```json
241
- { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
242
- ```
281
+ Works on any repo not just SaaS apps. vscode gets AUTH/EVENTS/DATABASE. zed (Rust) gets DATABASE/AUTH/EVENTS. A game engine would get RENDERER/PHYSICS/AUDIO.
243
282
 
244
- **Claude Desktop** `~/Library/Application Support/Claude/claude_desktop_config.json`
283
+ Custom domains via `carto.config.json`:
245
284
  ```json
246
- { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
285
+ {
286
+ "domains": {
287
+ "EDITOR": ["editor", "monaco", "text"],
288
+ "WORKBENCH": ["workbench", "layout", "panel"]
289
+ }
290
+ }
247
291
  ```
248
292
 
249
- **VS Code Copilot** `.vscode/mcp.json` in your project root, or Command Palette → `MCP: Add Server`
293
+ Full schema with anchor pinning (forces files into a domain regardless of clustering):
250
294
  ```json
251
- { "servers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
295
+ {
296
+ "domains": {
297
+ "AUTH": {
298
+ "keywords": ["auth", "login", "session"],
299
+ "anchor": ["src/auth/session.ts", "src/auth/middleware.ts"]
300
+ }
301
+ }
302
+ }
252
303
  ```
253
304
 
254
- **Windsurf** `~/.windsurf/mcp.json`
255
- ```json
256
- { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
305
+ **Stability tracking:** Carto tracks domain assignments across syncs. If >5% of files change domain, `carto check` flags it as unstable. Two consecutive syncs with no code changes always produce 0% drift.
306
+
307
+ ---
308
+
309
+ ## CLI commands
310
+
311
+ | Command | What it does |
312
+ |---------|-------------|
313
+ | `carto init` | Detect project, index codebase, generate AGENTS.md, install git hooks (pre-commit, post-checkout, post-merge, post-rewrite), auto-wire MCP into every AI tool found |
314
+ | `carto sync` | Full re-index (skips unchanged files via mtime+size cache). Called automatically by git hooks on commit/checkout/merge/rebase. |
315
+ | `carto serve` | Start MCP server (called by your AI tool — usually you don't run this directly). On every file-aware query the server mtime+size-checks the file and re-parses inline if stale. |
316
+ | `carto watch` | **Optional.** Live re-index on every file save. Not required — git hooks + lazy MCP re-parse keep the index fresh by default. Use only for AI-heavy workflows that write 50+ files between commits. |
317
+ | `carto agent` | Start ACP agent mode (for Zed / JetBrains / VS Code) |
318
+ | `carto impact <file>` | Blast radius: risk level, affected files, routes at risk |
319
+ | `carto check` | Cross-domain violations, high-risk uncommitted changes, domain health |
320
+ | `carto inspect` | Read-only diagnostic: index paths, sizes, freshness, bitmap sidecar shape, top-impact files, schema version, sync timestamps. `--json` for piping into `jq`. Never triggers a rebuild. |
321
+ | `carto remove` | Remove AGENTS.md and .carto/ from project |
322
+
323
+ ---
324
+
325
+ ## Benchmarks
326
+
327
+ Measured on real open-source repos. Apple M-series, 8 CPUs, 8GB RAM. SHAs pinned in `~/carto-test-repos`. Reproducible via `~/carto-test-repos/run-bench.sh`.
328
+
329
+ ### Indexing speed
330
+
331
+ | Repo | Language | Indexed Files | First Run | Second Run | DB Size | Import Edges |
332
+ |------|----------|---------------|-----------|------------|---------|--------------|
333
+ | [prisma/prisma](https://github.com/prisma/prisma) | TypeScript | 961 | **961ms** | **431ms** | 0.7 MB | 1,387 |
334
+ | [supabase/supabase](https://github.com/supabase/supabase) | TypeScript | 6,330 | **5.4s** | **1.2s** | 4.0 MB | 5,321 |
335
+ | [microsoft/vscode](https://github.com/microsoft/vscode) | TypeScript | 7,567 | **7.7s** | **1.0s** | 6.7 MB | 13,420 |
336
+ | [zed-industries/zed](https://github.com/zed-industries/zed) | Rust | 1,752 | **3.0s** | **491ms** | 4.4 MB | 2,113 |
337
+
338
+ **Indexed Files** counts what Carto actually parses — `.ts/.js/.py/.go/.rs/...` after excluding `node_modules`, build output, and per-file `*.test.*` / `*.spec.*` / `*.stories.*` / `test_*.py` patterns. The on-disk file count of the repo is larger.
339
+
340
+ **Second Run** = `carto sync` after no changes. mtime+size checked before reading content — if nothing changed, nothing is re-parsed.
341
+
342
+ ### MCP query latency (bitmap engine vs SQLite)
343
+
344
+ Carto's MCP query path is bitmap-backed on five tools, plus a sixth (`simulate_change_impact`) that's only feasible with bitmap OR-aggregation. Speedups measured against the same data, same DB, same machine — bitmap path vs the equivalent SQLite path.
345
+
346
+ | Tool | vscode (7,567 files) | Speedup vs SQLite |
347
+ |------|---------------------:|------------------:|
348
+ | `get_blast_radius` | sub-ms | **10.7×** |
349
+ | `get_cross_domain` | 2.1ms | **6.2×** |
350
+ | `get_high_impact_files` | sub-ms | **559×** |
351
+ | `get_similar_patterns` | sub-ms | **73×** |
352
+ | `simulate_change_impact` | sub-ms | **6.5×** (no SQLite equivalent at this latency) |
353
+
354
+ Median speedup across all five tools on vscode: **10.7×**. Smaller repos hit higher peaks — laravel-framework `get_high_impact_files` clocks at 155× on the smaller graph. Reproducible via `npm run bench:bitmap -- --repo <path>`.
355
+
356
+ ### `validate_diff` latency
357
+
358
+ The new diff-shaped query that lets the AI ask "is this patch safe?" before showing it to the user. Profiled with a representative 20-line diff against 20 random mid-blast-radius files per repo, 1000 calls each.
359
+
360
+ | Repo | Files | p50 | p99 |
361
+ |------|-------|----:|----:|
362
+ | supabase | 6,259 | **0.082ms** | **0.298ms** |
363
+ | vscode | 7,567 | **0.084ms** | **0.489ms** |
364
+
365
+ Budget was p50 ≤ 5ms, p99 ≤ 15ms. Both targets are cleared by 30-60×. The bitmap engine handles every blast-radius and cross-domain query in microseconds; what's left is diff parsing + result aggregation. Reproducible via `node bench/validation-perf/index.js --repo <path>`.
366
+
367
+ ### Domains detected
368
+
369
+ | Repo | Domains |
370
+ |------|---------|
371
+ | prisma | CORE · DATABASE · AUTH · EVENTS |
372
+ | supabase | CORE · AUTH · DATABASE · PAYMENTS · NOTIFICATIONS · EVENTS · TRPC |
373
+ | vscode | EXTENSIONS · AUTH · EVENTS · DATABASE · EXTENSION · CLI · CORE |
374
+ | zed (Rust) | CORE · DATABASE · AUTH · EVENTS · PAYMENTS · TRPC · NOTIFICATIONS |
375
+
376
+ vscode at 7,567 indexed files in under 8 seconds. Rust import graph working on zed (2,113 edges from `mod` declarations and `use crate::` paths).
377
+
378
+ ### Accuracy
379
+
380
+ 12 corpus repos pass `node test/accuracy-corpus.js --samples 100` — full parity between the bitmap path and the SQLite path on `blastRadius`, `crossDomain`, `highImpactFiles`, and `simulateChangeImpact`. The bitmap layer is a speedup, never a behavior change.
381
+
382
+ ---
383
+
384
+ ## How it works
385
+
386
+ ```
387
+ carto init
388
+
389
+ Discovers all files (no cap — SQLite handles the volume)
390
+ mtime+size check → skip unchanged files
391
+ tree-sitter parse → imports + symbols (0.05–0.2ms/file)
392
+ Babel deep parse → routes + models (API handler files only)
393
+ Leiden+CPM graph clustering → auto-detects domains
394
+ Computes reverse deps → blast radius for every file
395
+ Writes AGENTS.md + .carto/context/*.md (lazy, on-demand)
396
+ Auto-wires MCP into every AI tool found
397
+ Installs 4 git hooks: pre-commit, post-checkout, post-merge, post-rewrite
398
+
399
+ [no daemon, no watcher, no background process]
400
+
401
+ ─── Freshness mechanism 1: git hooks (90% of cases) ───
402
+ You commit / pull / switch branches / rebase
403
+ → hook runs `carto sync` quietly in <1s
404
+ → only changed files re-parsed
405
+
406
+ ─── Freshness mechanism 2: lazy mtime check (the gap) ───
407
+ You edit files between commits, AI asks "blast radius of db.ts?"
408
+ → MCP server stats db.ts (mtime+size vs DB row)
409
+ → if stale, re-parses just that file inline (<50ms)
410
+ → returns fresh answer
411
+
412
+ ─── Optional: carto watch (AI-heavy workflows only) ───
413
+ File saved → debounce 50ms → re-parse 1 file → SQLite write → <50ms
257
414
  ```
258
415
 
259
416
  ---
260
417
 
261
418
  ## What Carto never does
262
419
 
263
- - Sends your code anywhere. Local only. SQLite on disk.
264
- - Writes secrets into AGENTS.md. `.cartoignore` blocks `.env` and credential files by default.
265
- - Touches your manual notes. Writes only between `<!-- CARTO:AUTO:START -->` and `<!-- CARTO:AUTO:END -->`.
266
- - Costs money. MIT license. Free forever.
420
+ - **Sends your code anywhere.** Local only. SQLite on disk.
421
+ - **Writes secrets into AGENTS.md.** `.cartoignore` blocks `.env` and credential files by default.
422
+ - **Touches your manual notes.** Writes only between `<!-- CARTO:AUTO:START -->` and `<!-- CARTO:AUTO:END -->`.
423
+ - **Costs money.** MIT license. Free forever.
424
+
425
+ ---
426
+
427
+ ## Origin
428
+
429
+ I was building [Emfirge](https://www.emfirge.cloud) — a cloud security agent that maps AWS infrastructure into a graph and simulates the blast radius of every change.
430
+
431
+ To make the AI inside Emfirge understand infrastructure, I wrote a module called `cartography.py`. It mapped AWS resources, built a graph of how they connected, and wrote it into a structured map. The AI stopped hallucinating. It worked with facts, not guesses.
432
+
433
+ Carto is the same idea, applied to source code. Same insight: AI agents stop guessing once they can query the architecture.
267
434
 
268
435
  ---
269
436
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "carto-md",
3
- "version": "2.0.6",
3
+ "version": "2.0.8",
4
4
  "description": "Structural intelligence layer for AI coding tools. Indexes your codebase into SQLite — routes, models, import graph, blast radius, domains — and exposes 16 MCP tools for Kiro, Cursor, and Claude.",
5
5
  "bin": {
6
6
  "carto": "src/cli/index.js"
@@ -10,7 +10,9 @@
10
10
  "test": "node test/test.js",
11
11
  "test:correctness": "node test/correctness.js",
12
12
  "test:benchmark": "node test/benchmark.js",
13
- "test:bench-ci": "node test/bench-ci.js"
13
+ "test:bench-ci": "node test/bench-ci.js",
14
+ "postinstall": "node scripts/postinstall.js",
15
+ "bench:bitmap": "node bench/bitmap-validation/index.js"
14
16
  },
15
17
  "dependencies": {
16
18
  "@agentclientprotocol/sdk": "^0.22.1",
@@ -18,7 +20,9 @@
18
20
  "@modelcontextprotocol/sdk": "^1.0.0",
19
21
  "better-sqlite3": "11.7.0",
20
22
  "chokidar": "^3.6.0",
21
- "tree-sitter": "0.25.0",
23
+ "tree-sitter": "0.25.0"
24
+ },
25
+ "optionalDependencies": {
22
26
  "tree-sitter-c-sharp": "0.21.3",
23
27
  "tree-sitter-cpp": "0.23.4",
24
28
  "tree-sitter-go": "0.25.0",
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // Postinstall script — checks tree-sitter grammar availability and prints
5
+ // actionable guidance if any failed to install. Always exits 0.
6
+
7
+ if (process.env.CARTO_NO_POSTINSTALL === '1') process.exit(0);
8
+
9
+ const GRAMMARS = [
10
+ { pkg: 'tree-sitter-javascript', langs: 'JavaScript' },
11
+ { pkg: 'tree-sitter-typescript', langs: 'TypeScript' },
12
+ { pkg: 'tree-sitter-python', langs: 'Python' },
13
+ { pkg: 'tree-sitter-go', langs: 'Go' },
14
+ { pkg: 'tree-sitter-rust', langs: 'Rust' },
15
+ { pkg: 'tree-sitter-java', langs: 'Java' },
16
+ { pkg: 'tree-sitter-cpp', langs: 'C/C++' },
17
+ { pkg: 'tree-sitter-c-sharp', langs: 'C#' },
18
+ ];
19
+
20
+ const failed = [];
21
+ for (const g of GRAMMARS) {
22
+ try { require(g.pkg); } catch { failed.push(g); }
23
+ }
24
+
25
+ if (failed.length === 0) process.exit(0);
26
+
27
+ // Print guidance
28
+ const langs = failed.map(g => g.langs).join(', ');
29
+ const isWin = process.platform === 'win32';
30
+ const isMac = process.platform === 'darwin';
31
+
32
+ let fix;
33
+ if (isWin) {
34
+ fix = 'Install "Desktop development with C++" from https://aka.ms/vs/17/release/vs_BuildTools.exe then re-run: npm rebuild';
35
+ } else if (isMac) {
36
+ fix = 'Run: xcode-select --install && npm rebuild';
37
+ } else {
38
+ fix = 'Run: sudo apt-get install -y build-essential && npm rebuild (or equivalent for your distro)';
39
+ }
40
+
41
+ console.log('');
42
+ console.log('[CARTO] ⚠️ Some tree-sitter grammars failed to install.');
43
+ console.log(`[CARTO] Affected languages: ${langs}`);
44
+ console.log('[CARTO] These languages will use regex-only extraction (less accurate).');
45
+ console.log(`[CARTO] To fix: ${fix}`);
46
+ console.log('');
package/src/acp/agent.js CHANGED
@@ -70,19 +70,12 @@ class CartoAgent {
70
70
  }
71
71
 
72
72
  // Provider methods
73
- async unstable_listProviders(_params) {
74
- return { providers: this.providers.list() };
75
- }
76
-
77
- async unstable_setProvider(params) {
78
- this.providers.set(params);
79
- return {};
80
- }
81
-
82
- async unstable_disableProvider(_params) {
83
- this.providers.disable();
84
- return {};
85
- }
73
+ // The custom `unstable_*` provider-management methods (list / set / disable)
74
+ // were removed. The ACP SDK only dispatches the methods declared in
75
+ // its AGENT_METHODS constant, so those custom routes returned -32601
76
+ // "Method not found" anyway. Provider config flows through env vars /
77
+ // editor settings; ProviderRegistry remains as the internal
78
+ // configuration carrier.
86
79
 
87
80
  // Session list/load stubs
88
81
  async listSessions(_params) { return { sessions: [] }; }