crbro-memory 1.15.0 → 2.0.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 +70 -41
- package/bin/crbro.mjs +84 -41
- package/dist/engine/brain.js +1 -1
- package/dist/engine/brain.js.map +1 -1
- package/dist/engine/cortex.d.ts +189 -1
- package/dist/engine/cortex.d.ts.map +1 -1
- package/dist/engine/cortex.js +639 -17
- package/dist/engine/cortex.js.map +1 -1
- package/dist/engine/hippocampus.d.ts +27 -1
- package/dist/engine/hippocampus.d.ts.map +1 -1
- package/dist/engine/hippocampus.js +51 -2
- package/dist/engine/hippocampus.js.map +1 -1
- package/dist/engine/maintenance.d.ts +49 -2
- package/dist/engine/maintenance.d.ts.map +1 -1
- package/dist/engine/maintenance.js +301 -28
- package/dist/engine/maintenance.js.map +1 -1
- package/dist/engine/prefrontal.d.ts +25 -7
- package/dist/engine/prefrontal.d.ts.map +1 -1
- package/dist/engine/prefrontal.js +55 -27
- package/dist/engine/prefrontal.js.map +1 -1
- package/dist/engine/synapses.d.ts +38 -0
- package/dist/engine/synapses.d.ts.map +1 -1
- package/dist/engine/synapses.js +116 -11
- package/dist/engine/synapses.js.map +1 -1
- package/dist/search/index.d.ts +18 -2
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/index.js +54 -10
- package/dist/search/index.js.map +1 -1
- package/dist/search/semantic.d.ts +8 -0
- package/dist/search/semantic.d.ts.map +1 -1
- package/dist/search/semantic.js +34 -12
- package/dist/search/semantic.js.map +1 -1
- package/dist/server.d.ts +7 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +764 -827
- package/dist/server.js.map +1 -1
- package/dist/sync/materialize.d.ts +1 -1
- package/dist/sync/materialize.d.ts.map +1 -1
- package/dist/sync/materialize.js +40 -3
- package/dist/sync/materialize.js.map +1 -1
- package/dist/sync/ops.d.ts +9 -4
- package/dist/sync/ops.d.ts.map +1 -1
- package/dist/sync/ops.js.map +1 -1
- package/dist/sync/space.d.ts +27 -0
- package/dist/sync/space.d.ts.map +1 -1
- package/dist/sync/space.js +113 -1
- package/dist/sync/space.js.map +1 -1
- package/dist/types/index.d.ts +29 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +56 -54
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|

