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/README_CN.md
CHANGED
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
# RecallNest
|
|
4
4
|
|
|
5
|
-
**面向任意
|
|
5
|
+
**面向任意 AI 客户端的共享记忆层 —— CLI agent、桌面 app、你自己的脚本**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
*一套记忆,每个客户端,上下文跨窗口延续——也跨机器。*
|
|
8
8
|
|
|
9
9
|
基于 LanceDB 的本地优先记忆系统,把散落在各个终端的对话历史沉淀为可复用知识,跨终端共享,自动召回。
|
|
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 @@
|
|
|
29
29
|
RecallNest 的解法:**一个 LanceDB 驱动的记忆层,供你的编程 Agent 共读共写**。一个窗口存入的上下文,另一个窗口自动召回。会话退出时 checkpoint,启动时 resume。记忆会衰减、演化、自组织——不是简单的日志堆积。
|
|
30
30
|
|
|
31
31
|
|
|
32
|
+
## 谁能接上
|
|
33
|
+
|
|
34
|
+
**数据层不知道你的客户端长什么样。** RecallNest 把同一个 LanceDB 存储通过三个出口暴露出来,接法按客户端的能力选,而不是绑死在某一种协议上。
|
|
35
|
+
|
|
36
|
+
| 你的客户端能做什么 | 走哪条 | 已验证 |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| 执行本地命令(CLI agent) | **MCP over stdio** | Claude Code、Codex、Kimi、Antigravity |
|
|
39
|
+
| 执行本地命令(GUI app,手填 MCP 配置) | **MCP over stdio** | 豆包桌面端——与 Cherry Studio / ChatBox 同一形态 |
|
|
40
|
+
| 只会发 HTTP 请求 | **HTTP API** | 自定义 agent、脚本、定时任务 |
|
|
41
|
+
| 跑在另一台机器上 | 把 stdio 启动命令换成 `ssh <host> recallnest-mcp` | 笔记本上的四个客户端共读家里服务器上的同一个库 |
|
|
42
|
+
|
|
43
|
+
两条值得直说的推论:
|
|
44
|
+
|
|
45
|
+
- **不绑单一协议。** 支持填 MCP 配置的 GUI 聊天 app,接入方式和终端里的 agent 完全一样;只会发 HTTP 请求的客户端,读到的仍是同一份记忆。
|
|
46
|
+
- **不绑单台机器。** 因为 MCP 传输走 stdio,启动命令由你定义——把它指向 `ssh`,每台机器上的每个客户端共用同一个真相源,而不是各自长出一个数据库。
|
|
47
|
+
|
|
48
|
+
接一个新客户端不等于要改 RecallNest:够格的客户端自己写一行配置,能力受限的在 HTTP API 前面加一层薄网关。
|
|
49
|
+
|
|
50
|
+
### 手机上的 AI app:只读网关
|
|
51
|
+
|
|
52
|
+
HTTP API(`:4318`)只监听 `127.0.0.1`,并且会拒绝任何 Host 头不是本地的请求——这是**有意的**:它同时暴露写入路由(`/v1/store`、`/v1/checkpoint`),直接开到公网等于把写权限交出去。
|
|
53
|
+
|
|
54
|
+
所以要让手机上的 AI app 读到同一份记忆,前面加一层只读网关:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
openssl rand -hex 32 > ~/.config/recallnest/gateway-token
|
|
58
|
+
chmod 600 ~/.config/recallnest/gateway-token
|
|
59
|
+
|
|
60
|
+
bun run api # 本机 API,:4318
|
|
61
|
+
bun run gateway # 只读网关,:8791 → 转发到 :4318
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
网关只放行读路由(`/recall`、`/search`、`/stats`、`/health`),**任何写路由一律 404**;Bearer token 常量时间比较、每分钟限流、请求与响应都有大小上限。把它放到隧道后面(Tailscale Serve/Funnel、Cloudflare Tunnel 等)即可从手机访问。
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
curl -X POST https://<你的隧道地址>/recall \
|
|
68
|
+
-H "Authorization: Bearer $(cat ~/.config/recallnest/gateway-token)" \
|
|
69
|
+
-H 'content-type: application/json' \
|
|
70
|
+
-d '{"query":"上次那个部署问题怎么解决的","limit":3,"allScopes":true}'
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
可选:配 `RECALLNEST_GATEWAY_FILE_ROOTS="notes=/abs/path,wiki=/abs/path"` 会多出一个 `GET /files/search`,用 ripgrep 只读检索你指定的 markdown 目录(查询词以 argv 传入,不经过 shell)。不配就没有这个路由。
|
|
74
|
+
|
|
75
|
+
> 网关默认也只绑 `127.0.0.1`——把它暴露到公网是隧道的职责,请自行评估风险。
|
|
76
|
+
|
|
77
|
+
作者用这条路把 iPhone 上的 [OpenMinis](https://github.com/OpenMinis/OpenMinis) 接了上来:手机 app 经 Tailscale Funnel 打到网关,能查到同一份记忆库。有意思的是它查回的是**它自己**的历史——那些对话导出后回流、被索引,于是一个每次冷启动的手机 agent 有了跨会话的记忆。
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
32
81
|
## 快速开始
|
|
33
82
|
|
|
34
83
|
### 方式 A:Claude Code Plugin(推荐)
|
|
@@ -55,7 +104,7 @@ npm install -g recallnest # 全局安装
|
|
|
55
104
|
recallnest doctor
|
|
56
105
|
```
|
|
57
106
|
|
|
58
|
-
支持 Node.js
|
|
107
|
+
支持 Node.js 22+(通过 tsx)或 Bun,无需 clone 仓库。
|
|
59
108
|
|
|
60
109
|
### 方式 C:手动安装
|
|
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
|
|
|
@@ -143,8 +192,8 @@ bun run src/ui-server.ts
|
|
|
143
192
|
| 能力 | 说明 |
|
|
144
193
|
|---|---|
|
|
145
194
|
| **CC Plugin** | 一行命令装入 Claude Code,无需手动配置 MCP |
|
|
146
|
-
| **共享索引** |
|
|
147
|
-
| **双通道接入** | MCP(stdio)给 CLI
|
|
195
|
+
| **共享索引** | 所有客户端共用同一个 LanceDB 存储,跨机指向 `ssh` 即可共用真相源 |
|
|
196
|
+
| **双通道接入** | MCP(stdio)给 CLI agent 与能填 MCP 配置的 GUI app + HTTP API 给只会发请求的客户端 |
|
|
148
197
|
| **一键接入** | 集成脚本同时安装 MCP 和 continuity 规则 |
|
|
149
198
|
|
|
150
199
|
### 检索与连续性
|
|
@@ -196,6 +245,60 @@ bun run src/ui-server.ts
|
|
|
196
245
|
|
|
197
246
|
---
|
|
198
247
|
|
|
248
|
+
## v3.0 新增:一个受支持的运行时,和终于能被用起来的结论
|
|
249
|
+
|
|
250
|
+
v3.0 是大版本,原因有两个:一个在安装时看得见,一个在记忆的行为里。
|
|
251
|
+
|
|
252
|
+
**运行时边界提到了 Node 22。** RecallNest 一直带着 `openai@4`,它拽着
|
|
253
|
+
`formdata-node` → `node-domexception` 这条弃用链。openai 从 v5 起每个版本都是零依赖,
|
|
254
|
+
所以升到哪一版这条链都会消失 —— 但 v7 自己声明 `engines.node >= 22.0.0`,于是
|
|
255
|
+
「抬 Node 边界」和「甩掉弃用依赖链」变成同一件事,而不是两件。`engines.node` 现在是
|
|
256
|
+
`>=22`。这是本次大版本里唯一的破坏性改动。
|
|
257
|
+
|
|
258
|
+
**合成出的结论终于能进稳定记忆。** `dream` 把 cluster insight 和 cross-memory pattern
|
|
259
|
+
写在 evidence 层是有意的 —— 模型对自己记忆的再加工是通往源头的线索,不是压过源头的
|
|
260
|
+
权威 —— 但稳定记忆的选取对 evidence 层一律拒收。后果是绝对的:一条合成结论无论证据
|
|
261
|
+
多充分,下游都没法靠它。`promote_synthesis`(MCP)与 `recallnest promote-synthesis`
|
|
262
|
+
(CLI)给了它一条路,判据是这条结论自己那份经过校验的证据集,而不是「重复出现几次」
|
|
263
|
+
—— 合成物本身就是跨条目聚合,要求它重复是把一件事数了几次。合成行本身一个字不改;
|
|
264
|
+
晋升写的是另一条 durable 记录,带 `promotedFrom` 指回去,走的是和其他晋升同一条通道、
|
|
265
|
+
同一套 `canonicalKey` 去重。
|
|
266
|
+
|
|
267
|
+
本次还有:
|
|
268
|
+
|
|
269
|
+
- **retrieve 审计行会说清服务了什么。** 它以前只记查询词和命中数。而信念是就地修订的
|
|
270
|
+
—— id 不变、版本号加一、旧正文作为 `superseded` 行留下 —— 所以「memory X 被检索了」
|
|
271
|
+
这句话跨过任何一次信念变更都是有歧义的。现在每条结果的 id、版本、生命周期状态和
|
|
272
|
+
boundary 都记下来;列表有上限,而且**被截断时会说自己被截断了**。
|
|
273
|
+
- **embeddings 与 chat completions 有了 HTTP 契约测试。** 此前所有测试都把 SDK client
|
|
274
|
+
换成桩函数,没有一条碰过 socket,传输层的回归会全绿着放过去。新测试驱动真的类、经真的
|
|
275
|
+
SDK、打到本地回环服务器,覆盖成功 / 错误 / 超时三态,以及默认 OpenAI 形态加上 Jina、
|
|
276
|
+
Qwen 兼容端点。零出网、零凭据。
|
|
277
|
+
- **修复:被限流时反而会猛打对方。** 是上面那批测试当场查出来的。embedder 遇到
|
|
278
|
+
context-length 错误会分块重试,而分块器对短文本原样返回,判定「这是 context 错误」的
|
|
279
|
+
那条正则又会命中限流措辞 —— 于是一个 429 会拿同一段文本无限重打。实测 5 秒 61,000 多
|
|
280
|
+
个请求,对着一个正在叫我们慢一点的端点。现在失败是有界的。
|
|
281
|
+
- **一个已知的召回缺口变成了能跑的回归。** 一条又长、又旧、很少被读的记忆,可能用它自己
|
|
282
|
+
正文里的原话都召不回,而短的、新的、被频繁读的条目排在它前面。这是排序问题不是过滤
|
|
283
|
+
问题 —— 那条记忆过了所有阈值,然后排最后一名。复现已经进仓;排序的修复不在本次。
|
|
284
|
+
- **MCP 工具 44 个**(三层),此前 43 个。
|
|
285
|
+
|
|
286
|
+
### 从 v2.6 升级
|
|
287
|
+
|
|
288
|
+
- **需要 Node 22 或更新版本。** 用 Bun 的不受影响。这是本次唯一的破坏性改动。
|
|
289
|
+
- 已有 LanceDB 数据原地打开,不需要导出导入。
|
|
290
|
+
- `promote_synthesis` 默认 dry-run,不传 `dryRun=false` 不写任何东西。
|
|
291
|
+
- `audit.jsonl` 里检索那类行变大了(它现在列出服务了哪几条)。轮转仍是手动的,接近
|
|
292
|
+
50 MB 时归档一下。
|
|
293
|
+
|
|
294
|
+
### 关于 npm 历史的一句说明
|
|
295
|
+
|
|
296
|
+
npm 上的 `recallnest@2.6.1` 是一次维护发布,发布时这个包还没有配置 Trusted Publishing,
|
|
297
|
+
所以它不带构建 provenance。这是它当时怎么发的一个事实,不是包本身的缺陷,而且**无法追认**
|
|
298
|
+
—— 同一个 npm 版本不能为了补 provenance 再发一次。
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
199
302
|
## v2.6 新增:跨进程一致性与可靠分发
|
|
200
303
|
|
|
201
304
|
v2.6 把 v2.5.4 以来的开发整理成一版可升级、可安装、版本口径一致的正式候选:
|
|
@@ -277,7 +380,7 @@ v2.2 强化了检索质量;v2.3 通过标准 Connector 框架和运维健康
|
|
|
277
380
|
│ 集成层 │
|
|
278
381
|
│ ┌─────────────────────┐ ┌────────────────────────────┐ │
|
|
279
382
|
│ │ MCP Server │ │ HTTP API Server │ │
|
|
280
|
-
│ │
|
|
383
|
+
│ │ 44 个工具 │ │ 21 个端点 │ │
|
|
281
384
|
│ └─────────┬───────────┘ └──────────┬─────────────────┘ │
|
|
282
385
|
└────────────┼─────────────────────────┼───────────────────┘
|
|
283
386
|
└──────────┬──────────────┘
|
|
@@ -322,7 +425,7 @@ v2.2 强化了检索质量;v2.3 通过标准 Connector 框架和运维健康
|
|
|
322
425
|
|
|
323
426
|
RecallNest 提供两种接口:
|
|
324
427
|
|
|
325
|
-
- **MCP
|
|
428
|
+
- **MCP(stdio)** —— 给任何能启动一条命令的客户端:CLI agent(Claude Code、Codex、Kimi、Antigravity)与能填 MCP 配置的 GUI app(豆包、Cherry Studio、ChatBox)
|
|
326
429
|
- **HTTP API** —— 给自定义 Agent、SDK 应用和任何 HTTP 客户端使用
|
|
327
430
|
|
|
328
431
|
### Agent 框架示例
|
|
@@ -338,7 +441,7 @@ RecallNest 提供两种接口:
|
|
|
338
441
|
---
|
|
339
442
|
|
|
340
443
|
<details>
|
|
341
|
-
<summary><strong>MCP 工具(
|
|
444
|
+
<summary><strong>MCP 工具(44 个)</strong></summary>
|
|
342
445
|
|
|
343
446
|
| 工具 | 说明 |
|
|
344
447
|
|------|------|
|
|
@@ -350,6 +453,7 @@ RecallNest 提供两种接口:
|
|
|
350
453
|
| `store_case` | 存储问题-方案对 |
|
|
351
454
|
| `promote_memory` | 显式升级 evidence 为持久记忆 |
|
|
352
455
|
| `promote_scan` | 扫描近期 evidence,自动晋升合格记忆为持久存储 |
|
|
456
|
+
| `promote_synthesis` | 扫描 dream 合成出的结论,把自身证据集撑得住的那些晋升为持久记忆 |
|
|
353
457
|
| `list_conflicts` | 列出或查看冲突候选 |
|
|
354
458
|
| `audit_conflicts` | 汇总过期/升级的冲突优先级 |
|
|
355
459
|
| `escalate_conflicts` | 预览或应用冲突升级元数据 |
|
|
@@ -498,7 +602,7 @@ RecallNest 持续维护中。所有主要架构阶段已完成——完整路线
|
|
|
498
602
|
RecallNest 起源于 [memory-lancedb-pro](https://github.com/CortexReach/memory-lancedb-pro) 的 fork,共享混合检索、衰减建模、记忆即系统的核心理念。关键区别:
|
|
499
603
|
|
|
500
604
|
- **memory-lancedb-pro** 是 OpenClaw 插件——为单个 OpenClaw Agent 添加长期记忆。
|
|
501
|
-
- **RecallNest** 是独立记忆层——通过 MCP + HTTP API
|
|
605
|
+
- **RecallNest** 是独立记忆层——通过 MCP + HTTP API 同时服务 CLI agent、GUI 聊天 app 与纯 HTTP 调用方,内建会话连续性、结构化资产和冲突管理。
|
|
502
606
|
|
|
503
607
|
## 致谢
|
|
504
608
|
|
|
@@ -518,13 +622,13 @@ RecallNest 起源于 [memory-lancedb-pro](https://github.com/CortexReach/memory-
|
|
|
518
622
|
| 项目 | 说明 |
|
|
519
623
|
|------|------|
|
|
520
624
|
| [babel-memory](https://github.com/AliceLJY/babel-memory) | BM25 多语言预处理——27+ 种语言,零依赖 |
|
|
521
|
-
|
|
|
522
|
-
|
|
|
523
|
-
| [wechat-ai-bridge](https://github.com/AliceLJY/wechat-ai-bridge) | 在微信中运行 Claude Code / Codex
|
|
524
|
-
| [telegram-ai-bridge](https://github.com/AliceLJY/telegram-ai-bridge) | Telegram Bot:Claude、Codex、
|
|
625
|
+
| content-alchemy *(private)* | 5 阶段 AI 写作管线 |
|
|
626
|
+
| content-publisher *(private)* | 图片生成 + 排版 + 微信公众号发布 |
|
|
627
|
+
| [wechat-ai-bridge](https://github.com/AliceLJY/wechat-ai-bridge) | 在微信中运行 Claude Code / Codex |
|
|
628
|
+
| [telegram-ai-bridge](https://github.com/AliceLJY/telegram-ai-bridge) | Telegram Bot:Claude、Codex、Agy、Kimi |
|
|
525
629
|
| [telegram-cli-bridge](https://github.com/AliceLJY/telegram-cli-bridge) | Telegram CLI 桥接 Gemini CLI |
|
|
526
630
|
| [openclaw-tunnel](https://github.com/AliceLJY/openclaw-tunnel) | Docker ↔ 宿主机 CLI 桥接 |
|
|
527
|
-
|
|
|
631
|
+
| openclaw-config *(private)* | OpenClaw Bot 配置与记忆备份 |
|
|
528
632
|
| [digital-clone-skill](https://github.com/AliceLJY/digital-clone-skill) | 从语料构建数字分身 |
|
|
529
633
|
| [claude-code-studio](https://github.com/AliceLJY/claude-code-studio) | Claude Code 多会话协作平台 |
|
|
530
634
|
| [cc-genius](https://github.com/AliceLJY/cc-genius) | Web 版 Claude 客户端(PWA)—— 自托管,iPad 可用 |
|
package/config.json.example
CHANGED
|
@@ -25,6 +25,11 @@
|
|
|
25
25
|
"path": "auto",
|
|
26
26
|
"glob": "*.md",
|
|
27
27
|
"description": "Claude Code memory files"
|
|
28
|
+
},
|
|
29
|
+
"minis": {
|
|
30
|
+
"path": "~/Desktop/minis-outbox/ingest",
|
|
31
|
+
"glob": "*.jsonl",
|
|
32
|
+
"description": "Minis (iPhone) conversations, dropped here by the agent itself"
|
|
28
33
|
}
|
|
29
34
|
},
|
|
30
35
|
"retrieval": {
|
|
@@ -36,6 +41,8 @@
|
|
|
36
41
|
"hardMinScore": 0.3
|
|
37
42
|
},
|
|
38
43
|
"scopeRelations": {
|
|
39
|
-
"project:example-a": [
|
|
44
|
+
"project:example-a": [
|
|
45
|
+
"project:example-b"
|
|
46
|
+
]
|
|
40
47
|
}
|
|
41
48
|
}
|
package/docs/api-reference.md
CHANGED
|
@@ -298,7 +298,7 @@ Each memory item supports:
|
|
|
298
298
|
"source": "agent",
|
|
299
299
|
"storedAt": "2026-03-16T02:11:00.000Z",
|
|
300
300
|
"disposition": "stored",
|
|
301
|
-
"canonicalKey": "entities:recallnest-is-the-shared-memory-layer-for-claude-code-codex-and-
|
|
301
|
+
"canonicalKey": "entities:recallnest-is-the-shared-memory-layer-for-claude-code-codex-and-agy"
|
|
302
302
|
}
|
|
303
303
|
]
|
|
304
304
|
}
|
package/integrations/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Best for AI coding assistants that support Model Context Protocol natively.
|
|
|
11
11
|
| Tool | Setup | What it does |
|
|
12
12
|
|------|-------|-------------|
|
|
13
13
|
| [Claude Code](claude-code/) | `setup.sh` adds MCP to `~/.claude.json` and installs rules in `~/.claude/CLAUDE.md` | Proactive continuity plus shared recall |
|
|
14
|
-
| [
|
|
14
|
+
| [Antigravity CLI (agy)](agy/) | `setup.sh` adds MCP to `~/.gemini/config/mcp_config.json` and installs rules in `~/.gemini/config/GEMINI.md` | Same MCP tools, shared index, continuity prompts |
|
|
15
15
|
| [Codex](codex/) | `setup.sh` adds MCP to `~/.codex/config.toml` and installs rules in `~/.codex/AGENTS.md` | Same MCP tools, shared index, continuity prompts |
|
|
16
16
|
|
|
17
17
|
All three share the same LanceDB index, and all three setup scripts now install a managed RecallNest continuity block so fresh windows are instructed to call `resume_context` and `checkpoint_session` at the right times.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Antigravity CLI (agy) Integration
|
|
2
|
+
|
|
3
|
+
> agy 接入指南:一键配 MCP + continuity 规则,让 agy 在新窗口里主动恢复稳定上下文。
|
|
4
|
+
|
|
5
|
+
> **Note on naming.** Google retired the standalone `gemini` CLI for personal
|
|
6
|
+
> accounts on 2026-06-18; the [Antigravity CLI](https://antigravity.google)
|
|
7
|
+
> (`agy`) is its successor. This integration targets `agy`. If you are on a
|
|
8
|
+
> Code Assist Standard/Enterprise plan and still run the legacy CLI, point the
|
|
9
|
+
> same MCP entry at whatever config file your build reads.
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bash integrations/agy/setup.sh
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## What It Does
|
|
18
|
+
|
|
19
|
+
- Adds RecallNest as an MCP server in `~/.gemini/config/mcp_config.json`
|
|
20
|
+
- Installs a managed RecallNest block in `~/.gemini/config/GEMINI.md`
|
|
21
|
+
|
|
22
|
+
## Continuity Rules
|
|
23
|
+
|
|
24
|
+
The managed block comes from [agy-md-snippet.md](agy-md-snippet.md) and tells agy to:
|
|
25
|
+
|
|
26
|
+
- call `resume_context` at the start of fresh windows or continuity-sensitive tasks
|
|
27
|
+
- run lightweight `search_memory` on task pivots inside the same project before repo exploration drifts
|
|
28
|
+
- reuse known `scope` / `sessionId` and the resolved scope returned by `resume_context` in follow-up recall calls
|
|
29
|
+
- treat recalled or startup-hook repo state as unverified until this window explicitly checks the repo
|
|
30
|
+
- save `checkpoint_session` before leaving resumable work
|
|
31
|
+
- do not inspect repo state just to enrich a close-window checkpoint unless the user explicitly asked for repo state
|
|
32
|
+
- do not write unverified repo-state claims into `checkpoint_session`
|
|
33
|
+
- capture durable facts with `store_memory` and reusable workflows with `store_workflow_pattern`
|
|
34
|
+
|
|
35
|
+
## Shared Index
|
|
36
|
+
|
|
37
|
+
agy shares the same LanceDB index as Claude Code, Codex and Kimi. Memories ingested from any source are searchable by all of them.
|
|
38
|
+
|
|
39
|
+
## Manual Setup
|
|
40
|
+
|
|
41
|
+
Add to `~/.gemini/config/mcp_config.json`:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"mcpServers": {
|
|
46
|
+
"recallnest": {
|
|
47
|
+
"type": "stdio",
|
|
48
|
+
"command": "bun",
|
|
49
|
+
"args": ["run", "RECALLNEST_PATH/src/mcp-server.ts"]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Replace `RECALLNEST_PATH` with your actual path.
|
|
56
|
+
|
|
57
|
+
Then copy [agy-md-snippet.md](agy-md-snippet.md) into `~/.gemini/config/GEMINI.md` if you are not using `setup.sh`.
|
|
58
|
+
|
|
59
|
+
## Tool Permissions
|
|
60
|
+
|
|
61
|
+
agy gates tool calls separately from MCP registration. In non-interactive mode
|
|
62
|
+
(`agy -p`) it cannot prompt, so permission-requiring tools are auto-denied and
|
|
63
|
+
the agent silently returns nothing. If RecallNest tools appear registered but
|
|
64
|
+
never fire, set `toolPermission` in `~/.gemini/antigravity-cli/settings.json`,
|
|
65
|
+
or pass `--dangerously-skip-permissions` for a single run.
|
|
66
|
+
|
|
67
|
+
## Verify
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
agy -p "resume my context for RecallNest continuity work" --print-timeout 180s </dev/null
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
If `resume_context` or `search_memory` is called, you're set.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# RecallNest — Antigravity CLI (agy) MCP setup (idempotent)
|
|
3
|
+
# Usage: bash integrations/agy/setup.sh
|
|
4
|
+
#
|
|
5
|
+
# Google retired the standalone Gemini CLI for personal accounts on 2026-06-18.
|
|
6
|
+
# Its successor is the Antigravity CLI (`agy`), which reads MCP servers from
|
|
7
|
+
# ~/.gemini/config/mcp_config.json — not the old ~/.gemini/settings.json.
|
|
8
|
+
|
|
9
|
+
set -euo pipefail
|
|
10
|
+
|
|
11
|
+
AGY_CONFIG_DIR="$HOME/.gemini/config"
|
|
12
|
+
AGY_MCP_CONFIG="$AGY_CONFIG_DIR/mcp_config.json"
|
|
13
|
+
AGY_MD="$AGY_CONFIG_DIR/GEMINI.md"
|
|
14
|
+
RECALLNEST_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
15
|
+
MCP_ENTRY="$RECALLNEST_DIR/src/mcp-server.ts"
|
|
16
|
+
RULES_SNIPPET="$RECALLNEST_DIR/integrations/agy/agy-md-snippet.md"
|
|
17
|
+
RULES_HELPER="$RECALLNEST_DIR/integrations/shared/install-managed-block.sh"
|
|
18
|
+
|
|
19
|
+
if [[ ! -f "$MCP_ENTRY" ]]; then
|
|
20
|
+
echo "ERROR: $MCP_ENTRY not found. Run this from the recallnest repo root."
|
|
21
|
+
exit 1
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
if [[ ! -f "$RULES_HELPER" ]]; then
|
|
25
|
+
echo "ERROR: $RULES_HELPER not found."
|
|
26
|
+
exit 1
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
if ! command -v agy >/dev/null 2>&1; then
|
|
30
|
+
echo "WARNING: 'agy' not found on PATH. Install the Antigravity CLI first:"
|
|
31
|
+
echo " https://antigravity.google"
|
|
32
|
+
echo "Continuing anyway — the config will be written for when agy is installed."
|
|
33
|
+
echo ""
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
mkdir -p "$AGY_CONFIG_DIR"
|
|
37
|
+
if [[ ! -f "$AGY_MCP_CONFIG" ]]; then
|
|
38
|
+
echo '{"mcpServers":{}}' > "$AGY_MCP_CONFIG"
|
|
39
|
+
echo "Created $AGY_MCP_CONFIG"
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# Check if already configured
|
|
43
|
+
if bun -e "
|
|
44
|
+
const c = JSON.parse(require('fs').readFileSync('$AGY_MCP_CONFIG','utf8'));
|
|
45
|
+
process.exit(c.mcpServers?.recallnest ? 0 : 1);
|
|
46
|
+
" 2>/dev/null; then
|
|
47
|
+
echo "RecallNest MCP already configured in $AGY_MCP_CONFIG — skipping."
|
|
48
|
+
else
|
|
49
|
+
bun -e "
|
|
50
|
+
const fs = require('fs');
|
|
51
|
+
const c = JSON.parse(fs.readFileSync('$AGY_MCP_CONFIG','utf8'));
|
|
52
|
+
if (!c.mcpServers) c.mcpServers = {};
|
|
53
|
+
c.mcpServers.recallnest = {
|
|
54
|
+
type: 'stdio',
|
|
55
|
+
command: 'bun',
|
|
56
|
+
args: ['run', '$MCP_ENTRY']
|
|
57
|
+
};
|
|
58
|
+
fs.writeFileSync('$AGY_MCP_CONFIG', JSON.stringify(c, null, 2) + '\n');
|
|
59
|
+
"
|
|
60
|
+
echo "Added RecallNest MCP to $AGY_MCP_CONFIG"
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
. "$RULES_HELPER"
|
|
64
|
+
install_managed_markdown_block "$RULES_SNIPPET" "$AGY_MD" "recallnest-continuity"
|
|
65
|
+
echo "Installed RecallNest continuity rules in $AGY_MD"
|
|
66
|
+
|
|
67
|
+
echo ""
|
|
68
|
+
echo "Setup complete. Restart agy to activate, then verify with:"
|
|
69
|
+
echo " agy -p 'List your available MCP tools' --print-timeout 180s </dev/null"
|
|
70
|
+
echo ""
|
|
71
|
+
echo "Continuity baseline seed:"
|
|
72
|
+
echo " (cd \"$RECALLNEST_DIR\" && bun run seed:continuity)"
|
|
73
|
+
echo ""
|
|
74
|
+
echo "Managed snippet source:"
|
|
75
|
+
echo " $RULES_SNIPPET"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "recallnest",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "RecallNest — MCP-native, local-first memory search and distillation for AI conversations",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -54,21 +54,23 @@
|
|
|
54
54
|
"seed:continuity": "bun run seed:patterns && bun run seed:cases && bun run seed:memories",
|
|
55
55
|
"smoke:claude-continuity": "bash integrations/claude-code/smoke-continuity.sh",
|
|
56
56
|
"ui": "bun run src/ui-server.ts",
|
|
57
|
-
"api": "bun run src/api-server.ts"
|
|
57
|
+
"api": "bun run src/api-server.ts",
|
|
58
|
+
"gateway": "bun run src/gateway-server.ts"
|
|
58
59
|
},
|
|
59
60
|
"engines": {
|
|
60
|
-
"node": ">=
|
|
61
|
+
"node": ">=22"
|
|
61
62
|
},
|
|
62
63
|
"dependencies": {
|
|
64
|
+
"@hono/node-server": "1.19.17",
|
|
63
65
|
"@lancedb/lancedb": "^0.26.0",
|
|
64
66
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
65
67
|
"commander": "^12.0.0",
|
|
66
|
-
"openai": "^
|
|
68
|
+
"openai": "^7.5.0",
|
|
67
69
|
"tsx": "^4.19.0",
|
|
68
70
|
"zod": "^3.25.76"
|
|
69
71
|
},
|
|
70
72
|
"optionalDependencies": {
|
|
71
|
-
"babel-memory": "^2.1.
|
|
73
|
+
"babel-memory": "^2.1.2"
|
|
72
74
|
},
|
|
73
75
|
"repository": {
|
|
74
76
|
"type": "git",
|
|
@@ -268,6 +268,12 @@ describe("distinct-reader bookkeeping", () => {
|
|
|
268
268
|
});
|
|
269
269
|
|
|
270
270
|
it("dedups same reader and unions different readers", async () => {
|
|
271
|
+
// 2026-08-23 语义订正:同进程内的多个 AccessTracker 现在共享一个 readerId。
|
|
272
|
+
// 旧版每个实例各随机一个,与本文件测的那句注释(access-tracker.ts:63
|
|
273
|
+
// "one stdio MCP server process ≈ one CC session")直接矛盾——components 按
|
|
274
|
+
// profile 缓存,同一个会话开两个 profile 就凭空多出一个"读者",
|
|
275
|
+
// 把 distinctReaderCount 抬高、进而虚抬 skill-promotion 的 readBoost。
|
|
276
|
+
// 所以「不同读者」这一半改用显式 readerId 表达(跨进程/跨会话的真实形态)。
|
|
271
277
|
const entries = [makeEntry("a")];
|
|
272
278
|
const store = createMockStore(entries);
|
|
273
279
|
const t1 = new AccessTracker(store as any, { ...DEFAULT_ACCESS_TRACKER_CONFIG, flushIntervalMs: 1, cooldownMs: 0 });
|
|
@@ -276,9 +282,9 @@ describe("distinct-reader bookkeeping", () => {
|
|
|
276
282
|
t1.recordAccess(["a"]);
|
|
277
283
|
await t1.flush(); // same reader twice → still 1 distinct
|
|
278
284
|
|
|
279
|
-
const t2 = new AccessTracker(store as any, { ...DEFAULT_ACCESS_TRACKER_CONFIG, flushIntervalMs: 1, cooldownMs: 0 });
|
|
285
|
+
const t2 = new AccessTracker(store as any, { ...DEFAULT_ACCESS_TRACKER_CONFIG, flushIntervalMs: 1, cooldownMs: 0 }, "r-second99");
|
|
280
286
|
t2.recordAccess(["a"]);
|
|
281
|
-
await t2.flush(); //
|
|
287
|
+
await t2.flush(); // genuinely different reader → 2 distinct
|
|
282
288
|
|
|
283
289
|
const meta = JSON.parse(store.data.get("a")!.metadata!) as Record<string, unknown>;
|
|
284
290
|
expect(meta.accessCount).toBe(3);
|
|
@@ -286,6 +292,20 @@ describe("distinct-reader bookkeeping", () => {
|
|
|
286
292
|
expect(meta.distinctReaderCount).toBe(2);
|
|
287
293
|
});
|
|
288
294
|
|
|
295
|
+
it("does not inflate distinct readers when one session builds several trackers", async () => {
|
|
296
|
+
// 这是上面那条订正保护的东西:同一会话的两个 profile 不该被数成两个读者。
|
|
297
|
+
const entries = [makeEntry("a")];
|
|
298
|
+
const store = createMockStore(entries);
|
|
299
|
+
const cfg = { ...DEFAULT_ACCESS_TRACKER_CONFIG, flushIntervalMs: 1, cooldownMs: 0 };
|
|
300
|
+
for (const tracker of [new AccessTracker(store as any, cfg), new AccessTracker(store as any, cfg)]) {
|
|
301
|
+
tracker.recordAccess(["a"]);
|
|
302
|
+
await tracker.flush();
|
|
303
|
+
}
|
|
304
|
+
const meta = JSON.parse(store.data.get("a")!.metadata!) as Record<string, unknown>;
|
|
305
|
+
expect((meta.readerIds as string[]).length).toBe(1);
|
|
306
|
+
expect(meta.distinctReaderCount).toBe(1);
|
|
307
|
+
});
|
|
308
|
+
|
|
289
309
|
it("saturates readerIds at READER_ID_CAP without growing the array", async () => {
|
|
290
310
|
const capped = Array.from({ length: 8 }, (_, i) => `r-cap${i}`);
|
|
291
311
|
const entries = [makeEntry("a", {
|