carto-md 2.0.9 → 2.1.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.
Files changed (172) hide show
  1. package/CONTRIBUTING.md +19 -15
  2. package/README.md +192 -415
  3. package/docs/api/README.md +99 -0
  4. package/docs/api/did_we_discuss_this.md +34 -0
  5. package/docs/api/dismiss_suggestion.md +34 -0
  6. package/docs/api/explain_change_in_natural_language.md +33 -0
  7. package/docs/api/find_consumers_of_api.md +34 -0
  8. package/docs/api/get_action_patterns.md +32 -0
  9. package/docs/api/get_active_drift.md +32 -0
  10. package/docs/api/get_active_suggestions.md +25 -0
  11. package/docs/api/get_ai_cost_attribution.md +32 -0
  12. package/docs/api/get_arch_events.md +42 -0
  13. package/docs/api/get_architectural_drift.md +37 -0
  14. package/docs/api/get_architecture.md +25 -0
  15. package/docs/api/get_blast_radius.md +34 -0
  16. package/docs/api/get_canonical_pattern.md +39 -0
  17. package/docs/api/get_change_plan.md +34 -0
  18. package/docs/api/get_change_velocity.md +32 -0
  19. package/docs/api/get_churn_vs_blast_radius.md +32 -0
  20. package/docs/api/get_complexity_trend.md +39 -0
  21. package/docs/api/get_context.md +34 -0
  22. package/docs/api/get_conventions.md +32 -0
  23. package/docs/api/get_cross_domain.md +25 -0
  24. package/docs/api/get_cross_language_call_graph.md +25 -0
  25. package/docs/api/get_cross_repo_blast_radius.md +34 -0
  26. package/docs/api/get_cross_team_coupling.md +25 -0
  27. package/docs/api/get_data_flow.md +33 -0
  28. package/docs/api/get_dead_code_with_confidence.md +32 -0
  29. package/docs/api/get_decision_log.md +32 -0
  30. package/docs/api/get_dependency_surface.md +25 -0
  31. package/docs/api/get_domain.md +34 -0
  32. package/docs/api/get_domain_evolution.md +39 -0
  33. package/docs/api/get_domain_health.md +32 -0
  34. package/docs/api/get_domains_list.md +25 -0
  35. package/docs/api/get_drift_digest.md +32 -0
  36. package/docs/api/get_env_vars.md +32 -0
  37. package/docs/api/get_evolution_delta.md +36 -0
  38. package/docs/api/get_file_ownership.md +33 -0
  39. package/docs/api/get_file_summary.md +34 -0
  40. package/docs/api/get_high_impact_files.md +32 -0
  41. package/docs/api/get_hot_in_prod_no_tests.md +34 -0
  42. package/docs/api/get_hotspot_files.md +37 -0
  43. package/docs/api/get_iac_resources.md +25 -0
  44. package/docs/api/get_interface_contract.md +33 -0
  45. package/docs/api/get_intervention_history.md +32 -0
  46. package/docs/api/get_invariants.md +37 -0
  47. package/docs/api/get_llm_enrichment.md +33 -0
  48. package/docs/api/get_microservice_cut_points.md +32 -0
  49. package/docs/api/get_microservices_migration_cut_points.md +25 -0
  50. package/docs/api/get_minimal_context_for_intent.md +39 -0
  51. package/docs/api/get_models.md +32 -0
  52. package/docs/api/get_neighbors.md +39 -0
  53. package/docs/api/get_org_architecture.md +25 -0
  54. package/docs/api/get_org_domain_mapping.md +25 -0
  55. package/docs/api/get_pending_decisions.md +32 -0
  56. package/docs/api/get_predictive_risk.md +32 -0
  57. package/docs/api/get_progressive_disclosure_tree.md +25 -0
  58. package/docs/api/get_recent_decisions.md +37 -0
  59. package/docs/api/get_risk_weighted_blast_radius.md +32 -0
  60. package/docs/api/get_routes.md +25 -0
  61. package/docs/api/get_safety_checklist.md +33 -0
  62. package/docs/api/get_semantic_diff.md +34 -0
  63. package/docs/api/get_service_boundary_violations.md +25 -0
  64. package/docs/api/get_service_dependency_graph.md +25 -0
  65. package/docs/api/get_session_context.md +32 -0
  66. package/docs/api/get_similar_patterns.md +39 -0
  67. package/docs/api/get_stale_docs.md +25 -0
  68. package/docs/api/get_structure.md +25 -0
  69. package/docs/api/get_temporal_context.md +34 -0
  70. package/docs/api/get_test_coverage_map.md +25 -0
  71. package/docs/api/get_token_budget_report.md +36 -0
  72. package/docs/api/get_upgrade_risk.md +25 -0
  73. package/docs/api/get_working_memory.md +25 -0
  74. package/docs/api/ingest_otlp_traces.md +34 -0
  75. package/docs/api/scaffold_for_intent.md +34 -0
  76. package/docs/api/search_routes.md +34 -0
  77. package/docs/api/simulate_change_impact.md +37 -0
  78. package/docs/api/validate_change.md +39 -0
  79. package/docs/api/validate_diff.md +39 -0
  80. package/docs/concepts/anci.md +87 -0
  81. package/docs/concepts/blast-radius.md +66 -0
  82. package/docs/concepts/domains.md +91 -0
  83. package/docs/concepts/import-graph.md +102 -0
  84. package/docs/concepts/mcp-integration.md +148 -0
  85. package/docs/guides/adding-feature-safely.md +101 -0
  86. package/docs/guides/ci-integration.md +175 -0
  87. package/docs/guides/monorepo-setup.md +121 -0
  88. package/docs/guides/onboarding-new-engineer.md +121 -0
  89. package/docs/guides/pre-merge-review.md +139 -0
  90. package/docs/migration/v1-to-v2.md +110 -0
  91. package/docs/quickstart.md +95 -0
  92. package/docs/scale.md +2 -2
  93. package/docs/troubleshooting.md +180 -0
  94. package/package.json +10 -4
  95. package/scripts/gen-api-docs.js +170 -0
  96. package/src/acp/agent.js +83 -11
  97. package/src/acp/config.js +64 -0
  98. package/src/acp/persistence.js +146 -0
  99. package/src/acp/providers/anthropic.js +179 -27
  100. package/src/acp/providers/index.js +15 -2
  101. package/src/acp/providers/openai.js +164 -38
  102. package/src/acp/providers/sse.js +82 -0
  103. package/src/acp/safety.js +128 -0
  104. package/src/acp/session.js +73 -0
  105. package/src/adjacent/call-graph.js +170 -0
  106. package/src/adjacent/iac.js +167 -0
  107. package/src/adjacent/llm-enrich.js +35 -0
  108. package/src/adjacent/runtime.js +216 -0
  109. package/src/adjacent/semantic-diff.js +143 -0
  110. package/src/agents/scan-structure.js +1 -1
  111. package/src/ai/context-builder.js +215 -0
  112. package/src/ai/retrieval/lexical.js +122 -0
  113. package/src/ai/retrieval/rrf.js +121 -0
  114. package/src/ai/retrieval/semantic.js +35 -0
  115. package/src/ai/retrieval/structural.js +82 -0
  116. package/src/ai/tools.js +423 -0
  117. package/src/anci/emit.js +2 -2
  118. package/src/bitmap/index.js +1 -1
  119. package/src/bitmap/tools.js +2 -2
  120. package/src/brain/conventions/index.js +185 -0
  121. package/src/brain/index.js +31 -0
  122. package/src/brain/invariants/index.js +252 -0
  123. package/src/brain/procedural/index.js +181 -0
  124. package/src/brain/suggestions/index.js +153 -0
  125. package/src/brain/working/index.js +170 -0
  126. package/src/cli/check.js +47 -1
  127. package/src/cli/diff.js +83 -0
  128. package/src/cli/doctor.js +270 -0
  129. package/src/cli/explain.js +61 -0
  130. package/src/cli/index.js +101 -0
  131. package/src/cli/init.js +143 -5
  132. package/src/cli/org.js +172 -0
  133. package/src/cli/pr-impact.js +59 -2
  134. package/src/cli/serve.js +1 -1
  135. package/src/cli/status.js +211 -0
  136. package/src/cli/sync.js +2 -2
  137. package/src/cli/temporal.js +188 -0
  138. package/src/cli/validate.js +201 -0
  139. package/src/cli/watch.js +4 -4
  140. package/src/cli/why.js +101 -0
  141. package/src/extractors/frameworks.js +236 -0
  142. package/src/extractors/languages/dart.js +138 -0
  143. package/src/extractors/languages/go.js +11 -1
  144. package/src/extractors/languages/javascript.js +13 -3
  145. package/src/extractors/languages/kotlin.js +169 -0
  146. package/src/extractors/languages/php.js +195 -0
  147. package/src/extractors/languages/python.js +12 -1
  148. package/src/extractors/languages/swift.js +140 -0
  149. package/src/extractors/languages/typescript.js +15 -2
  150. package/src/extractors/plugin-api.js +102 -0
  151. package/src/mcp/files-without-tests.js +285 -0
  152. package/src/mcp/middleware/index.js +451 -0
  153. package/src/mcp/server.js +2292 -0
  154. package/src/mcp/validate.js +1 -1
  155. package/src/org/detect.js +262 -0
  156. package/src/org/queries.js +144 -0
  157. package/src/org/store.js +173 -0
  158. package/src/org/sync.js +106 -0
  159. package/src/predictive/cut-points.js +83 -0
  160. package/src/predictive/drift-digest.js +88 -0
  161. package/src/predictive/ownership.js +145 -0
  162. package/src/predictive/risk-score.js +121 -0
  163. package/src/predictive/validate-change.js +55 -0
  164. package/src/store/store-adapter.js +3 -3
  165. package/src/store/{sync-v2.js → sync.js} +53 -13
  166. package/src/temporal/backfill.js +211 -0
  167. package/src/temporal/delta.js +85 -0
  168. package/src/temporal/events.js +180 -0
  169. package/src/temporal/queries.js +358 -0
  170. package/src/temporal/snapshot.js +151 -0
  171. package/src/temporal/store.js +400 -0
  172. package/src/mcp/server-v2.js +0 -986
