recallnest 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/.claude-plugin/CLAUDE.md +29 -0
  2. package/.claude-plugin/marketplace.json +18 -0
  3. package/.env.example +3 -0
  4. package/.github/workflows/ci.yml +28 -0
  5. package/.mcp.json +9 -0
  6. package/CHANGELOG.md +51 -0
  7. package/CLAUDE.md +42 -0
  8. package/DEMO.md +94 -0
  9. package/EVAL.md +89 -0
  10. package/FAILURES.md +75 -0
  11. package/LICENSE +21 -0
  12. package/OPERATIONS.md +59 -0
  13. package/README.md +427 -0
  14. package/README_CN.md +425 -0
  15. package/ROADMAP.md +198 -0
  16. package/assets/recallnest-workbench.png +0 -0
  17. package/assets/ui/app.js +807 -0
  18. package/assets/ui/index.html +154 -0
  19. package/assets/ui/styles.css +605 -0
  20. package/assets/wechat-qr.jpg +0 -0
  21. package/config.json.example +38 -0
  22. package/daily-recall.sh +87 -0
  23. package/daily-reflections/2026-03-05.md +15 -0
  24. package/daily-reflections/2026-03-06.md +15 -0
  25. package/daily-reflections/2026-03-07.md +7 -0
  26. package/daily-reflections/2026-03-08.md +34 -0
  27. package/daily-reflections/2026-03-09.md +35 -0
  28. package/daily-reflections/2026-03-10.md +36 -0
  29. package/daily-reflections/2026-03-11.md +35 -0
  30. package/daily-reflections/2026-03-12.md +36 -0
  31. package/daily-reflections/2026-03-13.md +35 -0
  32. package/daily-reflections/2026-03-14.md +35 -0
  33. package/daily-reflections/2026-03-15.md +35 -0
  34. package/daily-reflections/2026-03-16.md +41 -0
  35. package/daily-reflections/2026-03-17.md +10 -0
  36. package/daily-reflections/2026-03-18.md +10 -0
  37. package/daily-reflections/2026-03-19.md +10 -0
  38. package/daily-reflections/2026-03-20.md +10 -0
  39. package/daily-reflections/2026-03-21.md +10 -0
  40. package/daily-reflections/2026-03-22.md +10 -0
  41. package/daily-reflections/2026-03-23.md +10 -0
  42. package/daily-reflections/2026-03-24.md +10 -0
  43. package/daily-reflections/2026-03-25.md +32 -0
  44. package/daily-reflections/2026-03-26.md +37 -0
  45. package/daily-reflections/2026-03-27.md +35 -0
  46. package/daily-reflections/2026-03-28.md +35 -0
  47. package/daily-reflections/2026-03-29.md +35 -0
  48. package/daily-reflections/2026-03-30.md +36 -0
  49. package/daily-reflections/2026-03-31.md +35 -0
  50. package/daily-reflections/2026-04-01.md +35 -0
  51. package/docs/api-reference.md +1291 -0
  52. package/docs/architecture.md +168 -0
  53. package/docs/memory-boundary-contract.md +226 -0
  54. package/docs/memory-categories.md +119 -0
  55. package/docs/pipeline-audit-ultramemory.md +177 -0
  56. package/docs/plans/2026-03-08-query-expansion.md +270 -0
  57. package/docs/plans/2026-03-16-continuity-layer.md +196 -0
  58. package/docs/plans/mcp-tiering-plan.md +126 -0
  59. package/docs/research/recall-quality-audit-2026-03-22.md +153 -0
  60. package/docs/self-evolution.md +198 -0
  61. package/docs/superpowers/plans/2026-03-19-ingest-pipeline-upgrade.md +782 -0
  62. package/docs/superpowers/specs/2026-03-19-ingest-pipeline-upgrade-design.md +77 -0
  63. package/docs/superpowers/specs/2026-03-23-pull-claude-desktop-design.md +95 -0
  64. package/eval/cases.json +85 -0
  65. package/eval/continuity/case-seeds.json +90 -0
  66. package/eval/continuity/cases.json +302 -0
  67. package/eval/continuity/memory-seeds.json +26 -0
  68. package/eval/continuity/pattern-seeds.json +100 -0
  69. package/eval/continuity/results-2026-03-16.md +117 -0
  70. package/eval/continuity/results-2026-03-19.md +453 -0
  71. package/eval/continuity/runbook.md +110 -0
  72. package/eval/continuity/seed-cases.md +54 -0
  73. package/eval/reports/2026-03-06-abstract-query-baseline.md +96 -0
  74. package/eval/reports/2026-03-06-aws-ssh-baseline.md +82 -0
  75. package/eval/reports/2026-03-06-baseline.md +82 -0
  76. package/eval/reports/query-expansion.md +138 -0
  77. package/integrations/README.md +57 -0
  78. package/integrations/claude-code/README.md +133 -0
  79. package/integrations/claude-code/claude-md-snippet.md +31 -0
  80. package/integrations/claude-code/setup.sh +66 -0
  81. package/integrations/claude-code/smoke-continuity.sh +452 -0
  82. package/integrations/codex/README.md +49 -0
  83. package/integrations/codex/agents-md-snippet.md +31 -0
  84. package/integrations/codex/setup.sh +58 -0
  85. package/integrations/examples/claude-agent-sdk/memory-agent.ts +182 -0
  86. package/integrations/examples/langchain/memory-chain.py +111 -0
  87. package/integrations/examples/openai-agents-sdk/memory-agent.py +109 -0
  88. package/integrations/gemini-cli/README.md +57 -0
  89. package/integrations/gemini-cli/gemini-md-snippet.md +31 -0
  90. package/integrations/gemini-cli/setup.sh +64 -0
  91. package/integrations/shared/install-managed-block.sh +51 -0
  92. package/lm +19 -0
  93. package/package.json +50 -0
  94. package/plan-v1.2-distributable.md +105 -0
  95. package/scripts/archive-distilled-junk.ts +116 -0
  96. package/scripts/backfill-l0l1l2.ts +98 -0
  97. package/scripts/blind-scan.ts +588 -0
  98. package/scripts/cleanup-step1-exact-dups.ts +117 -0
  99. package/scripts/cleanup-step2-template-dups.ts +113 -0
  100. package/scripts/cleanup-step3-stale-content.ts +149 -0
  101. package/scripts/cleanup-step4-orphan-scopes.ts +131 -0
  102. package/scripts/delete-distilled-junk.ts +88 -0
  103. package/scripts/distill-facts.ts +305 -0
  104. package/scripts/health-check.ts +343 -0
  105. package/scripts/incremental-ingest.sh +71 -0
  106. package/scripts/mlp-health-check.ts +382 -0
  107. package/scripts/pull-claude-desktop.ts +515 -0
  108. package/scripts/re-ingest-cc.sh +66 -0
  109. package/scripts/rebalance-memory-health.ts +181 -0
  110. package/scripts/run-desktop-ingest.sh +11 -0
  111. package/scripts/start-server.sh +12 -0
  112. package/scripts/viz-dashboard.html +423 -0
  113. package/scripts/viz-export.ts +703 -0
  114. package/src/__tests__/access-tracker-novelty.test.ts +228 -0
  115. package/src/__tests__/auto-consolidation.test.ts +168 -0
  116. package/src/__tests__/auto-recall.test.ts +131 -0
  117. package/src/__tests__/batch-dedup.test.ts +65 -0
  118. package/src/__tests__/capture-engine.test.ts +1142 -0
  119. package/src/__tests__/capture-heuristic.test.ts +171 -0
  120. package/src/__tests__/cascade-forget.test.ts +210 -0
  121. package/src/__tests__/category-min-scores.test.ts +33 -0
  122. package/src/__tests__/confidence-tracker.test.ts +196 -0
  123. package/src/__tests__/conflict-advisor.test.ts +206 -0
  124. package/src/__tests__/conflict-escalation.test.ts +149 -0
  125. package/src/__tests__/conflict-lifecycle.test.ts +83 -0
  126. package/src/__tests__/conflict-output.test.ts +85 -0
  127. package/src/__tests__/conflict-store.test.ts +374 -0
  128. package/src/__tests__/consolidation-engine.test.ts +181 -0
  129. package/src/__tests__/context-composer-pins.test.ts +64 -0
  130. package/src/__tests__/context-composer-task-selection.test.ts +24 -0
  131. package/src/__tests__/context-renderer.test.ts +91 -0
  132. package/src/__tests__/continuity-eval.test.ts +275 -0
  133. package/src/__tests__/continuity-schema.test.ts +97 -0
  134. package/src/__tests__/core-recall-eval.test.ts +235 -0
  135. package/src/__tests__/core-summary.test.ts +109 -0
  136. package/src/__tests__/dedup-actions.test.ts +58 -0
  137. package/src/__tests__/deterministic-id.test.ts +39 -0
  138. package/src/__tests__/doctor.test.ts +303 -0
  139. package/src/__tests__/drill-down.test.ts +108 -0
  140. package/src/__tests__/embedder.test.ts +122 -0
  141. package/src/__tests__/entity-resolver.test.ts +58 -0
  142. package/src/__tests__/event-segmenter.test.ts +153 -0
  143. package/src/__tests__/hotness-blend.test.ts +76 -0
  144. package/src/__tests__/ingest.test.ts +360 -0
  145. package/src/__tests__/kg-extractor.test.ts +184 -0
  146. package/src/__tests__/kg-store.test.ts +198 -0
  147. package/src/__tests__/llm-consolidation.test.ts +226 -0
  148. package/src/__tests__/memory-boundaries.test.ts +237 -0
  149. package/src/__tests__/memory-health-rebalance.test.ts +144 -0
  150. package/src/__tests__/memory-output.test.ts +215 -0
  151. package/src/__tests__/multi-vector.test.ts +242 -0
  152. package/src/__tests__/ppr-traversal.test.ts +256 -0
  153. package/src/__tests__/preference-guard-smoke.test.ts +211 -0
  154. package/src/__tests__/preference-matcher.test.ts +230 -0
  155. package/src/__tests__/preference-slots.test.ts +106 -0
  156. package/src/__tests__/prospective-memory.test.ts +283 -0
  157. package/src/__tests__/query-entity-detector.test.ts +171 -0
  158. package/src/__tests__/query-expander.test.ts +34 -0
  159. package/src/__tests__/recall-mode.test.ts +64 -0
  160. package/src/__tests__/result-synthesizer.test.ts +198 -0
  161. package/src/__tests__/resume-context.test.ts +4743 -0
  162. package/src/__tests__/retrieval-trace.test.ts +213 -0
  163. package/src/__tests__/retriever-boundary-weight.test.ts +136 -0
  164. package/src/__tests__/retroactive-boost.test.ts +223 -0
  165. package/src/__tests__/scope-inventory.test.ts +200 -0
  166. package/src/__tests__/scope-policy.test.ts +69 -0
  167. package/src/__tests__/session-checkpoint.test.ts +259 -0
  168. package/src/__tests__/session-gc.test.ts +215 -0
  169. package/src/__tests__/store-scope-audit.test.ts +81 -0
  170. package/src/__tests__/temporal-parser.test.ts +241 -0
  171. package/src/__tests__/term-registry.test.ts +121 -0
  172. package/src/__tests__/tool-output-compressor.test.ts +133 -0
  173. package/src/__tests__/version-manager.test.ts +213 -0
  174. package/src/__tests__/workflow-observation.test.ts +400 -0
  175. package/src/access-tracker.ts +316 -0
  176. package/src/adaptive-retrieval.ts +64 -0
  177. package/src/api-server.ts +667 -0
  178. package/src/asset-sync.ts +79 -0
  179. package/src/auto-consolidation.ts +133 -0
  180. package/src/auto-gc.ts +124 -0
  181. package/src/auto-recall.ts +95 -0
  182. package/src/capture-engine.ts +931 -0
  183. package/src/capture-heuristic.ts +177 -0
  184. package/src/cascade-forget.ts +135 -0
  185. package/src/chunker.ts +253 -0
  186. package/src/cli.ts +1917 -0
  187. package/src/confidence-tracker.ts +166 -0
  188. package/src/conflict-advisor.ts +433 -0
  189. package/src/conflict-engine.ts +181 -0
  190. package/src/conflict-escalation.ts +138 -0
  191. package/src/conflict-lifecycle.ts +67 -0
  192. package/src/conflict-output.ts +218 -0
  193. package/src/conflict-schema.ts +130 -0
  194. package/src/conflict-store.ts +127 -0
  195. package/src/consolidation-engine.ts +256 -0
  196. package/src/context-composer-pins.ts +183 -0
  197. package/src/context-composer-queries.ts +121 -0
  198. package/src/context-composer-scope.ts +56 -0
  199. package/src/context-composer-stable-selection.ts +200 -0
  200. package/src/context-composer-stable.ts +217 -0
  201. package/src/context-composer-task-fallbacks.ts +36 -0
  202. package/src/context-composer-task-ranking.ts +197 -0
  203. package/src/context-composer-task-results.ts +137 -0
  204. package/src/context-composer-task-selection.ts +342 -0
  205. package/src/context-composer-text.ts +57 -0
  206. package/src/context-composer.ts +300 -0
  207. package/src/context-renderer.ts +179 -0
  208. package/src/decay-engine.ts +189 -0
  209. package/src/doctor.ts +543 -0
  210. package/src/embedder.ts +557 -0
  211. package/src/entity-resolver.ts +131 -0
  212. package/src/eval.ts +632 -0
  213. package/src/event-segmenter.ts +216 -0
  214. package/src/ingest.ts +1822 -0
  215. package/src/kg-extractor.ts +217 -0
  216. package/src/kg-store.ts +353 -0
  217. package/src/legacy-scope-review.ts +53 -0
  218. package/src/llm-client.ts +629 -0
  219. package/src/llm-consolidation.ts +168 -0
  220. package/src/mcp-server.ts +1337 -0
  221. package/src/memory-assets.ts +475 -0
  222. package/src/memory-boundaries.ts +354 -0
  223. package/src/memory-health-rebalance.ts +220 -0
  224. package/src/memory-output.ts +474 -0
  225. package/src/memory-schema.ts +184 -0
  226. package/src/multi-vector.ts +234 -0
  227. package/src/noise-filter.ts +155 -0
  228. package/src/ppr-traversal.ts +279 -0
  229. package/src/preference-matcher.ts +174 -0
  230. package/src/preference-slots.ts +259 -0
  231. package/src/prospective-memory.ts +198 -0
  232. package/src/query-entity-detector.ts +207 -0
  233. package/src/query-expander.ts +98 -0
  234. package/src/result-synthesizer.ts +114 -0
  235. package/src/retrieval-profiles.ts +101 -0
  236. package/src/retrieval-trace.ts +94 -0
  237. package/src/retriever.ts +1338 -0
  238. package/src/retroactive-boost.ts +154 -0
  239. package/src/rif.ts +73 -0
  240. package/src/runtime-config.ts +172 -0
  241. package/src/schema-utils.ts +56 -0
  242. package/src/scope-inventory.ts +310 -0
  243. package/src/scope-policy.ts +142 -0
  244. package/src/session-engine.ts +168 -0
  245. package/src/session-output.ts +96 -0
  246. package/src/session-schema.ts +60 -0
  247. package/src/session-store.ts +293 -0
  248. package/src/stderr-log.ts +16 -0
  249. package/src/store.ts +903 -0
  250. package/src/temporal-parser.ts +318 -0
  251. package/src/term-registry.ts +791 -0
  252. package/src/tool-output-compressor.ts +115 -0
  253. package/src/tracker.ts +57 -0
  254. package/src/ui-server.ts +430 -0
  255. package/src/version-manager.ts +172 -0
  256. package/src/workflow-observation-engine.ts +316 -0
  257. package/src/workflow-observation-managed.ts +83 -0
  258. package/src/workflow-observation-output.ts +86 -0
  259. package/src/workflow-observation-schema.ts +87 -0
  260. package/src/workflow-observation-scope-review.ts +409 -0
  261. package/src/workflow-observation-store.ts +69 -0
