sverklo 0.18.1 β†’ 0.19.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 (41) hide show
  1. package/README.md +149 -29
  2. package/dist/bin/sverklo.js +44 -0
  3. package/dist/bin/sverklo.js.map +1 -1
  4. package/dist/src/indexer/grammars-install.js +5 -0
  5. package/dist/src/indexer/grammars-install.js.map +1 -1
  6. package/dist/src/indexer/parser-tree-sitter.js +29 -0
  7. package/dist/src/indexer/parser-tree-sitter.js.map +1 -1
  8. package/dist/src/indexer/parser.js +84 -0
  9. package/dist/src/indexer/parser.js.map +1 -1
  10. package/dist/src/server/audit-analysis.js +15 -1
  11. package/dist/src/server/audit-analysis.js.map +1 -1
  12. package/dist/src/server/mcp-server.js +8 -2
  13. package/dist/src/server/mcp-server.js.map +1 -1
  14. package/dist/src/server/tools/ask.js +8 -1
  15. package/dist/src/server/tools/ask.js.map +1 -1
  16. package/dist/src/server/tools/audit.js +20 -16
  17. package/dist/src/server/tools/audit.js.map +1 -1
  18. package/dist/src/server/tools/dependencies.js +6 -0
  19. package/dist/src/server/tools/dependencies.js.map +1 -1
  20. package/dist/src/server/tools/diff-search.js +8 -3
  21. package/dist/src/server/tools/diff-search.js.map +1 -1
  22. package/dist/src/server/tools/forget.js +3 -0
  23. package/dist/src/server/tools/forget.js.map +1 -1
  24. package/dist/src/server/tools/impact.js +5 -1
  25. package/dist/src/server/tools/impact.js.map +1 -1
  26. package/dist/src/server/tools/patterns.js +6 -5
  27. package/dist/src/server/tools/patterns.js.map +1 -1
  28. package/dist/src/server/tools/pin.js +12 -0
  29. package/dist/src/server/tools/pin.js.map +1 -1
  30. package/dist/src/server/tools/recall.js +7 -0
  31. package/dist/src/server/tools/recall.js.map +1 -1
  32. package/dist/src/server/tools/review-diff.js +17 -10
  33. package/dist/src/server/tools/review-diff.js.map +1 -1
  34. package/dist/src/server/tools/tier.js +3 -0
  35. package/dist/src/server/tools/tier.js.map +1 -1
  36. package/dist/src/storage/pattern-store.d.ts +2 -0
  37. package/dist/src/storage/pattern-store.js +7 -0
  38. package/dist/src/storage/pattern-store.js.map +1 -1
  39. package/dist/src/types/index.js +1 -0
  40. package/dist/src/types/index.js.map +1 -1
  41. package/package.json +1 -1
package/README.md CHANGED
@@ -2,16 +2,30 @@
2
2
  <img src="./docs/logo.svg" alt="sverklo" width="280" height="79"/>
3
3
  </p>
4
4
 
5
- > **The only code-intel MCP with a published benchmark and reproducible eval harness.**
6
- > Local-first MCP server that gives Claude Code, Cursor, Windsurf, and Zed a real symbol graph, a blast-radius lens, and a git-pinned memory β€” so the agent stops guessing. MIT. Zero config. Your code never leaves the machine.
5
+ <p align="left">
6
+ πŸ‡¬πŸ‡§ <b>English</b> Β· πŸ‡¨πŸ‡³ <a href="./README-zh-CN.md">δΈ­ζ–‡</a>
7
+ </p>
8
+
9
+ > *"The map is not the territory."* β€” Alfred Korzybski
7
10
  >