|
|
10
10
|
|
|
11
|
-
Free and open source (MIT). All
|
|
11
|
+
Free and open source (MIT). All 15 tools included — no license, no account, no tiers.
|
|
12
12
|
|
|
13
13
|
> ⭐ **If CRBRO gives your AI a memory worth keeping, a star on GitHub is the best way to support it.**
|
|
14
14
|
|
|
@@ -17,9 +17,9 @@ Free and open source (MIT). All 23 tools included — no license, no account, no
|
|
|
17
17
|
- **🧬 Biological Architecture** — Knowledge organized as neurons (cortex), connections (synapses), and session memory (hippocampus)
|
|
18
18
|
- **🔍 Fact-Level Search** — Powered by [Orama](https://orama.com/). Every fact is indexed on its own, so a topic with hundreds of facts stays as findable as one with three. Each result comes back with the exact line that matched, when it was recorded, a `confidence` label (`weak` = little of the question was covered) and, for the top results, the topic's next best lines. A short bilingual synonym table widens the question without inventing terms *(v1.13+)*
|
|
19
19
|
- **🗣️ The model in the loop** — Two levers no embedding model replaces, measured blind: keywords written at save time (the caller knows the synonyms: a line about Hetzner gets *hosting, alojamiento, servidor*) and several phrasings searched at once, fused by rank. Zero disk, zero RAM; numbers in the table below *(v1.15+)*
|
|
20
|
-
- **🧭 Semantic
|
|
20
|
+
- **🧭 Semantic recall** — `npx crbro-memory init` installs a local embedding model (`multilingual-e5-small`, int8) fused with the keyword engine, so paraphrases the words do not cover start to land. Measured: +8 points of recall@1 over the keyword engine, +2 to +5 on top of save-time keywords. Costs ~500 MB on disk once per machine and ~0.5 GB of RAM while a server runs; `init --no-semantic` skips it, `CRBRO_SEMANTIC=0` turns it off *(v1.14+, installed by default since v1.16)*
|
|
21
21
|
- **🔥 Heat Scores** — Automatic relevance tracking based on frequency, recency, and connectivity. Topics written in the same session are linked at consolidation, so the graph fills itself in *(v1.13+)*
|
|
22
|
-
- **✏️ Correctable** — Knowledge can be superseded or retracted, not just piled up. A memory that only appends keeps serving yesterday's answer with today's confidence
|
|
22
|
+
- **✏️ Correctable** — Knowledge can be superseded or retracted, not just piled up — facts, and since 2.0 decisions, patterns, errors and debts too. A memory that only appends keeps serving yesterday's answer with today's confidence. What was retired stays in the file and can come back (`status=active`); what must not exist on disk goes through `crbro_forget`, quarantine copy first
|
|
23
23
|
- **🔐 Credential-aware** — API keys, tokens and passwords are replaced with a marker before they touch the disk. The sentence around them survives; the secret does not — and `crbro_secret` puts the real value in your operating system's own keychain, so refusing it does not leave you with nowhere to put it
|
|
24
24
|
- **👥 Safe with two editors open** — Writes are serialised per neuron, so running CRBRO in two IDEs at once does not silently lose facts
|
|
25
25
|
- **🤝 Shareable per project** — Put one project in a team space and it stays in step across everyone's machine. Everything else in your brain never leaves it
|
|
@@ -27,9 +27,10 @@ Free and open source (MIT). All 23 tools included — no license, no account, no
|
|
|
27
27
|
- **📓 Error Ledger** — `type: "error"` stores each real mistake WITH its correction, on the topic where it happened, so the same error is not made twice. Dated since 1.13, so the newer correction wins on recall
|
|
28
28
|
- **⚖️ Debt Ledger** — `type: "debt"` records what you deliberately did NOT build — ceiling and revisit-trigger included — so dead ideas stop being re-proposed *(v1.11+)*
|
|
29
29
|
- **🏷️ Honest tool definitions** — Every tool carries MCP annotations (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`), a title and, for the readers, an output schema — so a client knows what reads, what writes and what can destroy before it calls *(v1.13+)*
|
|
30
|
+
- **🧰 15 tools, one lifecycle** — Every read is a view of `crbro_inspect`; `crbro_learn`, `crbro_revise` and `crbro_forget` are the three stages of one rule (a new truth supersedes the old, an outdated one is retired, a dangerous one is removed), and every description says in its first sentence whether it reads or writes and which neighbour does the adjacent job. Down from 23 in 1.x without touching the brain on disk; `crbro_boot` maps the old names to the new calls *(v2.0+)*
|
|
30
31
|
- **🛡️ Subagent Hook (opt-in)** — `npx crbro-memory install-hooks --inject` wires a Claude Code hook that hands your behavioral protocols to spawned subagents. Injection is off by default since 1.12 — three clean-control benchmark runs found no measured benefit in any model and real harm in small ones, and shipping an unmeasured default is not what this project does
|
|
31
32
|
- **⛏️ Knowledge Miner** — Optionally scans your local `.md`/`.txt` notes and feeds them into the brain
|
|
32
|
-
- **🔒 Fully Local** — Runs on Node.js alone: no Python, no Docker, no databases, no external services. Your memory never leaves your machine
|
|
33
|
+
- **🔒 Fully Local** — Runs on Node.js alone: no Python, no Docker, no databases, no external services. Your memory never leaves your machine. The one download is the embedding model at `init`, from Hugging Face, once per machine; nothing calls out afterwards
|
|
33
34
|
- **💾 File-Based** — All data stored as readable JSON files in `~/.crbro/` — inspectable, diffable, and versionable with git
|
|
34
35
|
- **🔌 MCP Native** — Works with Claude Desktop, Claude Code, Cursor, Windsurf, and any MCP-compatible client
|
|
35
36
|
|
|
@@ -40,11 +41,11 @@ Every number below comes from a deterministic benchmark in [`benchmarks/`](bench
|
|
|
40
41
|
| What | Result | The honest part |
|
|
41
42
|
|------|--------|-----------------|
|
|
42
43
|
| **Retrieval** (48 blind paraphrased queries, written by someone who never saw the stored text) | recall@1 **71%** · recall@3 **77%** · MRR 0.74 — and **79% / 85%** counting the neuron's `also_matched` lines | Was 56% / 69% in 1.12. Of the 13 misses, 8 were the *right neuron answering with the wrong line* (its name chunk, or a sibling fact) — fixed in the engine; the rest are vocabulary gaps, which a short bilingual synonym table now closes in part. A naive substring search scores 38% / 58%. Still no semantic model: the remaining misses are listed in the benchmark output |
|
|
43
|
-
| **Retrieval with the
|
|
44
|
+
| **Retrieval with the semantic layer** (same 48 queries) | recall@1 **79%** · recall@3 **83%** · MRR 0.81 — **88% / 92%** counting `also_matched` | Vectors from `multilingual-e5-small` (int8) fused with BM25 by reciprocal rank. Alone, the model scores 60% / 83%; fused, it adds 8 points at recall@1 and no distractor reaches a real hit's score (0 of 14; 12 return something, 11 of them labelled `weak`). The cosine floor under which a vector-only candidate is dropped (0.84) was picked on this same set — a tuned number, not a blind one. Costs ~500 MB on disk, ~0.5 GB of RAM while the server runs, a one-time embedding pass (~3 min for a 4k-line brain) and ~13 s of model load per process. Installed by `init` since 1.16; `CRBRO_SEMANTIC=0` turns it off *(v1.14+)* |
|
|
44
45
|
| **Retrieval with the model in the loop** (same 48 queries; keywords and rewrites written blind by a model that saw only one half of the test) | keywords alone: recall@1 **83%** · recall@3 **90%** — everything on (keywords + rewrites + semantic layer): **90% / 92%**, and **96% / 98%** counting `also_matched` | The biggest lever costs nothing: 2-5 keywords written when a fact is saved close exactly the gaps no embedding model closed. Rewrites alone barely move the keyword engine (71% → 71% / 79%); they add up on top of keywords. Every configuration and the three questions still missed are in [`benchmarks/README.md`](benchmarks/README.md) *(v1.15+)* |
|
|
45
46
|
| **Retrieval — false confidence** (14 questions about things that are NOT stored) | 11 return *something*; **2** at a real hit's score; **10 of 11** labelled `weak` | A keyword memory answers almost anything. Every result now carries `confidence`, and the label catches nearly every distractor — at the price of also calling 18 of 48 real hits weak. Weak means "little of the question was covered", not "wrong" |
|
|
46
47
|
| **Secret redaction** (20 credentials in adversarial disguises, 19 near-miss innocents) | **100%** caught · **0%** false positives | 100% on *this frozen set* — a floor, not a security proof. The set grows as new evasion shapes appear; four of its entries were misses in the first run and were fixed, not hidden |
|
|
47
|
-
| **Cost** (what CRBRO adds to a session) | ~**750 tokens** at boot · **~
|
|
48
|
+
| **Cost** (what CRBRO adds to a session) | ~**750 tokens** at boot · **~6.5k tokens** of tool definitions · **<1 ms** local recall over 300 facts | The boot block is paid once. The 15 tool definitions (25,866 characters of description + input schema, measured with a real `tools/list` and divided by 4; 34,047 counting the output schemas of the three readers, ~8.5k tokens) are paid on every request by clients that load all tools (Claude Desktop, Cursor); Claude Code defers them and pays only for the ones it uses. Fewer tools, not fewer characters: the 23 of 1.13 measured 21,662 (~5.4k tokens), because each parameter's text now lives in the tool that absorbed it |
|
|
48
49
|
|
|
49
50
|
What these benchmarks deliberately do **not** claim — human productivity, "it knows you", comparisons against other memory systems — is written down in [`benchmarks/LIMITS.md`](benchmarks/LIMITS.md).
|
|
50
51
|
|
|
@@ -52,6 +53,8 @@ What these benchmarks deliberately do **not** claim — human productivity, "it
|
|
|
52
53
|
|
|
53
54
|
### 1. Initialize
|
|
54
55
|
|
|
56
|
+
Creates the brain in `~/.crbro/` and, since 1.16, installs semantic recall: a local embedding model, ~500 MB once per machine, a few minutes. Add `--no-semantic` to skip it.
|
|
57
|
+
|
|
55
58
|
```bash
|
|
56
59
|
npx crbro-memory init
|
|
57
60
|
```
|
|
@@ -93,14 +96,14 @@ claude mcp add --scope user crbro -- npx -y crbro-memory
|
|
|
93
96
|
}
|
|
94
97
|
```
|
|
95
98
|
|
|
96
|
-
**Docker** (the brain lives in `/root/.crbro`; mount a volume to keep it):
|
|
99
|
+
**Docker** (the brain lives in `/root/.crbro`; mount a volume to keep it. The image carries no semantic runtime, so recall is keyword-only there):
|
|
97
100
|
```bash
|
|
98
101
|
docker build -t crbro-memory . && docker run -i -v crbro-brain:/root/.crbro crbro-memory
|
|
99
102
|
```
|
|
100
103
|
|
|
101
104
|
### 3. Start using it
|
|
102
105
|
|
|
103
|
-
Your AI will now have access to
|
|
106
|
+
Your AI will now have access to 15 memory tools. Start any session with `crbro_boot`.
|
|
104
107
|
|
|
105
108
|
### 4. (Claude Code, optional) The subagent hook
|
|
106
109
|
|
|
@@ -116,29 +119,52 @@ Session context never reaches Task-spawned subagents, so this hook can inject th
|
|
|
116
119
|
|
|
117
120
|
| Tool | Description |
|
|
118
121
|
|------|-------------|
|
|
119
|
-
| `crbro_boot` | Boot the brain at session start — loads hot topics and
|
|
120
|
-
| `
|
|
121
|
-
| `crbro_learn` | Store a fact, decision, pattern, preference, error or debt — with the keywords a future question may use |
|
|
122
|
-
| `crbro_neuron` | Read a specific neuron (topic) with all its knowledge |
|
|
123
|
-
| `crbro_neurons` | List neurons with optional filters (domain, type, heat) |
|
|
122
|
+
| `crbro_boot` | Boot the brain at session start — loads hot topics, context, the last three sessions and the `retired_tools` map |
|
|
123
|
+
| `crbro_inspect` | Read-only views by id or name: `view=status`, `neuron`, `neurons`, `sessions`, `global_map` |
|
|
124
|
+
| `crbro_learn` | Store a fact, decision, pattern, preference, error or debt — with the keywords a future question may use. `supersedes` retires the old version in the same call |
|
|
124
125
|
| `crbro_recall` | Search every stored line, not just topic names — returns what matched, how confidently, and the topic's next best lines. Several phrasings at once are fused by rank |
|
|
125
|
-
| `
|
|
126
|
-
| `
|
|
127
|
-
| `
|
|
128
|
-
| `
|
|
129
|
-
| `crbro_context` | Read/update active working context |
|
|
130
|
-
| `crbro_hot_topics` | Get the most active topics by heat score |
|
|
126
|
+
| `crbro_revise` | Retire facts (and decisions, patterns, errors, debts via `entries`) as superseded or retracted, reactivate them with `status=active`, and edit summary, domain, tags or name |
|
|
127
|
+
| `crbro_forget` | Remove for good, keeping a copy in `.quarantine/` first — entries of a neuron, a whole neuron (two-step with `confirm_token`), a session log; `restore` and `merge_into` too |
|
|
128
|
+
| `crbro_connect` | Create, strengthen, set the strength of or delete (`action=disconnect`) a connection between neurons |
|
|
129
|
+
| `crbro_context` | Read (no arguments) or update the active working context — topics, open items, discard or clear |
|
|
131
130
|
| `crbro_map` | Keep one living map of how a topic's system works — replaced whole, never patched |
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `crbro_audit` | Find credentials stored in the brain — reports the kind, never the value |
|
|
135
|
-
| `crbro_forget` | Remove facts for good, keeping a copy in `.quarantine/` first |
|
|
131
|
+
| `crbro_consolidate` | End-of-session consolidation — the only way to log a session; links the topics it wrote and syncs spaces |
|
|
132
|
+
| `crbro_maintenance` | Brain maintenance — heat, pruning, integrity, `repair`, `unarchive`, index rebuild |
|
|
133
|
+
| `crbro_audit` | Find credentials stored in the brain, session logs included — reports the kind, never the value |
|
|
136
134
|
| `crbro_secret` | Put a credential in the OS keychain and keep only its name in the brain |
|
|
137
|
-
| `crbro_space` | Create or
|
|
138
|
-
| `crbro_share` | Put one project into a space, after showing exactly what would be sent |
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
135
|
+
| `crbro_space` | Create, join, `sync` or `leave` a team space — a private git repo for shared projects |
|
|
136
|
+
| `crbro_share` | Put one project into a space, after showing exactly what would be sent; `unshare` stops following it |
|
|
137
|
+
|
|
138
|
+
### Upgrading from 1.x
|
|
139
|
+
|
|
140
|
+
2.0 went from 23 tools to 15 without touching the brain on disk: a 1.x brain
|
|
141
|
+
opens as it is, and the search index rebuilds itself once. The seven read
|
|
142
|
+
tools became views of `crbro_inspect`, the session log lives only in
|
|
143
|
+
`crbro_consolidate`, and `crbro_sync` is now `crbro_space action=sync`. The
|
|
144
|
+
eight verbs the cards teach (`boot`, `learn`, `recall`, `revise`, `forget`,
|
|
145
|
+
`connect`, `context`, `consolidate`) kept their names and their parameters.
|
|
146
|
+
`crbro_boot` returns the table below as `retired_tools` on every call, so a
|
|
147
|
+
model that learned the old surface finds its way without reading the docs; a
|
|
148
|
+
client that calls a retired name outright gets the MCP "unknown tool" error.
|
|
149
|
+
|
|
150
|
+
| Retired | Use instead |
|
|
151
|
+
|---------|-------------|
|
|
152
|
+
| `crbro_status` | `crbro_inspect view=status` |
|
|
153
|
+
| `crbro_neuron` | `crbro_inspect view=neuron neuron=<id or name>` |
|
|
154
|
+
| `crbro_neurons` | `crbro_inspect view=neurons [domain\|type\|min_heat\|limit\|offset]` |
|
|
155
|
+
| `crbro_hot_topics` | `crbro_inspect view=neurons` (rows) and `view=status` (`hot_topics_recalculated`) |
|
|
156
|
+
| `crbro_connections` | `crbro_inspect view=neuron neuron=<id> [min_strength]` |
|
|
157
|
+
| `crbro_sessions` | `crbro_inspect view=sessions [limit]` |
|
|
158
|
+
| `crbro_global_map` | `crbro_inspect view=global_map` |
|
|
159
|
+
| `crbro_session_log` | `crbro_consolidate summary=... [topics_touched=[...]]` — `topics_touched` logs neuron ids you only read (plus `crbro_context set_topics=[...]` to replace the active topics) |
|
|
160
|
+
| `crbro_sync` | `crbro_space action=sync [name]` |
|
|
161
|
+
|
|
162
|
+
If you use the Claude Code hooks, drop `mcp__crbro__crbro_session_log` from
|
|
163
|
+
any matcher in `~/.claude/settings.json` and from the session-start text:
|
|
164
|
+
every session start would otherwise order a call to a tool that no longer
|
|
165
|
+
exists. Cannot move yet? 1.x stays installable with `npx -y crbro-memory@1`;
|
|
166
|
+
it receives no new features. What changed inside each surviving tool is in
|
|
167
|
+
[CHANGELOG.md](CHANGELOG.md).
|
|
142
168
|
|
|
143
169
|
## Credentials
|
|
144
170
|
|
|
@@ -213,10 +239,12 @@ know next time they sit down.
|
|
|
213
239
|
- Credentials. `crbro_share` refuses outright if it finds one, and tells you
|
|
214
240
|
where. It will not redact it and send the rest.
|
|
215
241
|
|
|
216
|
-
> **
|
|
217
|
-
>
|
|
218
|
-
>
|
|
219
|
-
>
|
|
242
|
+
> **What was sent stays sent.** `crbro_share unshare:true` stops following a
|
|
243
|
+
> project — no more notes go out and the next sync ignores it — but once a
|
|
244
|
+
> teammate has pulled it, it is on their disk. Removing their repository
|
|
245
|
+
> access stops anything new from reaching them; it does not take back what
|
|
246
|
+
> they already have. That is true of any sync system — worth knowing before
|
|
247
|
+
> you share, not after.
|
|
220
248
|
|
|
221
249
|
## Architecture
|
|
222
250
|
|
|
@@ -232,8 +260,9 @@ know next time they sit down.
|
|
|
232
260
|
│ └── session_2026-05-06.json
|
|
233
261
|
├── prefrontal/ ← Working memory
|
|
234
262
|
│ ├── active_context.json
|
|
235
|
-
│
|
|
236
|
-
|
|
263
|
+
│ └── hot_topics.json (the global map is computed live since 2.0, never stored)
|
|
264
|
+
├── .quarantine/ ← What crbro_forget removed, kept until you delete it
|
|
265
|
+
├── unshared.json ← Projects you stopped following in a space (after an unshare)
|
|
237
266
|
├── archives/ ← Cold neurons (opt-in; nothing is archived unless you ask)
|
|
238
267
|
├── shared/ ← One git repo per team space. Notes only, never the cortex
|
|
239
268
|
│ └── team/
|
|
@@ -271,21 +300,21 @@ npx crbro-memory init # Initialize brain + detect IDEs
|
|
|
271
300
|
npx crbro-memory status # Show brain status
|
|
272
301
|
npx crbro-memory reindex # Rebuild the search index
|
|
273
302
|
npx crbro-memory eval # Measure retrieval quality against your own query set
|
|
274
|
-
npx crbro-memory semantic
|
|
303
|
+
npx crbro-memory semantic status | install | build # Semantic recall (installed by init; below)
|
|
275
304
|
npx crbro-memory --help # Help
|
|
276
305
|
```
|
|
277
306
|
|
|
278
|
-
### Semantic
|
|
307
|
+
### Semantic recall
|
|
279
308
|
|
|
280
|
-
The keyword engine has no synonyms, and the blind benchmark shows exactly where that bites:
|
|
309
|
+
The keyword engine has no synonyms, and the blind benchmark shows exactly where that bites: paraphrases — *"where are the sites hosted"* for a fact about a Hetzner VPS. Keywords written at save time close most of that gap for free (above); a small embedding model closes a little more. Since 1.16 `npx crbro-memory init` installs it by default, once per machine, and the layer is on wherever its runtime is present. What it costs, measured: ~500 MB on disk (runtime ~380 MB + model 118 MB), ~0.5 GB of RAM while a server runs, ~13 s of model load per process (in the background) and a one-time embedding pass. Skip it with `init --no-semantic`; turn it off any time with `CRBRO_SEMANTIC=0` in the server's env.
|
|
281
310
|
|
|
282
311
|
```bash
|
|
283
|
-
npx crbro-memory
|
|
284
|
-
|
|
285
|
-
npx crbro-memory semantic build #
|
|
312
|
+
npx crbro-memory init # installs it (skip with --no-semantic)
|
|
313
|
+
npx crbro-memory semantic status # runtime, model, on or off, and why
|
|
314
|
+
npx crbro-memory semantic build # embed an existing brain once (a 4k-line brain: ~3 min)
|
|
286
315
|
```
|
|
287
316
|
|
|
288
|
-
|
|
317
|
+
Every new line is embedded when it is saved (ids are content hashes, so nothing is embedded twice), the model warms in the background after boot, and `crbro_recall` fuses both rankings by reciprocal rank. Results the vectors ranked carry `semantic_score`; a vector-only match is `strong` from cosine 0.86. With `CRBRO_SEMANTIC=0`, or without the runtime, no vectors are read and no model is loaded: recall is the keyword engine byte for byte.
|
|
289
318
|
|
|
290
319
|
The model is `multilingual-e5-small` and stays so on purpose. `CRBRO_SEMANTIC_MODEL` accepts any e5-family model, and `e5-base` and `e5-large` were measured on the same benchmark: the large one is the better model alone (71% vs 63% recall@1) but fused with the keyword engine it scores the same or worse (75% / 85% vs 79% / 83%) for 4× the disk, 1.2 GB of RAM and 6× the time per line. The table is in [`benchmarks/README.md`](benchmarks/README.md).
|
|
291
320
|
|
package/bin/crbro.mjs
CHANGED
|
@@ -112,6 +112,51 @@ function generateMCPSnippet(envVars) {
|
|
|
112
112
|
|
|
113
113
|
// ─── Commands ───────────────────────────────────────────────────
|
|
114
114
|
|
|
115
|
+
// ─── Semantic recall: install, download, embed ──────────────────────
|
|
116
|
+
// Installed by `init` since 1.16 (skip with --no-semantic, turn off with
|
|
117
|
+
// CRBRO_SEMANTIC=0). The runtime (~380 MB) and the model (~118 MB) live in
|
|
118
|
+
// ~/.crbro/.semantic once per machine, outside the package.
|
|
119
|
+
async function semanticInstall(sem) {
|
|
120
|
+
const { spawnSync } = await import('child_process');
|
|
121
|
+
const fs = await import('fs');
|
|
122
|
+
const os = await import('os');
|
|
123
|
+
const home = sem.semanticHome();
|
|
124
|
+
fs.mkdirSync(home, { recursive: true });
|
|
125
|
+
const pkg = join(home, 'package.json');
|
|
126
|
+
if (!fs.existsSync(pkg)) {
|
|
127
|
+
fs.writeFileSync(pkg, JSON.stringify({ name: 'crbro-semantic', private: true }, null, 2));
|
|
128
|
+
}
|
|
129
|
+
if (!sem.resolveRuntime()) {
|
|
130
|
+
console.log(` ⬇️ Installing transformers.js into ${home} (~380 MB with onnxruntime)...`);
|
|
131
|
+
const r = spawnSync('npm', ['install', '--no-audit', '--no-fund', '--loglevel=error', '@huggingface/transformers@3'],
|
|
132
|
+
{ cwd: home, stdio: 'inherit', shell: true });
|
|
133
|
+
if (r.status !== 0) return false;
|
|
134
|
+
}
|
|
135
|
+
const st = sem.semanticStatus();
|
|
136
|
+
if (!st.model_downloaded) {
|
|
137
|
+
console.log(` ⬇️ Downloading the model (${st.model}, ~118 MB)...`);
|
|
138
|
+
const idx = new sem.SemanticIndex(fs.mkdtempSync(join(os.tmpdir(), 'crbro-warm-')));
|
|
139
|
+
await idx.upsert([{ id: 'warm', text: 'hello' }]); // the first use downloads and caches it
|
|
140
|
+
}
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function semanticBuild() {
|
|
145
|
+
process.env.CRBRO_SEMANTIC = '1';
|
|
146
|
+
const [{ Brain }, { SearchEngine }] = await Promise.all([
|
|
147
|
+
import('../dist/engine/brain.js'),
|
|
148
|
+
import('../dist/search/index.js'),
|
|
149
|
+
]);
|
|
150
|
+
const brain = new Brain();
|
|
151
|
+
const engine = new SearchEngine(brain);
|
|
152
|
+
const started = Date.now();
|
|
153
|
+
await engine.init(); // loads the stored vectors: unchanged lines are not embedded twice
|
|
154
|
+
const chunks = await engine.rebuild();
|
|
155
|
+
await engine.awaitEmbeddings();
|
|
156
|
+
await engine.persist();
|
|
157
|
+
return { chunks, vectors: engine.semanticCount(), seconds: ((Date.now() - started) / 1000).toFixed(1) };
|
|
158
|
+
}
|
|
159
|
+
|
|
115
160
|
if (command === 'init') {
|
|
116
161
|
// ─── Initialize brain + IDE detection ──────────────────────────
|
|
117
162
|
import('../dist/engine/brain.js').then(async ({ Brain }) => {
|
|
@@ -142,6 +187,28 @@ if (command === 'init') {
|
|
|
142
187
|
|
|
143
188
|
console.log('');
|
|
144
189
|
console.log(' ' + generateMCPSnippet().split('\n').join('\n '));
|
|
190
|
+
// Semantic recall, installed by default since 1.16: once per machine,
|
|
191
|
+
// about 500 MB on disk, ~0.5 GB of RAM while a server runs.
|
|
192
|
+
const skipSemantic = args.includes('--no-semantic')
|
|
193
|
+
|| ['0', 'off', 'false'].includes(String(process.env.CRBRO_SEMANTIC || '').toLowerCase());
|
|
194
|
+
console.log('');
|
|
195
|
+
if (skipSemantic) {
|
|
196
|
+
console.log(' npx crbro-memory semantic status Semantic recall (installed by init; --no-semantic skips it): status | install | build');
|
|
197
|
+
} else {
|
|
198
|
+
console.log(' 🧭 Semantic recall: installing (once per machine, ~500 MB)...');
|
|
199
|
+
try {
|
|
200
|
+
const sem = await import('../dist/search/semantic.js');
|
|
201
|
+
const ok = await semanticInstall(sem);
|
|
202
|
+
if (ok) {
|
|
203
|
+
const r = await semanticBuild();
|
|
204
|
+
console.log(` ✅ Semantic recall ready · ${r.vectors} lines embedded in ${r.seconds}s · CRBRO_SEMANTIC=0 turns it off`);
|
|
205
|
+
} else {
|
|
206
|
+
console.log(' ⚠️ Could not install it; recall stays keyword-only. Retry: npx crbro-memory semantic install');
|
|
207
|
+
}
|
|
208
|
+
} catch (err) {
|
|
209
|
+
console.log(` ⚠️ Semantic recall not installed (${err instanceof Error ? err.message : err}); recall stays keyword-only.`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
145
212
|
console.log('');
|
|
146
213
|
console.log(' Next steps:');
|
|
147
214
|
console.log(' 1. Add the config above to your IDE\'s MCP settings');
|
|
@@ -310,39 +377,21 @@ if (command === 'init') {
|
|
|
310
377
|
}).catch(console.error);
|
|
311
378
|
|
|
312
379
|
} else if (command === 'semantic') {
|
|
313
|
-
// ───
|
|
314
|
-
//
|
|
315
|
-
// Nothing semantic exists until the user runs `semantic install` AND sets
|
|
316
|
-
// CRBRO_SEMANTIC=1 in the server's env. The runtime (~380 MB with
|
|
317
|
-
// onnxruntime) and the model (~118 MB) live in ~/.crbro/.semantic, once per
|
|
318
|
-
// machine, outside the package — most users never need either.
|
|
380
|
+
// ─── Semantic recall: status | install | build ─────────────────
|
|
319
381
|
const sub = args[1];
|
|
320
382
|
import('../dist/search/semantic.js').then(async (sem) => {
|
|
321
383
|
if (sub === 'install') {
|
|
322
|
-
const { spawnSync } = await import('child_process');
|
|
323
|
-
const fs = await import('fs');
|
|
324
|
-
const home = sem.semanticHome();
|
|
325
|
-
fs.mkdirSync(home, { recursive: true });
|
|
326
|
-
const pkg = join(home, 'package.json');
|
|
327
|
-
if (!fs.existsSync(pkg)) {
|
|
328
|
-
fs.writeFileSync(pkg, JSON.stringify({ name: 'crbro-semantic', private: true }, null, 2));
|
|
329
|
-
}
|
|
330
384
|
console.log('');
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
{ cwd: home, stdio: 'inherit', shell: true });
|
|
334
|
-
if (r.status !== 0) {
|
|
385
|
+
const ok = await semanticInstall(sem);
|
|
386
|
+
if (!ok) {
|
|
335
387
|
console.log(' ❌ npm install failed. Nothing else changed.');
|
|
336
388
|
process.exit(1);
|
|
337
389
|
}
|
|
338
|
-
|
|
339
|
-
console.log(` ✅
|
|
340
|
-
console.log('
|
|
341
|
-
console.log(' 2. Run once: npx crbro-memory semantic build (embeds the whole brain)');
|
|
342
|
-
console.log(' Recall stays lexical until both are done; new lines are embedded as they are saved.');
|
|
390
|
+
const r = await semanticBuild();
|
|
391
|
+
console.log(` ✅ Semantic recall ready · ${r.chunks} chunks indexed · ${r.vectors} vectors · ${r.seconds}s`);
|
|
392
|
+
console.log(' It is on whenever this runtime is present; CRBRO_SEMANTIC=0 turns it off.');
|
|
343
393
|
console.log('');
|
|
344
394
|
} else if (sub === 'build') {
|
|
345
|
-
process.env.CRBRO_SEMANTIC = '1';
|
|
346
395
|
const st = sem.semanticStatus();
|
|
347
396
|
if (!st.installed) {
|
|
348
397
|
console.log('');
|
|
@@ -350,30 +399,24 @@ if (command === 'init') {
|
|
|
350
399
|
console.log('');
|
|
351
400
|
return;
|
|
352
401
|
}
|
|
353
|
-
const [{ Brain }, { SearchEngine }] = await Promise.all([
|
|
354
|
-
import('../dist/engine/brain.js'),
|
|
355
|
-
import('../dist/search/index.js'),
|
|
356
|
-
]);
|
|
357
|
-
const brain = new Brain();
|
|
358
|
-
const engine = new SearchEngine(brain);
|
|
359
402
|
console.log('');
|
|
360
|
-
console.log(' 🧭 Embedding the brain
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
await engine.persist();
|
|
364
|
-
const seconds = ((Date.now() - started) / 1000).toFixed(1);
|
|
365
|
-
console.log(` ✅ ${n} chunks indexed · ${engine.semanticCount()} vectors stored · ${seconds}s`);
|
|
403
|
+
console.log(' 🧭 Embedding the brain...');
|
|
404
|
+
const r = await semanticBuild();
|
|
405
|
+
console.log(` ✅ ${r.chunks} chunks indexed · ${r.vectors} vectors stored · ${r.seconds}s`);
|
|
366
406
|
console.log(' From now on each new line is embedded when it is saved.');
|
|
367
407
|
console.log('');
|
|
368
408
|
} else {
|
|
369
409
|
const st = sem.semanticStatus();
|
|
410
|
+
const enabled = st.enabled
|
|
411
|
+
? (st.mode === 'forced' ? '✅ on (CRBRO_SEMANTIC=1)' : '✅ on (installed; CRBRO_SEMANTIC=0 turns it off)')
|
|
412
|
+
: (st.mode === 'disabled' ? '⚪ off (CRBRO_SEMANTIC=0)' : '⚪ off (not installed)');
|
|
370
413
|
console.log('');
|
|
371
|
-
console.log(' 🧭 CRBRO semantic
|
|
372
|
-
console.log('
|
|
373
|
-
console.log(` Runtime: ${st.installed ? '✅ installed' : '❌ not installed → npx crbro-memory semantic install'}`);
|
|
374
|
-
console.log(`
|
|
414
|
+
console.log(' 🧭 CRBRO semantic recall');
|
|
415
|
+
console.log(' ────────────────────────');
|
|
416
|
+
console.log(` Runtime: ${st.installed ? '✅ installed' : '❌ not installed → npx crbro-memory init (or: semantic install)'}`);
|
|
417
|
+
console.log(` Model: ${st.model}${st.model_downloaded ? '' : ' (downloads on first use)'}`);
|
|
418
|
+
console.log(` Enabled: ${enabled}`);
|
|
375
419
|
console.log(` Home: ${st.home}`);
|
|
376
|
-
console.log(` Model: ${st.model}`);
|
|
377
420
|
console.log('');
|
|
378
421
|
}
|
|
379
422
|
}).catch(console.error);
|
package/dist/engine/brain.js
CHANGED
|
@@ -14,7 +14,7 @@ const MANIFEST_FILE = 'manifest.json';
|
|
|
14
14
|
// The brain FORMAT, not the release. It moves only when the on-disk layout
|
|
15
15
|
// changes in a way that needs a migration, which is why it has stayed at 1.0.0
|
|
16
16
|
// while the package went to 1.8. The running version is reported separately by
|
|
17
|
-
//
|
|
17
|
+
// crbro_inspect view=status.
|
|
18
18
|
const CRBRO_VERSION = '1.0.0';
|
|
19
19
|
// ─── Paths ───────────────────────────────────────────────────────
|
|
20
20
|
class BrainPaths {
|
package/dist/engine/brain.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"brain.js","sourceRoot":"","sources":["../../src/engine/brain.ts"],"names":[],"mappings":";AAAA,oEAAoE;AACpE,gEAAgE;;;;;;AAEhE,0DAA6B;AAC7B,qCAAyC;AACzC,0CAAqF;AAGrF,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,mBAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,GAAG,EAAE,QAAQ,CAAC,CAAC;AAC7H,MAAM,aAAa,GAAG,eAAe,CAAC;AACtC,2EAA2E;AAC3E,+EAA+E;AAC/E,+EAA+E;AAC/E,
|
|
1
|
+
{"version":3,"file":"brain.js","sourceRoot":"","sources":["../../src/engine/brain.ts"],"names":[],"mappings":"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"}
|