recallnest 2.6.0 → 3.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/CHANGELOG.md +191 -0
- package/README.md +131 -14
- package/README_CN.md +121 -17
- package/config.json.example +8 -1
- package/docs/api-reference.md +1 -1
- package/integrations/README.md +1 -1
- package/integrations/agy/README.md +73 -0
- package/integrations/agy/setup.sh +75 -0
- package/integrations/setup-all.sh +1 -1
- package/package.json +7 -5
- package/src/__tests__/access-tracker-novelty.test.ts +22 -2
- package/src/__tests__/activity-counter.test.ts +38 -38
- package/src/__tests__/age-label.test.ts +33 -0
- package/src/__tests__/cluster-consolidation.test.ts +313 -22
- package/src/__tests__/consolidation-engine.test.ts +90 -0
- package/src/__tests__/contracts.test.ts +2 -2
- package/src/__tests__/data-checkup.test.ts +31 -3
- package/src/__tests__/dream-pipeline.test.ts +41 -1
- package/src/__tests__/dream-scope-isolation.test.ts +386 -0
- package/src/__tests__/dream-write-batching.test.ts +211 -0
- package/src/__tests__/env-config-invariant.test.ts +80 -0
- package/src/__tests__/env-config.test.ts +60 -0
- package/src/__tests__/ingest-scope-prefix.test.ts +69 -0
- package/src/__tests__/maintenance-locks.test.ts +8 -0
- package/src/__tests__/memory-evolution-b2-b3-e1.test.ts +17 -0
- package/src/__tests__/memory-output.test.ts +9 -0
- package/src/__tests__/memory-utility.test.ts +256 -0
- package/src/__tests__/openai-contract.test.ts +513 -0
- package/src/__tests__/promotion-distinct-sources.test.ts +162 -0
- package/src/__tests__/retrieve-audit-revision.test.ts +255 -0
- package/src/__tests__/source-heartbeat.test.ts +6 -2
- package/src/__tests__/store-patch-metadata.test.ts +30 -0
- package/src/__tests__/synthesis-contract.test.ts +252 -0
- package/src/__tests__/synthesis-promotion.test.ts +369 -0
- package/src/__tests__/trusted-memory.test.ts +28 -0
- package/src/__tests__/utility-weight.test.ts +57 -0
- package/src/__tests__/verbatim-self-recall.test.ts +279 -0
- package/src/__tests__/version-manager.test.ts +35 -0
- package/src/access-tracker.ts +10 -1
- package/src/activity-counter.ts +69 -11
- package/src/age-label.ts +29 -0
- package/src/audit-log.ts +35 -0
- package/src/auto-gc.ts +97 -30
- package/src/cli.ts +224 -10
- package/src/consolidation-engine.ts +317 -123
- package/src/data-checkup.ts +17 -3
- package/src/dream-pipeline.ts +90 -12
- package/src/embedder.ts +20 -5
- package/src/env-config.ts +53 -0
- package/src/forget-engine.ts +8 -2
- package/src/gateway-server.ts +272 -0
- package/src/ingest.ts +23 -5
- package/src/llm-client.ts +86 -25
- package/src/mcp-server.ts +2 -1
- package/src/mcp-tools-advanced.ts +7 -2
- package/src/mcp-tools-core.ts +11 -1
- package/src/mcp-tools-governance.ts +45 -3
- package/src/memory-evolution.ts +16 -0
- package/src/memory-output.ts +12 -8
- package/src/memory-promotion.ts +280 -0
- package/src/memory-store-port.ts +32 -3
- package/src/memory-utility.ts +314 -0
- package/src/recall-ledger.ts +76 -0
- package/src/retriever.ts +82 -9
- package/src/scope-policy.ts +22 -1
- package/src/session-output.ts +4 -3
- package/src/skill-promotion.ts +152 -1
- package/src/store.ts +231 -71
- package/src/synthesis-contract.ts +286 -0
- package/src/version-manager.ts +83 -0
- package/src/workflow-observation-schema.ts +26 -0
- package/integrations/gemini-cli/README.md +0 -57
- package/integrations/gemini-cli/setup.sh +0 -64
- /package/integrations/{gemini-cli/gemini-md-snippet.md → agy/agy-md-snippet.md} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,196 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v3.0.0 — Node 22, and conclusions that can be used (2026-08-24)
|
|
4
|
+
|
|
5
|
+
Two things make this a major release: the runtime floor moves, and a synthesized
|
|
6
|
+
conclusion can finally reach stable memory. Everything else here is either in service of
|
|
7
|
+
those or was found while doing them.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **`engines.node` is now `>=22`** (was `>=18.14.1`). This is the only breaking change in
|
|
12
|
+
the release; Bun users are unaffected.
|
|
13
|
+
- **`openai` migrated from `^4.0.0` to `^7.5.0`**, which removes the
|
|
14
|
+
`openai@4 → formdata-node@4.4.1 → node-domexception@1.0.0` deprecated chain from the
|
|
15
|
+
dependency tree. Every `openai` release since v5 has zero dependencies, so the chain
|
|
16
|
+
disappears on any upgrade — v7 was chosen because it declares `engines.node >= 22.0.0`,
|
|
17
|
+
making the Node floor and the dependency cleanup one decision instead of two. Verified
|
|
18
|
+
against the SDK rather than its migration guide: the guide documents the `httpAgent`
|
|
19
|
+
removal, the move to built-in `fetch`, and the Node 22 floor, but says nothing about the
|
|
20
|
+
three things this codebase actually depends on — `embeddings.create`, the second
|
|
21
|
+
`RequestOptions` argument on `chat.completions.create`, and the error classes exposed as
|
|
22
|
+
statics on the default export. All three hold.
|
|
23
|
+
- **MCP tool count is 44**, up from 43 (`promote_synthesis`, governance tier).
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- **`promote_synthesis` (MCP) and `recallnest promote-synthesis` (CLI)** — a promotion road
|
|
28
|
+
for dream-synthesized conclusions. `buildDerivedBoundary` marks every cluster insight and
|
|
29
|
+
cross-memory pattern `layer: "evidence"` on purpose, and `shouldUseStableMemoryResult`
|
|
30
|
+
refuses the evidence layer, so a synthesized conclusion could never take part in stable
|
|
31
|
+
memory regardless of how well supported it was. Eligibility comes from the conclusion's
|
|
32
|
+
own validated evidence set — `synthesis_contract >= 2`, at least two distinct still-active
|
|
33
|
+
evidence memories — rather than from repetition, because a synthesis is already a
|
|
34
|
+
cross-entry aggregate. It abstains when the evidence cannot be resolved, counts every
|
|
35
|
+
rejection reason, defaults to dry-run, never modifies the synthesized row, and writes
|
|
36
|
+
through the existing `promoteMemory` path so `canonicalKey` dedup makes a re-run a
|
|
37
|
+
revision instead of a duplicate.
|
|
38
|
+
- **Retrieve audit rows carry revision and provenance.** `retrieved[]` records each served
|
|
39
|
+
result's id, `evolution.version`, lifecycle status, and boundary layer/authority;
|
|
40
|
+
`retrievedTotal` appears when the capped list is shorter than the truth. Beliefs are
|
|
41
|
+
revised in place — the canonical id survives, the version increments, the old text
|
|
42
|
+
remains as a `superseded` row — so a row saying only `hits=N` could not distinguish a
|
|
43
|
+
current answer from a stale one after the fact.
|
|
44
|
+
- **HTTP contract tests for embeddings and chat completions** (`openai-contract.test.ts`).
|
|
45
|
+
Every prior embedder/LLM test stubbed the SDK client, so none of them touched a socket
|
|
46
|
+
and a transport-level regression would have passed all of them. These drive the real
|
|
47
|
+
`Embedder` and `LLMClient` through the real SDK against a loopback `node:http` server,
|
|
48
|
+
covering success, error, and timeout for the default OpenAI request shape plus the Jina
|
|
49
|
+
(`task`/`normalized`/`dimensions`) and Qwen-compatible profiles. No network egress, no
|
|
50
|
+
vendor credentials, no paid calls.
|
|
51
|
+
- **A repeatable regression for verbatim self-recall** (`verbatim-self-recall.test.ts`).
|
|
52
|
+
A long, older, rarely-read entry can fail to be recalled by words copied out of its own
|
|
53
|
+
body while short, fresh, frequently-read entries outrank it. The reproduction pins the
|
|
54
|
+
mechanism: the entry is *not* filtered — `hard_min_score`, `layer_admission` and
|
|
55
|
+
`noise_filter` each drop zero rows and its score clears the threshold — it is admitted
|
|
56
|
+
and then ranked last. The ranking fix is deliberately not in this release.
|
|
57
|
+
- **`scripts/tier-exemption-snapshot.ts`** — captures tier and decay-exemption distribution
|
|
58
|
+
so "we did not change tiers" becomes checkable later rather than asserted.
|
|
59
|
+
|
|
60
|
+
### Added — synthesis quality (generation side)
|
|
61
|
+
|
|
62
|
+
Six changes to what `dream` produces, from a full diagnostic on 2026-08-22 whose core
|
|
63
|
+
finding was that **derived memories had a lower conclusion density than their own input**:
|
|
64
|
+
over the same 40–160 character band, with a deterministic regex and no LLM judge,
|
|
65
|
+
hand-written pivots scored 40.4%, raw transcripts 25.1%, insights 14.4%, patterns 12.1%.
|
|
66
|
+
Synthesis was subtracting.
|
|
67
|
+
|
|
68
|
+
- **`cluster_insight` no longer routes through `generateL0`.** That prompt is a chunk
|
|
69
|
+
summariser — it asks for a one-line summary for retrieval and explicitly preserves ports,
|
|
70
|
+
IPs, URLs and file paths verbatim; it never asks for a conclusion, a cause, or a decision.
|
|
71
|
+
The new `synthesizeClusterInsight` goes through `synthesis-contract.ts`, asks for a
|
|
72
|
+
reusable conclusion, and **may abstain**. The old path's `if (!insight)` only fired when
|
|
73
|
+
the LLM call itself failed, so "this cluster is not worth keeping" had no way to be
|
|
74
|
+
expressed and all 2,427 rows were episode summaries by construction.
|
|
75
|
+
- **`extractPattern` changed target concept and now requires evidence.** The old prompt
|
|
76
|
+
asked for recurring preferences, behavioural tendencies and values — a personality-profile
|
|
77
|
+
frame, which produced dispositional attribution in 56.1% of outputs against 1.4% in the
|
|
78
|
+
source material. The old prompt also claimed to want "at least 2 memories as supporting
|
|
79
|
+
evidence" while the implementation neither received nor checked any numbering, making the
|
|
80
|
+
sentence free. Two pieces of evidence is now a hard gate.
|
|
81
|
+
- **`validateSynthesis` runs before anything is written.** The old path checked only
|
|
82
|
+
`response.length < 5`, which is how 28 memories ended up holding their own system prompt
|
|
83
|
+
as their body. `has` must be a boolean, length must be in range, the text must not echo
|
|
84
|
+
the prompt, and evidence numbers must refer to real, distinct cluster members. Failures
|
|
85
|
+
are counted by reason instead of collapsing into one `null`.
|
|
86
|
+
- **Pattern and insight are decoupled.** `if (!insight) { continue; }` bound two different
|
|
87
|
+
target concepts to one fate: an abstaining insight meant pattern extraction never ran.
|
|
88
|
+
They now fail and abstain independently, and "this round produced nothing" is judged on
|
|
89
|
+
whether the cluster had any effect at all rather than on whether an insight existed.
|
|
90
|
+
- **Derived rows carry an explicit `boundary`.** All 4,749 historical derivatives had none;
|
|
91
|
+
the retriever's `isEvidenceLayer` fell back to scope matching, so 96.4% were classified
|
|
92
|
+
correctly only because they happened to sit in a `cc:`/`codex:` scope — by luck of naming,
|
|
93
|
+
not by design. The remaining 173 sat in `memory`/`project:*` scopes and silently held
|
|
94
|
+
durable authority. Derived rows are `layer: "evidence"`, `authority: "distillation"`.
|
|
95
|
+
- **`synthesis_contract` version stamp**, so "which code produced this output" stops being
|
|
96
|
+
a guess from timestamps. v2 adds a single-JSON-object constraint: v1 emitted multiple JSON
|
|
97
|
+
objects on 3.3% of calls (all with `finish_reason: stop`, unrelated to truncation), which
|
|
98
|
+
made the whole response unparsable; the same measurement after the constraint is 0.0%.
|
|
99
|
+
|
|
100
|
+
### Added — memory utility (MemOS value backtracking)
|
|
101
|
+
|
|
102
|
+
- **Value-backtracking join key (P0).** `workflow_observe` now records `readerId` and
|
|
103
|
+
`recalledIds`, supplying the `(memory_id, outcome)` pairing the database never had: one
|
|
104
|
+
side had outcomes without participants (observations did not record memories), the other
|
|
105
|
+
had participants without outcomes (the access tracker recorded hits but not task success).
|
|
106
|
+
New `src/recall-ledger.ts` keeps process-level reader identity and a retrieval-hit ledger;
|
|
107
|
+
managed observations from `resume_context` / `checkpoint_session` carry it automatically.
|
|
108
|
+
New CLI `memory-utility <id>` reports the success rate of tasks a memory took part in.
|
|
109
|
+
- **`utility` column (P1).** `src/memory-utility.ts` weights outcomes (success +0.8 /
|
|
110
|
+
corrected +0.2 / missed −0.3 / failure −0.8) with a 30-day half-life; **it can be
|
|
111
|
+
negative**. It lands in `metadata.utility` and deliberately not in `importance`, which is
|
|
112
|
+
threshold-valued (≥0.95 grants permanent decay exemption) and already written by structured
|
|
113
|
+
memory. Retrieval gained `utilityWeight`, default 0 (off), feeding ranking only — not tier,
|
|
114
|
+
not decay exemption.
|
|
115
|
+
- **Cross-source criterion for promotion (P2).** `scanForPromotions` gained
|
|
116
|
+
`minDistinctSources` (default 2). Counting "how many similar cases" and "how many distinct
|
|
117
|
+
episodes" differ in dimension, not degree — hitting the same problem three times is one
|
|
118
|
+
experience repeated, which belongs on the failure-burst path instead. It **abstains** when
|
|
119
|
+
source pointers are unavailable: only 1.2% of cases across the database carry a `src:` tag,
|
|
120
|
+
so judging strictly would mostly punish three different problems solved on one day.
|
|
121
|
+
|
|
122
|
+
### Fixed
|
|
123
|
+
|
|
124
|
+
- **A rate-limit reply could trigger an unbounded request storm.** Found by the new contract
|
|
125
|
+
tests. `embedSingle` retried a context-length error by chunking, and each chunk recursed
|
|
126
|
+
back into `embedSingle`, able to re-enter the same branch. Two facts made that
|
|
127
|
+
non-terminating: `smartChunk` returns short text unchanged, so the recursion re-embedded
|
|
128
|
+
the identical string and reproduced the identical error; and the gate
|
|
129
|
+
`/context|too long|exceed|length/i` also matches rate-limit wording — both
|
|
130
|
+
`"Rate limit exceeded"` and `"429 quota exceeded"` trigger chunking. Measured before the
|
|
131
|
+
fix: **61,724 requests in five seconds** against an endpoint asking us to slow down. The
|
|
132
|
+
batch path had the same shape. The missing terminating condition is now present: chunking
|
|
133
|
+
that cannot produce anything smaller than its input throws instead of recursing, and a
|
|
134
|
+
chunk's own embed call cannot re-enter the branch. After: 4 ms, one request, correct error.
|
|
135
|
+
- **Multiple `AccessTracker` instances in one process no longer invent separate readers.**
|
|
136
|
+
`createComponentResolver` caches components per profile, so one session opening two
|
|
137
|
+
profiles produced a phantom second reader, inflating `distinctReaderCount` and the
|
|
138
|
+
skill-promotion read boost. The implementation now matches what `access-tracker.ts` says
|
|
139
|
+
about itself ("one stdio MCP server process ≈ one CC session").
|
|
140
|
+
|
|
141
|
+
### Documentation
|
|
142
|
+
|
|
143
|
+
- `docs/memory-boundary-contract.md` documents both promotion scans, why their eligibility
|
|
144
|
+
gates differ, and the abstention rule.
|
|
145
|
+
- `retriever.ts` records that `candidatePoolSize` above 20 has never had any effect — both
|
|
146
|
+
candidate legs land in `store.ts`'s `clampInt(limit, 1, 20)`. The clamp has been there
|
|
147
|
+
since the first commit while the 2026-07-16 tuning only touched the retriever, so that
|
|
148
|
+
`30` was inert from the day it landed. Left alone deliberately: raising it means widening
|
|
149
|
+
the candidate pool, which was measured and rejected on 2026-08-22.
|
|
150
|
+
|
|
151
|
+
### Upgrade notes
|
|
152
|
+
|
|
153
|
+
- **Node 22 or newer is required.** This is the release's only breaking change.
|
|
154
|
+
- Existing LanceDB data opens in place; no export/import step.
|
|
155
|
+
- `promote_synthesis` defaults to dry-run and writes nothing until `dryRun=false`.
|
|
156
|
+
- `audit.jsonl` retrieve rows are larger now that they list what was served. The list is
|
|
157
|
+
capped at 10 entries with `retrievedTotal` marking truncation. Rotation is still manual;
|
|
158
|
+
archive it if it approaches 50 MB.
|
|
159
|
+
- `utilityWeight` defaults to 0 and `metadata.utility` is written only by an explicit
|
|
160
|
+
`memory-utility --apply` run, so the MemOS work above is **available but not yet acting on
|
|
161
|
+
anything**. The resident MCP server was restarted on 2026-08-24, so `readerId` is now being
|
|
162
|
+
written (verified end-to-end on a fresh server: a `workflow_observe` call landed an
|
|
163
|
+
observation carrying `readerId`); `recalledIds` only gets a value when a retrieval hit
|
|
164
|
+
actually occurs, and no row carries `metadata.utility` yet because `--apply` has not been
|
|
165
|
+
run. Real data therefore starts accumulating from this release forward, not before it.
|
|
166
|
+
This is the intended shadow period, not a defect.
|
|
167
|
+
|
|
168
|
+
### Verification
|
|
169
|
+
|
|
170
|
+
- 2,324 tests pass across 165 files, 0 fail (2,281 at the 3.0 gate → +14 contract, +6 audit
|
|
171
|
+
revision, +8 verbatim self-recall, +15 synthesis promotion). Verified under three
|
|
172
|
+
feature-flag combinations, including the CI default, after CI caught one assertion
|
|
173
|
+
that had been reading the developer's local `.env` rather than product behaviour.
|
|
174
|
+
- The deprecated chain is absent from `npm ls`, `node_modules/`, `bun.lock` and
|
|
175
|
+
`package-lock.json`; installed `openai@7.5.0` reports zero dependencies and
|
|
176
|
+
`engines.node >= 22.0.0`.
|
|
177
|
+
- SDK compatibility was measured, not assumed: 20 sandbox probes against v7.5.0 (9 API
|
|
178
|
+
surface, 11 loopback-HTTP runtime) plus a `tsc --strict` check of all five call sites,
|
|
179
|
+
with a deliberately-broken control run to confirm the type check actually reports errors.
|
|
180
|
+
- `promote_synthesis` was exercised read-only against the live database: 52 contract-stamped
|
|
181
|
+
derivatives exist; `project:codex-self-evolution` yielded 10 candidates from 10 examined,
|
|
182
|
+
`project:antigravity-cli` 4 from 9 (5 below importance), `learnings` 3 from 4 (1 with too
|
|
183
|
+
few distinct sources). Nothing was written.
|
|
184
|
+
- The verbatim self-recall and synthesis-promotion suites were both reverse-verified —
|
|
185
|
+
removing the behaviour each asserts turns the relevant tests red and no others.
|
|
186
|
+
|
|
187
|
+
### A note on npm history
|
|
188
|
+
|
|
189
|
+
`recallnest@2.6.1` was a maintenance release published before Trusted Publishing was
|
|
190
|
+
configured for this package and therefore carries no build provenance. That describes how it
|
|
191
|
+
was published; it is not retroactively fixable, since the same npm version cannot be
|
|
192
|
+
republished to add provenance.
|
|
193
|
+
|
|
3
194
|
## v2.6.0 — Cross-process consistency and reliable distribution (2026-08-13)
|
|
4
195
|
|
|
5
196
|
### Added
|
package/README.md
CHANGED
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
# RecallNest
|
|
4
4
|
|
|
5
|
-
**Shared Memory Layer for
|
|
5
|
+
**Shared Memory Layer for Every AI Client — CLI agents, desktop apps, your own scripts**
|
|
6
6
|
|
|
7
|
-
*One memory. Every
|
|
7
|
+
*One memory. Every client. Context that survives across windows — and across machines.*
|
|
8
8
|
|
|
9
9
|
A local-first memory system backed by LanceDB that turns scattered conversation history into reusable knowledge — shared across your coding agents, recalled automatically.
|
|
10
10
|
|
|
11
11
|
[](https://github.com/AliceLJY/recallnest)
|
|
12
12
|
[](LICENSE)
|
|
13
|
-
[](https://bun.sh)
|
|
14
14
|
[](https://lancedb.com)
|
|
15
|
-
[](https://modelcontextprotocol.io)
|
|
16
16
|
[](https://github.com/AliceLJY/recallnest/actions/workflows/ci.yml)
|
|
17
17
|
[](https://github.com/AliceLJY/recallnest)
|
|
18
18
|
|
|
@@ -29,6 +29,55 @@ Coding agents forget everything between windows. Your context — project config
|
|
|
29
29
|
RecallNest solves this: **a single LanceDB-backed memory layer that your coding agents read and write**. Context stored in one window is auto-recalled in another. Sessions checkpoint on exit and resume on start. Memory decays, evolves, and self-organizes — not just raw log storage.
|
|
30
30
|
|
|
31
31
|
|
|
32
|
+
## Who Can Connect
|
|
33
|
+
|
|
34
|
+
**The data layer does not know what your client looks like.** RecallNest exposes the same LanceDB store through three outlets, so the right one is picked per client — not per protocol.
|
|
35
|
+
|
|
36
|
+
| What your client can do | Route | Verified with |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| Run a local command (CLI agent) | **MCP over stdio** | Claude Code, Codex, Kimi, Antigravity |
|
|
39
|
+
| Run a local command (GUI app, MCP config filled by hand) | **MCP over stdio** | Doubao desktop — same shape as Cherry Studio / ChatBox |
|
|
40
|
+
| Only speak HTTP | **HTTP API** | custom agents, scripts, cron |
|
|
41
|
+
| Run on another machine | swap the stdio command for `ssh <host> recallnest-mcp` | four clients on a laptop reading one store on a home server |
|
|
42
|
+
|
|
43
|
+
Two consequences worth stating plainly:
|
|
44
|
+
|
|
45
|
+
- **Not tied to one protocol.** A GUI chat app that supports MCP config connects the same way a terminal agent does. A client that can only issue HTTP requests still reads the same memory.
|
|
46
|
+
- **Not tied to one machine.** Because the MCP transport is stdio, the launch command is yours to define — point it at `ssh` and every client on every machine shares a single source of truth instead of each host growing its own database.
|
|
47
|
+
|
|
48
|
+
Adding a client does not mean changing RecallNest. A capable client writes one config line; a limited one gets a thin gateway in front of the HTTP API.
|
|
49
|
+
|
|
50
|
+
### AI apps on a phone: the read-only gateway
|
|
51
|
+
|
|
52
|
+
The HTTP API (`:4318`) binds to `127.0.0.1` and rejects any request whose Host header is not local. That is **deliberate** — it also exposes write routes (`/v1/store`, `/v1/checkpoint`), so putting it on a public address would hand out write access.
|
|
53
|
+
|
|
54
|
+
To let an AI app on your phone read the same memory, put a read-only gateway in front:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
openssl rand -hex 32 > ~/.config/recallnest/gateway-token
|
|
58
|
+
chmod 600 ~/.config/recallnest/gateway-token
|
|
59
|
+
|
|
60
|
+
bun run api # local API on :4318
|
|
61
|
+
bun run gateway # read-only gateway on :8791 → forwards to :4318
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The gateway allows read routes only (`/recall`, `/search`, `/stats`, `/health`); **every write route is a 404**. Bearer token compared in constant time, per-minute rate limit, hard caps on request and response size. Put it behind a tunnel (Tailscale Serve/Funnel, Cloudflare Tunnel, …) to reach it from a phone.
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
curl -X POST https://<your-tunnel>/recall \
|
|
68
|
+
-H "Authorization: Bearer $(cat ~/.config/recallnest/gateway-token)" \
|
|
69
|
+
-H 'content-type: application/json' \
|
|
70
|
+
-d '{"query":"how did we fix that deploy issue","limit":3,"allScopes":true}'
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Optional: set `RECALLNEST_GATEWAY_FILE_ROOTS="notes=/abs/path,wiki=/abs/path"` to add `GET /files/search`, a read-only ripgrep search over markdown directories you name (the query is passed as an argv element, never through a shell). Leave it unset and the route does not exist.
|
|
74
|
+
|
|
75
|
+
> The gateway also binds to `127.0.0.1` by default — exposing it is the tunnel's job. Evaluate that risk yourself.
|
|
76
|
+
|
|
77
|
+
This is how the author connected [OpenMinis](https://github.com/OpenMinis/OpenMinis) on an iPhone: the phone app reaches the gateway over a Tailscale Funnel and queries the same memory store. The interesting part is what it reads back — its own history. Those conversations get exported, flow back, and are indexed, so a phone agent that cold-starts every time ends up with memory that survives its sessions.
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
32
81
|
## Quick Start
|
|
33
82
|
|
|
34
83
|
### Option A: Claude Code Plugin (recommended)
|
|
@@ -55,7 +104,7 @@ npm install -g recallnest # install globally
|
|
|
55
104
|
recallnest doctor
|
|
56
105
|
```
|
|
57
106
|
|
|
58
|
-
Works with Node.js
|
|
107
|
+
Works with Node.js 22+ (via tsx) or Bun. No git clone needed.
|
|
59
108
|
|
|
60
109
|
### Option C: Manual setup
|
|
61
110
|
|
|
@@ -96,7 +145,7 @@ curl http://localhost:4318/v1/stats
|
|
|
96
145
|
|
|
97
146
|
```bash
|
|
98
147
|
bash integrations/claude-code/setup.sh
|
|
99
|
-
bash integrations/
|
|
148
|
+
bash integrations/agy/setup.sh
|
|
100
149
|
bash integrations/codex/setup.sh
|
|
101
150
|
```
|
|
102
151
|
|
|
@@ -196,6 +245,71 @@ bun run src/ui-server.ts
|
|
|
196
245
|
|
|
197
246
|
---
|
|
198
247
|
|
|
248
|
+
## New in v3.0: A Supported Runtime, and Conclusions That Can Be Used
|
|
249
|
+
|
|
250
|
+
v3.0 is a major release for one reason that shows up on install and one that shows up in
|
|
251
|
+
how memory behaves.
|
|
252
|
+
|
|
253
|
+
**The runtime boundary moved to Node 22.** RecallNest had been carrying `openai@4`, which
|
|
254
|
+
pulls in the deprecated `formdata-node` → `node-domexception` chain. Every `openai` release
|
|
255
|
+
since v5 has zero dependencies, so the chain disappears on any upgrade — but v7 declares
|
|
256
|
+
`engines.node >= 22.0.0`, which makes "raise the Node floor" and "move off a deprecated
|
|
257
|
+
dependency chain" the same piece of work rather than two. `engines.node` is now `>=22`.
|
|
258
|
+
This is the breaking part of the major.
|
|
259
|
+
|
|
260
|
+
**A synthesized conclusion can now reach stable memory.** `dream` writes cluster insights
|
|
261
|
+
and cross-memory patterns on the evidence layer deliberately — a model re-reading its own
|
|
262
|
+
memories is a lead to its sources, not authority over them — but stable-memory selection
|
|
263
|
+
refuses the evidence layer outright. The consequence was absolute: no matter how well
|
|
264
|
+
supported a synthesized conclusion was, nothing downstream could lean on it. `promote_synthesis`
|
|
265
|
+
(MCP) and `recallnest promote-synthesis` (CLI) give it a road, gated on the conclusion's own
|
|
266
|
+
validated evidence set rather than on repetition, because a synthesis is already a
|
|
267
|
+
cross-entry aggregate. The synthesized row is never modified; promotion writes a separate
|
|
268
|
+
durable entry carrying `promotedFrom` back to it, through the same path and the same
|
|
269
|
+
`canonicalKey` dedup as every other promotion.
|
|
270
|
+
|
|
271
|
+
Also in this release:
|
|
272
|
+
|
|
273
|
+
- **Retrieve audit rows say what was served.** They used to record the query and a hit
|
|
274
|
+
count. Because beliefs are revised in place — the id stays, the version increments, the
|
|
275
|
+
old text survives as a `superseded` row — "memory X was retrieved" was ambiguous across
|
|
276
|
+
every belief change. Rows now carry each result's id, revision, lifecycle status, and
|
|
277
|
+
boundary. The list is capped, and a capped list says so.
|
|
278
|
+
- **HTTP contract tests for embeddings and chat completions.** Every previous test stubbed
|
|
279
|
+
the SDK client, so nothing exercised a socket, and a transport-level regression would
|
|
280
|
+
have passed all of them. These drive the real classes through the real SDK against a
|
|
281
|
+
loopback server, covering success, error, and timeout for the default OpenAI shape plus
|
|
282
|
+
the Jina and Qwen-compatible profiles. No network egress, no vendor credentials.
|
|
283
|
+
- **Fixed: a rate-limit reply could trigger an unbounded request storm.** Found by those
|
|
284
|
+
tests. The embedder retried a context-length error by chunking, the chunker returns short
|
|
285
|
+
text unchanged, and the gate that decided "this is a context error" also matched
|
|
286
|
+
rate-limit wording — so a 429 re-embedded the same text forever. Measured at over 61,000
|
|
287
|
+
requests in five seconds against an endpoint asking us to slow down. Failure is bounded now.
|
|
288
|
+
- **A known recall gap is now a runnable regression.** A memory that is long, older, and
|
|
289
|
+
rarely read can fail to be recalled by words copied out of its own body, while short,
|
|
290
|
+
fresh, frequently-read entries outrank it. It is a ranking problem, not a filtering one —
|
|
291
|
+
the entry clears every threshold and then places last. The reproduction is checked in; the
|
|
292
|
+
ranking fix is not in this release.
|
|
293
|
+
- **44 MCP tools** across three tiers, up from 43.
|
|
294
|
+
|
|
295
|
+
### Upgrading from v2.6
|
|
296
|
+
|
|
297
|
+
- **Node 22 or newer is required.** Bun users are unaffected. This is the only breaking
|
|
298
|
+
change in the release.
|
|
299
|
+
- Existing LanceDB data is opened in place. No export or import step.
|
|
300
|
+
- `promote_synthesis` defaults to dry-run and writes nothing until `dryRun=false`.
|
|
301
|
+
- `audit.jsonl` rows for retrievals are larger now that they list what was served. Rotation
|
|
302
|
+
is still manual; archive it if it approaches 50 MB.
|
|
303
|
+
|
|
304
|
+
### A note on npm history
|
|
305
|
+
|
|
306
|
+
`recallnest@2.6.1` on npm was a maintenance release published before Trusted Publishing was
|
|
307
|
+
configured for this package, so it carries no build provenance. That is a fact about how it
|
|
308
|
+
was published, not a defect in the package, and it is not retroactively fixable — the same
|
|
309
|
+
npm version cannot be republished to add provenance.
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
199
313
|
## New in v2.6: Reliable Cross-Process Memory and Distribution
|
|
200
314
|
|
|
201
315
|
v2.6 turns the development since v2.5.4 into a release-ready upgrade:
|
|
@@ -266,8 +380,8 @@ v2.2 hardened retrieval quality; v2.3 opens RecallNest to external data sources
|
|
|
266
380
|
┌──────────────────────────────────────────────────────────┐
|
|
267
381
|
│ Client Layer │
|
|
268
382
|
├──────────┬──────────┬──────────┬──────────────────────────┤
|
|
269
|
-
│ Claude │
|
|
270
|
-
│ Code │
|
|
383
|
+
│ Claude │ Anti- │ Codex │ Custom Agents / curl │
|
|
384
|
+
│ Code │ gravity │ │ │
|
|
271
385
|
└────┬─────┴────┬─────┴────┬─────┴──────┬──────────────────┘
|
|
272
386
|
│ │ │ │
|
|
273
387
|
└──── MCP (stdio) ───┘ HTTP API (port 4318)
|
|
@@ -277,7 +391,7 @@ v2.2 hardened retrieval quality; v2.3 opens RecallNest to external data sources
|
|
|
277
391
|
│ Integration Layer │
|
|
278
392
|
│ ┌─────────────────────┐ ┌────────────────────────────┐ │
|
|
279
393
|
│ │ MCP Server │ │ HTTP API Server │ │
|
|
280
|
-
│ │
|
|
394
|
+
│ │ 44 tools │ │ 21 endpoints │ │
|
|
281
395
|
│ └─────────┬───────────┘ └──────────┬─────────────────┘ │
|
|
282
396
|
└────────────┼─────────────────────────┼───────────────────┘
|
|
283
397
|
└──────────┬──────────────┘
|
|
@@ -323,7 +437,7 @@ v2.2 hardened retrieval quality; v2.3 opens RecallNest to external data sources
|
|
|
323
437
|
|
|
324
438
|
RecallNest serves two interfaces:
|
|
325
439
|
|
|
326
|
-
- **MCP** — for any
|
|
440
|
+
- **MCP (stdio)** — for any client that can launch a command: CLI agents (Claude Code, Codex, Kimi, Antigravity) and GUI apps that accept an MCP config (Doubao, Cherry Studio, ChatBox)
|
|
327
441
|
- **HTTP API** — for custom agents, SDK-based apps, and any HTTP client
|
|
328
442
|
|
|
329
443
|
### Agent framework examples
|
|
@@ -339,7 +453,7 @@ Examples live in [`integrations/examples/`](integrations/examples/):
|
|
|
339
453
|
---
|
|
340
454
|
|
|
341
455
|
<details>
|
|
342
|
-
<summary><strong>MCP Tools (
|
|
456
|
+
<summary><strong>MCP Tools (44 tools)</strong></summary>
|
|
343
457
|
|
|
344
458
|
| Tool | Description |
|
|
345
459
|
|------|-------------|
|
|
@@ -351,6 +465,7 @@ Examples live in [`integrations/examples/`](integrations/examples/):
|
|
|
351
465
|
| `store_case` | Store a reusable problem-solution pair as durable `cases` memory |
|
|
352
466
|
| `promote_memory` | Explicitly promote evidence into durable memory |
|
|
353
467
|
| `promote_scan` | Scan recent evidence and auto-promote qualifying memories into durable storage |
|
|
468
|
+
| `promote_synthesis` | Scan dream-synthesized conclusions and promote the ones their own evidence set supports |
|
|
354
469
|
| `list_conflicts` | List or inspect promotion conflict candidates |
|
|
355
470
|
| `audit_conflicts` | Summarize stale/escalated conflict priorities |
|
|
356
471
|
| `escalate_conflicts` | Preview or apply conflict escalation metadata |
|
|
@@ -492,6 +607,8 @@ RecallNest auto-detects babel-memory at startup — no configuration needed. Wit
|
|
|
492
607
|
|
|
493
608
|
RecallNest is actively maintained. All major architecture phases are complete — see the full [Roadmap](ROADMAP.md) for current priorities and future plans.
|
|
494
609
|
|
|
610
|
+
Maintainers: see [Publishing RecallNest](https://github.com/AliceLJY/recallnest/blob/main/docs/releasing.md) for the npm Trusted Publishing, validation, and recovery process.
|
|
611
|
+
|
|
495
612
|
---
|
|
496
613
|
|
|
497
614
|
## Relationship to memory-lancedb-pro
|
|
@@ -499,7 +616,7 @@ RecallNest is actively maintained. All major architecture phases are complete
|
|
|
499
616
|
RecallNest started as a fork of [memory-lancedb-pro](https://github.com/CortexReach/memory-lancedb-pro) and shares its core ideas around hybrid retrieval, decay modeling, and memory-as-engineering-system. The key difference:
|
|
500
617
|
|
|
501
618
|
- **memory-lancedb-pro** is an OpenClaw plugin — it adds long-term memory to a single OpenClaw agent.
|
|
502
|
-
- **RecallNest** is a standalone memory layer — it serves
|
|
619
|
+
- **RecallNest** is a standalone memory layer — it serves CLI agents, GUI chat apps and plain HTTP callers simultaneously through MCP + HTTP API, with session continuity, structured assets, and conflict management built in.
|
|
503
620
|
|
|
504
621
|
## Credit
|
|
505
622
|
|
|
@@ -520,9 +637,9 @@ Part of the **小试AI** open-source AI workflow:
|
|
|
520
637
|
|---------|-------------|
|
|
521
638
|
| [babel-memory](https://github.com/AliceLJY/babel-memory) | Multilingual preprocessing for BM25 — 27+ languages, zero deps |
|
|
522
639
|
| cc-empire *(private)* | Hooks/rules/methodology — the connective tissue of the whole ecosystem |
|
|
523
|
-
| [telegram-ai-bridge](https://github.com/AliceLJY/telegram-ai-bridge) | Telegram bots for Claude, Codex, and
|
|
640
|
+
| [telegram-ai-bridge](https://github.com/AliceLJY/telegram-ai-bridge) | Telegram bots for Claude, Codex, Agy, and Kimi |
|
|
524
641
|
| [tg-bridge-channel](https://github.com/AliceLJY/tg-bridge-channel) | Sister Telegram bridge using Claude Agent View background sessions |
|
|
525
|
-
| [wechat-ai-bridge](https://github.com/AliceLJY/wechat-ai-bridge) | Run Claude Code / Codex
|
|
642
|
+
| [wechat-ai-bridge](https://github.com/AliceLJY/wechat-ai-bridge) | Run Claude Code / Codex in WeChat with session management |
|
|
526
643
|
| [openclaw-tunnel](https://github.com/AliceLJY/openclaw-tunnel) | Docker ↔ host CLI bridge (maintenance mode — LanceDB test only) |
|
|
527
644
|
| [digital-clone-skill](https://github.com/AliceLJY/digital-clone-skill) | Build digital clones from corpus data |
|
|
528
645
|
| [claude-code-studio](https://github.com/AliceLJY/claude-code-studio) | Multi-session collaboration platform for Claude Code |
|