recallnest 3.0.0 → 3.0.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 (184) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/README.md +222 -254
  3. package/README_CN.md +206 -243
  4. package/package.json +3 -2
  5. package/src/capture-engine.ts +26 -4
  6. package/src/context-composer-stable.ts +5 -1
  7. package/src/embedder.ts +24 -0
  8. package/src/env-config.ts +18 -0
  9. package/src/ingest.ts +225 -17
  10. package/src/kg-extractor.ts +17 -0
  11. package/src/memory-output.ts +35 -0
  12. package/src/pivot-apply.ts +52 -1
  13. package/src/pivot-evidence.ts +128 -0
  14. package/src/ppr-traversal.ts +25 -1
  15. package/src/runtime-config.ts +9 -0
  16. package/src/session-engine.ts +11 -4
  17. package/src/session-output.ts +9 -1
  18. package/src/session-store.ts +2 -3
  19. package/src/skill-promotion.ts +67 -1
  20. package/src/__tests__/access-tracker-novelty.test.ts +0 -324
  21. package/src/__tests__/activity-counter.test.ts +0 -125
  22. package/src/__tests__/adaptive-fidelity.test.ts +0 -102
  23. package/src/__tests__/admission-control.test.ts +0 -206
  24. package/src/__tests__/age-label.test.ts +0 -33
  25. package/src/__tests__/anchor-generator.test.ts +0 -67
  26. package/src/__tests__/api-server-security.test.ts +0 -102
  27. package/src/__tests__/auto-consolidation.test.ts +0 -168
  28. package/src/__tests__/auto-recall.test.ts +0 -131
  29. package/src/__tests__/babel-integration.test.ts +0 -144
  30. package/src/__tests__/batch-dedup.test.ts +0 -65
  31. package/src/__tests__/belief-history.test.ts +0 -220
  32. package/src/__tests__/canary-eval.test.ts +0 -114
  33. package/src/__tests__/capture-engine.test.ts +0 -1328
  34. package/src/__tests__/capture-heuristic.test.ts +0 -171
  35. package/src/__tests__/cascade-forget.test.ts +0 -210
  36. package/src/__tests__/category-min-scores.test.ts +0 -116
  37. package/src/__tests__/cc8-cc1-essential-context.test.ts +0 -298
  38. package/src/__tests__/circuit-breaker.test.ts +0 -99
  39. package/src/__tests__/cluster-consolidation.test.ts +0 -1236
  40. package/src/__tests__/confidence-metadata.test.ts +0 -125
  41. package/src/__tests__/confidence-tracker.test.ts +0 -261
  42. package/src/__tests__/conflict-advisor.test.ts +0 -206
  43. package/src/__tests__/conflict-escalation.test.ts +0 -149
  44. package/src/__tests__/conflict-lifecycle.test.ts +0 -83
  45. package/src/__tests__/conflict-output.test.ts +0 -85
  46. package/src/__tests__/conflict-store.test.ts +0 -418
  47. package/src/__tests__/connector-v1.test.ts +0 -181
  48. package/src/__tests__/consolidation-engine.test.ts +0 -520
  49. package/src/__tests__/constructive-retrieval.test.ts +0 -509
  50. package/src/__tests__/context-collapse-renderer.test.ts +0 -214
  51. package/src/__tests__/context-composer-pins.test.ts +0 -64
  52. package/src/__tests__/context-composer-task-selection.test.ts +0 -24
  53. package/src/__tests__/context-reconstructor.test.ts +0 -65
  54. package/src/__tests__/context-renderer.test.ts +0 -91
  55. package/src/__tests__/continuity-eval.test.ts +0 -275
  56. package/src/__tests__/continuity-schema.test.ts +0 -97
  57. package/src/__tests__/contracts.test.ts +0 -262
  58. package/src/__tests__/conversation-importer.test.ts +0 -692
  59. package/src/__tests__/core-recall-eval.test.ts +0 -235
  60. package/src/__tests__/core-summary.test.ts +0 -109
  61. package/src/__tests__/data-checkup.test.ts +0 -304
  62. package/src/__tests__/decay-exemption.test.ts +0 -129
  63. package/src/__tests__/dedup-actions.test.ts +0 -58
  64. package/src/__tests__/dedup-guard.test.ts +0 -39
  65. package/src/__tests__/deterministic-id.test.ts +0 -39
  66. package/src/__tests__/distill-lock.test.ts +0 -305
  67. package/src/__tests__/distill-session-argshape.test.ts +0 -79
  68. package/src/__tests__/doctor.test.ts +0 -319
  69. package/src/__tests__/dream-pipeline.test.ts +0 -820
  70. package/src/__tests__/dream-scope-isolation.test.ts +0 -386
  71. package/src/__tests__/dream-write-batching.test.ts +0 -211
  72. package/src/__tests__/drill-down.test.ts +0 -108
  73. package/src/__tests__/embedder.test.ts +0 -122
  74. package/src/__tests__/emotion-decay.test.ts +0 -46
  75. package/src/__tests__/emotion-detector.test.ts +0 -56
  76. package/src/__tests__/emotion-phase1-integration.test.ts +0 -153
  77. package/src/__tests__/emotion-retrieval.test.ts +0 -56
  78. package/src/__tests__/entity-resolver.test.ts +0 -58
  79. package/src/__tests__/env-config-invariant.test.ts +0 -80
  80. package/src/__tests__/env-config.test.ts +0 -211
  81. package/src/__tests__/error-signature-boost.test.ts +0 -87
  82. package/src/__tests__/error-signature.test.ts +0 -95
  83. package/src/__tests__/error-taxonomy.test.ts +0 -129
  84. package/src/__tests__/ethics-layer.test.ts +0 -476
  85. package/src/__tests__/event-segmenter.test.ts +0 -153
  86. package/src/__tests__/feature-flags-integration.test.ts +0 -54
  87. package/src/__tests__/frequency-tracker.test.ts +0 -113
  88. package/src/__tests__/freshness.test.ts +0 -186
  89. package/src/__tests__/graph-export.test.ts +0 -489
  90. package/src/__tests__/hotness-blend.test.ts +0 -283
  91. package/src/__tests__/ingest-chunking.test.ts +0 -44
  92. package/src/__tests__/ingest-scope-prefix.test.ts +0 -69
  93. package/src/__tests__/ingest.test.ts +0 -360
  94. package/src/__tests__/interference-detector.test.ts +0 -203
  95. package/src/__tests__/kg-extractor.test.ts +0 -192
  96. package/src/__tests__/kg-store.test.ts +0 -300
  97. package/src/__tests__/llm-client-pivot.test.ts +0 -628
  98. package/src/__tests__/llm-consolidation.test.ts +0 -226
  99. package/src/__tests__/maintenance-locks.test.ts +0 -197
  100. package/src/__tests__/mcp-efficiency.test.ts +0 -288
  101. package/src/__tests__/mcp-related-scopes.test.ts +0 -151
  102. package/src/__tests__/memory-boundaries.test.ts +0 -282
  103. package/src/__tests__/memory-evolution-b2-b3-e1.test.ts +0 -362
  104. package/src/__tests__/memory-evolution.test.ts +0 -271
  105. package/src/__tests__/memory-health-rebalance.test.ts +0 -144
  106. package/src/__tests__/memory-lint.test.ts +0 -421
  107. package/src/__tests__/memory-output.test.ts +0 -224
  108. package/src/__tests__/memory-promotion.test.ts +0 -315
  109. package/src/__tests__/memory-utility.test.ts +0 -256
  110. package/src/__tests__/migrate-dedup-ids.test.ts +0 -65
  111. package/src/__tests__/multi-vector.test.ts +0 -242
  112. package/src/__tests__/narrative-architecture.test.ts +0 -456
  113. package/src/__tests__/noise-filter.test.ts +0 -205
  114. package/src/__tests__/noise-prototype-bank.test.ts +0 -280
  115. package/src/__tests__/obsidian-connector.test.ts +0 -363
  116. package/src/__tests__/omitted-reporting.test.ts +0 -98
  117. package/src/__tests__/openai-contract.test.ts +0 -513
  118. package/src/__tests__/pending-review.test.ts +0 -77
  119. package/src/__tests__/pii-redact.test.ts +0 -333
  120. package/src/__tests__/pivot-apply.test.ts +0 -373
  121. package/src/__tests__/pivot-distill-supervisor.test.ts +0 -457
  122. package/src/__tests__/pivot-distill.test.ts +0 -1178
  123. package/src/__tests__/post-retrieval-filter.test.ts +0 -178
  124. package/src/__tests__/ppr-traversal.test.ts +0 -256
  125. package/src/__tests__/prediction-engine.test.ts +0 -349
  126. package/src/__tests__/predictive-prospective-memory.test.ts +0 -416
  127. package/src/__tests__/preference-guard-smoke.test.ts +0 -211
  128. package/src/__tests__/preference-matcher.test.ts +0 -282
  129. package/src/__tests__/preference-slots.test.ts +0 -205
  130. package/src/__tests__/promotion-distinct-sources.test.ts +0 -162
  131. package/src/__tests__/prospective-memory.test.ts +0 -283
  132. package/src/__tests__/pull-from-macbook-sync-only.test.ts +0 -679
  133. package/src/__tests__/query-entity-detector.test.ts +0 -171
  134. package/src/__tests__/query-expander-alias.test.ts +0 -146
  135. package/src/__tests__/query-expander.test.ts +0 -34
  136. package/src/__tests__/recall-gate.test.ts +0 -266
  137. package/src/__tests__/recall-governor.test.ts +0 -227
  138. package/src/__tests__/recall-mode.test.ts +0 -64
  139. package/src/__tests__/resolve-db-path.test.ts +0 -130
  140. package/src/__tests__/resolve-tier.test.ts +0 -64
  141. package/src/__tests__/result-synthesizer.test.ts +0 -198
  142. package/src/__tests__/resume-context.test.ts +0 -4898
  143. package/src/__tests__/retrieval-eval.test.ts +0 -163
  144. package/src/__tests__/retrieval-trace.test.ts +0 -213
  145. package/src/__tests__/retrieve-audit-revision.test.ts +0 -255
  146. package/src/__tests__/retriever-boundary-weight.test.ts +0 -136
  147. package/src/__tests__/retriever-lazy-init-dispatch.test.ts +0 -123
  148. package/src/__tests__/retroactive-boost.test.ts +0 -223
  149. package/src/__tests__/salience-scoring.test.ts +0 -106
  150. package/src/__tests__/scope-inventory.test.ts +0 -200
  151. package/src/__tests__/scope-policy.test.ts +0 -69
  152. package/src/__tests__/scope-suggester.test.ts +0 -80
  153. package/src/__tests__/session-checkpoint.test.ts +0 -291
  154. package/src/__tests__/session-distiller.test.ts +0 -640
  155. package/src/__tests__/session-gc.test.ts +0 -215
  156. package/src/__tests__/skill-engine.test.ts +0 -552
  157. package/src/__tests__/skill-promotion.test.ts +0 -654
  158. package/src/__tests__/skill-verifier.test.ts +0 -122
  159. package/src/__tests__/source-heartbeat.test.ts +0 -254
  160. package/src/__tests__/stable-context-length-contract.test.ts +0 -62
  161. package/src/__tests__/store-patch-metadata.test.ts +0 -235
  162. package/src/__tests__/store-read-consistency.test.ts +0 -122
  163. package/src/__tests__/store-schema-migration.test.ts +0 -87
  164. package/src/__tests__/store-scope-audit.test.ts +0 -81
  165. package/src/__tests__/store-upsert.test.ts +0 -201
  166. package/src/__tests__/supersede-chain.test.ts +0 -154
  167. package/src/__tests__/synthesis-contract.test.ts +0 -252
  168. package/src/__tests__/synthesis-promotion.test.ts +0 -369
  169. package/src/__tests__/temporal-parser.test.ts +0 -241
  170. package/src/__tests__/temporal-validity.test.ts +0 -160
  171. package/src/__tests__/term-registry-terminal-roster.test.ts +0 -127
  172. package/src/__tests__/term-registry.test.ts +0 -121
  173. package/src/__tests__/tool-error-surfacing.test.ts +0 -98
  174. package/src/__tests__/tool-output-compressor.test.ts +0 -160
  175. package/src/__tests__/topic-tag.test.ts +0 -113
  176. package/src/__tests__/trusted-memory.test.ts +0 -867
  177. package/src/__tests__/ui-server-security.test.ts +0 -93
  178. package/src/__tests__/usage-tracker.test.ts +0 -287
  179. package/src/__tests__/utility-weight.test.ts +0 -57
  180. package/src/__tests__/verbatim-self-recall.test.ts +0 -279
  181. package/src/__tests__/version-manager.test.ts +0 -248
  182. package/src/__tests__/workflow-observation-skill-outcome.test.ts +0 -352
  183. package/src/__tests__/workflow-observation.test.ts +0 -433
  184. package/src/__tests__/write-verifier.test.ts +0 -122