package/README.md CHANGED
@@ -5,9 +5,9 @@
5
5
  [![MIT License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
6
6
  [![npm downloads](https://img.shields.io/npm/dm/carto-md)](https://www.npmjs.com/package/carto-md)
7
7
 
8
- **The structural intelligence layer for AI coding tools.**
8
+ **Carto gives your AI tools a brain for your codebase.** One that remembers decisions across chats, tracks how the code evolves, and flags risky edits before they ship.
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.
10
+ > *"Touch that file and 22 things could break. That's exactly what you want to know before refactoring."* Claude Code, on supabase
11
11
 
12
12
  ```bash
13
13
  npm install -g carto-md
@@ -15,552 +15,329 @@ cd your-project
15
15
  carto init
16
16
  ```
17
17
 
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.
18
+ That's it. Carto auto-wires into every AI tool installed on your machine. Restart it. Your AI now knows your codebase — and keeps a memory of every decision it makes inside it.
19
19
 
20
- **Works with:** Cursor · Claude Code · Codex · Kiro · Claude Desktop · Windsurf · VS Code Copilot · JetBrains · Zed
20
+ **Works with:** Cursor · Claude Code · Codex · Kiro · Claude Desktop · Windsurf · VS Code Copilot · Zed · JetBrains
21
21
 
22
- > Carto also publishes [**ANCI**](#anci--the-open-spec-for-codebases-describing-themselves-to-ai) the open file format for any codebase to describe its architecture to AI tools. Carto is the reference implementation; the spec is open and any tool can consume it. ANCI ↓](#anci--the-open-spec-for-codebases-describing-themselves-to-ai)
22
+ Six weeks later, a new chat can ask "did we agree on snake_case here?" and get the actual prior verdict back. Nothing is re-decided.
23
23
 
24
- ---
24
+ ## What Carto actually does
25
25
 
26
- ## Use it with your AI tool
26
+ ```
27
+ ─────────────────────────────────────────────────────────────────────
28
+ carto init reads your repo, builds the map (imports, routes,
29
+ models, domains, blast radius), wires every AI tool
30
+ on your machine. one minute, done.
31
+
32
+ every chat your AI gets the 6–12 files it actually needs.
33
+ every diff it proposes runs validate_diff first —
34
+ risky ones blocked before they hit your screen.
35
+ carto also pushes nudges back: "coupling jumped in
36
+ AUTH", "two sessions are editing this file."
37
+
38
+ brain invariants and conventions are mined from your
39
+ import graph. action patterns ("when a route is
40
+ added, auth/middleware is touched 89% of the time")
41
+ are mined from your git history. nobody writes
42
+ these rules.
43
+
44
+ timeline every commit takes a snapshot. drift, churn, and
45
+ architectural events accumulate. your AI can read
46
+ the whole story at any time: "AUTH grew 18 files
47
+ and lost stability when payments/billing.ts moved
48
+ out." carto gets smarter the longer the repo lives.
49
+
50
+ predicts every file is scored: P(causes the next bug).
51
+ the score blends blast radius × churn × past
52
+ interventions × test coverage. high-risk files
53
+ surface on every PR, before the PR is opened.
54
+
55
+ always one SQLite file on your disk. no network, no
56
+ telemetry, no cloud.
57
+ ─────────────────────────────────────────────────────────────────────
58
+ ```
27
59
 
28
- `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.**
60
+ ---
29
61
 
30
- ### Cursor
62
+ <details>
63
+ <summary>Manual MCP wiring (if your tool wasn't auto-detected)</summary>
31
64
 
32
- `carto init` writes this for you. Manual: `~/.cursor/mcp.json`
65
+ ### Cursor `~/.cursor/mcp.json`
33
66
  ```json
34
67
  { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
35
68
  ```
36
69
 
37
- ### Claude Code (CLI)
38
-
39
- `carto init` writes `<project>/.mcp.json` for you when Claude Code is detected (`claude` binary on PATH or `~/.claude/` exists). Manual:
70
+ ### Claude Code — `<project>/.mcp.json`
40
71
  ```bash
41
72
  claude mcp add carto -- carto serve
42
73
  ```
43
- Or create `.mcp.json` at the project root:
44
- ```json
45
- { "mcpServers": { "carto": { "command": "carto", "args": ["serve"] } } }
46
- ```
47
74
 
48
- ### Codex (CLI)
49
-
50
- `carto init` writes `~/.codex/config.toml` for you when Codex is detected (`codex` binary on PATH or `~/.codex/` exists). Manual:
51
- ```bash
52
- codex mcp add carto -- carto serve
53
- ```
54
- Or edit `~/.codex/config.toml`:
75
+ ### Codex — `~/.codex/config.toml`
55
76
  ```toml
56
77
  [mcp_servers.carto]
57
78
  command = "carto"
58
79
  args = ["serve"]
59
- cwd = "/your/project"
60
- enabled = true
61
80
  ```
62
81
 
63
- ### Kiro
64
-
65
- `carto init` writes this for you. Manual: `~/.kiro/settings/mcp.json`
82
+ ### Kiro — `~/.kiro/settings/mcp.json`
66
83
  ```json
67
84
  { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
68
85
  ```
69
86
 
70
87
  ### Claude Desktop
71
-
72
- `carto init` writes this for you (cross-platform). Manual paths:
73
88
  - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
74
89
  - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
75
- - Linux: `~/.config/Claude/claude_desktop_config.json` (community Linux builds)
90
+ - Linux: `~/.config/Claude/claude_desktop_config.json`
76
91
 
77
92
  ```json
78
93
  { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
79
94
  ```
80
95
 
81
- ### VS Code Copilot
82
-
83
- `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"`.
96
+ ### VS Code Copilot — `.vscode/mcp.json`
84
97
  ```json
85
98
  { "servers": { "carto": { "type": "stdio", "command": "carto", "args": ["serve"] } } }
86
99
  ```
87
100
 
88
- ### Windsurf
89
-
90
- `carto init` writes this for you when Windsurf is detected. Manual: `~/.codeium/windsurf/mcp_config.json`
101
+ ### Windsurf — `~/.codeium/windsurf/mcp_config.json`
91
102
  ```json
92
103
  { "mcpServers": { "carto": { "command": "carto", "args": ["serve"], "cwd": "/your/project" } } }
93
104
  ```
94
105
 
95
- ### Zed / JetBrains / VS Code (full agent mode)
96
-
97
- 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.
106
+ </details>
98
107
 
99
108
  ---
100
109
 
101
- ## What changes for your AI
110
+ ## What's actually different
102
111
 
103
- Without carto, your AI greps text and guesses. With carto, it queries structural facts:
112
+ Most code indexers build a snapshot. Cursor's index, Sourcegraph's graph, GitHub's search — they all tell your AI what's in the repo *right now*. That's table stakes.
104
113
 
105
- > *"Add rate limiting to /api/users"*
114
+ Carto does that too and then layers five kinds of memory on top:
106
115
 
107
- **Without carto:** AI grep-searches your codebase, finds 12 files mentioning "users", picks 3 at random, hopes for the best.
116
+ - **Episodic** every diff it validated, every decision it made. Six weeks later, your AI can ask `did_we_discuss_this("snake_case naming")` and get back the prior verdict.
117
+ - **Temporal** — snapshots, churn, deltas. *"AUTH grew 18 files this quarter and lost stability when `payments/billing.ts` moved out."*
118
+ - **Semantic** — invariants and conventions mined from the import graph itself, not declared by humans.
119
+ - **Procedural** — patterns mined from git history. *"When a route gets added, the auth middleware is touched 89% of the time."*
120
+ - **Working** — one call that returns what's open, what's drifting, what warnings are unresolved. Read at the start of every session.
108
121
 
109
- **With carto:** AI calls `get_change_plan("add rate limiting to /api/users")` and gets back:
110
- - The exact route handler file
111
- - All 7 files that import it (blast radius)
112
- - The AUTH domain it lives in
113
- - Similar middleware patterns already in the codebase
114
- - Cross-domain dependencies that could break
122
+ Your AI tool sees files. Carto sees architecture *and history*. Every chat starts where the last one left off.
115
123
 
116
- Your AI's response goes from "here's a guess" to "here's the right change with the architectural context."
124
+ ---
117
125
 
118
- ### Catching bad changes before save
126
+ ## What it looks like in practice
119
127
 
120
- 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:
128
+ ### Stopping a bad refactor before you see the diff
121
129
 
122
- > *AI proposes a 12-line patch to `packages/pg-meta/src/pg-format/index.ts`. Before showing the diff, it calls `validate_diff(patch)`.*
130
+ The AI is about to propose a 12-line patch. Before showing it to you, it calls `validate_diff`:
123
131
 
124
132
  ```
125
- # Diff Validation
126
-
127
- **Risk:** 🔴 HIGH
128
- **Files changed:** 1
129
- **Union blast radius:** 83 transitive dependents
130
-
131
- ## Violations (1)
133
+ Risk: 🔴 HIGH
134
+ Files changed: 1
135
+ Union blast radius: 83 transitive dependents
132
136
 
133
- | Severity | Kind | File | Detail |
134
- |----------|-------------|----------------------------------------|-----------------------------------------------------------------|
135
- | HIGH | high_blast | `packages/pg-meta/src/pg-format/index.ts` | Modifying this file affects 83 transitive dependents (>50). |
137
+ Violations
138
+ HIGH · high_blast · packages/pg-meta/src/pg-format/index.ts
139
+ 83 transitive dependents (threshold: 50)
136
140
  ```
137
141
 
138
- 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.
142
+ The AI sees this *before* the diff hits your screen. It revises, splits the change, or asks. Sub-millisecond on a 7,000-file repo.
139
143
 
140
- 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.
144
+ ### Packing context that actually fits
141
145
 
142
- ### In the wild
146
+ You ask: *"add rate limiting to /api/users."* The AI calls `get_minimal_context_for_intent` with a 4,000-token budget. Carto runs hybrid retrieval (structural + lexical + semantic), fuses the channels with RRF, boosts files in the same domain and recent churn, and returns the smallest file set that covers the intent — usually 6–12 files instead of the usual 40+.
143
147
 
144
- ![Claude Code reviewing the supabase repo through carto's MCP server](docs/screenshots/claude-code-supabase.png)
145
-
146
- *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."*
148
+ ### Remembering decisions across sessions
147
149
 
148
- ---
150
+ Every `validate_diff` call writes a row into `.carto/carto.db`. Five hours later, a different chat asks `did_we_discuss_this("snake_case naming")` and gets back the prior decision verbatim. Your AI stops re-deciding settled questions.
149
151
 
150
- ## Languages and frameworks
152
+ ### Spotting the bug before the bug
151
153
 
152
- ### Import graph + symbols (any repo)
153
-
154
- | Language | Extensions |
155
- |----------|-----------|
156
- | JavaScript / TypeScript | `.js` `.jsx` `.ts` `.tsx` `.mjs` `.cjs` |
157
- | Python | `.py` |
158
- | Go | `.go` |
159
- | Rust | `.rs` |
160
- | Java | `.java` |
161
- | C / C++ | `.cpp` `.cc` `.cxx` `.h` `.hpp` |
162
- | C# | `.cs` |
163
- | Ruby | `.rb` |
164
- | R | `.r` `.R` |
165
- | Prisma schema | `.prisma` |
166
- | HTML | `.html` (for `fetch()` discovery) |
167
-
168
- ### Route extraction (framework-aware)
169
-
170
- | Framework | Language |
171
- |-----------|---------|
172
- | Express, Next.js (App + Pages), tRPC, React Router | TypeScript / JavaScript |
173
- | FastAPI, Flask, Django | Python |
174
- | Gin, Echo, Chi, net/http | Go |
175
- | Actix-web, Axum, Rocket | Rust |
176
- | Spring MVC / Boot, JAX-RS | Java |
177
- | ASP.NET Core | C# |
178
- | Rails, Sinatra | Ruby |
179
-
180
- ### Model extraction
181
-
182
- | ORM / Schema | Language |
183
- |-------------|---------|
184
- | Prisma, Zod, Drizzle, TypeScript interfaces | TypeScript / JavaScript |
185
- | Pydantic, SQLAlchemy | Python |
186
- | Go structs | Go |
187
- | Rust structs | Rust |
188
- | JPA `@Entity`, Java records | Java |
189
- | EF Core, C# records | C# |
190
- | ActiveRecord | Ruby |
191
-
192
- ### TypeScript path aliases
193
-
194
- 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.
154
+ `get_predictive_risk` returns a 0–1 score per file: P(this file causes the next incident). It combines blast radius, commit churn, cross-domain coupling, prior intervention history, and test coverage. High-risk files surface in `carto check` and on every PR.
195
155
 
196
156
  ---
197
157
 
198
- ## ACP Agent (Zed / JetBrains / VS Code)
199
-
200
- Beyond MCP, Carto runs as a full **ACP agent** — an active coding agent with built-in architectural awareness.
201
-
202
- ```
203
- User: "Add rate limiting to /api/users"
204
-
205
- Carto auto-queries its own SQLite:
206
- - Blast radius of relevant files
207
- - Domain context (AUTH)
208
- - Similar patterns in codebase
209
-
210
- Builds rich prompt with structural context
211
-
212
- Sends to LLM (your API key) → streams answer + diffs back to editor
213
- ```
214
-
215
- ### Setup in Zed
158
+ ## In the wild
216
159
 
217
- `~/.config/zed/settings.json`:
218
- ```json
219
- {
220
- "agent_servers": {
221
- "Carto": { "command": "carto", "args": ["agent"] }
222
- }
223
- }
224
- ```
225
-
226
- ### Bring Your Own Key
227
-
228
- Carto supports any LLM provider — configure in your editor:
160
+ ![Claude Code reviewing the supabase repo through carto's MCP server](docs/screenshots/claude-code-supabase.png)
229
161
 
230
- | Provider | Models |
231
- |----------|--------|
232
- | Anthropic | Claude Sonnet 4, Haiku |
233
- | OpenAI | GPT-4o, GPT-4o-mini, o1, o3 |
234
- | Google Gemini | Gemini 2.5 Pro, 2.5 Flash |
235
- | Ollama | Any local model (free) |
236
- | OpenRouter | Any model via single API |
237
- | Groq | Ultra-fast inference |
238
- | Together AI | Open-source models |
239
- | Azure OpenAI | Enterprise deployments |
162
+ 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.
240
163
 
241
164
  ---
242
165
 
243
- ## GitHub Action — PR impact reports
244
-
245
- Drop carto onto every PR your repo gets. Posts a sticky comment on each pull request with the diff's blast radius, cross-domain violations, affected routes, and a risk badge.
166
+ ## How fast
246
167
 
247
- `.github/workflows/carto.yml`:
248
- ```yaml
249
- name: Carto Impact Report
250
-
251
- on:
252
- pull_request:
253
- branches: [main]
254
-
255
- permissions:
256
- contents: read
257
- pull-requests: write
258
-
259
- jobs:
260
- carto:
261
- runs-on: ubuntu-latest
262
- steps:
263
- - uses: actions/checkout@v4
264
- with: { fetch-depth: 0 }
265
- - uses: theanshsonkar/carto@v2.0.9
266
- ```
168
+ Measured on real open-source repos, fresh runs on Apple M-series, 8 CPUs, 8 GB RAM.
267
169
 
268
- That's the whole config. The action handles `npm install`, builds (or restores from cache) the `.carto/` index, runs `carto pr-impact`, and posts the comment via `GITHUB_TOKEN`.
170
+ | Repo | Files | First index | Re-index | DB size |
171
+ |---|--:|--:|--:|--:|
172
+ | [cal.com](https://github.com/calcom/cal.com) | 4,352 | 3.9s | 805ms | 3.1 MB |
173
+ | [supabase/supabase](https://github.com/supabase/supabase) | 6,358 | 5.9s | 967ms | 4.8 MB |
174
+ | [vercel/next.js](https://github.com/vercel/next.js) | 6,193 | 6.9s | 978ms | 15.1 MB |
175
+ | [microsoft/vscode](https://github.com/microsoft/vscode) | 7,567 | 8.6s | 1.1s | 14.3 MB |
269
176
 
270
- ### Inputs
177
+ **Query latency** on vscode (7,567 files):
271
178
 
272
- | Input | Default | What it does |
273
- |-------|---------|--------------|
274
- | `carto-version` | `latest` | The `carto-md` npm version to install. Pin in production for reproducibility. |
275
- | `base` | auto (`origin/$GITHUB_BASE_REF`) | Git ref the PR branched from. |
276
- | `head` | auto (`$GITHUB_SHA`) | Git ref of the PR head. |
277
- | `fail-on` | _(empty)_ | Fail the workflow when risk meets/exceeds this severity. One of `HIGH`, `MEDIUM`, `LOW`. Empty = comment-only. |
278
- | `comment-mode` | `sticky` | `sticky` updates the existing carto comment in place. `new` posts a new comment every push. `none` skips posting (renders to stdout). |
279
- | `node-version` | `20` | Node.js version on the runner. |
179
+ - `validate_diff` p50 **84 µs**, p99 **489 µs** (budget was 5 ms / 15 ms)
180
+ - `get_blast_radius` — p50 **2.7 µs**, **10.7×** faster than the SQLite path
181
+ - `get_high_impact_files` p50 **750 ns**, **559×** faster
182
+ - `simulate_change_impact` p50 **19.3 µs**, multi-file blast radius via bitmap OR-aggregation
280
183
 
281
- ### Outputs
184
+ Bitmap-backed reverse dependency graph. Median speedup across five core tools on vscode: **10.7×**. Synthetic stress at 50K files holds `blast_radius` p50 at **22 µs**. Full table in [`docs/scale.md`](docs/scale.md). Reproducible via `npm run bench:bitmap -- --repo <path>`.
282
185
 
283
- | Output | Description |
284
- |--------|-------------|
285
- | `risk` | Rolled-up risk: `SAFE` \| `LOW` \| `MEDIUM` \| `HIGH`. Lets downstream steps gate behavior on Carto's verdict. |
286
- | `comment-url` | URL of the posted/updated PR comment. |
287
-
288
- ### What the comment looks like
289
-
290
- ```markdown
291
- ## 🗺️ Carto Impact Report
186
+ ---
292
187
 
293
- This PR touches AUTH and DATABASE domains.
188
+ ## Tools your AI can call
294
189
 
295
- | Metric | Value |
296
- |--------|-------|
297
- | Risk | 🔴 HIGH |
298
- | Blast radius (union) | 23 files |
299
- | Files changed | 6 |
300
- | Cross-domain violations introduced | 2 |
301
- | High-impact file changed | src/auth/session.ts (8 direct dependents) |
190
+ About 75 tools, grouped by what they're for:
302
191
 
303
- <details>
304
- <summary>Affected routes (4)</summary>
192
+ | Group | Tools |
193
+ |---|---|
194
+ | **Structure** | `get_change_plan` · `get_blast_radius` · `simulate_change_impact` · `validate_diff` · `get_context` · `get_routes` · `get_models` · `get_cross_domain` · `get_high_impact_files` |
195
+ | **Episodic memory** | `did_we_discuss_this` · `get_decision_log` · `get_session_context` · `get_pending_decisions` · `get_intervention_history` |
196
+ | **Temporal** | `get_architectural_drift` · `get_domain_evolution` · `get_hotspot_files` · `get_arch_events` · `get_temporal_context` · `get_change_velocity` · `get_complexity_trend` |
197
+ | **Brain** | `get_invariants` · `get_conventions` · `get_canonical_pattern` · `get_action_patterns` · `get_working_memory` · `get_active_suggestions` · `scaffold_for_intent` |
198
+ | **Predictive** | `get_predictive_risk` · `get_safety_checklist` · `get_drift_digest` · `get_test_coverage_map` |
199
+ | **Retrieval** | `get_minimal_context_for_intent` · `get_progressive_disclosure_tree` |
200
+ | **Org / multi-repo** | `get_org_architecture` · `get_service_dependency_graph` · `get_cross_repo_blast_radius` · `find_consumers_of_api` · `get_service_boundary_violations` |
201
+ | **Adjacent** | `get_cross_language_call_graph` · `get_iac_resources` · `ingest_otlp_traces` · `get_risk_weighted_blast_radius` · `get_dead_code_with_confidence` · `get_semantic_diff` |
305
202
 
306
- - POST /auth/loginrisk: HIGH
307
- - GET /auth/me — risk: HIGH
308
- - POST /auth/register — risk: MEDIUM
309
- - POST /api/users — risk: LOW
203
+ Full reference at [`docs/api/`](docs/api/). You don't need to memorize any of these your AI picks the right one mid-task.
310
204
 
311
- </details>
312
-
313
- <details>
314
- <summary>Cross-domain violations (2)</summary>
315
-
316
- - auth/login.ts now imports from payments/billing.ts (AUTH→PAYMENTS)
317
- - database/user-repo.ts now imports from auth/jwt.ts (DATABASE→AUTH)
318
-
319
- </details>
320
- ```
205
+ ---
321
206
 
322
- ### Standalone CLI use
207
+ ## Multi-repo
323
208
 
324
- The action is a thin wrapper around `carto pr-impact`. Use it locally, in custom CI, or in pre-commit hooks:
209
+ Register a group of repos under one org. Carto builds a service graph across them — npm, pypi, go-mod, maven edges all resolved.
325
210
 
326
211
  ```bash
327
- carto pr-impact --base origin/main --head HEAD # markdown to stdout
328
- carto pr-impact --base origin/main --head HEAD --format json
329
- carto pr-impact --base origin/main --head HEAD --fail-on HIGH # exit 2 on HIGH risk
212
+ carto org init
213
+ carto org add ../service-a ../service-b ../service-c
214
+ carto org sync
330
215
  ```
331
216
 
332
- ---
333
-
334
- ## ANCI — the open spec for codebases describing themselves to AI
217
+ Then ask: *"if I rename `User.email` in service-a, who notices?"* — one `get_cross_repo_blast_radius` call away.
335
218
 
336
- Every AI coding tool today re-discovers a codebase's architecture from scratch on every session. Cursor builds its own embedding index. Cline builds its own. Continue builds its own. Same parsing, every tool, every session.
219
+ ---
337
220
 
338
- **ANCI** (Architecturally Normalized Code Index) is the file format that fixes this. Two files at `.carto/anci.{yaml,bin}` that describe the codebase's architecture in a form any AI tool can read without indexing it itself. OpenAPI did this for REST APIs. ANCI does it for codebases.
221
+ ## MCP middleware
339
222
 
340
- `carto sync` writes both files automatically. The header is grep-able YAML; the body is a compact binary import graph. Spec lives in [`docs/anci/v0.1-DRAFT.md`](docs/anci/v0.1-DRAFT.md). Carto is the reference implementation.
223
+ Carto can sit in front of *any* MCP server and block bad writes before they reach the model:
341
224
 
342
225
  ```bash
343
- carto anci publish # re-emit anci.{yaml,bin} from the index
344
- carto anci show # human-readable summary
345
- carto anci validate ./.carto # validate a published pair
346
- ```
347
-
348
- Any tool can consume an ANCI pair without depending on Carto:
349
-
350
- ```js
351
- const { loadAnci } = require('carto-md/src/anci/consumer');
352
-
353
- const reader = loadAnci('./.carto');
354
- console.log(reader.domains); // [{ name: 'AUTH', file_count: 42 }, ...]
355
- console.log(reader.getHighImpactFiles(5)); // top 5 by transitive dependents
356
- console.log(reader.blastRadius('src/auth/session.ts'));// { count, hops, files: [...] }
357
- console.log(reader.simulateChangeImpact([ // multi-file change blast radius
358
- 'src/auth/session.ts',
359
- 'src/db/connection.ts',
360
- ]));
226
+ carto mcp-middleware --block-on HIGH -- claude-code
361
227
  ```
362
228
 
363
- > **Status:** v0.1.0-DRAFT wire format may change up to v1.0. The reference implementation lives in this repo at `src/anci/`.
229
+ Every `tools/call` that writes to disk is intercepted. Carto synthesizes a unified diff, runs `validate_diff`, and rejects HIGH-risk writes with the violation reasons surfaced back to the AI. Works with any stdio-based MCP server.
364
230
 
365
231
  ---
366
232
 
233
+ ## Languages and frameworks
367
234
 
235
+ <details>
236
+ <summary>Import graph + symbols (any repo)</summary>
368
237
 
369
- 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.
370
-
371
- | Tool | What it returns |
372
- |------|----------------|
373
- | `get_architecture()` | 500-word project overview: domains, entry points, stack, key patterns. **Use this first.** |
374
- | `get_change_plan(intent)` | Given "add rate limiting to /api/users" → files to touch, domains affected, blast radius, similar patterns |
375
- | `get_blast_radius(file)` | All files affected by changing a given file, with hop distance |
376
- | `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. |
377
- | `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. |
378
- | `get_context(file)` | Everything about a file: domain, blast radius, neighbors, routes, models |
379
- | `get_file_summary(file)` | What a file does, its role, key deps and dependents |
380
- | `get_similar_patterns(file)` | Files with same domain, route shape, or shared deps — find conventions before writing new code |
381
- | `get_routes()` | All API endpoints with file mapping |
382
- | `get_structure()` | Import graph, entry points, high-impact files, tech stack |
383
- | `get_domain(name)` | All routes, models, functions for a domain. Lazily regenerated when stale. |
384
- | `get_neighbors(file, hops)` | Import graph neighbors: nodes and edges |
385
- | `get_cross_domain()` | Import edges that cross domain boundaries |
386
- | `search_routes(query)` | Search API routes by path or method |
387
- | `get_models(domain?)` | All data models, optionally filtered by domain |
388
- | `get_high_impact_files(n)` | Top N files by blast radius |
389
- | `get_env_vars(domain?)` | All env vars with domain mapping |
390
- | `get_domains_list()` | All detected domains with file, route, model counts |
391
- | `get_recent_decisions(time_range, kind?)` | Recent validation decisions and architectural choices the AI has made in this project |
392
- | `get_session_context(session_id?)` | Full context for an AI session: every decision and intervention, ordered chronologically |
393
- | `did_we_discuss_this(topic)` | Substring search over the episodic memory log — avoid re-deciding settled questions |
394
- | `get_intervention_history(file?)` | Past Carto-issued violations and suggestions, optionally filtered by file |
395
-
396
- **Latency:** All bitmap-backed queries return in microseconds on real repos; cross-domain and `simulate_change_impact` settle under 2ms even on a 7.5K-file codebase like vscode. See [Benchmarks](#benchmarks) for the per-tool table.
397
-
398
- ## Episodic Memory
399
-
400
- 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.
401
-
402
- ---
403
-
404
- ## Domain detection
238
+ | Language | Extensions |
239
+ |---|---|
240
+ | JavaScript / TypeScript | `.js` `.jsx` `.ts` `.tsx` `.mjs` `.cjs` |
241
+ | Python | `.py` |
242
+ | Go | `.go` |
243
+ | Rust | `.rs` |
244
+ | Java / Kotlin | `.java` `.kt` |
245
+ | C / C++ | `.cpp` `.cc` `.h` `.hpp` |
246
+ | C# | `.cs` |
247
+ | Ruby | `.rb` |
248
+ | PHP | `.php` |
249
+ | Swift | `.swift` |
250
+ | Dart | `.dart` |
251
+ | R | `.r` `.R` |
252
+ | Prisma schema | `.prisma` |
253
+ | HTML | `.html` (for `fetch()` discovery) |
405
254
 
406
- 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.).
255
+ TypeScript path aliases from `tsconfig.json` / `jsconfig.json` are resolved into the import graph. `@/components/Button` lands on the real file.
407
256
 
408
- **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.
257
+ </details>
409
258
 
410
- 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.
259
+ <details>
260
+ <summary>Route + model extraction</summary>
411
261
 
412
- Custom domains via `carto.config.json`:
413
- ```json
414
- {
415
- "domains": {
416
- "EDITOR": ["editor", "monaco", "text"],
417
- "WORKBENCH": ["workbench", "layout", "panel"]
418
- }
419
- }
420
- ```
262
+ **Routes:** Express, Next.js (App + Pages), tRPC, React Router, FastAPI, Flask, Django, Gin, Echo, Chi, net/http, Actix-web, Axum, Rocket, Spring MVC, JAX-RS, ASP.NET Core, Rails, Sinatra.
421
263
 
422
- Full schema with anchor pinning (forces files into a domain regardless of clustering):
423
- ```json
424
- {
425
- "domains": {
426
- "AUTH": {
427
- "keywords": ["auth", "login", "session"],
428
- "anchor": ["src/auth/session.ts", "src/auth/middleware.ts"]
429
- }
430
- }
431
- }
432
- ```
264
+ **Models:** Prisma, Zod, Drizzle, TS interfaces, Pydantic, SQLAlchemy, Go structs, Rust structs, JPA, EF Core, ActiveRecord.
433
265
 
434
- **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.
266
+ </details>
435
267
 
436
268
  ---
437
269
 
438
- ## CLI commands
270
+ ## CLI
439
271
 
440
272
  | Command | What it does |
441
- |---------|-------------|
442
- | `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 |
443
- | `carto sync` | Full re-index (skips unchanged files via mtime+size cache). Called automatically by git hooks on commit/checkout/merge/rebase. |
444
- | `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. |
445
- | `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. |
446
- | `carto agent` | Start ACP agent mode (for Zed / JetBrains / VS Code) |
447
- | `carto impact <file>` | Blast radius: risk level, affected files, routes at risk |
448
- | `carto pr-impact` | Diff-shaped impact report between two git refs. Markdown (default) or JSON. Used by the [GitHub Action](#github-action--pr-impact-reports); works locally too. `--fail-on HIGH\|MEDIUM\|LOW` exits non-zero on threshold trip. |
449
- | `carto check` | Cross-domain violations, high-risk uncommitted changes, domain health |
450
- | `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. |
451
- | `carto remove` | Remove AGENTS.md and .carto/ from project |
273
+ |---|---|
274
+ | `carto init` | Index, generate AGENTS.md, install git hooks, wire MCP into every AI tool found |
275
+ | `carto sync` | Re-index changed files (auto-runs on commit / checkout / merge / rebase) |
276
+ | `carto serve` | Start the MCP server (your AI tool runs this) |
277
+ | `carto agent` | ACP agent mode for Zed / JetBrains |
278
+ | `carto impact <file>` | Blast radius of one file |
279
+ | `carto pr-impact` | Diff-shaped impact report between two refs |
280
+ | `carto check` | Domain health, cross-domain violations, drift |
281
+ | `carto status` | One-screen project health |
282
+ | `carto doctor` | 9-check setup diagnostic |
283
+ | `carto why <file>` | 3-line file summary |
284
+ | `carto explain <intent>` | Natural-language intent → architectural plan |
285
+ | `carto inspect` | Index paths, sizes, freshness (read-only) |
452
286
 
453
287
  ---
454
288
 
455
- ## Benchmarks
456
-
457
- 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`.
458
-
459
- ### Indexing speed
460
-
461
- | Repo | Language | Indexed Files | First Run | Second Run | DB Size | Import Edges |
462
- |------|----------|---------------|-----------|------------|---------|--------------|
463
- | [prisma/prisma](https://github.com/prisma/prisma) | TypeScript | 961 | **1.0s** | **350ms** | 1.1 MB | 1,387 |
464
- | [supabase/supabase](https://github.com/supabase/supabase) | TypeScript | 6,330 | **5.4s** | **1.2s** | 4.8 MB | 5,189 |
465
- | [microsoft/vscode](https://github.com/microsoft/vscode) | TypeScript | 7,567 | **8.0s** | **935ms** | 14.3 MB | 13,335 |
466
- | [zed-industries/zed](https://github.com/zed-industries/zed) | Rust | 1,752 | **2.9s** | **468ms** | 4.8 MB | 2,110 |
467
-
468
- **Indexed Files** counts what Carto actually parses — `.ts/.js/.py/.go/.rs/...` after excluding `node_modules`, build output, and per-file test patterns (`*.test.*` / `*.spec.*` / `*.stories.*` for JS/TS, `test_*.py` / `*_test.py` for Python, `test_*` / `*_test.r` for R). The on-disk file count of the repo is larger.
469
-
470
- **Second Run** = `carto sync` after no changes. mtime+size checked before reading content — if nothing changed, nothing is re-parsed.
471
-
472
- ### MCP query latency (bitmap engine vs SQLite)
473
-
474
- 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.
475
-
476
- | Tool | vscode (7,567 files) | Speedup vs SQLite |
477
- |------|---------------------:|------------------:|
478
- | `get_blast_radius` | sub-ms | **10.7×** |
479
- | `get_cross_domain` | 2.1ms | **6.2×** |
480
- | `get_high_impact_files` | sub-ms | **559×** |
481
- | `get_similar_patterns` | sub-ms | **73×** |
482
- | `simulate_change_impact` | sub-ms | **6.5×** (no SQLite equivalent at this latency) |
289
+ ## ACP agent (Zed / JetBrains / VS Code)
483
290
 
484
- Median speedup across all five tools on vscode: **10.7×**. Smaller repos with denser graphs hit higher peaks supabase `get_high_impact_files` clocks well over 100× on its tighter import graph. Reproducible via `npm run bench:bitmap -- --repo <path>`.
291
+ Carto also runs as a full ACP agent not just a passive MCP server. It pulls its own context, streams tokens, applies diffs.
485
292
 
486
- ### `validate_diff` latency
487
-
488
- 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.
293
+ ```json
294
+ { "agent_servers": { "Carto": { "command": "carto", "args": ["agent"] } } }
295
+ ```
489
296
 
490
- | Repo | Files | p50 | p99 |
491
- |------|-------|----:|----:|
492
- | supabase | 6,259 | **0.082ms** | **0.298ms** |
493
- | vscode | 7,567 | **0.084ms** | **0.489ms** |
297
+ Bring your own key: Anthropic, OpenAI, Gemini, Groq, Ollama, OpenRouter, Together, Azure.
494
298
 
495
- 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>`.
299
+ ---
496
300
 
497
- ### Scale
301
+ ## GitHub Action
498
302
 
499
- Synthetic stress sweep + real-world corpus, dense-fan-out worst case all the way to 50K files. Headline numbers (full table in [`docs/scale.md`](docs/scale.md)):
303
+ Drop Carto onto every PR. Sticky comment with blast radius, cross-domain violations, affected routes, risk badge.
500
304
 
501
- - Synth 50K files: init 1.1m, `blast_radius` p50 22µs, `simulate_change_impact` p50 50µs, `high_impact_files` p50 750ns. The dense Uint32Array bitset hits 415 MB on disk and 1.35 GB peak RSS at this size — the Tier-2 Roaring upgrade per PEAK §9.6 is the next move.
502
- - Real-world (vscode, 7,567 files): `blast_radius` p50 2.7µs, `cross_domain` p50 1.23ms, `similar_patterns` p50 834ns, `simulate_change_impact` p50 19µs.
305
+ ```yaml
306
+ - uses: theanshsonkar/carto@v2.0.9
307
+ ```
503
308
 
504
- Reproducible via `npm run bench:scale -- --size <N>` (synth) and `node bench/scale-test/real-world.js --repo <path>` (any local clone, including Linux kernel or Chromium).
309
+ `fail-on: HIGH | MEDIUM | LOW` gates the workflow on Carto's verdict. Full config in [`docs/guides/ci-integration.md`](docs/guides/ci-integration.md).
505
310
 
506
- ### Domains detected
311
+ ---
507
312
 
508
- | Repo | Domains |
509
- |------|---------|
510
- | prisma | CORE · DATABASE · AUTH · EVENTS |
511
- | supabase | CORE · AUTH · DATABASE · PAYMENTS · NOTIFICATIONS · EVENTS · TRPC |
512
- | vscode | EXTENSIONS · AUTH · EVENTS · DATABASE · EXTENSION · CLI · CORE |
513
- | zed (Rust) | CORE · DATABASE · AUTH · EVENTS · PAYMENTS · TRPC · NOTIFICATIONS |
313
+ ## ANCI the open format for codebases describing themselves to AI
514
314
 
515
- vscode at 7,567 indexed files in around 8 seconds. Rust import graph working on zed (2,110 edges from `mod` declarations and `use crate::` paths).
315
+ Every AI tool today re-indexes from scratch on every session. Cursor builds its own. Cline builds its own. Continue builds its own. Same parsing, every tool, every time.
516
316
 
517
- ### Accuracy
317
+ **ANCI** (Architecturally Normalized Code Index) fixes that. Two files at `.carto/anci.{yaml,bin}` that describe a codebase's architecture in a form any AI tool can read without doing its own indexing. OpenAPI did this for REST APIs. ANCI does it for codebases.
518
318
 
519
- 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.
319
+ `carto sync` writes both files automatically. Spec at [`docs/anci/v0.1-DRAFT.md`](docs/anci/v0.1-DRAFT.md). Carto is the reference implementation; any tool can consume an ANCI pair:
520
320
 
521
- ---
522
-
523
- ## How it works
321
+ ```js
322
+ const { loadAnci } = require('carto-md/src/anci/consumer');
323
+ const reader = loadAnci('./.carto');
524
324
 
325
+ reader.domains; // [{ name: 'AUTH', file_count: 42 }, ...]
326
+ reader.getHighImpactFiles(5); // top 5 by transitive dependents
327
+ reader.blastRadius('src/auth/session.ts'); // { count, hops, files: [...] }
525
328
  ```
526
- carto init
527
-
528
- Discovers all files (no cap — SQLite handles the volume)
529
- mtime+size check → skip unchanged files
530
- tree-sitter parse → imports + symbols (0.05–0.2ms/file)
531
- Babel deep parse → routes + models (API handler files only)
532
- Leiden+CPM graph clustering → auto-detects domains
533
- Computes reverse deps → blast radius for every file
534
- Writes AGENTS.md + .carto/context/*.md (lazy, on-demand)
535
- Auto-wires MCP into every AI tool found
536
- Installs 4 git hooks: pre-commit, post-checkout, post-merge, post-rewrite
537
-
538
- [no daemon, no watcher, no background process]
539
-
540
- ─── Freshness mechanism 1: git hooks (90% of cases) ───
541
- You commit / pull / switch branches / rebase
542
- → hook runs `carto sync` quietly in <1s
543
- → only changed files re-parsed
544
-
545
- ─── Freshness mechanism 2: lazy mtime check (the gap) ───
546
- You edit files between commits, AI asks "blast radius of db.ts?"
547
- → MCP server stats db.ts (mtime+size vs DB row)
548
- → if stale, re-parses just that file inline (<50ms)
549
- → returns fresh answer
550
-
551
- ─── Optional: carto watch (AI-heavy workflows only) ───
552
- File saved → debounce 50ms → re-parse 1 file → SQLite write → <50ms
553
- ```
329
+
330
+ > Status: v0.1.0-DRAFT — wire format may change up to v1.0.
554
331
 
555
332
  ---
556
333
 
557
334
  ## What Carto never does
558
335
 
559
- - **Sends your code anywhere.** Local only. SQLite on disk.
336
+ - **Sends your code anywhere.** Local only. SQLite on disk. No telemetry.
560
337
  - **Writes secrets into AGENTS.md.** `.cartoignore` blocks `.env` and credential files by default.
561
- - **Touches your manual notes.** Writes only between `<!-- CARTO:AUTO:START -->` and `<!-- CARTO:AUTO:END -->`.
562
- - **Forces you to install a C++ toolchain.** Prebuilt native binaries ship for macOS arm64, Linux x64 (glibc + musl/Alpine), and Windows x64. Intel Macs and other platforms transparently fall back to building from source, then to regex-only extraction if that fails.
563
- - **Costs money.** MIT license. Free forever.
338
+ - **Touches your manual notes.** Only writes between `<!-- CARTO:AUTO -->` markers.
339
+ - **Forces you to install a C++ toolchain.** Prebuilt binaries for macOS arm64, Linux x64 (glibc + musl), Windows x64. Other platforms fall back to source build, then regex-only extraction.
340
+ - **Costs money.** MIT. Free forever.
564
341
 
565
342
  ---
566
343
 
@@ -568,9 +345,9 @@ File saved → debounce 50ms → re-parse 1 file → SQLite write → <50ms
568
345
 
569
346
  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.
570
347
 
571
- 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.
348
+ The AI inside Emfirge kept hallucinating about resources it had only half-seen. So I wrote a module called `cartography.py` that mapped every account into a structured graph the AI could query directly. The hallucinations stopped. The AI worked with facts.
572
349
 
573
- Carto is the same idea, applied to source code. Same insight: AI agents stop guessing once they can query the architecture.
350
+ Carto is that idea, applied to source code. Same insight: agents stop guessing once they can query the architecture — and they stop forgetting once the architecture remembers them.
574
351
 
575
352
  ---
576
353
 
@@ -580,4 +357,4 @@ MIT. Free forever.
580
357
 
581
358
  ---
582
359
 
583
- *Your code changes. Carto knows. Every AI you use knows.*
360
+ *Your code changes. Carto knows. Every AI you use knows — and remembers.*