brainbank 0.5.0 → 0.7.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 (46) hide show
  1. package/README.md +233 -126
  2. package/dist/{base-DZWtdgIf.d.ts → base-3SNc_CeY.d.ts} +24 -24
  3. package/dist/chunk-424UFCY7.js +78 -0
  4. package/dist/chunk-424UFCY7.js.map +1 -0
  5. package/dist/{chunk-HNPABX7L.js → chunk-7EZR47JV.js} +1 -1
  6. package/dist/{chunk-HNPABX7L.js.map → chunk-7EZR47JV.js.map} +1 -1
  7. package/dist/chunk-B77KABWH.js +41 -0
  8. package/dist/chunk-B77KABWH.js.map +1 -0
  9. package/dist/{chunk-MY36UPPQ.js → chunk-DI3H6JVZ.js} +357 -379
  10. package/dist/chunk-DI3H6JVZ.js.map +1 -0
  11. package/dist/{chunk-DDECTPRM.js → chunk-FGL32LUJ.js} +20 -14
  12. package/dist/chunk-FGL32LUJ.js.map +1 -0
  13. package/dist/{chunk-TTXVJFAE.js → chunk-JRSKWF6K.js} +4 -3
  14. package/dist/{chunk-TTXVJFAE.js.map → chunk-JRSKWF6K.js.map} +1 -1
  15. package/dist/{chunk-YRGUIRN5.js → chunk-VQ27YUHH.js} +18 -14
  16. package/dist/chunk-VQ27YUHH.js.map +1 -0
  17. package/dist/{chunk-BNV43SEF.js → chunk-VVXYZIIB.js} +5 -5
  18. package/dist/chunk-VVXYZIIB.js.map +1 -0
  19. package/dist/chunk-ZNLN2VWV.js +110 -0
  20. package/dist/chunk-ZNLN2VWV.js.map +1 -0
  21. package/dist/cli.js +102 -45
  22. package/dist/cli.js.map +1 -1
  23. package/dist/code.d.ts +4 -2
  24. package/dist/code.js +1 -1
  25. package/dist/docs.d.ts +7 -3
  26. package/dist/docs.js +1 -1
  27. package/dist/git.d.ts +4 -2
  28. package/dist/git.js +1 -1
  29. package/dist/index.d.ts +77 -17
  30. package/dist/index.js +21 -9
  31. package/dist/index.js.map +1 -1
  32. package/dist/local-embedding-ZIMTK6PU.js +8 -0
  33. package/dist/local-embedding-ZIMTK6PU.js.map +1 -0
  34. package/dist/memory.d.ts +2 -2
  35. package/dist/memory.js +1 -1
  36. package/dist/notes.d.ts +2 -2
  37. package/dist/notes.js +1 -1
  38. package/dist/qwen3-reranker-3MHEENT5.js +8 -0
  39. package/dist/qwen3-reranker-3MHEENT5.js.map +1 -0
  40. package/dist/resolve-CUJWY6HP.js +10 -0
  41. package/dist/resolve-CUJWY6HP.js.map +1 -0
  42. package/package.json +10 -9
  43. package/dist/chunk-BNV43SEF.js.map +0 -1
  44. package/dist/chunk-DDECTPRM.js.map +0 -1
  45. package/dist/chunk-MY36UPPQ.js.map +0 -1
  46. package/dist/chunk-YRGUIRN5.js.map +0 -1
package/README.md CHANGED
@@ -5,13 +5,14 @@
5
5
  BrainBank gives LLMs a long-term memory that persists between sessions.
6
6
 
7
7
  - **All-in-one** — core + code + git + docs + CLI in a single `brainbank` package
8
- - **Pluggable indexers** — `.use()` only what you need (code, git, docs, or custom)
8
+ - **Pluggable plugins** — `.use()` only what you need (code, git, docs, or custom)
9
9
  - **Dynamic collections** — `brain.collection('errors')` for any structured data
10
10
  - **Hybrid search** — vector + BM25 fused with Reciprocal Rank Fusion
11
11
  - **Pluggable embeddings** — local WASM (free), OpenAI, or Perplexity (standard & contextualized)
12
12
  - **Multi-repo** — index multiple repositories into one shared database
13
13
  - **Portable** — single `.brainbank/brainbank.db` file