@@ -0,0 +1,1291 @@
1
+ # RecallNest HTTP API Reference
2
+
3
+ > HTTP API 文档:所有端点的请求/响应格式。服务默认监听 `127.0.0.1:4318`。
4
+
5
+ Base URL: `http://localhost:4318`
6
+
7
+ All endpoints accept and return JSON. Set `Content-Type: application/json` for POST requests.
8
+
9
+ Workflow observation endpoints use a dedicated append-only store under `data/workflow-observations`. They do not write into the regular memory index or durable memory categories.
10
+
11
+ ---
12
+
13
+ ## Health Check
14
+
15
+ ```
16
+ GET /v1/health
17
+ ```
18
+
19
+ Returns server status.
20
+
21
+ **Response:**
22
+
23
+ ```json
24
+ {
25
+ "status": "ok",
26
+ "version": "1.0.0",
27
+ "totalMemories": 1247,
28
+ "timestamp": "2026-03-15T10:00:00.000Z"
29
+ }
30
+ ```
31
+
32
+ ---
33
+
34
+ ## Recall (Quick Search)
35
+
36
+ ```
37
+ POST /v1/recall
38
+ ```
39
+
40
+ Semantic search across scoped memories. Best for quick, conversational lookups when the caller already knows the active scope or session.
41
+
42
+ > 主动回忆:用关键词搜索相关记忆,返回按相关度排序的结果。默认需要显式 `scope`、`sessionId`,或环境里的默认 scope;只有 `allScopes=true` 才会跨 scope 搜索。
43
+
44
+ **Request:**
45
+
46
+ ```json
47
+ {
48
+ "query": "Docker bot debugging",
49
+ "scope": "project:docker-bot",
50
+ "limit": 5,
51
+ "minScore": 0.5
52
+ }
53
+ ```
54
+
55
+ | Field | Type | Required | Default | Description |
56
+ |-------|------|----------|---------|-------------|
57
+ | `query` | string | yes | — | Search query (2-3 key nouns work best) |
58
+ | `scope` | string | no | — | Explicit shared scope for the search |
59
+ | `sessionId` | string | no | — | Session identifier used to infer `session:{id}` scope |
60
+ | `allScopes` | boolean | no | `false` | Explicitly allow cross-scope search |
61
+ | `limit` | number | no | 5 | Max results (1-20) |
62
+ | `minScore` | number | no | 0 | Minimum relevance score (0-1). 0 = no filter |
63
+ | `category` | string | no | — | Filter: `profile`, `preferences`, `entities`, `events`, `cases`, `patterns` |
64
+ | `profile` | string | no | `"default"` | Retrieval profile: `default`, `writing`, `debug`, `fact-check` |
65
+
66
+ **Response:**
67
+
68
+ ```json
69
+ {
70
+ "results": [
71
+ {
72
+ "id": "a1b2c3d4",
73
+ "text": "Docker bot crash troubleshooting: check logs first with docker logs...",
74
+ "category": "cases",
75
+ "tier": "core",
76
+ "source": "cc",
77
+ "scope": "cc:a1b2c3d4",
78
+ "score": 0.87,
79
+ "date": "2026-03-04",
80
+ "boundary": {
81
+ "layer": "evidence",
82
+ "authority": "transcript-ingest",
83
+ "conflictPolicy": "append-only",
84
+ "originalCategory": "cases"
85
+ },
86
+ "canonicalKey": null,
87
+ "promotedFrom": null
88
+ }
89
+ ],
90
+ "query": "Docker bot debugging",
91
+ "profile": "default",
92
+ "totalMemories": 1247
93
+ }
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Auto Recall (Resume + Focused Search)
99
+
100
+ ```
101
+ POST /v1/auto-recall
102
+ ```
103
+
104
+ Compose startup continuity context and then run a focused scoped search in one call. Best for agent frameworks that want a single "recall at task start" hook without exposing extra MCP tools.
105
+
106
+ > 自动回忆:先做 `resume_context` 式的连续性恢复,再在同一 scope 下补一轮 focused search。适合 agent SDK / HTTP 集成在每次任务开始时直接调用。
107
+
108
+ **Request:**
109
+
110
+ ```json
111
+ {
112
+ "message": "RecallNest continuity",
113
+ "scope": "project:recallnest",
114
+ "limit": 3,
115
+ "limitPerSection": 3,
116
+ "includeLatestCheckpoint": true,
117
+ "profile": "default"
118
+ }
119
+ ```
120
+
121
+ | Field | Type | Required | Default | Description |
122
+ |-------|------|----------|---------|-------------|
123
+ | `message` | string | yes | — | Raw user message or task-start query |
124
+ | `task` | string | no | `message` | Optional broader task hint for resume composition |
125
+ | `scope` | string | no | — | Explicit shared scope |
126
+ | `sessionId` | string | no | — | Session identifier used to recover the latest checkpoint and infer scope |
127
+ | `allScopes` | boolean | no | `false` | Explicitly allow cross-scope focused search |
128
+ | `limit` | number | no | 5 | Max focused search results (1-20) |
129
+ | `limitPerSection` | number | no | 3 | Max items per resume section (1-6) |
130
+ | `includeLatestCheckpoint` | boolean | no | `true` | Whether to include the latest checkpoint in the resume payload |
131
+ | `category` | string | no | — | Optional focused search category filter |
132
+ | `profile` | string | no | `"default"` | Retrieval profile: `default`, `writing`, `debug`, `fact-check` |
133
+
134
+ **Response:**
135
+
136
+ ```json
137
+ {
138
+ "mode": "resume+search",
139
+ "query": "RecallNest continuity",
140
+ "profile": "default",
141
+ "resolvedScope": "project:recallnest",
142
+ "searchSkippedReason": null,
143
+ "resume": {
144
+ "summary": "Loaded 3 stable context item(s), 2 pattern(s), and 1 case(s). Latest checkpoint from codex-2026-03-16-001 on 2026-03-16: Implement startup continuity for fresh windows.",
145
+ "resolvedScope": "project:recallnest",
146
+ "stableContext": [
147
+ "Entity: RecallNest continuity revolves around three primitives."
148
+ ],
149
+ "relevantPatterns": [
150
+ "At task start, run search_memory before coding."
151
+ ],
152
+ "recentCases": [
153
+ "Case: RecallNest scope fallback cleanup"
154
+ ],
155
+ "latestCheckpoint": {
156
+ "sessionId": "codex-2026-03-16-001",
157
+ "resolvedScope": "project:recallnest",
158
+ "summary": "Implement startup continuity for fresh windows",
159
+ "updatedAt": "2026-03-16T05:00:00.000Z"
160
+ },
161
+ "generatedAt": "2026-03-16T05:10:00.000Z"
162
+ },
163
+ "results": [
164
+ {
165
+ "id": "a1b2c3d4",
166
+ "text": "RecallNest continuity revolves around three primitives: store_memory, checkpoint_session, resume_context.",
167
+ "category": "entities",
168
+ "scope": "project:recallnest",
169
+ "score": 0.91
170
+ }
171
+ ],
172
+ "count": 1
173
+ }
174
+ ```
175
+
176
+ If no explicit or inferred scope is available, `mode` becomes `resume-only`, `results` is empty, and `searchSkippedReason` explains why focused search was skipped.
177
+
178
+ ---
179
+
180
+ ## Store
181
+
182
+ ```
183
+ POST /v1/store
184
+ ```
185
+
186
+ Store a new durable memory entry.
187
+
188
+ > 存入长期记忆:适合 profile、preferences、entities、cases、patterns 这类跨窗口仍然有价值的信息。
189
+
190
+ **Request:**
191
+
192
+ ```json
193
+ {
194
+ "text": "User prefers code changes to be committed and pushed immediately",
195
+ "category": "preferences",
196
+ "source": "agent",
197
+ "tags": ["workflow", "git"],
198
+ "importance": 0.85
199
+ }
200
+ ```
201
+
202
+ | Field | Type | Required | Default | Description |
203
+ |-------|------|----------|---------|-------------|
204
+ | `text` | string | yes | — | Memory content |
205
+ | `category` | string | no | `"events"` | One of: `profile`, `preferences`, `entities`, `events`, `cases`, `patterns` |
206
+ | `source` | string | no | `"manual"` | One of: `manual`, `agent`, `api` |
207
+ | `scope` | string | yes | — | Required explicit scope such as `project:recallnest` or `session:abc123` |
208
+ | `importance` | number | no | 0.7 | Importance score (0-1), affects decay and ranking |
209
+ | `tags` | string[] | no | `[]` | Optional tags, max 8 items |
210
+ | `canonicalKey` | string | no | derived from content | Optional stable key for dedupe/update semantics |
211
+
212
+ **Response:**
213
+
214
+ ```json
215
+ {
216
+ "id": "e5f6g7h8-...",
217
+ "stored": true,
218
+ "disposition": "stored",
219
+ "storedAt": "2026-03-16T02:10:00.000Z",
220
+ "category": "preferences",
221
+ "scope": "memory:agent",
222
+ "canonicalKey": "preferences:user-prefers-code-changes-to-be-committed-and-pushed-immediately"
223
+ }
224
+ ```
225
+
226
+ If the same `canonicalKey` is already occupied by a different durable category, RecallNest returns `disposition = "conflict"` plus a `conflictId` instead of silently creating a second durable owner.
227
+
228
+ For slot-aware preferences, RecallNest now derives structured keys instead of collapsing everything into a broader same-topic key. Examples:
229
+
230
+ - atomic brand-item preference: `我喜欢吃麦当劳的麦辣鸡翅` -> `preferences:brand-item:麦当劳:麦辣鸡翅`
231
+ - reply-style preference: `User prefers concise, direct replies.` -> `preferences:reply-style:concise:direct`
232
+ - tool-choice preference: `Uses Bun over Node.` -> `preferences:tool-choice:bun:over:node`
233
+
234
+ ---
235
+
236
+ ## Capture (Structured Batch Write)
237
+
238
+ ```
239
+ POST /v1/capture
240
+ ```
241
+
242
+ Store multiple structured memories in one request.
243
+
244
+ > 批量结构化写入:适合上层 agent 一次性提炼多条 durable memory 后统一写入。
245
+
246
+ **Request:**
247
+
248
+ ```json
249
+ {
250
+ "scope": "agent:codex",
251
+ "source": "agent",
252
+ "defaultImportance": 0.7,
253
+ "memories": [
254
+ {
255
+ "text": "RecallNest is the shared memory layer for Claude Code, Codex, and Gemini CLI",
256
+ "category": "entities"
257
+ },
258
+ {
259
+ "text": "Use search_memory at task start",
260
+ "category": "patterns",
261
+ "importance": 0.9,
262
+ "tags": ["workflow", "memory"]
263
+ }
264
+ ]
265
+ }
266
+ ```
267
+
268
+ | Field | Type | Required | Default | Description |
269
+ |-------|------|----------|---------|-------------|
270
+ | `scope` | string | no | — | Default scope applied to items that do not specify one |
271
+ | `source` | string | no | `"agent"` | Default source for items that do not specify one |
272
+ | `defaultImportance` | number | no | 0.7 | Default importance for items that do not specify one |
273
+ | `memories` | array | yes | — | 1-20 structured memory items |
274
+
275
+ Each memory item supports:
276
+
277
+ | Field | Type | Required | Default | Description |
278
+ |-------|------|----------|---------|-------------|
279
+ | `text` | string | yes | — | Memory content |
280
+ | `category` | string | no | `"events"` | Durable memory category |
281
+ | `importance` | number | no | envelope default | Optional per-item override |
282
+ | `scope` | string | no | envelope scope | Optional per-item override; every stored memory still needs a scope via the envelope or item override |
283
+ | `source` | string | no | envelope source | Optional per-item override |
284
+ | `tags` | string[] | no | `[]` | Optional tags |
285
+ | `canonicalKey` | string | no | derived from content | Optional stable key for dedupe/update semantics |
286
+
287
+ **Response:**
288
+
289
+ ```json
290
+ {
291
+ "stored": 2,
292
+ "memories": [
293
+ {
294
+ "id": "a1b2c3d4-...",
295
+ "text": "RecallNest is the shared memory layer for Claude Code, Codex, and Gemini CLI",
296
+ "category": "entities",
297
+ "scope": "agent:codex",
298
+ "source": "agent",
299
+ "storedAt": "2026-03-16T02:11:00.000Z",
300
+ "disposition": "stored",
301
+ "canonicalKey": "entities:recallnest-is-the-shared-memory-layer-for-claude-code-codex-and-gemini-cli"
302
+ }
303
+ ]
304
+ }
305
+ ```
306
+
307
+ Each item may also carry `disposition = "conflict"` and a `conflictId` when batch input reuses an existing `canonicalKey` under a different durable category.
308
+
309
+ ---
310
+
311
+ ## Pattern (Structured Workflow Capture)
312
+
313
+ ```
314
+ POST /v1/pattern
315
+ ```
316
+
317
+ Store a reusable workflow as durable `patterns` memory.
318
+
319
+ > 专门写 workflow pattern:适合把“什么时候用、怎么做、做完得到什么”这种可复用流程沉淀成高质量 `patterns` 记忆。
320
+
321
+ **Request:**
322
+
323
+ ```json
324
+ {
325
+ "title": "Cross-window continuity handoff",
326
+ "trigger": "When opening a fresh terminal window for the same project",
327
+ "steps": [
328
+ "Call resume_context before coding",
329
+ "Review stable context and latest checkpoint",
330
+ "Save checkpoint_session before leaving the window"
331
+ ],
332
+ "outcome": "The next window recovers decisions and next actions faster",
333
+ "tools": ["resume_context", "checkpoint_session"],
334
+ "importance": 0.9,
335
+ "source": "agent",
336
+ "tags": ["continuity", "handoff"]
337
+ }
338
+ ```
339
+
340
+ | Field | Type | Required | Default | Description |
341
+ |-------|------|----------|---------|-------------|
342
+ | `title` | string | yes | — | Short workflow title |
343
+ | `trigger` | string | yes | — | When this workflow should be used |
344
+ | `steps` | string[] | yes | — | Ordered workflow steps, 1-8 items |
345
+ | `outcome` | string | no | — | Optional expected outcome |
346
+ | `tools` | string[] | no | `[]` | Optional tools, commands, or interfaces involved |
347
+ | `importance` | number | no | 0.82 | Importance score (0-1) |
348
+ | `scope` | string | yes | — | Required explicit scope such as `project:recallnest` or `session:abc123` |
349
+ | `source` | string | no | `"agent"` | One of: `manual`, `agent`, `api` |
350
+ | `tags` | string[] | no | `[]` | Optional tags; `workflow` and `pattern` are auto-added |
351
+ | `canonicalKey` | string | no | derived from title | Optional stable key for dedupe/update semantics |
352
+
353
+ **Response:**
354
+
355
+ ```json
356
+ {
357
+ "id": "f0e1d2c3-...",
358
+ "stored": true,
359
+ "category": "patterns",
360
+ "title": "Cross-window continuity handoff",
361
+ "scope": "memory:agent",
362
+ "tags": ["continuity", "handoff", "workflow", "pattern"],
363
+ "storedAt": "2026-03-16T08:10:00.000Z"
364
+ }
365
+ ```
366
+
367
+ ---
368
+
369
+ ## Case (Structured Problem-Solution Capture)
370
+
371
+ ```
372
+ POST /v1/case
373
+ ```
374
+
375
+ Store a reusable problem-solution case as durable `cases` memory.
376
+
377
+ > 专门写 problem-solution case:适合把“遇到什么问题、怎么解决、最后效果怎样”这种可复用经验沉淀成高质量 `cases` 记忆。
378
+
379
+ **Request:**
380
+
381
+ ```json
382
+ {
383
+ "title": "RecallNest sparse startup context cleanup",
384
+ "problem": "resume_context was returning noisy transcript fragments instead of a clean project handoff",
385
+ "context": "This happened in a fresh RecallNest window after continuity setup was already in place",
386
+ "solutionSteps": [
387
+ "Filter low-signal transcript fragments from stable recall",
388
+ "Backfill stable context from checkpoint focus, summary, and decisions",
389
+ "Use a lightweight task focus fallback only when no checkpoint-backed context is available"
390
+ ],
391
+ "outcome": "Fresh windows now recover cleaner RecallNest continuity context",
392
+ "tools": ["resume_context", "checkpoint_session"],
393
+ "importance": 0.9,
394
+ "source": "agent",
395
+ "tags": ["continuity", "startup-context"]
396
+ }
397
+ ```
398
+
399
+ | Field | Type | Required | Default | Description |
400
+ |-------|------|----------|---------|-------------|
401
+ | `title` | string | yes | — | Short case title |
402
+ | `problem` | string | yes | — | What problem happened |
403
+ | `context` | string | no | — | Optional context or preconditions |
404
+ | `solutionSteps` | string[] | yes | — | Ordered solution steps, 1-8 items |
405
+ | `outcome` | string | no | — | Optional result or resolution |
406
+ | `tools` | string[] | no | `[]` | Optional tools, commands, or interfaces involved |
407
+ | `importance` | number | no | 0.84 | Importance score (0-1) |
408
+ | `scope` | string | yes | — | Required explicit scope such as `project:recallnest` or `session:abc123` |
409
+ | `source` | string | no | `"agent"` | One of: `manual`, `agent`, `api` |
410
+ | `tags` | string[] | no | `[]` | Optional tags; `case` and `solution` are auto-added |
411
+ | `canonicalKey` | string | no | derived from title | Optional stable key for dedupe/update semantics |
412
+
413
+ ---
414
+
415
+ ## Promote (Evidence -> Durable)
416
+
417
+ ```
418
+ POST /v1/promote
419
+ ```
420
+
421
+ Promote an evidence memory into durable memory.
422
+
423
+ > 显式升级:把 transcript / import evidence 中的高价值片段升级成 durable memory,而不是让 raw ingest 直接冒充长期事实。
424
+
425
+ **Request:**
426
+
427
+ ```json
428
+ {
429
+ "memoryId": "12345678-1234-1234-1234-123456789abc",
430
+ "text": "User prefers concise, direct replies.",
431
+ "category": "preferences",
432
+ "canonicalKey": "user-reply-style",
433
+ "tags": ["writing"]
434
+ }
435
+ ```
436
+
437
+ | Field | Type | Required | Default | Description |
438
+ |-------|------|----------|---------|-------------|
439
+ | `memoryId` | string | yes | — | Evidence memory ID or unique prefix |
440
+ | `text` | string | no | source text | Optional cleaned durable text |
441
+ | `category` | string | no | inferred from source | Target durable category |
442
+ | `importance` | number | no | 0.78 | Importance score (0-1) |
443
+ | `scope` | string | yes | — | Required explicit target scope such as `project:recallnest` or `session:abc123` |
444
+ | `source` | string | no | `"agent"` | Promotion source label |
445
+ | `tags` | string[] | no | `[]` | Optional tags |
446
+ | `canonicalKey` | string | no | derived from text | Optional stable key for dedupe/update semantics |
447
+
448
+ **Response:**
449
+
450
+ ```json
451
+ {
452
+ "id": "c0ffee00-...",
453
+ "stored": true,
454
+ "disposition": "promoted",
455
+ "category": "preferences",
456
+ "scope": "memory:agent",
457
+ "sourceMemoryId": "12345678-1234-1234-1234-123456789abc",
458
+ "sourceCategory": "events",
459
+ "storedAt": "2026-03-16T02:20:00.000Z",
460
+ "canonicalKey": "user-reply-style"
461
+ }
462
+ ```
463
+
464
+ When a promotion would overwrite an existing durable memory with the same `canonicalKey`, RecallNest now creates an open conflict candidate instead of silently applying `latest-wins`.
465
+
466
+ The same slot-aware key inference also applies during promotion when `category = "preferences"` and the text resolves to a supported preference slot such as an atomic brand-item preference, a reply-style preference, or a tool-choice preference.
467
+
468
+ If the promotion resolves to the same preference slot as the existing durable owner, RecallNest now collapses it onto that owner instead of opening a conflict. This currently applies to slot-aware brand-item keys such as `preferences:brand-item:麦当劳:麦辣鸡翅`, reply-style keys such as `preferences:reply-style:concise:direct`, and tool-choice keys such as `preferences:tool-choice:bun:over:node`.
469
+
470
+ ```json
471
+ {
472
+ "id": "baddcafe-...",
473
+ "stored": false,
474
+ "disposition": "conflict",
475
+ "category": "preferences",
476
+ "scope": "memory:agent",
477
+ "sourceMemoryId": "12345678-1234-1234-1234-123456789abc",
478
+ "sourceCategory": "events",
479
+ "storedAt": "2026-03-16T02:20:00.000Z",
480
+ "canonicalKey": "user-reply-style",
481
+ "conflictId": "4f71a1f1-..."
482
+ }
483
+ ```
484
+
485
+ Notes:
486
+
487
+ - `disposition = "promoted"` means a new durable memory was written
488
+ - `disposition = "deduped"` means the durable text already existed under the same `canonicalKey`
489
+ - `disposition = "conflict"` means RecallNest kept the existing durable memory and opened a review item
490
+
491
+ ---
492
+
493
+ ## Conflicts
494
+
495
+ ### List / Inspect Conflicts
496
+
497
+ ```
498
+ GET /v1/conflicts
499
+ GET /v1/conflicts?status=open&canonicalKey=user-reply-style&limit=10
500
+ GET /v1/conflicts?attention=stale&limit=10
501
+ GET /v1/conflicts?groupBy=cluster&attention=resolved&limit=10
502
+ GET /v1/conflicts?conflictId=4f71a1f1-...
503
+ ```
504
+
505
+ List recent conflict candidates or fetch a single conflict record.
506
+
507
+ **List response:**
508
+
509
+ ```json
510
+ {
511
+ "groupBy": "record",
512
+ "conflicts": [
513
+ {
514
+ "conflictId": "4f71a1f1-...",
515
+ "status": "open",
516
+ "reason": "promotion_conflicts_with_existing_durable",
517
+ "canonicalKey": "user-reply-style",
518
+ "category": "preferences",
519
+ "reopenCount": 1,
520
+ "lastReopenedAt": "2026-03-16T05:20:00.000Z",
521
+ "lifecycle": {
522
+ "attention": "aging",
523
+ "openAgeDays": 1,
524
+ "reopenCount": 1,
525
+ "isOpen": true,
526
+ "needsAttention": false
527
+ },
528
+ "advice": {
529
+ "suggestedResolution": "keep_existing",
530
+ "confidence": "medium",
531
+ "similarity": 0.84,
532
+ "clusterKey": "user-reply-style::promotion_conflicts_with_existing_durable::preferences",
533
+ "clusterLabel": "preferences / user-reply-style",
534
+ "reasons": [
535
+ "Existing durable text already looks like the tighter rewrite."
536
+ ]
537
+ },
538
+ "existing": {
539
+ "memoryId": "baddcafe-...",
540
+ "text": "User prefers concise, direct replies."
541
+ },
542
+ "incoming": {
543
+ "sourceMemoryId": "12345678-1234-1234-1234-123456789abc",
544
+ "text": "User prefers colloquial writing that stays grounded and non-salesy."
545
+ }
546
+ }
547
+ ],
548
+ "count": 1
549
+ }
550
+ ```
551
+
552
+ **Cluster response:**
553
+
554
+ ```json
555
+ {
556
+ "groupBy": "cluster",
557
+ "clusters": [
558
+ {
559
+ "clusterKey": "user-reply-style::promotion_conflicts_with_existing_durable::preferences",
560
+ "clusterLabel": "preferences / user-reply-style",
561
+ "canonicalKey": "user-reply-style",
562
+ "category": "preferences",
563
+ "reason": "promotion_conflicts_with_existing_durable",
564
+ "totalCount": 3,
565
+ "openCount": 1,
566
+ "latestUpdatedAt": "2026-03-16T05:20:00.000Z",
567
+ "latestConflictId": "4f71a1f1-...",
568
+ "attentionCounts": {
569
+ "fresh": 0,
570
+ "aging": 1,
571
+ "stale": 0,
572
+ "escalated": 0,
573
+ "resolved": 2
574
+ },
575
+ "suggestedResolution": "keep_existing",
576
+ "confidence": "medium"
577
+ }
578
+ ],
579
+ "count": 1
580
+ }
581
+ ```
582
+
583
+ Query parameters:
584
+
585
+ | Parameter | Type | Description |
586
+ |-----------|------|-------------|
587
+ | `status` | string | Optional raw status filter: `open`, `accepted-incoming`, `kept-existing` |
588
+ | `attention` | string | Optional lifecycle filter: `fresh`, `aging`, `stale`, `escalated`, `resolved` |
589
+ | `groupBy` | string | Optional output mode: `record` (default) or `cluster` |
590
+ | `canonicalKey` | string | Optional canonical key filter |
591
+ | `limit` | number | Max results, default `20` |
592
+ | `conflictId` | string | Fetch a single conflict by full ID or unique prefix |
593
+
594
+ `advice.mergeSuggestion` is optional. It appears only when RecallNest can derive a conservative merged wording suggestion for `manual_review` conflicts.
595
+
596
+ **Single conflict response:**
597
+
598
+ ```json
599
+ {
600
+ "conflict": {
601
+ "conflictId": "4f71a1f1-...",
602
+ "status": "open",
603
+ "canonicalKey": "user-reply-style",
604
+ "category": "preferences",
605
+ "lifecycle": {
606
+ "attention": "aging",
607
+ "openAgeDays": 1,
608
+ "reopenCount": 1,
609
+ "isOpen": true,
610
+ "needsAttention": false
611
+ },
612
+ "advice": {
613
+ "suggestedResolution": "keep_existing",
614
+ "confidence": "medium",
615
+ "similarity": 0.84,
616
+ "clusterKey": "user-reply-style::promotion_conflicts_with_existing_durable::preferences",
617
+ "clusterLabel": "preferences / user-reply-style",
618
+ "reasons": [
619
+ "Existing durable text already looks like the tighter rewrite."
620
+ ]
621
+ }
622
+ }
623
+ }
624
+ ```
625
+
626
+ ### Resolve Conflict
627
+
628
+ ```
629
+ POST /v1/conflicts/resolve
630
+ ```
631
+
632
+ Resolve an open conflict candidate by keeping the existing durable memory, accepting the incoming promoted text, or merging the two into a conservative durable rewrite.
633
+
634
+ **Request:**
635
+
636
+ ```json
637
+ {
638
+ "conflictId": "4f71a1f1-...",
639
+ "resolution": "accept_incoming",
640
+ "notes": "Incoming wording is cleaner."
641
+ }
642
+ ```
643
+
644
+ | Field | Type | Required | Description |
645
+ |-------|------|----------|-------------|
646
+ | `conflictId` | string | yes | Conflict candidate ID |
647
+ | `resolution` | string | yes | `accept_incoming`, `keep_existing`, or `merge` |
648
+ | `mergedText` | string | no | Optional merged durable wording when `resolution=merge`; otherwise RecallNest uses `advice.mergeSuggestion` when available |
649
+ | `notes` | string | no | Optional operator notes |
650
+
651
+ **Response:**
652
+
653
+ ```json
654
+ {
655
+ "conflictId": "4f71a1f1-...",
656
+ "status": "accepted-incoming",
657
+ "updatedAt": "2026-03-16T05:00:00.000Z",
658
+ "resolvedAt": "2026-03-16T05:00:00.000Z",
659
+ "updatedMemoryId": "baddcafe-..."
660
+ }
661
+ ```
662
+
663
+ If you keep the existing durable memory, `updatedMemoryId` is omitted and the conflict status becomes `kept-existing`.
664
+ If you resolve with `merge`, the conflict status becomes `merged` and `updatedMemoryId` points to the rewritten durable memory that kept the same canonical owner.
665
+
666
+ ### Conflict Audit
667
+
668
+ ```
669
+ GET /v1/conflicts/audit
670
+ GET /v1/conflicts/audit?limit=100&top=5
671
+ GET /v1/conflicts/audit?canonicalKey=user-reply-style
672
+ ```
673
+
674
+ Generate a terminal-friendly audit summary so stale or escalated clusters can be reviewed first.
675
+
676
+ **Response:**
677
+
678
+ ```json
679
+ {
680
+ "totalConflicts": 7,
681
+ "totalClusters": 3,
682
+ "openConflicts": 4,
683
+ "openClusters": 2,
684
+ "attentionCounts": {
685
+ "fresh": 1,
686
+ "aging": 1,
687
+ "stale": 1,
688
+ "escalated": 1,
689
+ "resolved": 3
690
+ },
691
+ "priorityClusters": [
692
+ {
693
+ "clusterKey": "user-reply-style::promotion_conflicts_with_existing_durable::preferences",
694
+ "clusterLabel": "preferences / user-reply-style",
695
+ "canonicalKey": "user-reply-style",
696
+ "category": "preferences",
697
+ "reason": "promotion_conflicts_with_existing_durable",
698
+ "totalCount": 4,
699
+ "openCount": 2,
700
+ "latestUpdatedAt": "2026-03-16T05:20:00.000Z",
701
+ "latestConflictId": "4f71a1f1-...",
702
+ "attention": "escalated",
703
+ "suggestedResolution": "keep_existing",
704
+ "confidence": "medium"
705
+ }
706
+ ],
707
+ "suggestedActions": [
708
+ "Resolve 1 escalated cluster(s) first."
709
+ ]
710
+ }
711
+ ```
712
+
713
+ Query parameters:
714
+
715
+ | Parameter | Type | Description |
716
+ |-----------|------|-------------|
717
+ | `status` | string | Optional raw status filter: `open`, `accepted-incoming`, `kept-existing` |
718
+ | `canonicalKey` | string | Optional canonical key filter |
719
+ | `limit` | number | Max records to scan, default `100` |
720
+ | `top` | number | Max priority clusters to return, default `5` |
721
+
722
+ ### Escalate Conflicts
723
+
724
+ ```
725
+ POST /v1/conflicts/escalate
726
+ ```
727
+
728
+ Preview or apply escalation metadata for `stale` / `escalated` open conflicts.
729
+
730
+ **Request:**
731
+
732
+ ```json
733
+ {
734
+ "attention": "stale",
735
+ "limit": 100,
736
+ "top": 10,
737
+ "apply": false,
738
+ "notes": "nightly escalation audit"
739
+ }
740
+ ```
741
+
742
+ | Field | Type | Required | Description |
743
+ |-------|------|----------|-------------|
744
+ | `attention` | string | no | `stale` or `escalated`, default `stale` |
745
+ | `canonicalKey` | string | no | Optional canonical key filter |
746
+ | `limit` | number | no | Max open conflicts to scan, default `100` |
747
+ | `top` | number | no | Max eligible conflicts to include, default `10` |
748
+ | `apply` | boolean | no | When `false`, preview only. When `true`, writes escalation metadata |
749
+ | `notes` | string | no | Optional operator note stored on escalated conflicts |
750
+
751
+ **Response:**
752
+
753
+ ```json
754
+ {
755
+ "apply": false,
756
+ "scanned": 12,
757
+ "eligible": 2,
758
+ "escalated": 0,
759
+ "skipped": 0,
760
+ "items": [
761
+ {
762
+ "conflictId": "4f71a1f1-...",
763
+ "canonicalKey": "user-reply-style",
764
+ "attention": "stale",
765
+ "openAgeDays": 4,
766
+ "reopenCount": 1,
767
+ "escalationCount": 0,
768
+ "suggestedResolution": "manual_review",
769
+ "confidence": "high",
770
+ "action": "pending",
771
+ "clusterKey": "user-reply-style::promotion_conflicts_with_existing_durable::preferences"
772
+ }
773
+ ]
774
+ }
775
+ ```
776
+
777
+ ---
778
+
779
+ ## Checkpoint (Save Current Work State)
780
+
781
+ ```
782
+ POST /v1/checkpoint
783
+ ```
784
+
785
+ Store a session checkpoint outside the durable memory index.
786
+
787
+ > 保存当前工作状态:适合跨窗口延续任务,但不应该混入长期 durable memory。
788
+
789
+ **Request:**
790
+
791
+ ```json
792
+ {
793
+ "sessionId": "codex-2026-03-16-001",
794
+ "scope": "agent:codex",
795
+ "summary": "Implement session checkpoint storage",
796
+ "decisions": ["Keep checkpoints out of LanceDB"],
797
+ "openLoops": ["Need resume_context next"],
798
+ "nextActions": ["Add checkpoint MCP tool"],
799
+ "entities": ["RecallNest", "Codex"],
800
+ "files": ["src/session-store.ts"]
801
+ }
802
+ ```
803
+
804
+ | Field | Type | Required | Default | Description |
805
+ |-------|------|----------|---------|-------------|
806
+ | `sessionId` | string | yes | — | Current session identifier |
807
+ | `scope` | string | no | `session:{sessionId}` | Optional shared scope |
808
+ | `summary` | string | yes | — | Compact summary of the current work state |
809
+ | `task` | string | no | — | Optional task label |
810
+ | `decisions` | string[] | no | `[]` | Key decisions already made |
811
+ | `openLoops` | string[] | no | `[]` | Unresolved questions or pending items |
812
+ | `nextActions` | string[] | no | `[]` | Next actions to take |
813
+ | `entities` | string[] | no | `[]` | Relevant projects, tools, or people |
814
+ | `files` | string[] | no | `[]` | Relevant files or paths |
815
+ | `updatedAt` | string | no | `now()` | Optional ISO timestamp override |
816
+
817
+ RecallNest sanitizes repo-state text such as `git status`, modified-file lists, and untracked-file notes out of saved checkpoint content. Verify volatile repo state locally in the next window instead of relying on checkpoint text.
818
+ Managed MCP / HTTP checkpoint calls now also append a dedicated workflow observation automatically: normal saves record `success`, while repo-state sanitization records `corrected` with signal `repo-state-sanitized`.
819
+
820
+ **Response:**
821
+
822
+ ```json
823
+ {
824
+ "sessionId": "codex-2026-03-16-001",
825
+ "scope": "agent:codex",
826
+ "summary": "Implement session checkpoint storage",
827
+ "decisions": ["Keep checkpoints out of LanceDB"],
828
+ "openLoops": ["Need resume_context next"],
829
+ "nextActions": ["Add checkpoint MCP tool"],
830
+ "entities": ["RecallNest", "Codex"],
831
+ "files": ["src/session-store.ts"],
832
+ "updatedAt": "2026-03-16T09:30:00.000Z"
833
+ }
834
+ ```
835
+
836
+ ---
837
+
838
+ ## Resume (Compose Startup Context)
839
+
840
+ ```
841
+ POST /v1/resume
842
+ ```
843
+
844
+ Compose startup context for a fresh window by combining stable durable memory, relevant patterns and cases, plus the latest checkpoint for a session or scope.
845
+
846
+ > 为新窗口编排上下文:返回的是组合后的连续性上下文,不是原始检索结果堆积。
847
+
848
+ Managed MCP / HTTP resume calls now also append a dedicated `resume_context` workflow observation with source `managed`; this stays in the workflow observation store and does not enter durable recall.
849
+
850
+ **Request:**
851
+
852
+ ```json
853
+ {
854
+ "task": "Implement startup continuity for fresh windows",
855
+ "scope": "agent:codex",
856
+ "sessionId": "codex-2026-03-16-001",
857
+ "limitPerSection": 3,
858
+ "includeLatestCheckpoint": true,
859
+ "profile": "default"
860
+ }
861
+ ```
862
+
863
+ | Field | Type | Required | Default | Description |
864
+ |-------|------|----------|---------|-------------|
865
+ | `task` | string | no | — | Optional current task or question to bias recall |
866
+ | `scope` | string | no | — | Optional shared scope for project or terminal continuity |
867
+ | `sessionId` | string | no | — | Optional session identifier used to recover the latest checkpoint |
868
+ | `limitPerSection` | number | no | 3 | Max items returned per section (1-6) |
869
+ | `includeLatestCheckpoint` | boolean | no | `true` | Whether to include the latest checkpoint summary |
870
+ | `profile` | string | no | `"default"` | Retrieval profile: `default`, `writing`, `debug`, `fact-check` |
871
+
872
+ **Response:**
873
+
874
+ ```json
875
+ {
876
+ "summary": "Loaded 3 stable context item(s), 2 pattern(s), and 1 case(s). Latest checkpoint from codex-2026-03-16-001 on 2026-03-16: Implement startup continuity for fresh windows.",
877
+ "resolvedScope": "agent:codex",
878
+ "stableContext": [
879
+ "Profile: User builds local-first memory systems.",
880
+ "Preference: User prefers concise technical replies.",
881
+ "Entity: RecallNest is shared across Claude Code, Codex, and Gemini CLI."
882
+ ],
883
+ "relevantPatterns": [
884
+ "At task start, run search_memory before coding."
885
+ ],
886
+ "recentCases": [
887
+ "Keep session state in a checkpoint store instead of the durable index."
888
+ ],
889
+ "latestCheckpoint": {
890
+ "sessionId": "codex-2026-03-16-001",
891
+ "resolvedScope": "agent:codex",
892
+ "summary": "Implement startup continuity for fresh windows",
893
+ "updatedAt": "2026-03-16T05:00:00.000Z"
894
+ },
895
+ "generatedAt": "2026-03-16T05:10:00.000Z",
896
+ "profile": "default"
897
+ }
898
+ ```
899
+
900
+ Use `resolvedScope` as the default scope for follow-up `search_memory`, `brief_memory`, `pin_memory`, and similar recall calls when the client did not already provide a stricter shared scope.
901
+
902
+ ---
903
+
904
+ ## Latest Checkpoint
905
+
906
+ ```
907
+ GET /v1/checkpoint/latest
908
+ ```
909
+
910
+ Fetch the latest checkpoint for a given `sessionId` or `scope`.
911
+
912
+ > 获取最新 checkpoint:适合调试当前工作状态是否已写入,也可以和 `POST /v1/resume` 配合使用。
913
+
914
+ Query params:
915
+
916
+ | Param | Required | Description |
917
+ |-------|----------|-------------|
918
+ | `sessionId` | no | Filter by session ID |
919
+ | `scope` | no | Filter by shared scope |
920
+
921
+ **Response:**
922
+
923
+ ```json
924
+ {
925
+ "checkpoint": {
926
+ "sessionId": "codex-2026-03-16-001",
927
+ "summary": "Implement session checkpoint storage",
928
+ "updatedAt": "2026-03-16T03:20:00.000Z",
929
+ "checkpointId": "b1c2d3e4-...",
930
+ "resolvedScope": "agent:codex"
931
+ }
932
+ }
933
+ ```
934
+
935
+ If nothing matches:
936
+
937
+ ```json
938
+ {
939
+ "checkpoint": null
940
+ }
941
+ ```
942
+
943
+ ---
944
+
945
+ ## Workflow Observe
946
+
947
+ ```
948
+ POST /v1/workflow-observe
949
+ ```
950
+
951
+ Store one append-only workflow observation outside durable memory.
952
+
953
+ > 记录 workflow observation:适合追踪 `resume_context`、`checkpoint_session` 等 primitive 是成功、失败、被纠正,还是被漏掉。
954
+
955
+ **Request:**
956
+
957
+ ```json
958
+ {
959
+ "workflowId": "resume_context",
960
+ "outcome": "missed",
961
+ "summary": "Fresh window skipped continuity recovery before repo exploration.",
962
+ "scope": "project:recallnest",
963
+ "source": "smoke",
964
+ "signal": "missed-startup-trigger",
965
+ "task": "headless continuity smoke",
966
+ "tags": ["continuity"],
967
+ "tools": ["resume_context"]
968
+ }
969
+ ```
970
+
971
+ | Field | Type | Required | Default | Description |
972
+ |-------|------|----------|---------|-------------|
973
+ | `workflowId` | string | yes | — | Workflow primitive id such as `resume_context` |
974
+ | `outcome` | string | no | `"success"` | One of: `success`, `failure`, `corrected`, `missed` |
975
+ | `summary` | string | yes | — | Short description of what happened |
976
+ | `scope` | string | no | `"global"` | Optional scope such as `project:recallnest` |
977
+ | `source` | string | no | `"manual"` | Source label such as `agent`, `managed`, `smoke`, `eval`, `manual` |
978
+ | `signal` | string | no | — | Optional failure/correction signal tag |
979
+ | `task` | string | no | — | Optional related task |
980
+ | `tags` | string[] | no | `[]` | Optional tags |
981
+ | `tools` | string[] | no | `[]` | Optional tools involved |
982
+ | `recordedAt` | string | no | `now()` | Optional ISO timestamp override |
983
+
984
+ **Response:**
985
+
986
+ ```json
987
+ {
988
+ "observationId": "resume_context-missed-2026-03-17T03-00-00-000Z",
989
+ "workflowId": "resume_context",
990
+ "outcome": "missed",
991
+ "summary": "Fresh window skipped continuity recovery before repo exploration.",
992
+ "scope": "project:recallnest",
993
+ "resolvedScope": "project:recallnest",
994
+ "source": "smoke",
995
+ "signal": "missed-startup-trigger",
996
+ "task": "headless continuity smoke",
997
+ "tags": ["continuity"],
998
+ "tools": ["resume_context"],
999
+ "recordedAt": "2026-03-17T03:00:00.000Z"
1000
+ }
1001
+ ```
1002
+
1003
+ ---
1004
+
1005
+ ## Workflow Health
1006
+
1007
+ ```
1008
+ GET /v1/workflow-health
1009
+ GET /v1/workflow-health?workflowId=resume_context&scope=project:recallnest
1010
+ ```
1011
+
1012
+ Inspect one workflow primitive or return a dashboard of degraded workflows.
1013
+
1014
+ > 查看 workflow 健康度:支持单个 workflow 的 7 天 / 30 天汇总,也支持全局 dashboard。
1015
+
1016
+ Query params:
1017
+
1018
+ | Param | Required | Description |
1019
+ |-------|----------|-------------|
1020
+ | `workflowId` | no | Optional workflow primitive id |
1021
+ | `scope` | no | Optional scope filter |
1022
+ | `limit` | no | Dashboard max rows, default `10` |
1023
+
1024
+ **Workflow response:**
1025
+
1026
+ ```json
1027
+ {
1028
+ "workflowId": "resume_context",
1029
+ "scope": "project:recallnest",
1030
+ "status": "watch",
1031
+ "summary": "3 observations in the last 30d, success rate 33.3%, 2 issue observations.",
1032
+ "latestObservationAt": "2026-03-17T03:00:00.000Z",
1033
+ "windows": [
1034
+ {
1035
+ "days": 7,
1036
+ "total": 2,
1037
+ "successes": 1,
1038
+ "failures": 0,
1039
+ "corrected": 1,
1040
+ "missed": 0,
1041
+ "issueCount": 1,
1042
+ "successRate": 0.5,
1043
+ "issueRate": 0.5,
1044
+ "latestAt": "2026-03-17T03:00:00.000Z",
1045
+ "topSignals": [
1046
+ { "signal": "user-correction", "count": 1 }
1047
+ ]
1048
+ }
1049
+ ]
1050
+ }
1051
+ ```
1052
+
1053
+ **Dashboard response:**
1054
+
1055
+ ```json
1056
+ {
1057
+ "dashboard": [
1058
+ {
1059
+ "workflowId": "checkpoint_session",
1060
+ "scope": "project:recallnest",
1061
+ "status": "critical",
1062
+ "total": 1,
1063
+ "issueCount": 1,
1064
+ "successRate": 0,
1065
+ "latestObservationAt": "2026-03-17T04:00:00.000Z",
1066
+ "summary": "1 observations in the last 30d, success rate 0.0%, 1 issue observations."
1067
+ }
1068
+ ]
1069
+ }
1070
+ ```
1071
+
1072
+ ---
1073
+
1074
+ ## Workflow Evidence
1075
+
1076
+ ```
1077
+ GET /v1/workflow-evidence?workflowId=checkpoint_session&scope=project:recallnest&limit=5
1078
+ ```
1079
+
1080
+ Build an evidence pack for one workflow primitive from recent issue observations.
1081
+
1082
+ > 生成 workflow evidence pack:把最近问题 observation、top signals 和修复建议打包出来,方便做规则、prompt、测试收口。
1083
+
1084
+ Query params:
1085
+
1086
+ | Param | Required | Description |
1087
+ |-------|----------|-------------|
1088
+ | `workflowId` | yes | Workflow primitive id |
1089
+ | `scope` | no | Optional scope filter |
1090
+ | `limit` | no | Max recent issue observations, default `5` |
1091
+
1092
+ **Response:**
1093
+
1094
+ ```json
1095
+ {
1096
+ "workflowId": "checkpoint_session",
1097
+ "scope": "project:recallnest",
1098
+ "generatedAt": "2026-03-17T10:10:00.000Z",
1099
+ "summary": "1 issue observations in the last 30d for checkpoint_session.",
1100
+ "topSignals": [
1101
+ { "signal": "repo-state-contamination", "count": 1 }
1102
+ ],
1103
+ "recentIssues": [
1104
+ {
1105
+ "observationId": "checkpoint_session-failure-2026-03-17T04-00-00-000Z",
1106
+ "outcome": "failure",
1107
+ "summary": "Checkpoint still carried repo-state text before the product-side guard landed.",
1108
+ "signal": "repo-state-contamination",
1109
+ "recordedAt": "2026-03-17T04:00:00.000Z",
1110
+ "task": "headless continuity smoke"
1111
+ }
1112
+ ],
1113
+ "suggestions": [
1114
+ "Keep volatile repo-state text out of saved checkpoints and handoff summaries unless this window verified it."
1115
+ ]
1116
+ }
1117
+ ```
1118
+
1119
+ ---
1120
+
1121
+ ## Search (Advanced)
1122
+
1123
+ ```
1124
+ POST /v1/search
1125
+ ```
1126
+
1127
+ Advanced search with full metadata, retrieval path details, and scope filtering.
1128
+
1129
+ > 高级搜索:返回完整元数据、检索路径、重要度等详情。
1130
+
1131
+ **Request:**
1132
+
1133
+ ```json
1134
+ {
1135
+ "query": "API authentication patterns",
1136
+ "limit": 5,
1137
+ "category": "patterns",
1138
+ "profile": "fact-check"
1139
+ }
1140
+ ```
1141
+
1142
+ | Field | Type | Required | Default | Description |
1143
+ |-------|------|----------|---------|-------------|
1144
+ | `query` | string | yes | — | Search query |
1145
+ | `limit` | number | no | 5 | Max results (1-20) |
1146
+ | `category` | string | no | — | Filter: `profile`, `preferences`, `entities`, `events`, `cases`, `patterns` |
1147
+ | `profile` | string | no | `"default"` | Retrieval profile: `default`, `writing`, `debug`, `fact-check` |
1148
+ | `scope` | string | no | — | Filter by source scope (e.g. `cc`, `codex`, `api:my-agent`) |
1149
+ | `minScore` | number | no | 0 | Minimum relevance score (0-1) |
1150
+
1151
+ **Response:**
1152
+
1153
+ ```json
1154
+ {
1155
+ "results": [
1156
+ {
1157
+ "id": "a1b2c3d4-...",
1158
+ "text": "Authentication pattern: use JWT with...",
1159
+ "category": "patterns",
1160
+ "scope": "cc:abc12345",
1161
+ "score": 0.82,
1162
+ "importance": 0.8,
1163
+ "timestamp": 1741219200000,
1164
+ "date": "2026-03-06",
1165
+ "metadata": { "source": "cc", "tier": "working", "file": "..." },
1166
+ "boundary": {
1167
+ "layer": "durable",
1168
+ "authority": "structured-memory",
1169
+ "conflictPolicy": "latest-wins",
1170
+ "originalCategory": "patterns"
1171
+ },
1172
+ "canonicalKey": "patterns:cross-window-continuity-handoff",
1173
+ "promotedFrom": null,
1174
+ "sources": { "vector": { "score": 0.85, "rank": 1 }, "bm25": { "score": 0.7, "rank": 3 } }
1175
+ }
1176
+ ],
1177
+ "query": "API authentication patterns",
1178
+ "profile": "fact-check",
1179
+ "count": 1
1180
+ }
1181
+ ```
1182
+
1183
+ Derived provenance fields:
1184
+
1185
+ | Field | Type | Description |
1186
+ |-------|------|-------------|
1187
+ | `boundary` | object \| null | Parsed boundary metadata: `layer`, `authority`, `conflictPolicy`, and optional `originalCategory` / `downgradedFrom` |
1188
+ | `canonicalKey` | string \| null | Stable dedupe/update key if the memory has one |
1189
+ | `promotedFrom` | object \| null | Present when a durable memory was explicitly promoted from evidence; includes source `memoryId`, `scope`, `category`, `source`, and source `boundary` |
1190
+ | `provenanceHistory` | array | Observed evidence trail for the durable memory. Falls back to `[promotedFrom]` when no explicit history has been materialized yet |
1191
+ | `provenanceHistoryCount` | number | Total provenance-history observations tracked for the durable memory |
1192
+
1193
+ ---
1194
+
1195
+ ## Stats
1196
+
1197
+ ```
1198
+ GET /v1/stats
1199
+ ```
1200
+
1201
+ Memory index statistics.
1202
+
1203
+ **Response:**
1204
+
1205
+ ```json
1206
+ {
1207
+ "totalMemories": 35176,
1208
+ "byScope": {
1209
+ "cc:abc12345": 773,
1210
+ "memory": 974,
1211
+ "codex:019ccbe4": 277
1212
+ },
1213
+ "byCategory": {
1214
+ "fact": 31582,
1215
+ "events": 1546,
1216
+ "cases": 1337,
1217
+ "entities": 455,
1218
+ "patterns": 156,
1219
+ "preferences": 65,
1220
+ "profile": 26
1221
+ }
1222
+ }
1223
+ ```
1224
+
1225
+ > Note: `byScope` shows raw scope keys. Use `byCategory` for the 6-category distribution.
1226
+
1227
+ ---
1228
+
1229
+ ## Consolidate (Phase 3 — not yet implemented)
1230
+
1231
+ ```
1232
+ POST /v1/consolidate
1233
+ ```
1234
+
1235
+ > This endpoint is planned for Phase 3 (self-evolution). See [docs/self-evolution.md](self-evolution.md) for the design.
1236
+
1237
+ ---
1238
+
1239
+ ## Gaps (Phase 3 — not yet implemented)
1240
+
1241
+ ```
1242
+ GET /v1/gaps
1243
+ ```
1244
+
1245
+ > This endpoint is planned for Phase 3 (self-evolution). See [docs/self-evolution.md](self-evolution.md) for the design.
1246
+
1247
+ ---
1248
+
1249
+ ## Error Responses
1250
+
1251
+ All endpoints return errors in this format:
1252
+
1253
+ ```json
1254
+ {
1255
+ "error": "Description of what went wrong"
1256
+ }
1257
+ ```
1258
+
1259
+ | HTTP Status | Meaning |
1260
+ |-------------|---------|
1261
+ | 400 | Bad request (missing required fields, invalid values) |
1262
+ | 404 | Endpoint not found |
1263
+ | 500 | Internal server error |
1264
+ | 503 | Service unavailable (health check failed) |
1265
+
1266
+ ---
1267
+
1268
+ ## Quick Test
1269
+
1270
+ ```bash
1271
+ # Health check
1272
+ curl http://localhost:4318/v1/health
1273
+
1274
+ # Recall
1275
+ curl -X POST http://localhost:4318/v1/recall \
1276
+ -H "Content-Type: application/json" \
1277
+ -d '{"query": "Docker debugging", "limit": 3}'
1278
+
1279
+ # Store
1280
+ curl -X POST http://localhost:4318/v1/store \
1281
+ -H "Content-Type: application/json" \
1282
+ -d '{"text": "Test memory entry", "category": "events"}'
1283
+
1284
+ # Advanced search with category filter
1285
+ curl -X POST http://localhost:4318/v1/search \
1286
+ -H "Content-Type: application/json" \
1287
+ -d '{"query": "debugging", "category": "cases", "profile": "debug"}'
1288
+
1289
+ # Stats
1290
+ curl http://localhost:4318/v1/stats
1291
+ ```