package/CHANGELOG.md CHANGED
@@ -1,5 +1,63 @@
1
1
  # Changelog
2
2
 
3
+ <!-- Before cutting a release, run every entry past these five:
4
+ 1. before / after — a number, not an adjective. No number, no claim.
5
+ (Nothing measurable? Then one plain sentence. Do not manufacture a figure.)
6
+ 2. under what conditions was it measured — version, sample size, environment.
7
+ 3. what does this cost and who gets hit by it — state it, do not bury it.
8
+ 4. what alternative was rejected and why — the reason must be specific
9
+ enough that someone could refute it.
10
+ 5. what looks like it belongs here but deliberately does not, and on what evidence.
11
+
12
+ When condensing this file into a GitHub Release body, 2 / 4 / 5 are the first
13
+ things to go: a conclusion reads as information, a reason reads as filler.
14
+ Protect them by name. The v3.0.0 Release body dropped 11 of 11 such items in
15
+ exactly that step, while this file had every one of them. -->
16
+
17
+ ## v3.0.1 — Publication hygiene (2026-09-06)
18
+
19
+ ### Added
20
+
21
+ - **`embedding.timeoutMs` — an opt-in per-request timeout for the embedding client**
22
+ (config.json, or `RECALLNEST_EMBEDDING_TIMEOUT_MS`, which wins over the file so one
23
+ deployment can bound itself without editing a shared config). **Default behavior is
24
+ unchanged**: with neither set, no `timeout` is passed to the SDK at all and the client
25
+ keeps its own default — 600s in `openai` v7 — exactly as in every release through
26
+ v3.0.0. The knob exists because that default stacks badly: the SDK retries twice on its
27
+ own and `Embedder` retries twice more, so a black-holed endpoint issues **9 requests for
28
+ a single `embedPassage` call** (measured against a loopback endpoint that never answers),
29
+ putting the worst case at roughly 90 minutes. Lowering the default for everyone was
30
+ rejected instead of shipped — bulk embedding of long documents is legitimately slow, and
31
+ a global cut would turn working ingests into failures — so the timeout is only ever
32
+ shortened by a caller that asks. Non-finite, zero and negative values are ignored rather
33
+ than throwing, so a typo degrades to the old behavior instead of to an embedder that
34
+ aborts every request. Covered by the loopback suite (abort within the configured budget)
35
+ and by `runtime-config-embedding.test.ts` (config.json → client, env precedence, and a
36
+ whole-client comparison against the pre-change construction expression proving the unset
37
+ path is unchanged).
38
+
39
+ ### Changed
40
+
41
+ - **Publication hygiene: no machine-local identifiers in the tree, no tests in the tarball.**
42
+ Three eval scripts (`eval/ghost-scan.ts`, `eval/lengthnorm-shadow.ts`,
43
+ `eval/term-registry-shadow.ts`) imported the runtime through an absolute path that only
44
+ existed on the author's machine; they now resolve the repository root from
45
+ `RECALLNEST_ROOT`, falling back to `~/recallnest` — the identical path on the original
46
+ install, a working one everywhere else. `scripts/pivot-distill-supervisor.ts` derives its
47
+ user-level launchd labels from the current account (`com.<user>.<task>`, overridable via
48
+ `PIVOT_DISTILL_LAUNCHD_PREFIX`) instead of a hardcoded username; the supervised set is
49
+ unchanged for the original account, and the suite now asserts the derivation rule and the
50
+ override. `package.json#files` excludes `src/**/__tests__/**` — `.npmignore` alone never
51
+ could, because `files` wins — so the dry-run tarball goes from 357 files / 965.8 kB
52
+ (3.8 MB unpacked) to 189 files / 620.0 kB (2.1 MB unpacked), measured with npm 11.19.0
53
+ on this commit; `scripts/verify-package-contents.mjs` now rejects any `__tests__` directory,
54
+ so the CI gate turns red if this regresses. A new `privacy-regression.test.ts` scans
55
+ `src/`, `scripts/`, `eval/`, `bin/`, root-level `*.md` and shipped `data/*.example.*` for the
56
+ removed identifiers and for macOS home paths (obvious placeholder accounts excepted).
57
+ Rejected: relative imports in the eval scripts, because these are reproduction tools for
58
+ figures measured against the production install and must keep pointing at it even when
59
+ invoked from another checkout. Deliberately not here: the README acknowledgements are unchanged.
60
+
3
61
  ## v3.0.0 — Node 22, and conclusions that can be used (2026-08-24)