14
- - **Optional packages** — [`@brainbank/memory`](#memory) (fact extraction + entity graph), [`@brainbank/reranker`](#reranker) (Qwen3 cross-encoder), [`@brainbank/mcp`](#mcp-server) (MCP server)
14
+ - **Optional packages** — [`@brainbank/memory`](#memory) (fact extraction + entity graph), [`@brainbank/mcp`](#mcp-server) (MCP server)
15
+ - **Optional reranker** — Qwen3-0.6B cross-encoder via `Qwen3Reranker` (opt-in)
15
16
 
16
17
  ![BrainBank Architecture](assets/architecture.png)
17
18
 
@@ -19,29 +20,16 @@ BrainBank gives LLMs a long-term memory that persists between sessions.
19
20
 
20
21
  ## Why BrainBank?
21
22
 
22
- Built for a multi-repo codebase that needed unified AI context. Zero infrastructure, zero ongoing cost.
23
+ BrainBank is a **code-aware knowledge engine** not just a memory layer. It parses your codebase with tree-sitter ASTs, indexes git history and co-edit patterns, and makes everything searchable with hybrid vector + keyword retrieval. Optional packages add conversational memory (`@brainbank/memory`) and MCP integration (`@brainbank/mcp`).
23
24
 
24
- Most AI memory solutions (mem0, Zep, LangMem) require cloud services, external databases, or LLM calls just to store a memory. BrainBank takes a different approach:
25
-
26
- | | **BrainBank** | **mem0** | **Zep** | **LangMem** |
25
+ | | **BrainBank** | **QMD** | **mem0 / Zep** | **LangChain** |
27
26
  |---|:---:|:---:|:---:|:---:|
28
- | Infrastructure | **SQLite file** | Vector DB + cloud | Neo4j + cloud | LangGraph Platform |
29
- | LLM required to write | **No**¹ | Yes | Yes | Yes |
30
- | Code-aware | **19 AST-parsed languages (tree-sitter), git, co-edits** | | | |
31
- | Custom indexers | **`.use()` plugin system** | | | |
32
- | Search | **Vector + BM25 + RRF** | Vector + graph² | Vector + BM25 + graph | Vector only |
33
- | Framework lock-in | **None** | Optional | Zep cloud | LangChain |
34
- | Portable | **Copy one file** | Tied to DB | Tied to cloud | Tied to platform |
35
-
36
- > ¹ mem0 and Zep use LLMs to auto-extract memories from raw text. BrainBank is explicit — you decide what gets stored. Less magic, more control.
37
- >
38
- > ² mem0's graph store (mem0g) is available in the paid platform version.
39
-
40
- **In short:**
41
- - **Code-first** — the only memory layer that understands code structure, git history, and file co-edit relationships
42
- - **Framework-agnostic** — plain TypeScript, works with any agent framework (LangChain, Vercel AI SDK, custom) or none at all. Unopinionated — doesn't force you into a specific pattern
43
- - **$0 memory bill** — no LLM calls to extract/consolidate. You store what you want, BrainBank embeds deterministically
44
- - **Truly portable** — `.brainbank/brainbank.db` is a normal file. Copy it, back it up, `git lfs` it
27
+ | Code-aware (AST) | **19 languages** (tree-sitter) | | | |
28
+ | Git + co-edits | | | | |
29
+ | Search | **Vector + BM25 + RRF** | Vector + reranker | Vector + graph | Vector only |
30
+ | Infra | **SQLite file** | Local GGUF | Vector DB + cloud | Vector DB |
31
+ | Plugins | **`.use()` builder** | | | |
32
+ | Memory | **`@brainbank/memory`** (opt-in) | | **Core feature** | |
45
33
 
46
34
  ### Table of Contents
47
35
 
@@ -50,16 +38,17 @@ Most AI memory solutions (mem0, Zep, LangMem) require cloud services, external d
50
38
  - [Quick Start](#quick-start)
51
39
  - [CLI](#cli)
52
40
  - [Programmatic API](#programmatic-api)
53
- - [Indexers](#indexers)
41
+ - [Plugins](#plugins)
54
42
  - [Collections](#collections)
55
43
  - [Search](#search)
56
44
  - [Document Collections](#document-collections)
57
45
  - [Context Generation](#context-generation)
58
- - [Custom Indexers](#custom-indexers)
46
+ - [Custom Plugins](#custom-plugins)
59
47
  - [AI Agent Integration](#ai-agent-integration)
60
48
  - [Examples](#examples)
61
49
  - [Watch Mode](#watch-mode)
62
50
  - [MCP Server](#mcp-server)
51
+ - [Project Config](#project-config)
63
52
  - [Configuration](#configuration)
64
53
  - [Embedding Providers](#embedding-providers)
65
54
  - [Reranker](#reranker)
@@ -73,7 +62,8 @@ Most AI memory solutions (mem0, Zep, LangMem) require cloud services, external d
73
62
  - [Benchmarks](#benchmarks)
74
63
  - [Search Quality: AST vs Sliding Window](#search-quality-ast-vs-sliding-window)
75
64
  - [Grammar Support](#grammar-support)
76
- - [RAG Retrieval Quality](#rag-retrieval-quality) · [Full Results →](./BENCHMARKS.md)
65
+ - [RAG Retrieval Quality](#rag-retrieval-quality)
66
+ · [Full Results →](./BENCHMARKS.md)
77
67
 
78
68
  ---
79
69
 
@@ -88,20 +78,48 @@ npm install brainbank
88
78
  | Package | When to install |
89
79
  |---------|----------------|
90
80
  | `@brainbank/memory` | Deterministic memory extraction + entity graph for LLM conversations |
91
- | `@brainbank/reranker` | Cross-encoder reranker (Qwen3-0.6B, ~640MB model) |
92
81
  | `@brainbank/mcp` | MCP server for AI tool integration |
93
82
 
94
83
  ```bash
95
84
  # Memory — automatic fact extraction & dedup for chatbots/agents
96
85
  npm install @brainbank/memory
97
86
 
98
- # Reranker — improves search ranking with local neural inference
99
- npm install @brainbank/reranker node-llama-cpp
87
+ # Reranker — built-in, install the runtime dependency to enable
88
+ npm install node-llama-cpp
100
89
 
101
90
  # MCP server — for Antigravity, Claude Desktop, etc.
102
91
  npm install @brainbank/mcp
103
92
  ```
104
93
 
94
+ ### Tree-Sitter Grammars
95
+
96
+ BrainBank uses [tree-sitter](https://tree-sitter.github.io/) for AST-aware code chunking. **JavaScript, TypeScript, and Python grammars are included by default.** Other languages require installing the corresponding grammar package:
97
+
98
+ ```bash
99
+ # Install only the grammars you need
100
+ npm install tree-sitter-go tree-sitter-rust tree-sitter-ruby
101
+ ```
102
+
103
+ If you index a file whose grammar isn't installed, BrainBank will throw a clear error:
104
+
105
+ ```
106
+ BrainBank: Grammar 'tree-sitter-go' is not installed. Run: npm install tree-sitter-go
107
+ ```
108
+
109
+ <details>
110
+ <summary>All available grammars (19 languages)</summary>
111
+
112
+ | Category | Packages |
113
+ |----------|----------|
114
+ | **Included** | `tree-sitter-javascript`, `tree-sitter-typescript`, `tree-sitter-python` |
115
+ | Web | `tree-sitter-html`, `tree-sitter-css` |
116
+ | Systems | `tree-sitter-go`, `tree-sitter-rust`, `tree-sitter-c`, `tree-sitter-cpp`, `tree-sitter-swift` |
117
+ | JVM | `tree-sitter-java`, `tree-sitter-kotlin`, `tree-sitter-scala` |
118
+ | Scripting | `tree-sitter-ruby`, `tree-sitter-php`, `tree-sitter-lua`, `tree-sitter-bash`, `tree-sitter-elixir` |
119
+ | .NET | `tree-sitter-c-sharp` |
120
+
121
+ </details>
122
+
105
123
  ---
106
124
 
107
125
  ## Quick Start
@@ -178,10 +196,10 @@ brainbank watch # Watch repo, auto re-index on save
178
196
  # Watching /path/to/repo for changes...
179
197
  # 14:30:02 ✓ code: src/api.ts
180
198
  # 14:30:05 ✓ code: src/routes.ts
181
- # 14:30:08 ✓ csv: data/metrics.csv ← custom indexer
199
+ # 14:30:08 ✓ csv: data/metrics.csv ← custom plugin
182
200
  ```
183
201
 
184
- > Watch mode monitors **code files** by default. [Custom indexers](#custom-indexers) that implement `watchPatterns()` and `onFileChange()` are automatically picked up — their name appears in the console output alongside the built-in `code` indexer. Git history and document collections are not affected by file-system changes and must be re-indexed explicitly with `brainbank index` / `brainbank docs`.
202
+ > Watch mode monitors **code files** by default. [Custom plugins](#custom-plugins) that implement `watchPatterns()` and `onFileChange()` are automatically picked up — their name appears in the console output alongside the built-in `code` plugin. Git history and document collections are not affected by file-system changes and must be re-indexed explicitly with `brainbank index` / `brainbank docs`.
185
203
 
186
204
  ### Document Collections
187
205
 
@@ -235,34 +253,44 @@ brainbank serve # Start MCP server (stdio)
235
253
 
236
254
  Use BrainBank as a library in your TypeScript/Node.js project.
237
255
 
238
- ### Indexers
256
+ ### Plugins
239
257
 
240
- BrainBank uses pluggable indexers. Register only what you need with `.use()`:
258
+ BrainBank uses pluggable plugins. Register only what you need with `.use()`:
241
259
 
242
- | Indexer | Import | Description |
260
+ | Plugin | Import | Description |
243
261
  |---------|--------|-------------|
244
262
  | `code` | `brainbank/code` | AST-aware code chunking via tree-sitter (19 languages) |
245
263
  | `git` | `brainbank/git` | Git commit history, diffs, co-edit relationships |
246
264
  | `docs` | `brainbank/docs` | Document collections (markdown, wikis) |
247
265
 
248
266
  ```typescript
249
- import { BrainBank } from 'brainbank';
267
+ import { BrainBank, OpenAIEmbedding } from 'brainbank';
250
268
  import { code } from 'brainbank/code';
251
269
  import { git } from 'brainbank/git';
252
270
  import { docs } from 'brainbank/docs';
253
271
 
254
- // Pick only the indexers you need
255
- const brain = new BrainBank({ repoPath: '.' })
256
- .use(code())
257
- .use(git())
258
- .use(docs());
272
+ // Each plugin can use a different embedding provider
273
+ const brain = new BrainBank({ repoPath: '.' }) // default: local WASM (384d, free)
274
+ .use(code({ embeddingProvider: new OpenAIEmbedding() })) // code: OpenAI (1536d)
275
+ .use(git()) // git: local (384d)
276
+ .use(docs()); // docs: local (384d)
259
277
 
260
278
  // Index code + git (incremental — only processes changes)
261
279
  await brain.index();
262
280
 
263
- // Index document collections
281
+ // Register and index document collections
264
282
  await brain.addCollection({ name: 'wiki', path: '~/docs', pattern: '**/*.md' });
265
283
  await brain.indexDocs();
284
+
285
+ // Dynamic collections — store anything
286
+ const decisions = brain.collection('decisions');
287
+ await decisions.add(
288
+ 'Use SQLite with WAL mode instead of PostgreSQL. Portable, zero infra.',
289
+ { tags: ['architecture'] }
290
+ );
291
+ const hits = await decisions.search('why not postgres');
292
+
293
+ brain.close();
266
294
  ```
267
295
 
268
296
  ### Collections
@@ -302,7 +330,7 @@ Auto-re-index when files change:
302
330
  // API
303
331
  const watcher = brain.watch({
304
332
  debounceMs: 2000,
305
- onIndex: (file, indexer) => console.log(`${indexer}: ${file}`),
333
+ onIndex: (file, plugin) => console.log(`${plugin}: ${file}`),
306
334
  onError: (err) => console.error(err.message),
307
335
  });
308
336
 
@@ -318,15 +346,15 @@ brainbank watch
318
346
  # 14:30:05 ✓ code: src/routes.ts
319
347
  ```
320
348
 
321
- #### Custom Indexer Watch
349
+ #### Custom Plugin Watch
322
350
 
323
- Custom indexers can hook into watch mode by implementing `onFileChange` and `watchPatterns`:
351
+ Custom plugins can hook into watch mode by implementing `onFileChange` and `watchPatterns`:
324
352
 
325
353
  ```typescript
326
- import type { Indexer, IndexerContext } from 'brainbank';
354
+ import type { Plugin, PluginContext } from 'brainbank';
327
355
 
328
- function csvIndexer(): Indexer {
329
- let ctx: IndexerContext;
356
+ function csvPlugin(): Plugin {
357
+ let ctx: PluginContext;
330
358
 
331
359
  return {
332
360
  name: 'csv',
@@ -335,7 +363,7 @@ function csvIndexer(): Indexer {
335
363
  ctx = context;
336
364
  },
337
365
 
338
- // Tell watch which files this indexer cares about
366
+ // Tell watch which files this plugin cares about
339
367
  watchPatterns() {
340
368
  return ['**/*.csv', '**/*.tsv'];
341
369
  },
@@ -357,7 +385,7 @@ function csvIndexer(): Indexer {
357
385
 
358
386
  const brain = new BrainBank({ dbPath: './brain.db' })
359
387
  .use(code())
360
- .use(csvIndexer());
388
+ .use(csvPlugin());
361
389
 
362
390
  await brain.initialize();
363
391
  brain.watch(); // Now watches .ts, .py, etc. AND .csv, .tsv
@@ -424,16 +452,16 @@ const context = await brain.getContext('add rate limiting to the API', {
424
452
  // Returns: ## Relevant Code, ## Git History, ## Relevant Documents
425
453
  ```
426
454
 
427
- ### Custom Indexers
455
+ ### Custom Plugins
428
456
 
429
- Implement the `Indexer` interface to build your own:
457
+ Implement the `Plugin` interface to build your own:
430
458
 
431
459
  ```typescript
432
- import type { Indexer, IndexerContext } from 'brainbank';
460
+ import type { Plugin, PluginContext } from 'brainbank';
433
461
 
434
- const myIndexer: Indexer = {
462
+ const myPlugin: Plugin = {
435
463
  name: 'custom',
436
- async initialize(ctx: IndexerContext) {
464
+ async initialize(ctx: PluginContext) {
437
465
  // ctx.db — shared SQLite database
438
466
  // ctx.embedding — shared embedding provider
439
467
  // ctx.collection() — create dynamic collections
@@ -442,10 +470,10 @@ const myIndexer: Indexer = {
442
470
  },
443
471
  };
444
472
 
445
- brain.use(myIndexer);
473
+ brain.use(myPlugin);
446
474
  ```
447
475
 
448
- #### Using custom indexers with the CLI
476
+ #### Using custom plugins with the CLI
449
477
 
450
478
  Drop `.ts` files into `.brainbank/indexers/` — the CLI auto-discovers them:
451
479
 
@@ -457,11 +485,11 @@ Drop `.ts` files into `.brainbank/indexers/` — the CLI auto-discovers them:
457
485
  └── jira.ts
458
486
  ```
459
487
 
460
- Each file exports a default `Indexer`:
488
+ Each file exports a default `Plugin`:
461
489
 
462
490
  ```typescript
463
491
  // .brainbank/indexers/slack.ts
464
- import type { Indexer } from 'brainbank';
492
+ import type { Plugin } from 'brainbank';
465
493
 
466
494
  export default {
467
495
  name: 'slack',
@@ -469,43 +497,83 @@ export default {
469
497
  const msgs = ctx.collection('slack_messages');
470
498
  // ... fetch and index slack messages
471
499
  },
472
- } satisfies Indexer;
500
+ } satisfies Plugin;
473
501
  ```
474
502
 
475
- That's it — all CLI commands automatically pick up your indexers:
503
+ That's it — all CLI commands automatically pick up your plugins:
476
504
 
477
505
  ```bash
478
506
  brainbank index # runs code + git + docs + slack + jira
479
- brainbank stats # shows all indexers
507
+ brainbank stats # shows all plugins
480
508
  brainbank kv search slack_messages "deploy" # search slack data
481
509
  ```
482
510
 
483
- #### Advanced: config file
511
+ ---
484
512
 
485
- For fine-grained control, create a `.brainbank/config.ts`:
513
+ ## Project Config
486
514
 
487
- ```typescript
488
- // .brainbank/config.ts
489
- export default {
490
- builtins: ['code', 'docs'], // exclude git (default: all three)
491
- brainbank: { // BrainBank constructor options
492
- dbPath: '.brainbank/brain.db',
515
+ Drop a `.brainbank/config.json` in your repo root. Every `brainbank index` reads it automatically — no CLI flags needed.
516
+
517
+ ```jsonc
518
+ // .brainbank/config.json
519
+ {
520
+ // Which built-in plugins to load (default: all three)
521
+ "plugins": ["code", "git", "docs"],
522
+
523
+ // Per-plugin options
524
+ "code": {
525
+ "embedding": "openai", // use OpenAI embeddings for code
526
+ "maxFileSize": 512000
493
527
  },
494
- };
528
+ "git": {
529
+ "depth": 200 // index last 200 commits
530
+ },
531
+ "docs": {
532
+ "embedding": "perplexity-context",
533
+ "collections": [
534
+ { "name": "docs", "path": "./docs", "pattern": "**/*.md" },
535
+ { "name": "wiki", "path": "~/team-wiki", "pattern": "**/*.md", "ignore": ["drafts/**"] }
536
+ ]
537
+ },
538
+
539
+ // Global defaults
540
+ "embedding": "local", // default for plugins without their own
541
+ "reranker": "qwen3"
542
+ }
495
543
  ```
496
544
 
497
- Everything lives in `.brainbank/` — DB, config, and custom indexers:
545
+ **Embedding keys:** `"local"` (default, free), `"openai"`, `"perplexity"`, `"perplexity-context"`.
546
+
547
+ **Per-plugin embeddings** — each plugin creates its own HNSW index with the correct dimensions. A plugin without an `embedding` key uses the global default.
548
+
549
+ **Docs collections** — registered automatically on every `brainbank index` run. No need for `--docs` flags.
550
+
551
+ **Custom plugins** — auto-discovered from `.brainbank/indexers/`:
498
552
 
499
553
  ```
500
554
  .brainbank/
501
555
  ├── brainbank.db # SQLite database (auto-created)
502
- ├── config.ts # Optional project config
503
- └── indexers/ # Optional custom indexer files
556
+ ├── config.json # Project config (optional)
557
+ └── indexers/ # Custom plugin files (optional)
504
558
  ├── slack.ts
505
559
  └── jira.ts
506
560
  ```
507
561
 
508
- No folder and no config file? The CLI uses the built-in indexers (`code`, `git`, `docs`).
562
+ Custom plugins can also have their own config section:
563
+
564
+ ```jsonc
565
+ {
566
+ "plugins": ["code", "git"],
567
+ "slack": { "embedding": "openai" }, // matched by plugin name
568
+ "jira": { "embedding": "perplexity" }
569
+ }
570
+ ```
571
+
572
+ **Config priority:** CLI flags > `config.json` > auto-resolve from DB > defaults.
573
+
574
+ > `.brainbank/config.ts` (or `.js`, `.mjs`) is still supported for programmatic config with custom plugin instances. JSON is preferred for declarative setups.
575
+
576
+ No config file? The CLI uses all built-in plugins with local embeddings — zero config required.
509
577
 
510
578
  ---
511
579
 
@@ -556,19 +624,19 @@ Teach your AI coding agent to use BrainBank as persistent memory. Add an `AGENTS
556
624
  | **Cursor** | Add rules in `.cursor/rules` |
557
625
  | **MCP** (any agent) | See [MCP Server](#mcp-server) config below |
558
626
 
559
- #### Custom Indexer: Auto-Ingest Conversation Logs
627
+ #### Custom Plugin: Auto-Ingest Conversation Logs
560
628
 
561
629
  For agents that produce structured logs (e.g. Antigravity's `brain/` directory), auto-index them:
562
630
 
563
631
  ```typescript
564
632
  // .brainbank/indexers/conversations.ts
565
- import type { Indexer, IndexerContext } from 'brainbank';
633
+ import type { Plugin, PluginContext } from 'brainbank';
566
634
  import * as fs from 'node:fs';
567
635
  import * as path from 'node:path';
568
636
 
569
637
  export default {
570
638
  name: 'conversations',
571
- async initialize(ctx: IndexerContext) {
639
+ async initialize(ctx: PluginContext) {
572
640
  const conversations = ctx.collection('conversations');
573
641
  const logsDir = path.join(ctx.config.repoPath, '.gemini/antigravity/brain');
574
642
  if (!fs.existsSync(logsDir)) return;
@@ -584,7 +652,7 @@ export default {
584
652
  });
585
653
  }
586
654
  },
587
- } satisfies Indexer;
655
+ } satisfies Plugin;
588
656
  ```
589
657
 
590
658
  ```bash
@@ -619,48 +687,36 @@ Add to your MCP config (`~/.gemini/antigravity/mcp_config.json` or Claude Deskto
619
687
  "mcpServers": {
620
688
  "brainbank": {
621
689
  "command": "npx",
622
- "args": ["-y", "@brainbank/mcp"],
623
- "env": {
624
- "BRAINBANK_EMBEDDING": "openai"
625
- }
690
+ "args": ["-y", "@brainbank/mcp"]
626
691
  }
627
692
  }
628
693
  }
629
694
  ```
630
695
 
631
- The agent passes the `repo` parameter on each tool call based on the active workspace — no hardcoded paths needed.
696
+ **Zero-config.** The MCP server auto-detects:
697
+ - **Repo path** — from `repo` tool param > `BRAINBANK_REPO` env > `findRepoRoot(cwd)`
698
+ - **Embedding provider** — from `provider_key` stored in the DB (set during `brainbank index --embedding openai`)
632
699
 
633
- > Set `BRAINBANK_EMBEDDING` to `openai`, `perplexity`, or `perplexity-context` for higher quality search. Omit to use the free local WASM embeddings.
700
+ > [!TIP]
701
+ > Index your repo once with the CLI to set up the embedding provider:
702
+ > ```bash
703
+ > brainbank index . --embedding openai # stores provider_key=openai in DB
704
+ > ```
705
+ > After that, the MCP server (and any future CLI runs) auto-resolve the correct provider from the DB — no env vars needed.
634
706
 
635
- > Optionally set `BRAINBANK_REPO` as a default fallback repo. If omitted, every tool call must include the `repo` parameter (recommended for multi-workspace setups).
636
-
637
- > [!CAUTION]
638
- > **Embedding Provider Consistency is Critical**
639
- >
640
- > The embedding provider used by the MCP server **must match** the one used during indexing. Mismatched dimensions cause `initialize()` to throw or search to return empty results.
641
- >
642
- > **Common failure scenario:**
643
- > 1. You index via CLI with `BRAINBANK_EMBEDDING=openai` (1536 dims)
644
- > 2. MCP server starts without `BRAINBANK_EMBEDDING` env var → defaults to local (384 dims)
645
- > 3. **Result:** BrainBank throws `Embedding dimension mismatch` on every search
646
- >
647
- > **Fix:** Always set `BRAINBANK_EMBEDDING` consistently in your MCP config, CLI, and API usage. If you indexed with OpenAI, your MCP config **must** include `"BRAINBANK_EMBEDDING": "openai"`. Same for `perplexity` or `perplexity-context`. If you switch providers, run `brainbank reembed` to regenerate all vectors.
707
+ > [!NOTE]
708
+ > If you switch embedding providers (e.g. local → OpenAI), run `brainbank reembed` to regenerate all vectors. BrainBank auto-detects dimension mismatches and warns you.
648
709
 
649
710
  ### Available Tools
650
711
 
651
712
  | Tool | Description |
652
713
  |------|-------------|
653
- | `brainbank_hybrid_search` | Best quality: vector + BM25 + reranker |
654
- | `brainbank_search` | Semantic vector search |
655
- | `brainbank_keyword_search` | Instant BM25 full-text |
656
- | `brainbank_context` | Formatted context for a task |
657
- | `brainbank_index` | Trigger code/git indexing |
658
- | `brainbank_stats` | Index statistics |
659
- | `brainbank_history` | Git history for a file |
660
- | `brainbank_coedits` | Files that change together |
661
- | `brainbank_collection_add` | Add item to a KV collection |
662
- | `brainbank_collection_search` | Search a KV collection |
663
- | `brainbank_collection_trim` | Trim a KV collection |
714
+ | `brainbank_search` | Unified search — `mode: hybrid` (default), `vector`, or `keyword` |
715
+ | `brainbank_context` | Formatted context block for a task (code + git + co-edits) |
716
+ | `brainbank_index` | Trigger incremental code/git/docs indexing |
717
+ | `brainbank_stats` | Index statistics (files, commits, chunks, collections) |
718
+ | `brainbank_history` | Git history for a specific file |
719
+ | `brainbank_collection` | KV collection ops — `action: add`, `search`, or `trim` |
664
720
 
665
721
  ---
666
722
 
@@ -668,7 +724,7 @@ The agent passes the `repo` parameter on each tool call based on the active work
668
724
 
669
725
  ```typescript
670
726
  import { BrainBank, OpenAIEmbedding } from 'brainbank';
671
- import { Qwen3Reranker } from '@brainbank/reranker'; // separate package
727
+ import { Qwen3Reranker } from 'brainbank'; // built-in, requires node-llama-cpp
672
728
 
673
729
  const brain = new BrainBank({
674
730
  repoPath: '.',
@@ -691,6 +747,50 @@ const brain = new BrainBank({
691
747
  | **Perplexity** | `PerplexityEmbedding` | 2560 (4b) / 1024 (0.6b) | ~100ms | $0.02/1M tokens |
692
748
  | **Perplexity Context** | `PerplexityContextEmbedding` | 2560 (4b) / 1024 (0.6b) | ~100ms | $0.06/1M tokens |
693
749
 
750
+ #### How It Works
751
+
752
+ BrainBank **auto-resolves** the embedding provider. Set it once → it's stored in the DB → every future run uses the same provider automatically.
753
+
754
+ **Programmatic API** — pass `embeddingProvider` to the constructor:
755
+
756
+ ```typescript
757
+ import { BrainBank, OpenAIEmbedding } from 'brainbank';
758
+
759
+ const brain = new BrainBank({
760
+ repoPath: '.',
761
+ embeddingProvider: new OpenAIEmbedding(), // stored in DB on first index
762
+ });
763
+ ```
764
+
765
+ **CLI** — use the `--embedding` flag on first index:
766
+
767
+ ```bash
768
+ brainbank index . --embedding openai # stores provider_key=openai in DB
769
+ brainbank index . # auto-resolves openai from DB
770
+ brainbank hsearch "auth middleware" # uses the same provider
771
+ ```
772
+
773
+ **MCP** — zero-config. Reads the provider from the DB automatically.
774
+
775
+ > The provider key is persisted in the `embedding_meta` table. Priority on startup: explicit `embeddingProvider` in config > stored `provider_key` in DB > local WASM (default).
776
+
777
+ **Per-plugin override** — each plugin can use a different embedding provider:
778
+
779
+ ```typescript
780
+ import { BrainBank, OpenAIEmbedding } from 'brainbank';
781
+ import { PerplexityContextEmbedding } from 'brainbank';
782
+ import { code } from 'brainbank/code';
783
+ import { git } from 'brainbank/git';
784
+ import { docs } from 'brainbank/docs';
785
+
786
+ const brain = new BrainBank({ repoPath: '.' }) // default: local WASM (384d)
787
+ .use(code({ embeddingProvider: new OpenAIEmbedding() })) // code: OpenAI (1536d)
788
+ .use(git()) // git: local (384d)
789
+ .use(docs({ embeddingProvider: new PerplexityContextEmbedding() })); // docs: Perplexity (2560d)
790
+ ```
791
+
792
+ > Each plugin creates its own HNSW index with the correct dimensions. The global `embeddingProvider` (or local default) is used for any plugin that doesn't specify one.
793
+
694
794
  #### OpenAI
695
795
 
696
796
  ```typescript
@@ -754,7 +854,12 @@ Real benchmarks on a production NestJS backend (1052 code chunks + git history):
754
854
 
755
855
  ### Reranker
756
856
 
757
- BrainBank includes an optional cross-encoder reranker using **Qwen3-Reranker-0.6B** via `node-llama-cpp`. It runs 100% locally — no API keys needed. The reranker is **disabled by default**.
857
+ BrainBank ships with an optional cross-encoder reranker using **Qwen3-Reranker-0.6B** via `node-llama-cpp`. It runs 100% locally — no API keys needed. The reranker is **disabled by default**.
858
+
859
+ ```bash
860
+ # Only requirement — the LLM runtime (model auto-downloads on first use)
861
+ npm install node-llama-cpp
862
+ ```
758
863
 
759
864
  #### When to Use It
760
865
 
@@ -777,7 +882,7 @@ The reranker runs local neural inference on every search result, which improves
777
882
 
778
883
  ```typescript
779
884
  import { BrainBank } from 'brainbank';
780
- import { Qwen3Reranker } from '@brainbank/reranker';
885
+ import { Qwen3Reranker } from 'brainbank';
781
886
 
782
887
  const brain = new BrainBank({
783
888
  reranker: new Qwen3Reranker(), // ~640MB model, auto-downloaded on first use
@@ -837,7 +942,7 @@ const brain = new BrainBank({ repoPath: '.' });
837
942
  brain.use(notes());
838
943
  await brain.initialize();
839
944
 
840
- const notesPlugin = brain.indexer('notes');
945
+ const notesPlugin = brain.plugin('notes');
841
946
 
842
947
  // Store a conversation digest
843
948
  await notesPlugin.remember({
@@ -879,7 +984,7 @@ const brain = new BrainBank({ repoPath: '.' });
879
984
  brain.use(memory());
880
985
  await brain.initialize();
881
986
 
882
- const mem = brain.indexer('memory');
987
+ const mem = brain.plugin('memory');
883
988
 
884
989
  // Record a learning pattern
885
990
  await mem.learn({
@@ -974,10 +1079,12 @@ The `LLMProvider` interface works with any framework:
974
1079
  | Variable | Description |
975
1080
  |----------|-------------|
976
1081
  | `BRAINBANK_REPO` | Default repository path (optional — auto-detected from `.git/` or passed per tool call) |
977
- | `BRAINBANK_EMBEDDING` | Embedding provider: `local` (default), `openai`, `perplexity`, `perplexity-context` |
1082
+ | `BRAINBANK_RERANKER` | Reranker: `none` (default), `qwen3` |
978
1083
  | `BRAINBANK_DEBUG` | Show full stack traces |
979
- | `OPENAI_API_KEY` | Required when using `BRAINBANK_EMBEDDING=openai` |
980
- | `PERPLEXITY_API_KEY` | Required when using `BRAINBANK_EMBEDDING=perplexity` or `perplexity-context` |
1084
+ | `OPENAI_API_KEY` | Required when using `--embedding openai` |
1085
+ | `PERPLEXITY_API_KEY` | Required when using `--embedding perplexity` or `perplexity-context` |
1086
+
1087
+ > **Note:** `BRAINBANK_EMBEDDING` env var has been removed. Use `brainbank index --embedding <provider>` on first index — the provider is stored in the DB and auto-resolved on subsequent runs.
981
1088
 
982
1089
  ---
983
1090
 
@@ -987,7 +1094,7 @@ BrainBank can index multiple repositories into a **single shared database**. Thi
987
1094
 
988
1095
  ### How It Works
989
1096
 
990
- When you point BrainBank at a directory that contains multiple Git repositories (subdirectories with `.git/`), the CLI **auto-detects** them and creates namespaced indexers:
1097
+ When you point BrainBank at a directory that contains multiple Git repositories (subdirectories with `.git/`), the CLI **auto-detects** them and creates namespaced plugins:
991
1098
 
992
1099
  ```bash
993
1100
  ~/projects/
@@ -1021,9 +1128,9 @@ brainbank hsearch "cancel job confirmation" --repo ~/projects
1021
1128
  # and shared utilities — all in one search.
1022
1129
  ```
1023
1130
 
1024
- ### Namespaced Indexers
1131
+ ### Namespaced Plugins
1025
1132
 
1026
- Each sub-repository gets its own namespaced indexer instances (e.g., `code:frontend`, `git:backend`). Same-type indexers share a single HNSW vector index for efficient memory usage and unified search.
1133
+ Each sub-repository gets its own namespaced plugin instances (e.g., `code:frontend`, `git:backend`). Same-type plugins share a single HNSW vector index for efficient memory usage and unified search.
1027
1134
 
1028
1135
  ### Programmatic API
1029
1136
 
@@ -1080,13 +1187,13 @@ BrainBank uses **native tree-sitter** to parse source code into ASTs and extract
1080
1187
 
1081
1188
  For large classes (>80 lines), the chunker descends into the class body and extracts each method as a separate chunk. For unsupported languages, it falls back to a sliding window with overlap.
1082
1189
 
1083
- > Tree-sitter grammars are **optional dependencies**. If a grammar isn't installed, that language falls back to the generic sliding window. Install only the grammars you need: `npm install tree-sitter-ruby tree-sitter-go` etc.
1190
+ > Tree-sitter grammars are **optional dependencies** (except JS and TS, which are included). If you index a file whose grammar isn't installed, BrainBank throws a clear error with the exact `npm install` command. See [Tree-Sitter Grammars](#tree-sitter-grammars) for the full list.
1084
1191
 
1085
1192
  ### Incremental Indexing
1086
1193
 
1087
1194
  All indexing is **incremental by default** — only new or changed content is processed:
1088
1195
 
1089
- | Indexer | How it detects changes | What gets skipped |
1196
+ | Plugin | How it detects changes | What gets skipped |
1090
1197
  |---------|----------------------|-------------------|
1091
1198
  | **Code** | FNV-1a hash of file content | Unchanged files |
1092
1199
  | **Git** | Unique commit hash | Already-indexed commits |
@@ -1242,7 +1349,7 @@ BrainBank's hybrid search pipeline (Vector + BM25 → RRF) with Perplexity Conte
1242
1349
  | Benchmark | Metric | Score |
1243
1350
  |---|---|:---:|
1244
1351
  | **BEIR SciFact** (5,183 docs, 300 queries) | NDCG@10 | **0.761** |
1245
- | **Custom semantic** (127 docs, 20 queries) | R@5 | **83%** |
1352
+ | **Custom semantic** (69 docs, 20 queries) | R@5 | **83%** |
1246
1353
 
1247
1354
  The hybrid pipeline improved R@5 by **+26pp over vector-only** retrieval on our custom eval.
1248
1355
 
@@ -1287,7 +1394,7 @@ PERPLEXITY_API_KEY=pplx-... npx tsx test/benchmarks/rag/eval.ts --docs ~/path/to
1287
1394
  │ │
1288
1395
  │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌────────────┐│
1289
1396
  │ │ Code │ │ Git │ │ Docs │ │ Collection ││
1290
- │ │ Indexer │ │ Indexer │ │ Indexer │ │ (dynamic) ││
1397
+ │ │ Plugin │ │ Indexer │ │ Indexer │ │ (dynamic) ││
1291
1398
  │ └────┬────┘ └────┬────┘ └────┬────┘ └─────┬──────┘│
1292
1399
  │ │ │ │ │ │
1293
1400
  │ ┌────▼────┐ ┌────▼────┐ ┌────▼────┐ ┌─────▼──────┐│
@@ -1337,7 +1444,7 @@ Final results (sorted by blended score)
1337
1444
 
1338
1445
  ### Data Flow
1339
1446
 
1340
- 1. **Index** — Indexers parse files into chunks (tree-sitter AST for code, heading-based for docs)
1447
+ 1. **Index** — Plugins parse files into chunks (tree-sitter AST for code, heading-based for docs)
1341
1448
  2. **Embed** — Each chunk gets a vector (local WASM or OpenAI)
1342
1449
  3. **Store** — Chunks + vectors → SQLite, vectors → HNSW index
1343
1450
  4. **Search** — Query → HNSW k-NN + BM25 keyword → RRF fusion → optional reranker
@@ -1348,8 +1455,8 @@ Final results (sorted by blended score)
1348
1455
  ## Testing
1349
1456
 
1350
1457
  ```bash
1351
- npm test # Unit tests (129 tests)
1352
- npm test -- --integration # Full suite (211 tests, includes real models + all domains)
1458
+ npm test # Unit tests (172 tests)
1459
+ npm test -- --integration # Full suite (includes real models + all domains)
1353
1460
  npm test -- --filter code # Filter by test name
1354
1461
  npm test -- --verbose # Show assertion details
1355
1462
  ```