8
- > [Paper (Zenodo, CC BY 4.0)](https://doi.org/10.5281/zenodo.19802051) Β· [bench:primitives](./benchmark/) β€” sverklo cuts agent context by **65 % vs grep** (255 vs 731 tokens per task, n=60) Β· [bench:swe](https://sverklo.com/blog/bench-swe-first-results/) β€” 38/65 perfect recall on 5 OSS repos, including the runs we lose.
11
+ > Training data is the map. Your codebase is the territory. **Sverklo gives the agent the territory.**
12
+
13
+ **The only code-intel MCP with a published benchmark and reproducible eval harness.** Local-first MCP server that gives Claude Code, Cursor, Windsurf, and Zed a real symbol graph, a blast-radius lens, and a git-pinned memory β€” so the agent stops guessing. MIT. Zero config. Your code never leaves the machine.
14
+
15
+ [Paper (Zenodo, CC BY 4.0)](https://doi.org/10.5281/zenodo.19802051) Β· [bench:primitives](https://sverklo.com/bench/) β€” **62Γ— fewer tokens than naive grep**, 2.9Γ— fewer than tuned grep, single tool call vs grep's 7-12 (n=60) Β· [bench:swe](https://sverklo.com/blog/bench-swe-first-results/) β€” 38/65 perfect recall on 5 OSS repos, including the runs we lose.
16
+
17
+ ### One-click install
18
+
19
+ [![Install in Claude Code](https://img.shields.io/badge/Claude_Code-Install_Plugin-CC785C?style=for-the-badge&logoColor=white)](#claude-code) [![Install in Cursor](https://img.shields.io/badge/Cursor-Install_MCP-F14C28?style=for-the-badge&logo=cursor&logoColor=white)](cursor://anysphere.cursor-deeplink/mcp/install?name=sverklo&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsInN2ZXJrbG8iXX0=) [![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_MCP-0098FF?style=for-the-badge&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=sverklo&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22sverklo%22%5D%7D) [![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install_MCP-24bfa5?style=for-the-badge&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=sverklo&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22sverklo%22%5D%7D&quality=insiders) [![Install in Windsurf](https://img.shields.io/badge/Windsurf-sverklo_init-09B6A2?style=for-the-badge&logoColor=white)](#windsurf--zed--vs-code--jetbrains)
9
20
 
10
21
  [![npm version](https://img.shields.io/npm/v/sverklo.svg?color=E85A2A)](https://www.npmjs.com/package/sverklo)
11
22
  [![npm downloads](https://img.shields.io/npm/dw/sverklo.svg?color=E85A2A)](https://www.npmjs.com/package/sverklo)
12
23
  [![License: MIT](https://img.shields.io/badge/license-MIT-E85A2A.svg)](LICENSE)
13
24
  [![Audited repos](https://img.shields.io/badge/audited_repos-47-E85A2A)](https://sverklo.com/report)
14
25
  [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.19802051.svg)](https://doi.org/10.5281/zenodo.19802051)
26
+ [![GitHub stars](https://img.shields.io/github/stars/sverklo/sverklo?style=social)](https://github.com/sverklo/sverklo/stargazers)
27
+
28
+ > ⭐ **If sverklo saved your AI from hallucinating, please star this repo** β€” it's the single most useful thing you can do to help others find it. Then [share with one teammate](https://twitter.com/intent/tweet?text=Local-first%20MCP%20code%20intelligence%20for%20AI%20coding%20agents%20%E2%80%94%20MIT%2C%20zero-deps%2C%20honest%20benchmark%20%40%20https%3A%2F%2Fsverklo.com%2Fbench%2F) who's tired of `getUserByEmail()` not existing in their codebase.
15
29
 
16
30
  ![Sverklo cuts agent context by 65 % vs grep β€” bench:primitives, 60 retrieval tasks, peer-reviewable](./docs/hero-token-comparison.png)
17
31
 
@@ -26,7 +40,7 @@ Sverklo drills into your repo before the agent does β€” symbol graph, blast radi
26
40
  <table>
27
41
  <tr>
28
42
  <td align="center"><b>37</b><br/>MCP tools your agent uses</td>
29
- <td align="center"><b>&lt; 2 s</b><br/>to index a 1,700-file monorepo</td>
43
+ <td align="center"><b>&lt; 1 s</b><br/>incremental refresh after each edit</td>
30
44
  <td align="center"><b>0 bytes</b><br/>of your code leave the machine</td>
31
45
  </tr>
32
46
  </table>
@@ -44,6 +58,30 @@ That's it. `sverklo init` auto-detects your installed AI coding agent (Claude Co
44
58
 
45
59
  ---
46
60
 
61
+ ## "But isn't this just…?"
62
+
63
+ Likely you've seen tools that look adjacent. The honest one-paragraph answers, with detailed comparisons linked.
64
+
65
+ **…just grep with extra steps?** No, but tuned grep is genuinely competitive on F1. On the [60-task bench](https://sverklo.com/bench/) a tuned grep beats sverklo on F1 by 9 points. Sverklo wins by 62Γ— on input tokens and 7-12Γ— on tool-call count. For an AI agent inside a 200K context window, that's the load-bearing axis. For a human at a terminal, smart grep is fine.
66
+
67
+ **…just Sourcegraph Cody?** Same retrieval surface (hybrid BM25 + vector + graph), different deployment model and license. Cody is source-available with enterprise per-developer pricing ($9-19/dev/mo); sverklo is MIT and runs on a laptop with no signup. [Full comparison β†’](https://sverklo.com/vs/sourcegraph-cody/)
68
+
69
+ **…just Greptile?** Greptile is a hosted PR-review bot ($30/dev/mo). Sverklo is local-first MCP. Same risk-scoring goal, opposite deployment model. If your code can't leave the machine for compliance reasons, Greptile isn't an option. [Full comparison β†’](https://sverklo.com/vs/greptile/)
70
+
71
+ **…just Cursor's @codebase?** Cursor's indexing is cloud-based and editor-bound. Sverklo runs alongside Cursor as an MCP server, adding the symbol graph, blast-radius, and bi-temporal memory that Cursor's @codebase doesn't expose. [Full comparison β†’](https://sverklo.com/vs/cursor-codebase/)
72
+
73
+ **…just Claude Context (Zilliz)?** Claude Context requires a Milvus database. Sverklo runs entirely on embedded SQLite β€” no extra services to manage. [Full comparison β†’](https://sverklo.com/vs/claude-context/)
74
+
75
+ **…just Aider's repo-map?** Aider's repo-map is a static signal in the system prompt β€” fine for small repos, doesn't scale past ~100 files. Sverklo is the queryable retrieval layer Aider can call via MCP for larger codebases. They're complementary, not competing. [Full comparison β†’](https://sverklo.com/vs/aider/)
76
+
77
+ **…a niche memory MCP?** Most memory MCPs are wrappers around an external vector DB. Sverklo's memory is bi-temporal (`valid_from_sha`, `valid_until_sha`, `superseded_by`) and pinned to git SHAs, so you can ask "what did this team believe about auth at commit `abc123`?" and get the answer that was true *then*. [Full comparison vs codebase-memory-mcp β†’](https://sverklo.com/vs/codebase-memory-mcp/)
78
+
79
+ **…what about Aider, Continue, Codex CLI, Claude Code?** Those are *agents* β€” they generate and apply edits. Sverklo is the *retrieval layer* the agent calls before writing code. Use both. [`sverklo init` auto-detects which agents you have β†’](#works-with-every-mcp-editor)
80
+
81
+ If something is missing here that you'd ask about, [open an issue](https://github.com/sverklo/sverklo/issues) β€” I'll add it.
82
+
83
+ ---
84
+
47
85
  ## What's new in 0.18
48
86
 
49
87
  - **Vue.js (.vue) support.** Single-file components are now first-class: the `<script>` block parses through the existing TS/JS pipeline (with line remapping back to the SFC), Composition API helpers (`ref`, `computed`, `reactive`, `defineProps`, …) are indexed as symbols, and PascalCase template tags emit relative imports so PageRank sees component graphs. Also fixes a preexisting TS bug where `import type { X } from 'y'` was missed.
@@ -108,10 +146,16 @@ If the answer to your question is "exact string X exists somewhere," grep wins.
108
146
  | Tool | What |
109
147
  |------|------|
110
148
  | `sverklo_search` | Hybrid BM25 + ONNX vector + PageRank, fused with Reciprocal Rank Fusion |
149
+ | `sverklo_search_iterative` | Wider candidate pool with refinement hints between rounds |
150
+ | `sverklo_investigate` | Parallel multi-channel fan-out (FTS / vector / path / symbol) with per-channel RRF |
151
+ | `sverklo_ask` | Natural-language router β€” concepts + investigate + refs in one call |
111
152
  | `sverklo_overview` | Structural codebase map ranked by PageRank importance |
112
153
  | `sverklo_lookup` | Find any function, class, or type by name (typo-tolerant) |
113
154
  | `sverklo_context` | One-call onboarding β€” combines overview, code, and saved memories |
114
155
  | `sverklo_ast_grep` | Structural pattern matching across the AST, not just text |
156
+ | `sverklo_concepts` | Browse the LLM-derived concept index (themes across the codebase) |
157
+ | `sverklo_clusters` | Semantic clusters of related symbols, computed offline |
158
+ | `sverklo_patterns` | Query symbols tagged with a design pattern (observer, repository, validator, ...) |
115
159
 
116
160
  ### Impact β€” refactor without the regression
117
161
  | Tool | What |
@@ -119,14 +163,16 @@ If the answer to your question is "exact string X exists somewhere," grep wins.
119
163
  | `sverklo_impact` | Walk the symbol graph, return ranked transitive callers (the real blast radius) |
120
164
  | `sverklo_refs` | Find all references to a symbol, with caller context |
121
165
  | `sverklo_deps` | File dependency graph β€” both directions, importers and imports |
122
- | `sverklo_audit` | Surface god nodes, hub files, dead code candidates in one call |
166
+ | `sverklo_audit` | **Lint your codebase for AI-readiness.** God nodes, hub files, dead code, circular deps, security smells, A-F health grade β€” all in one call |
123
167
 
124
168
  ### Review β€” diff-aware MR review with risk scoring
125
169
  | Tool | What |
126
170
  |------|------|
127
171
  | `sverklo_review_diff` | Risk-scored review of `git diff` β€” touched-symbol importance x coverage x churn |
172
+ | `sverklo_critique` | Second-pass critique of a review β€” what did the first read miss |
128
173
  | `sverklo_test_map` | Which tests cover which changed symbols; flag untested production changes |
129
174
  | `sverklo_diff_search` | Semantic search restricted to the changed surface of a diff |
175
+ | `sverklo_verify` | Verify a quoted code span is still present at the cited SHA β€” citation gate |
130
176
 
131
177
  ### Memory β€” bi-temporal, git-aware, never stale
132
178
  | Tool | What |
@@ -135,13 +181,24 @@ If the answer to your question is "exact string X exists somewhere," grep wins.
135
181
  | `sverklo_recall` | Semantic search over saved memories with staleness detection |
136
182
  | `sverklo_memories` | List all memories with health metrics (still valid / stale / orphaned) |
137
183
  | `sverklo_forget` | Delete a memory |
138
- | `sverklo_promote` / `sverklo_demote` | Move memories between tiers (project / global / archived) |
184
+ | `sverklo_promote` / `sverklo_demote` | Move memories between tiers (core / archive) |
185
+ | `sverklo_pin` / `sverklo_unpin` | Pin a memory to a file path or symbol so recall surfaces it without semantic search |
186
+
187
+ ### Post-filter primitives β€” refine the last response without re-querying
188
+ | Tool | What |
189
+ |------|------|
190
+ | `sverklo_grep_results` | Grep inside the previous result block instead of re-running the search |
191
+ | `sverklo_head_results` | Take the first N hits from the previous response |
192
+ | `sverklo_ctx_peek` | Peek at a referenced span by its handle without expanding it fully |
193
+ | `sverklo_ctx_slice` | Slice a stored response by line range |
194
+ | `sverklo_ctx_grep` | Grep within a stored context window |
195
+ | `sverklo_ctx_stats` | Token-budget stats for stored response handles |
139
196
 
140
197
  ### Index health
141
198
  | Tool | What |
142
199
  |------|------|
143
200
  | `sverklo_status` | Index health check, file counts, last update |
144
- | `sverklo_wakeup` | Warm the index after a long pause; incremental refresh |
201
+ | `sverklo_wakeup` | 500-token codebase summary for system prompts on agents that can't run MCP |
145
202
 
146
203
  </details>
147
204
 
@@ -211,28 +268,57 @@ Every memory carries `valid_from_sha` and `valid_until_sha`. Updating a memory d
211
268
 
212
269
  ## How It Works
213
270
 
214
- ```mermaid
215
- graph LR
216
- A[Your Code] --> B[Parse<br/>11 languages]
217
- B --> C[Embed<br/>ONNX/Ollama]
218
- B --> D[Build Graph<br/>imports/exports]
219
- D --> E[PageRank<br/>importance]
220
-
221
- F[Agent Query] --> G[BM25]
222
- F --> H[Vector Search]
223
- E --> I[PageRank Boost]
224
- G --> J[RRF Fusion]
225
- H --> J
226
- I --> J
227
- J --> K[Token-Budgeted<br/>Response]
271
+ ```
272
+ Your codebase Agent query
273
+ β”‚ β”‚
274
+ β–Ό β–Ό
275
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
276
+ β”‚ Parse β”‚ tree-sitter (12 langs) or β”‚ Tool call β”‚
277
+ β”‚ chunks β”‚ regex fallback β”‚ (1 of 37) β”‚
278
+ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
279
+ β”‚ β”‚
280
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” Index time β”‚
281
+ β”‚ β”‚ β”‚
282
+ β–Ό β–Ό β”‚
283
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
284
+ β”‚ Embed β”‚ β”‚ Import β”‚ β”‚
285
+ β”‚ ONNX β”‚ β”‚ graph β”‚ β”‚
286
+ β”‚ MiniLM β”‚ β”‚ + PageRank β”‚
287
+ β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β”‚
288
+ β”‚ β”‚ β”‚
289
+ β–Ό β–Ό β”‚
290
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
291
+ β”‚ SQLite + sqlite-vec β”‚ ← single-file index, ~/.sverklo/ β”‚
292
+ β”‚ chunks Β· embeddings Β· β”‚ β”‚
293
+ β”‚ symbols Β· refs Β· imports β”‚ β”‚
294
+ β”‚ memories (bi-temporal) β”‚ β”‚
295
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
296
+ β”‚ β”‚
297
+ β”‚ Query time β”‚
298
+ β–Ό β–Ό
299
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
300
+ β”‚ Channelized RRF retrieval β”‚
301
+ β”‚ β”‚
302
+ β”‚ FTS Β· Vector Β· Doc-section Β· Path Β· Symbol-name β”‚
303
+ β”‚ └─ each ranked independently β”€β”˜ β”‚
304
+ β”‚ β”‚
305
+ β”‚ Fused with channel weights (path 1.5Γ—, doc 0.7Γ—, …) β”‚
306
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
307
+ β”‚
308
+ β–Ό
309
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
310
+ β”‚ Token-budgeted answer β”‚ ← the agent gets
311
+ β”‚ file:line + chunk β”‚ ranked code, not
312
+ β”‚ + provenance β”‚ a wall of text
313
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
228
314
  ```
229
315
 
230
- 1. **Parses** your codebase into functions, classes, types (TS, JS, Vue, Python, Go, Rust, Java, C, C++, Ruby, PHP)
231
- 2. **Embeds** code using all-MiniLM-L6-v2 ONNX model (384d, fully local) β€” or any Ollama model via config
232
- 3. **Builds** a dependency graph and computes PageRank (structurally important files rank higher)
233
- 4. **Searches** using hybrid BM25 + vector similarity + PageRank, fused via Reciprocal Rank Fusion
234
- 5. **Remembers** decisions and patterns across sessions, linked to git state
235
- 6. **Watches** for file changes and updates incrementally
316
+ 1. **Parse** your codebase into functions, classes, types (TS, JS, Vue, Python, Go, Rust, Java, C, C++, Ruby, PHP, C#)
317
+ 2. **Embed** code using all-MiniLM-L6-v2 ONNX (384d, fully local) β€” or any Ollama model via config
318
+ 3. **Graph** dependencies and compute PageRank (structurally important files rank higher)
319
+ 4. **Retrieve** via channelized RRF β€” per-channel rank fusion with channel-specific weights, the architectural choice that closes the private-helper-function recall gap
320
+ 5. **Remember** decisions across sessions, pinned to git SHAs (bi-temporal memory)
321
+ 6. **Watch** for file changes and re-index incrementally (~1 s per edit)
236
322
 
237
323
  ---
238
324
 
@@ -250,6 +336,18 @@ Real measurements on real codebases. Reproducible via `npm run bench` ([methodol
250
336
  - **Impact analysis is sub-millisecond** β€” indexed SQL join, not a string scan
251
337
  - **11 languages:** TS, JS, Vue, Python, Go, Rust, Java, C, C++, Ruby, PHP
252
338
 
339
+ ### Retrieval benchmark β€” bench:primitives
340
+
341
+ Hybrid retrieval F1 vs grep baselines on a 60-task hand-verified evaluation across two OSS codebases. Public report at **[sverklo.com/bench/](https://sverklo.com/bench/)** β€” including the slice where sverklo *loses* (P5 dead-code detection, F1 = 0.02).
342
+
343
+ | baseline | F1 | input tokens | tool calls |
344
+ |---|---:|---:|---:|
345
+ | naive-grep | 0.35 | 15,814 | 7.6 |
346
+ | smart-grep (tuned) | 0.67 | 731 | 11.8 |
347
+ | **sverklo** | 0.58 | **255** | **1.0** |
348
+
349
+ A tuned grep beats sverklo on F1. Sverklo wins decisively on token economy (62Γ— fewer than naive grep, 2.9Γ— fewer than tuned grep) and tool-call count, which is the load-bearing axis for AI agents with bounded context windows. Reproduce with `npm run bench:primitives`.
350
+
253
351
  ---
254
352
 
255
353
  ## Quick Start
@@ -308,9 +406,19 @@ npx sverklo /path/to/your/project
308
406
 
309
407
  ---
310
408
 
311
- ## Audit formats
409
+ ## Lint for AI-readiness β€” `sverklo audit`
410
+
411
+ Most lints check syntax. `sverklo audit` lints whether your codebase is **legible to an AI agent**: high blast-radius "god nodes" the agent will trip on, hub files that cascade widely on every change, orphan symbols that might be dead code or might be public API, circular dependencies that confuse the symbol graph, and a security smell scan. Outputs an A-F health grade you can pin as a README badge.
312
412
 
313
- `sverklo audit` generates codebase health reports in six formats: `markdown`, `html`, `json`, `sarif`, `csv`, and `badges`. Run `sverklo audit --format html --open` for a self-contained report with god nodes, hub files, orphan detection, coupling analysis, and language distribution. Use `sverklo audit --badge` to add an A-F health grade shield to your README.
413
+ ```bash
414
+ sverklo audit # markdown report in the terminal
415
+ sverklo audit --format html --open # self-contained HTML you can share
416
+ sverklo audit --badge # A-F shield markdown for your README
417
+ sverklo audit --format sarif # GitHub code-scanning alerts
418
+ sverklo audit --format json # machine-readable for CI gates
419
+ ```
420
+
421
+ Six formats: `markdown`, `html`, `json`, `sarif`, `csv`, `badges`. Pair with `sverklo_impact` (the MCP tool) when you want to see the per-symbol blast radius before refactoring.
314
422
 
315
423
  ---
316
424
 
@@ -390,6 +498,18 @@ BibTeX:
390
498
  }
391
499
  ```
392
500
 
501
+ ## Star history
502
+
503
+ <a href="https://www.star-history.com/#sverklo/sverklo&type=date&legend=top-left">
504
+ <picture>
505
+ <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=sverklo/sverklo&type=date&theme=dark&legend=top-left" />
506
+ <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=sverklo/sverklo&type=date&legend=top-left" />
507
+ <img alt="Star History Chart" src="https://api.star-history.com/svg?repos=sverklo/sverklo&type=date&legend=top-left" />
508
+ </picture>
509
+ </a>
510
+
511
+ If sverklo saved your AI from inventing function names that don't exist in your codebase, the most useful thing you can do is **⭐ star this repo** and share with one teammate.
512
+
393
513
  ## License
394
514
 
395
515
  MIT
@@ -1883,6 +1883,50 @@ if (modeResolution.mode !== "embedded") {
1883
1883
  const positionalArgs = args.filter((a) => !a.startsWith("--mode=") && !a.startsWith("--global"));
1884
1884
  const hasExplicitPath = positionalArgs.length > 0 && positionalArgs[0] !== undefined;
1885
1885
  const isGlobalFlag = args.includes("--global");
1886
+ // Bug-bash 2 finding: `sverklo search "query"` silently fell through
1887
+ // to MCP-server-start with "search" treated as a project path. The
1888
+ // server then hung on stdin waiting for MCP protocol traffic. First-
1889
+ // time users would conclude sverklo was broken. Detect that case
1890
+ // up-front and emit a friendly error.
1891
+ const MCP_TOOL_VERBS = new Set([
1892
+ "search", "lookup", "refs", "find-references", "impact", "deps", "dependencies",
1893
+ "overview", "context", "ask", "recall", "remember", "forget", "promote", "demote",
1894
+ "memories", "ast-grep", "ast_grep", "review-diff", "review_diff", "test-map", "test_map",
1895
+ "diff-search", "diff_search", "status", "pin", "unpin", "clusters", "concepts",
1896
+ "patterns", "critique", "verify", "investigate", "search-iterative", "search_iterative",
1897
+ "grep-results", "grep_results", "head-results", "head_results",
1898
+ "ctx-peek", "ctx_peek", "ctx-slice", "ctx_slice", "ctx-grep", "ctx_grep",
1899
+ "ctx-stats", "ctx_stats",
1900
+ ]);
1901
+ if (hasExplicitPath) {
1902
+ const candidate = positionalArgs[0];
1903
+ if (MCP_TOOL_VERBS.has(candidate.toLowerCase())) {
1904
+ process.stderr.write(`Error: \`sverklo ${candidate}\` is an MCP tool, not a CLI command.\n\n`);
1905
+ process.stderr.write(`MCP tools are called by AI agents (Claude Code, Cursor, Windsurf, Zed) β€”\n`);
1906
+ process.stderr.write(`not from the command line. To use them:\n\n`);
1907
+ process.stderr.write(` 1. cd to your project\n`);
1908
+ process.stderr.write(` 2. sverklo init # set up MCP integration\n`);
1909
+ process.stderr.write(` 3. claude # ask in natural language\n\n`);
1910
+ process.stderr.write(`If you wanted to start the MCP server directly (e.g. for a custom\n`);
1911
+ process.stderr.write(`client), run \`sverklo\` with no args from the project root.\n\n`);
1912
+ process.stderr.write(`For CLI commands (init, audit, doctor, ui, …) run \`sverklo --help\`.\n`);
1913
+ process.exit(2);
1914
+ }
1915
+ // Validate the path actually exists, otherwise the user typo'd a
1916
+ // command verb and starting an MCP server on a non-existent dir
1917
+ // would silently hang on stdin like the case above.
1918
+ const { statSync: _stat } = await import("node:fs");
1919
+ try {
1920
+ if (!_stat(resolve(candidate)).isDirectory())
1921
+ throw new Error("not a directory");
1922
+ }
1923
+ catch {
1924
+ process.stderr.write(`Error: \`${candidate}\` is not a valid project path or known command.\n\n`);
1925
+ process.stderr.write(`Run \`sverklo --help\` to see available commands, or \`sverklo init\`\n`);
1926
+ process.stderr.write(`from a project directory to set up MCP integration.\n`);
1927
+ process.exit(2);
1928
+ }
1929
+ }
1886
1930
  // Auto-download model if missing (no separate setup step needed)
1887
1931
  const { existsSync } = await import("node:fs");
1888
1932
  const { join } = await import("node:path");