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.
- package/README.md +233 -126
- package/dist/{base-DZWtdgIf.d.ts → base-3SNc_CeY.d.ts} +24 -24
- package/dist/chunk-424UFCY7.js +78 -0
- package/dist/chunk-424UFCY7.js.map +1 -0
- package/dist/{chunk-HNPABX7L.js → chunk-7EZR47JV.js} +1 -1
- package/dist/{chunk-HNPABX7L.js.map → chunk-7EZR47JV.js.map} +1 -1
- package/dist/chunk-B77KABWH.js +41 -0
- package/dist/chunk-B77KABWH.js.map +1 -0
- package/dist/{chunk-MY36UPPQ.js → chunk-DI3H6JVZ.js} +357 -379
- package/dist/chunk-DI3H6JVZ.js.map +1 -0
- package/dist/{chunk-DDECTPRM.js → chunk-FGL32LUJ.js} +20 -14
- package/dist/chunk-FGL32LUJ.js.map +1 -0
- package/dist/{chunk-TTXVJFAE.js → chunk-JRSKWF6K.js} +4 -3
- package/dist/{chunk-TTXVJFAE.js.map → chunk-JRSKWF6K.js.map} +1 -1
- package/dist/{chunk-YRGUIRN5.js → chunk-VQ27YUHH.js} +18 -14
- package/dist/chunk-VQ27YUHH.js.map +1 -0
- package/dist/{chunk-BNV43SEF.js → chunk-VVXYZIIB.js} +5 -5
- package/dist/chunk-VVXYZIIB.js.map +1 -0
- package/dist/chunk-ZNLN2VWV.js +110 -0
- package/dist/chunk-ZNLN2VWV.js.map +1 -0
- package/dist/cli.js +102 -45
- package/dist/cli.js.map +1 -1
- package/dist/code.d.ts +4 -2
- package/dist/code.js +1 -1
- package/dist/docs.d.ts +7 -3
- package/dist/docs.js +1 -1
- package/dist/git.d.ts +4 -2
- package/dist/git.js +1 -1
- package/dist/index.d.ts +77 -17
- package/dist/index.js +21 -9
- package/dist/index.js.map +1 -1
- package/dist/local-embedding-ZIMTK6PU.js +8 -0
- package/dist/local-embedding-ZIMTK6PU.js.map +1 -0
- package/dist/memory.d.ts +2 -2
- package/dist/memory.js +1 -1
- package/dist/notes.d.ts +2 -2
- package/dist/notes.js +1 -1
- package/dist/qwen3-reranker-3MHEENT5.js +8 -0
- package/dist/qwen3-reranker-3MHEENT5.js.map +1 -0
- package/dist/resolve-CUJWY6HP.js +10 -0
- package/dist/resolve-CUJWY6HP.js.map +1 -0
- package/package.json +10 -9
- package/dist/chunk-BNV43SEF.js.map +0 -1
- package/dist/chunk-DDECTPRM.js.map +0 -1
- package/dist/chunk-MY36UPPQ.js.map +0 -1
- 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
|
|
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/
|
|
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
|

|
|
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
|
-
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
| | **BrainBank** | **mem0** | **Zep** | **LangMem** |
|
|
25
|
+
| | **BrainBank** | **QMD** | **mem0 / Zep** | **LangChain** |
|
|
27
26
|
|---|:---:|:---:|:---:|:---:|
|
|
28
|
-
|
|
|
29
|
-
|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
32
|
-
|
|
|
33
|
-
|
|
|
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
|
-
- [
|
|
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
|
|
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)
|
|
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 —
|
|
99
|
-
npm install
|
|
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
|
|
199
|
+
# 14:30:08 ✓ csv: data/metrics.csv ← custom plugin
|
|
182
200
|
```
|
|
183
201
|
|
|
184
|
-
> Watch mode monitors **code files** by default. [Custom
|
|
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
|
-
###
|
|
256
|
+
### Plugins
|
|
239
257
|
|
|
240
|
-
BrainBank uses pluggable
|
|
258
|
+
BrainBank uses pluggable plugins. Register only what you need with `.use()`:
|
|
241
259
|
|
|
242
|
-
|
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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,
|
|
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
|
|
349
|
+
#### Custom Plugin Watch
|
|
322
350
|
|
|
323
|
-
Custom
|
|
351
|
+
Custom plugins can hook into watch mode by implementing `onFileChange` and `watchPatterns`:
|
|
324
352
|
|
|
325
353
|
```typescript
|
|
326
|
-
import type {
|
|
354
|
+
import type { Plugin, PluginContext } from 'brainbank';
|
|
327
355
|
|
|
328
|
-
function
|
|
329
|
-
let ctx:
|
|
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
|
|
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(
|
|
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
|
|
455
|
+
### Custom Plugins
|
|
428
456
|
|
|
429
|
-
Implement the `
|
|
457
|
+
Implement the `Plugin` interface to build your own:
|
|
430
458
|
|
|
431
459
|
```typescript
|
|
432
|
-
import type {
|
|
460
|
+
import type { Plugin, PluginContext } from 'brainbank';
|
|
433
461
|
|
|
434
|
-
const
|
|
462
|
+
const myPlugin: Plugin = {
|
|
435
463
|
name: 'custom',
|
|
436
|
-
async initialize(ctx:
|
|
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(
|
|
473
|
+
brain.use(myPlugin);
|
|
446
474
|
```
|
|
447
475
|
|
|
448
|
-
#### Using custom
|
|
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 `
|
|
488
|
+
Each file exports a default `Plugin`:
|
|
461
489
|
|
|
462
490
|
```typescript
|
|
463
491
|
// .brainbank/indexers/slack.ts
|
|
464
|
-
import type {
|
|
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
|
|
500
|
+
} satisfies Plugin;
|
|
473
501
|
```
|
|
474
502
|
|
|
475
|
-
That's it — all CLI commands automatically pick up your
|
|
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
|
|
507
|
+
brainbank stats # shows all plugins
|
|
480
508
|
brainbank kv search slack_messages "deploy" # search slack data
|
|
481
509
|
```
|
|
482
510
|
|
|
483
|
-
|
|
511
|
+
---
|
|
484
512
|
|
|
485
|
-
|
|
513
|
+
## Project Config
|
|
486
514
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
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
|
-
|
|
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.
|
|
503
|
-
└── indexers/ #
|
|
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
|
-
|
|
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
|
|
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 {
|
|
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:
|
|
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
|
|
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
|
|
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
|
-
>
|
|
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
|
-
>
|
|
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
|
-
| `
|
|
654
|
-
| `
|
|
655
|
-
| `
|
|
656
|
-
| `
|
|
657
|
-
| `
|
|
658
|
-
| `
|
|
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 '
|
|
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
|
|
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 '
|
|
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.
|
|
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.
|
|
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
|
-
| `
|
|
1082
|
+
| `BRAINBANK_RERANKER` | Reranker: `none` (default), `qwen3` |
|
|
978
1083
|
| `BRAINBANK_DEBUG` | Show full stack traces |
|
|
979
|
-
| `OPENAI_API_KEY` | Required when using
|
|
980
|
-
| `PERPLEXITY_API_KEY` | Required when using
|
|
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
|
|
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
|
|
1131
|
+
### Namespaced Plugins
|
|
1025
1132
|
|
|
1026
|
-
Each sub-repository gets its own namespaced
|
|
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
|
|
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
|
-
|
|
|
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** (
|
|
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
|
-
│ │
|
|
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** —
|
|
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 (
|
|
1352
|
-
npm test -- --integration # Full suite (
|
|
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
|
```
|