4
62
 
5
63
  Two things make this a major release: the runtime floor moves, and a synthesized
@@ -327,6 +385,49 @@ P0 反馈闭环:让 skill 的 `successCount` / `failureCount` 真有真实使
327
385
 
328
386
  - 基线 1486 → 1520 / 0 fail(+13 新 case 覆盖 outcome 映射 + 错误路径 + 元数据完整性 + 时间戳;+1 顺手修 workflow-observation.test.ts dashboard 漏传 now 参数 pre-existing bug)
329
387
 
388
+ ## v2.3 — Connector ecosystem + source health
389
+
390
+ > Migrated out of README on 2026-08-28. These three entries lived in the README as
391
+ > "New in vX" sections and were never in this file; release dates were not recorded at
392
+ > the time, so none is stated here rather than guessed. They sit between v2.5.0-pre
393
+ > (2026-05-27) and v1.3.1 (2026-03-12) by position in the sequence.
394
+
395
+ v2.2 hardened retrieval quality; v2.3 opens RecallNest to external data sources with a standard connector framework and operational health monitoring.
396
+
397
+ - **Connector-v1 Standard** *(GB-2)* — A JSON format (`ConnectorOutputV1`) that any external script can produce. Obsidian vaults, emails, RSS feeds, log files — normalize once, ingest through the full dedup/embed/extract pipeline. See [`docs/connector-spec.md`](docs/connector-spec.md) for the specification and [`connectors/examples/`](connectors/examples/) for adapter skeletons (email, logs, RSS).
398
+
399
+ - **Obsidian Vault Ingestion** *(GB-1)* — First-party Obsidian connector: scans `.md` files, extracts frontmatter + wikilinks, maps folder structure to tags. One command: `lm ingest --obsidian /path/to/vault`.
400
+
401
+ - **Source Health Monitoring** *(GB-3)* — Every connector ingest writes a heartbeat to `data/source-heartbeat.json`. `data_checkup` flags stale sources (>7d warning, >30d error). `doctor --ci` shows a per-source heartbeat summary with human-readable age.
402
+
403
+ ## v2.2 — Retrieval quality hardening
404
+
405
+ v2.1 added philosophy-informed behavior; v2.2 closes the last three engine-layer gaps identified by a frontier research scan (ACC, PI-LLM, TSM).
406
+
407
+ - **Memory Confidence Meta-tags** *(ACC / Dual-Process UQ)* — Each memory now carries structured `ConfidenceMetadata` (score, reliability tier: `direct` / `inferred` / `hearsay`). Auto-assigned from source on write (`manual` = 0.9, `agent` = 0.7, `conversation_import` = 0.5). Retrieval scores are weighted by confidence. `resume_context` tags low-confidence items with `[低置信]`.
408
+
409
+ - **Interference Detection + Active Forgetting Gate** *(PI-LLM / SleepGate)* — Semantic cluster detection identifies groups of near-duplicate memories competing for retrieval. Enhanced RIF keeps only top-K (default 3) per cluster; extras are demoted 50% instead of removed. Write-time pre-warning: when a scope accumulates ≥5 high-similarity active memories, the weakest is flagged `pending_review`. `data_checkup` reports interference density.
410
+
411
+ - **Temporal Validity Windows** *(TSM / TiMem / Zep)* — `store_memory` accepts `validUntil` (expiration) and `eventTime` (when the event actually happened). `search_memory` supports `validAt` (point-in-time query) and `includeExpired` (demote 80% instead of hide). Auto-GC applies 2× decay acceleration to expired memories.
412
+
413
+ - **Usage-Adjusted Auto-GC** *(off by default)* — `RECALLNEST_USAGE_DECAY=true` enables a GC-only cold-memory penalty when constructive retrieval is also active. Cold memories discount the frequency component instead of changing online retrieval ranking.
414
+
415
+ ## v2.1 — Philosophy-informed memory
416
+
417
+ v2.0 built the operational memory platform; v2.1 added philosophy-informed memory behavior.
418
+
419
+ Five upgrades derived from 9 research dimensions in philosophy of memory, each mapped to concrete engineering:
420
+
421
+ - **Emotion-Aware Decay** *(Affective Memory Theory)* — Memories with strong emotional content decay 20-30% slower. Keyword-based emotion detection computes `salience` (mnemonic significance), which feeds into the Weibull half-life formula and a rebalanced 4-factor evolution score. Zero LLM cost.
422
+
423
+ - **Memory Ethics Layer** *(Right to Be Forgotten / GDPR Art. 17)* — Four privacy tiers (`ephemeral` / `private` / `durable` / `shared`). Cascade forgetting engine that propagates deletion through KG triples, evolution chains, pin assets, and briefs. Full audit trail. `forget_memory` MCP tool for agent-driven deletion.
424
+
425
+ - **Autobiographical Narrative** *(Narrative Identity Theory / Conway's 3-layer model)* — Memories are tagged with `lifePeriod → generalEvent → specificEvent` hierarchy, orthogonal to existing 6 categories. Retrieval pulls narrative siblings. Context rendering groups by life period. Rule-based tagger with EN+CN support.
426
+
427
+ - **Constructive Retrieval** *(Simulation Theory / Michaelian)* — Instead of returning raw stored text, RecallNest now reconstructs context from an expanded candidate set: KG neighbors + evolution chains + cluster members + narrative siblings. Source-map grounded coverage replaces lexical overlap. Contradictions are detected and flagged.
428
+
429
+ - **Predictive Prospective Memory** *(Mental Time Travel / Tulving)* — Heuristic prediction engine that surfaces "you might need this" reminders from behavioral signals: stale checkpoint open loops, corrected workflow observations, high-frequency dormant memories, and uncovered query topics. Zero LLM cost. Auto-expire in 7 days if unaccepted.
430
+
330
431
  ## v1.3.1 — Upstream Sync (2026-03-12)
331
432
 
332
433
  Synced with [CortexReach/memory-lancedb-pro](https://github.com/CortexReach/memory-lancedb-pro) master (v1.1.0-beta.6+).
package/README.md CHANGED
@@ -26,8 +26,127 @@ A local-first memory system backed by LanceDB that turns scattered conversation
26
26
 
27
27
  Coding agents forget everything between windows. Your context — project configs, debugging decisions, entity mappings — is scattered across Claude Code, Codex, Kimi, Antigravity — and every other terminal you open — with no shared memory.
28
28
 
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.
29
+ RecallNest is **one LanceDB-backed memory layer that all of them read and write**. Context stored in one window is recalled in another. Sessions checkpoint on exit and resume on start. Memory decays, evolves, and self-organizes — it is not a log you grep.
30
30
 
31
+ ### What a recall actually looks like
32
+
33
+ ```text
34
+ Query : deploy rollback
35
+ Hits : 5
36
+
37
+ # ID Score Category Tier Source Date Age Retrieval Path
38
+ 1 ee79037a 46.1% cases peripheral cc 2026-08-25 2d vector
39
+ [assistant] Rolled back to the previous image and pinned the digest so the next…
40
+ prov : evidence/transcript-ingest
41
+ imgs : 52 agent-made in this session · read sess=dca70d4a
42
+ ```
43
+
44
+ Three things in that block carry most of the design:
45
+
46
+ - **`Source cc` · `Age 2d`** — this came out of a Claude Code window two days ago and you
47
+ are reading it from a different terminal, possibly on a different machine. That is the
48
+ premise the whole project is built on.
49
+ - **`prov : evidence/…`** — every row states which layer it sits on. A fragment scraped out
50
+ of a transcript never gets to pose as a decision you actually made; moving to durable
51
+ memory is a separate, gated step with its own evidence requirement.
52
+ - **`imgs : …`** — that session contained 52 images. **Not one of them is in the database.**
53
+ The line exists so you know there is something to go look at, and producing it cost no
54
+ model call, no vector, and no storage.
55
+
56
+ That last one is the approach in miniature: **store what makes a thing findable, not
57
+ everything that could ever be asked about it.** The full reasoning — including the two
58
+ places where the obvious implementation was wrong — is in
59
+ [Images: addressable, not embedded](#images-addressable-not-embedded).
60
+
61
+
62
+ ## Core Capabilities
63
+
64
+ ### Access & Setup
65
+
66
+ | Capability | Description |
67
+ |---|---|
68
+ | **CC Plugin** | Install in Claude Code with one command — no manual config |
69
+ | **Shared Index** | One LanceDB store shared by every terminal that speaks MCP |
70
+ | **Dual Interface** | MCP (stdio) for CLI tools + HTTP API for custom agents |
71
+ | **One-Click Setup** | Integration scripts install MCP access and continuity rules |
72
+
73
+ ### Recall & Continuity
74
+
75
+ | Capability | Description |
76
+ |---|---|
77
+ | **Hybrid Retrieval** | 6-channel: vector + BM25 + L0/L1/L2 multi-vector + KG graph (PPR) |
78
+ | **4 Retrieval Profiles** | default, writing, debug, fact-check — tuned for different tasks |
79
+ | **Session Continuity** | `checkpoint_session` + `resume_context` (full/light/summary modes) with repo-state guard |
80
+ | **Session Distiller** | 3-layer conversation compression: microcompact → LLM summary → knowledge extraction |
81
+ | **Conversation Import** | Import from Claude Code, Claude.ai, ChatGPT, Slack, and plaintext |
82
+ | **Topic Tags** | Intra-scope topic partitioning — auto-detected, filterable in search |
83
+ | **Related Scope Sidecar** | Opt-in `includeRelatedScopes` search over configured `scopeRelations`, shown separately from the main scoped ranking |
84
+
85
+ ### Memory Lifecycle & Governance
86
+
87
+ | Capability | Description |
88
+ |---|---|
89
+ | **Memory Evolution** | Supersede chains, decay scoring, LLM importance, consolidation, archival |
90
+ | **Smart Promotion** | Evidence → durable memory with conflict guards, merge resolution, and audit trail |
91
+ | **Privacy Tiers** | 4-tier (`ephemeral` / `private` / `durable` / `shared`) with cascade forgetting |
92
+ | **Admission Control** | Write-time gating: noise filter, importance floor, dedup, rate limiting |
93
+ | **Memory Lint** | Contradiction, duplicate, stale, and orphan detection with health score |
94
+ | **Offline Consolidation** | `dream` command: clustering, merging, pruning of accumulated memories |
95
+
96
+ ### Reasoning & Structure
97
+
98
+ | Capability | Description |
99
+ |---|---|
100
+ | **Knowledge Graph** | Entity relation graph with PPR algorithm for multi-hop questions |
101
+ | **Constructive Retrieval** | Multi-source candidate expansion + grounded context reconstruction |
102
+ | **Narrative Architecture** | 3-layer autobiographical metadata (life-period → general-event → specific-event) |
103
+ | **Skill Memory** | Store, retrieve, and promote executable skills from recurring patterns |
104
+ | **Predictive Reminders** | Behavioral-signal prediction engine surfaces "you might need this" suggestions |
105
+ | **6 Categories** | profile, preferences, entities, events, cases, patterns — with category-aware merge strategies |
106
+
107
+ ### Visibility & Operations
108
+
109
+ | Capability | Description |
110
+ |---|---|
111
+ | **Dashboard** | Web UI with stats, category distribution, growth trends, and health |
112
+ | **Workflow Observation** | Dedicated append-only workflow health records, outside regular memory |
113
+ | **Structured Assets** | Pins, briefs, and distilled summaries — not just raw logs |
114
+ | **Data Checkup** | Data quality health checks on the memory store (including source health) |
115
+ | **Source Heartbeats** | Automatic ingest health tracking per data source with staleness alerts |
116
+ | **Export Graph** | Export interactive HTML knowledge graph visualization |
117
+ | **Batch Operations** | Store up to 20 memories in a single call with dedup |
118
+ | **Connector Framework** | Standard connector-v1 format for external data sources with example adapters |
119
+
120
+ ---
121
+
122
+ ## Architecture
123
+
124
+ ```
125
+ CLIENTS ACCESS CORE ENGINE STORAGE
126
+ ────────────────────── ─────────────────────── ──────────────────────────── ──────────────────────
127
+
128
+ Claude Code MCP over stdio Retriever LanceDB
129
+ Codex ───▶ 44 tools, 3 tiers ───▶ vector + BM25 + RRF ───▶ vector + columnar
130
+ Kimi · Antigravity Classifier · 6 categories
131
+ Doubao desktop Context composer
132
+ HTTP API :4318 resume_context Jina embeddings v5
133
+ your scripts · cron ───▶ 21 endpoints ───▶ Decay · Weibull half-life ─▶ 1024-dim, task-aware
134
+ Conflict · audit + merge
135
+ phone app ───▶ read-only gateway ───▶ Capture: evidence → durable
136
+ :8791, token-gated
137
+ ```
138
+
139
+ ### Internal Design
140
+
141
+ - **L0 / L1 / L2 Dynamic Folding** — every memory stores 3 granularity layers (one-liner / bullet summary / full content); retrieval dynamically selects which layer to return based on relevance score and token budget
142
+ - **Weibull Decay + Emotion Modulation** — memories decay along a parametric Weibull curve; importance scores modulate the half-life, and emotional salience extends it further (up to 30%)
143
+ - **Vector Pre-filter + LLM Dedup** — 90% of dedup decisions use cheap cosine similarity (>= 0.92); only borderline cases invoke LLM judgment, keeping costs low without sacrificing accuracy
144
+ - **Category-Aware Merge Strategies** — `profile` and `preferences` use merge-on-conflict (latest wins); `events` and `cases` use append-only (history preserved)
145
+ - **Display Score vs Elimination Score** — dual-track retrieval: tier floor prevents core memories from ever dropping out, while decay boost lets fresh memories surface temporarily without permanently displacing stable ones
146
+
147
+ > Full architecture deep-dive: [`docs/architecture.md`](docs/architecture.md)
148
+
149
+ ---
31
150
 
32
151
  ## Who Can Connect
33
152
 
@@ -161,277 +280,84 @@ bun run src/cli.ts doctor
161
280
 
162
281
  ---
163
282
 
164
- ## Web UI
283
+ ## Images: addressable, not embedded
165
284
 
166
- <p align="center">
167
- <img src="assets/dashboard.png" alt="RecallNest Dashboard" width="800" />
168
- <br><em>Dashboard — total count, category distribution, health score, and growth trends at a glance.</em>
169
- </p>
285
+ Conversations contain images. A text memory layer does not. The usual answer is a
286
+ multimodal embedding model — encode every image into the same space as the text. That is
287
+ right for photo libraries. It is the wrong shape here, for a cheap reason: **in a
288
+ conversation an image almost never arrives alone.** It comes wrapped in "look at this
289
+ error", and the reply right after it usually describes what was in the picture. The words
290
+ around the image are already an index of it. What was missing was never semantic search
291
+ over pixels — it was knowing a picture is sitting there at all.
170
292
 
171
- <p align="center">
172
- <img src="assets/screenshots/ui-full.png" alt="RecallNest Search Workbench" width="800" />
173
- <br><em>Search Workbench — hybrid search with topic tag filtering, 4 retrieval profiles, Skills browser, and asset management.</em>
174
- </p>
293
+ So RecallNest does not encode images. It records **how many images are in the session a
294
+ memory came from**, and lets you decide whether to open the original transcript. Meaning
295
+ is resolved on demand, by whatever model is asking, at the moment it matters.
175
296
 
176
- <p align="center">
177
- <img src="assets/knowledge-graph.png" alt="RecallNest Knowledge Graph" width="800" />
178
- <br><em>Knowledge Graph — interactive force-directed visualization with semantic bridges revealing cross-domain connections.</em>
179
- </p>
297
+ The cost is worth stating plainly: **no multimodal model, no re-embedding, no image
298
+ storage, no change to any vector.** Backfilling 21,319 existing memories touched metadata
299
+ only.
180
300
 
181
- ```bash
182
- bun run src/ui-server.ts
183
- # → http://localhost:4317
184
- ```
301
+ Two design choices in it were not obvious, and both were wrong on the first attempt.
185
302
 
186
- ---
303
+ ### Session-level, on purpose
187
304
 
188
- ## Core Capabilities
305
+ The marker counts the whole session, not the turn — coarser than it first looks like it
306
+ should be, and the coarseness is the point.
189
307
 
190
- ### Access & Setup
308
+ A turn that is nothing but a pasted screenshot has almost no text, so it never cleared the
309
+ length gate and never entered the store. Measured on real transcripts, **12.5% of turns
310
+ containing a pasted image were dropped whole** — including the ones worth the most, like
311
+ seven screenshots with no caption, or "here are the steps" attached to a picture that *is*
312
+ the steps. A turn-level marker has nothing to attach to for exactly those. A session-level
313
+ marker lands on that session's *other* memories, which did get stored, and those are what
314
+ a search surfaces.
191
315
 
192
- | Capability | Description |
193
- |---|---|
194
- | **CC Plugin** | Install in Claude Code with one command — no manual config |
195
- | **Shared Index** | One LanceDB store shared by every terminal that speaks MCP |
196
- | **Dual Interface** | MCP (stdio) for CLI tools + HTTP API for custom agents |
197
- | **One-Click Setup** | Integration scripts install MCP access and continuity rules |
316
+ The trade-off is undisguised: every memory from a session carries the same count, so the
317
+ images may have nothing to do with the row you are looking at. The line says
318
+ `in this session`, not `in this memory`, for that reason.
198
319
 
199
- ### Recall & Continuity
320
+ ### Two classes, because they answer different questions
200
321
 
201
- | Capability | Description |
202
- |---|---|
203
- | **Hybrid Retrieval** | 6-channel: vector + BM25 + L0/L1/L2 multi-vector + KG graph (PPR) |
204
- | **4 Retrieval Profiles** | default, writing, debug, fact-check — tuned for different tasks |
205
- | **Session Continuity** | `checkpoint_session` + `resume_context` (full/light/summary modes) with repo-state guard |
206
- | **Session Distiller** | 3-layer conversation compression: microcompact → LLM summary → knowledge extraction |
207
- | **Conversation Import** | Import from Claude Code, Claude.ai, ChatGPT, Slack, and plaintext |
208
- | **Topic Tags** | Intra-scope topic partitioning — auto-detected, filterable in search |
209
- | **Related Scope Sidecar** | Opt-in `includeRelatedScopes` search over configured `scopeRelations`, shown separately from the main scoped ranking |
210
-
211
- ### Memory Lifecycle & Governance
212
-
213
- | Capability | Description |
214
- |---|---|
215
- | **Memory Evolution** | Supersede chains, decay scoring, LLM importance, consolidation, archival |
216
- | **Smart Promotion** | Evidence → durable memory with conflict guards, merge resolution, and audit trail |
217
- | **Privacy Tiers** | 4-tier (`ephemeral` / `private` / `durable` / `shared`) with cascade forgetting |
218
- | **Admission Control** | Write-time gating: noise filter, importance floor, dedup, rate limiting |
219
- | **Memory Lint** | Contradiction, duplicate, stale, and orphan detection with health score |
220
- | **Offline Consolidation** | `dream` command: clustering, merging, pruning of accumulated memories |
221
-
222
- ### Reasoning & Structure
223
-
224
- | Capability | Description |
225
- |---|---|
226
- | **Knowledge Graph** | Entity relation graph with PPR algorithm for multi-hop questions |
227
- | **Constructive Retrieval** | Multi-source candidate expansion + grounded context reconstruction |
228
- | **Narrative Architecture** | 3-layer autobiographical metadata (life-period → general-event → specific-event) |
229
- | **Skill Memory** | Store, retrieve, and promote executable skills from recurring patterns |
230
- | **Predictive Reminders** | Behavioral-signal prediction engine surfaces "you might need this" suggestions |
231
- | **6 Categories** | profile, preferences, entities, events, cases, patterns — with category-aware merge strategies |
232
-
233
- ### Visibility & Operations
234
-
235
- | Capability | Description |
236
- |---|---|
237
- | **Dashboard** | Web UI with stats, category distribution, growth trends, and health |
238
- | **Workflow Observation** | Dedicated append-only workflow health records, outside regular memory |
239
- | **Structured Assets** | Pins, briefs, and distilled summaries — not just raw logs |
240
- | **Data Checkup** | Data quality health checks on the memory store (including source health) |
241
- | **Source Heartbeats** | Automatic ingest health tracking per data source with staleness alerts |
242
- | **Export Graph** | Export interactive HTML knowledge graph visualization |
243
- | **Batch Operations** | Store up to 20 memories in a single call with dedup |
244
- | **Connector Framework** | Standard connector-v1 format for external data sources with example adapters |
245
-
246
- ---
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
-
313
- ## New in v2.6: Reliable Cross-Process Memory and Distribution
314
-
315
- v2.6 turns the development since v2.5.4 into a release-ready upgrade:
316
-
317
- - **Cross-process visibility** — LanceDB now checks for external commits on every read by default, so resident MCP/API/UI processes see writes from CLI ingestion without a restart. Set `RECALLNEST_READ_CONSISTENCY_INTERVAL=<seconds>` for bounded staleness or `off` for the legacy unchecked behavior.
318
- - **Safer memory evolution** — belief changes preserve the old row as `superseded`; procedural memories avoid time decay; cold-start and length-normalization behavior no longer suppress short entity queries or stable memories.
319
- - **More reliable consolidation** — `dream` now distinguishes failure classes, honors wall-clock budgets, refills vectors before semantic clustering, and asserts that successful runs actually produced work.
320
- - **Broader conversation coverage** — Kimi, AGY/Antigravity, and minis sources are recognized across ingestion, scope boundaries, and term resolution.
321
- - **One public version** — npm metadata, CLI `--version`, MCP handshakes, HTTP health responses, and the Claude Code marketplace all follow the `2.6.0` release contract.
322
- - **Installable Claude Code plugin** — installation now registers the 43-tool MCP server and continuity skill, asks for the Jina key through sensitive plugin configuration, and keeps config plus LanceDB data in Claude Code's persistent plugin data directory.
323
-
324
- ### Upgrading from v2.5.4
325
-
326
- - Existing LanceDB data is opened in place. Legacy tables missing newer fields are migrated automatically, including empty tables.
327
- - Plugin data survives plugin updates because it is stored outside the versioned cache. A manual clone continues to use its existing `config.json` and database path.
328
- - Retrieval auditing now includes read operations. `audit.jsonl` has no automatic rotation yet; consider archiving it if it approaches 50 MB.
329
- - `RECALLNEST_LAYER_ADMISSION` remains opt-in (`observe` or `on`); the default is `off`.
330
-
331
- ---
332
-
333
- ## New in v2.1: Philosophy-Informed Memory
334
-
335
- v2.0 built the operational memory platform; v2.1 added philosophy-informed memory behavior.
336
-
337
- Five upgrades derived from 9 research dimensions in philosophy of memory, each mapped to concrete engineering:
338
-
339
- - **Emotion-Aware Decay** *(Affective Memory Theory)* — Memories with strong emotional content decay 20-30% slower. Keyword-based emotion detection computes `salience` (mnemonic significance), which feeds into the Weibull half-life formula and a rebalanced 4-factor evolution score. Zero LLM cost.
340
-
341
- - **Memory Ethics Layer** *(Right to Be Forgotten / GDPR Art. 17)* — Four privacy tiers (`ephemeral` / `private` / `durable` / `shared`). Cascade forgetting engine that propagates deletion through KG triples, evolution chains, pin assets, and briefs. Full audit trail. `forget_memory` MCP tool for agent-driven deletion.
342
-
343
- - **Autobiographical Narrative** *(Narrative Identity Theory / Conway's 3-layer model)* — Memories are tagged with `lifePeriod → generalEvent → specificEvent` hierarchy, orthogonal to existing 6 categories. Retrieval pulls narrative siblings. Context rendering groups by life period. Rule-based tagger with EN+CN support.
344
-
345
- - **Constructive Retrieval** *(Simulation Theory / Michaelian)* — Instead of returning raw stored text, RecallNest now reconstructs context from an expanded candidate set: KG neighbors + evolution chains + cluster members + narrative siblings. Source-map grounded coverage replaces lexical overlap. Contradictions are detected and flagged.
346
-
347
- - **Predictive Prospective Memory** *(Mental Time Travel / Tulving)* — Heuristic prediction engine that surfaces "you might need this" reminders from behavioral signals: stale checkpoint open loops, corrected workflow observations, high-frequency dormant memories, and uncovered query topics. Zero LLM cost. Auto-expire in 7 days if unaccepted.
348
-
349
- ---
350
-
351
- ## New in v2.2: Retrieval Quality Hardening
352
-
353
- v2.1 added philosophy-informed behavior; v2.2 closes the last three engine-layer gaps identified by a frontier research scan (ACC, PI-LLM, TSM).
354
-
355
- - **Memory Confidence Meta-tags** *(ACC / Dual-Process UQ)* — Each memory now carries structured `ConfidenceMetadata` (score, reliability tier: `direct` / `inferred` / `hearsay`). Auto-assigned from source on write (`manual` = 0.9, `agent` = 0.7, `conversation_import` = 0.5). Retrieval scores are weighted by confidence. `resume_context` tags low-confidence items with `[低置信]`.
356
-
357
- - **Interference Detection + Active Forgetting Gate** *(PI-LLM / SleepGate)* — Semantic cluster detection identifies groups of near-duplicate memories competing for retrieval. Enhanced RIF keeps only top-K (default 3) per cluster; extras are demoted 50% instead of removed. Write-time pre-warning: when a scope accumulates ≥5 high-similarity active memories, the weakest is flagged `pending_review`. `data_checkup` reports interference density.
358
-
359
- - **Temporal Validity Windows** *(TSM / TiMem / Zep)* — `store_memory` accepts `validUntil` (expiration) and `eventTime` (when the event actually happened). `search_memory` supports `validAt` (point-in-time query) and `includeExpired` (demote 80% instead of hide). Auto-GC applies 2× decay acceleration to expired memories.
360
-
361
- - **Usage-Adjusted Auto-GC** *(off by default)* — `RECALLNEST_USAGE_DECAY=true` enables a GC-only cold-memory penalty when constructive retrieval is also active. Cold memories discount the frequency component instead of changing online retrieval ranking.
362
-
363
- ---
364
-
365
- ## New in v2.3: Connector Ecosystem + Source Health
366
-
367
- v2.2 hardened retrieval quality; v2.3 opens RecallNest to external data sources with a standard connector framework and operational health monitoring.
322
+ | Bucket | What it is | The question it answers |
323
+ |---|---|---|
324
+ | user-pasted | Pictures a human put into a message | *Where is that screenshot I sent?* |
325
+ | agent-made | Everything else the session produced | *What did the page look like? What did I generate?* |
368
326
 
369
- - **Connector-v1 Standard** *(GB-2)* — A JSON format (`ConnectorOutputV1`) that any external script can produce. Obsidian vaults, emails, RSS feeds, log files — normalize once, ingest through the full dedup/embed/extract pipeline. See [`docs/connector-spec.md`](docs/connector-spec.md) for the specification and [`connectors/examples/`](connectors/examples/) for adapter skeletons (email, logs, RSS).
327
+ Keeping only the first is tempting — a person searching their own memory wants their own
328
+ screenshots. But an agent reconstructing its past work wants the other: the diagram it
329
+ drew, the rendering it captured, the illustration it made for a post. **Of 1,767 sessions
330
+ carrying images, 1,103 contain no human-pasted image at all.** Keep one bucket and those
331
+ sessions go silent — precisely the ones where the agent did visual work.
370
332
 
371
- - **Obsidian Vault Ingestion** *(GB-1)* — First-party Obsidian connector: scans `.md` files, extracts frontmatter + wikilinks, maps folder structure to tags. One command: `lm ingest --obsidian /path/to/vault`.
333
+ ### The second bucket is a complement, not a list
372
334
 
373
- - **Source Health Monitoring** *(GB-3)* — Every connector ingest writes a heartbeat to `data/source-heartbeat.json`. `data_checkup` flags stale sources (>7d warning, >30d error). `doctor --ci` shows a per-source heartbeat summary with human-readable age.
335
+ The first implementation defined agent-made images by enumeration: inside `tool_result`,
336
+ inside `payload.output`, inside `tool.result`. Every location was real. The list was still
337
+ wrong, because **the set of ways an image can appear only grows**, and an enumeration
338
+ silently drops whatever it did not anticipate.
374
339
 
375
- ---
340
+ So the second bucket is a complement: count every image signal in the record, subtract the
341
+ ones positively identified as human-pasted, attribute the rest without asking where it came
342
+ from. Across 9,619 transcripts:
376
343
 
377
- ## Architecture
378
-
379
- ```
380
- ┌──────────────────────────────────────────────────────────┐
381
- │ Client Layer │
382
- ├──────────┬──────────┬──────────┬──────────────────────────┤
383
- │ Claude │ Anti- │ Codex │ Custom Agents / curl │
384
- │ Code │ gravity │ │ │
385
- └────┬─────┴────┬─────┴────┬─────┴──────┬──────────────────┘
386
- │ │ │ │
387
- └──── MCP (stdio) ───┘ HTTP API (port 4318)
388
- │ │
389
- ▼ ▼
390
- ┌──────────────────────────────────────────────────────────┐
391
- │ Integration Layer │
392
- │ ┌─────────────────────┐ ┌────────────────────────────┐ │
393
- │ │ MCP Server │ │ HTTP API Server │ │
394
- │ │ 44 tools │ │ 21 endpoints │ │
395
- │ └─────────┬───────────┘ └──────────┬─────────────────┘ │
396
- └────────────┼─────────────────────────┼───────────────────┘
397
- └──────────┬──────────────┘
398
- ▼
399
- ┌──────────────────────────────────────────────────────────┐
400
- │ Core Engine │
401
- │ │
402
- │ ┌────────────┐ ┌────────────┐ ┌─────────────────────┐ │
403
- │ │ Retriever │ │ Classifier │ │ Context Composer │ │
404
- │ │ (vector + │ │ (6 cats) │ │ (resume_context) │ │
405
- │ │ BM25 + RRF)│ │ │ │ │ │
406
- │ └────────────┘ └────────────┘ └──────────────────────┘ │
407
- │ ┌────────────┐ ┌────────────┐ ┌─────────────────────┐ │
408
- │ │ Decay │ │ Conflict │ │ Capture Engine │ │
409
- │ │ Engine │ │ Engine │ │ (evidence → durable) │ │
410
- │ │ (Weibull) │ │ (audit + │ │ │ │
411
- │ │ │ │ merge) │ │ │ │
412
- │ └────────────┘ └────────────┘ └──────────────────────┘ │
413
- └──────────────────────────┬───────────────────────────────┘
414
- ▼
415
- ┌──────────────────────────────────────────────────────────┐
416
- │ Storage Layer │
417
- │ ┌─────────────────────┐ ┌────────────────────────────┐ │
418
- │ │ LanceDB │ │ Jina Embeddings v5 │ │
419
- │ │ (vector + columnar) │ │ (1024-dim, task-aware) │ │
420
- │ └─────────────────────┘ └────────────────────────────┘ │
421
- └──────────────────────────────────────────────────────────┘
422
- ```
423
-
424
- ### Internal Design
344
+ | | Enumerated | Complement |
345
+ |---|---|---|
346
+ | Agent-made images | 5,812 | **10,938** |
347
+ | Sessions with any image | 1,507 | **1,767** |
348
+ | Human-pasted images | 1,629 | 1,629 |
425
349
 
426
- - **L0 / L1 / L2 Dynamic Folding** — every memory stores 3 granularity layers (one-liner / bullet summary / full content); retrieval dynamically selects which layer to return based on relevance score and token budget
427
- - **Weibull Decay + Emotion Modulation** — memories decay along a parametric Weibull curve; importance scores modulate the half-life, and emotional salience extends it further (up to 30%)
428
- - **Vector Pre-filter + LLM Dedup** — 90% of dedup decisions use cheap cosine similarity (>= 0.92); only borderline cases invoke LLM judgment, keeping costs low without sacrificing accuracy
429
- - **Category-Aware Merge Strategies** — `profile` and `preferences` use merge-on-conflict (latest wins); `events` and `cases` use append-only (history preserved)
430
- - **Display Score vs Elimination Score** — dual-track retrieval: tier floor prevents core memories from ever dropping out, while decay boost lets fresh memories surface temporarily without permanently displacing stable ones
350
+ **The enumeration missed 5,126 images and 376 sessions** — nearly half. The largest class
351
+ it dropped was image *generation*, which lives in neither container the list knew about.
352
+ Human-pasted counts are identical under both definitions, which is the check that matters:
353
+ widening the second bucket did not contaminate the precise one. A regression test feeds the
354
+ parser an `image_generation_call` — a shape the source never names — and asserts it lands
355
+ in the second bucket; under the enumerated implementation that test fails.
431
356
 
432
- > Full architecture deep-dive: [`docs/architecture.md`](docs/architecture.md)
357
+ One caveat: the complement counts *signals*, not certified pictures. A single generation can
358
+ leave both a call and a completion record and be counted twice. That direction was chosen
359
+ deliberately — the question is "is there anything here to look at", not "exactly how many".
433
360
 
434
- ---
435
361
 
436
362
  ## Interfaces
437
363
 
@@ -578,6 +504,48 @@ bun run src/cli.ts doctor
578
504
 
579
505
  ---
580
506
 
507
+ ## Web UI
508
+
509
+ <p align="center">
510
+ <img src="assets/dashboard.png" alt="RecallNest Dashboard" width="800" />
511
+ <br><em>Dashboard — total count, category distribution, health score, and growth trends at a glance.</em>
512
+ </p>
513
+
514
+ <p align="center">
515
+ <img src="assets/screenshots/ui-full.png" alt="RecallNest Search Workbench" width="800" />
516
+ <br><em>Search Workbench — hybrid search with topic tag filtering, 4 retrieval profiles, Skills browser, and asset management.</em>
517
+ </p>
518
+
519
+ <p align="center">
520
+ <img src="assets/knowledge-graph.png" alt="RecallNest Knowledge Graph" width="800" />
521
+ <br><em>Knowledge Graph — interactive force-directed visualization with semantic bridges revealing cross-domain connections.</em>
522
+ </p>
523
+
524
+ ```bash
525
+ bun run src/ui-server.ts
526
+ # → http://localhost:4317
527
+ ```
528
+
529
+ ---
530
+
531
+ ## What's new
532
+
533
+ **v3.0** raised the runtime floor to **Node 22** (the only breaking change — Bun users are
534
+ unaffected) and gave synthesized conclusions a road into stable memory: a `dream` insight
535
+ can now be promoted on the strength of its own validated evidence set, instead of being
536
+ permanently stuck on the evidence layer where nothing downstream could lean on it.
537
+
538
+ It also fixed a rate-limit reply that could trigger an unbounded request storm — measured
539
+ at over 61,000 requests in five seconds against an endpoint asking us to slow down. Found
540
+ by the new HTTP contract tests, which drive the real client classes against a loopback
541
+ server instead of stubbing the SDK.
542
+
543
+ Existing LanceDB data opens in place; there is no export or import step.
544
+
545
+ **Full history — v3.0 through v1.0, with the upgrade notes for each — is in
546
+ [CHANGELOG.md](CHANGELOG.md).**
547
+
548
+
581
549
  ## Multilingual Support
582
550
 
583
551
  RecallNest works out of the box with English. For multilingual memory (Chinese, Japanese, Thai, and 20+ more), install [babel-memory](https://github.com/AliceLJY/babel-memory) with the language packs you need: