@seanhogg/builderforce-memory-mcp 2026.10.2 → 2026.10.22

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 (82) hide show
  1. package/README.md +22 -5
  2. package/dist/backend.d.ts +26 -0
  3. package/dist/backend.d.ts.map +1 -1
  4. package/dist/backends/memory-store.d.ts +50 -2
  5. package/dist/backends/memory-store.d.ts.map +1 -1
  6. package/dist/backends/memory-store.js +88 -10
  7. package/dist/backends/memory-store.js.map +1 -1
  8. package/dist/bin/http.js +7 -1
  9. package/dist/bin/http.js.map +1 -1
  10. package/dist/bin/install.js +6 -3
  11. package/dist/bin/install.js.map +1 -1
  12. package/dist/bin/stdio.d.ts +9 -4
  13. package/dist/bin/stdio.d.ts.map +1 -1
  14. package/dist/bin/stdio.js +20 -5
  15. package/dist/bin/stdio.js.map +1 -1
  16. package/dist/compaction-tools.d.ts +15 -0
  17. package/dist/compaction-tools.d.ts.map +1 -0
  18. package/dist/compaction-tools.js +192 -0
  19. package/dist/compaction-tools.js.map +1 -0
  20. package/dist/compaction.d.ts +114 -8
  21. package/dist/compaction.d.ts.map +1 -1
  22. package/dist/compaction.js +161 -7
  23. package/dist/compaction.js.map +1 -1
  24. package/dist/experience/file-store.d.ts +2 -1
  25. package/dist/experience/file-store.d.ts.map +1 -1
  26. package/dist/experience/file-store.js +4 -0
  27. package/dist/experience/file-store.js.map +1 -1
  28. package/dist/experience/train.d.ts +13 -4
  29. package/dist/experience/train.d.ts.map +1 -1
  30. package/dist/experience/train.js +14 -5
  31. package/dist/experience/train.js.map +1 -1
  32. package/dist/index.d.ts +13 -6
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +11 -7
  35. package/dist/index.js.map +1 -1
  36. package/dist/install/claude-hooks.d.ts +5 -0
  37. package/dist/install/claude-hooks.d.ts.map +1 -1
  38. package/dist/install/claude-hooks.js +69 -9
  39. package/dist/install/claude-hooks.js.map +1 -1
  40. package/dist/install/server-spec.d.ts +33 -7
  41. package/dist/install/server-spec.d.ts.map +1 -1
  42. package/dist/install/server-spec.js +59 -9
  43. package/dist/install/server-spec.js.map +1 -1
  44. package/dist/model/recall-probe.d.ts +29 -0
  45. package/dist/model/recall-probe.d.ts.map +1 -0
  46. package/dist/model/recall-probe.js +72 -0
  47. package/dist/model/recall-probe.js.map +1 -0
  48. package/dist/persistence/fact-archive.d.ts +47 -0
  49. package/dist/persistence/fact-archive.d.ts.map +1 -0
  50. package/dist/persistence/fact-archive.js +85 -0
  51. package/dist/persistence/fact-archive.js.map +1 -0
  52. package/dist/persistence/shared-json-file.d.ts +24 -1
  53. package/dist/persistence/shared-json-file.d.ts.map +1 -1
  54. package/dist/persistence/shared-json-file.js +46 -1
  55. package/dist/persistence/shared-json-file.js.map +1 -1
  56. package/dist/restore.d.ts +56 -0
  57. package/dist/restore.d.ts.map +1 -0
  58. package/dist/restore.js +118 -0
  59. package/dist/restore.js.map +1 -0
  60. package/dist/tools.d.ts +13 -0
  61. package/dist/tools.d.ts.map +1 -1
  62. package/dist/tools.js +11 -90
  63. package/dist/tools.js.map +1 -1
  64. package/package.json +6 -6
  65. package/server.json +2 -2
  66. package/src/backend.ts +29 -0
  67. package/src/backends/memory-store.ts +141 -11
  68. package/src/bin/http.ts +7 -1
  69. package/src/bin/install.ts +7 -3
  70. package/src/bin/stdio.ts +20 -5
  71. package/src/compaction-tools.ts +206 -0
  72. package/src/compaction.ts +228 -9
  73. package/src/experience/file-store.ts +5 -0
  74. package/src/experience/train.ts +26 -9
  75. package/src/index.ts +55 -10
  76. package/src/install/claude-hooks.ts +72 -9
  77. package/src/install/server-spec.ts +74 -8
  78. package/src/model/recall-probe.ts +81 -0
  79. package/src/persistence/fact-archive.ts +101 -0
  80. package/src/persistence/shared-json-file.ts +54 -1
  81. package/src/restore.ts +144 -0
  82. package/src/tools.ts +24 -93
package/dist/tools.d.ts CHANGED
@@ -14,6 +14,7 @@
14
14
  * store back into context is more expensive than inlining it.
15
15
  */
16
16
  import type { MemoryBackend } from "./backend.js";
17
+ import { type RecallProbe } from "./compaction.js";
17
18
  import type { ExperienceHost } from "./experience/host.js";
18
19
  import { type MemoryTool } from "./tool-core.js";
19
20
  export type { MemoryTool, ToolResult } from "./tool-core.js";
@@ -37,6 +38,18 @@ export interface MemoryToolsOptions {
37
38
  * beside the memory tools. See {@link createExperienceHost}.
38
39
  */
39
40
  experience?: ExperienceHost | null;
41
+ /**
42
+ * The local model `memory_compact` proves absorption with before it stubs a
43
+ * fact (see `planLosslessCompaction`). Null/absent → compaction stubs nothing
44
+ * and says why. The bins pass `lazyRecallProbe()` (the configured Evermind).
45
+ */
46
+ recallProbe?: RecallProbe | null;
47
+ /**
48
+ * Reads a restore source by path for `memory_restore`. Only hosts that may read
49
+ * their own disk pass it (the stdio bin); without it the tool takes inline JSON
50
+ * only, so a networked server never reads a caller-named file.
51
+ */
52
+ readRestoreFile?: (path: string) => Promise<string>;
40
53
  }
41
54
  /**
42
55
  * Builds the memory tool set bound to `backend`. Write tools are included only
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAwD,MAAM,cAAc,CAAC;AAGxG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAkB,KAAK,UAAU,EAAmB,MAAM,gBAAgB,CAAC;AAElF,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IAC/B,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oGAAoG;IACpG,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,UAAU,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;CACtC;AA2DD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,IAAI,GAAE,kBAAuB,GAAG,UAAU,EAAE,CAiOpG"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAyC,MAAM,cAAc,CAAC;AACzF,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,EAAkB,KAAK,UAAU,EAAmB,MAAM,gBAAgB,CAAC;AAElF,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IAC/B,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oGAAoG;IACpG,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,UAAU,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IACnC;;;;OAIG;IACH,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACvD;AAiDD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,IAAI,GAAE,kBAAuB,GAAG,UAAU,EAAE,CAyJpG"}
package/dist/tools.js CHANGED
@@ -14,7 +14,8 @@
14
14
  * store back into context is more expensive than inlining it.
15
15
  */
16
16
  import { z } from "zod";
17
- import { DEFAULT_STUB_CHARS, planCompaction } from "./compaction.js";
17
+ import { CONTENT_LOST_LABEL } from "./compaction.js";
18
+ import { appendCompactionTools } from "./compaction-tools.js";
18
19
  import { buildExperienceTools } from "./experience/tools.js";
19
20
  import { appendGatewayCostTools } from "./gateway-tools.js";
20
21
  import { clip, fail, ok } from "./tool-core.js";
@@ -32,6 +33,8 @@ const RANKER_LINE = {
32
33
  embedding: "Ranked by: semantic recall (SSM embedding fused with lexical).",
33
34
  lexical: "Ranked by: lexical recall (fallback - no embedding model loaded).",
34
35
  };
36
+ /** A stub whose original is gone is surfaced WITH the label, never as a plain fact. */
37
+ const lostLabel = (h) => (h.contentLost ? ` ${CONTENT_LOST_LABEL}` : "");
35
38
  function renderHits(hits, maxChars, method) {
36
39
  const ranker = method ? `\n${RANKER_LINE[method]}` : "";
37
40
  if (hits.length === 0)
@@ -40,7 +43,7 @@ function renderHits(hits, maxChars, method) {
40
43
  .map((h) => {
41
44
  const tags = h.tags?.length ? ` tags=[${h.tags.join(", ")}]` : "";
42
45
  const score = h.score != null ? ` score=${h.score.toFixed(3)}` : "";
43
- return `• ${h.key}${score}${tags}\n ${clip(h.content, maxChars)}`;
46
+ return `• ${h.key}${score}${tags}${lostLabel(h)}\n ${clip(h.content, maxChars)}`;
44
47
  })
45
48
  .join("\n") + ranker);
46
49
  }
@@ -54,18 +57,6 @@ async function rankedRecall(backend, query, topK) {
54
57
  return backend.recallRanked(query, topK);
55
58
  return { hits: await backend.recall(query, topK) };
56
59
  }
57
- const SKIP_REASONS = {
58
- not_found: "not found",
59
- already_compacted: "already compacted",
60
- not_smaller: "already shorter than its stub",
61
- };
62
- /** One-line compaction receipt: what shrank, what it saved, and what was left alone. */
63
- function renderCompaction(compacted, bytesSaved, skipped) {
64
- const lines = [`Compacted ${compacted} memory(ies), ${bytesSaved} character(s) reclaimed.`];
65
- for (const s of skipped)
66
- lines.push(`• skipped ${s.key} — ${SKIP_REASONS[s.reason]}`);
67
- return lines.join("\n");
68
- }
69
60
  /**
70
61
  * Builds the memory tool set bound to `backend`. Write tools are included only
71
62
  * when `writable` is not false AND the backend actually implements them.
@@ -119,7 +110,9 @@ export function buildMemoryTools(backend, opts = {}) {
119
110
  if (!key)
120
111
  return fail("key is required.");
121
112
  const hit = await backend.get(key);
122
- return hit ? ok(`• ${hit.key}\n ${hit.content}`) : ok(`No memory found for key "${key}".`);
113
+ return hit
114
+ ? ok(`• ${hit.key}${lostLabel(hit)}\n ${hit.content}`)
115
+ : ok(`No memory found for key "${key}".`);
123
116
  }
124
117
  catch (err) {
125
118
  return fail(`get failed: ${String(err)}`);
@@ -190,81 +183,9 @@ export function buildMemoryTools(backend, opts = {}) {
190
183
  },
191
184
  });
192
185
  }
193
- // memory_compact — the FIRST-CLASS compaction path. It writes through the live
194
- // store (get → plan → remember), so a durable backend's in-memory state and its
195
- // on-disk snapshot agree afterwards. Compacting the snapshot file behind the
196
- // server's back instead is what races: the server still holds the full bodies and
197
- // re-snapshots over them on its next write. Requires read + write, so it is
198
- // registered alongside the other write tools.
199
- if (writable && backend.remember) {
200
- tools.push({
201
- name: "memory_compact",
202
- description: "Shrink memories that have already been absorbed elsewhere (folded into a model, " +
203
- "summarised into a longer-lived note) down to a one-line pointer stub, reclaiming the " +
204
- "context they were eating. Call this AFTER something durable has learned the facts — " +
205
- "never as a way to tidy up, because the full body is gone afterwards. Already-compacted " +
206
- "keys are skipped, so repeating the call is safe.",
207
- inputSchema: {
208
- keys: z.array(z.string()).min(1).describe("Exact keys of the memories to compact."),
209
- stub: z
210
- .string()
211
- .optional()
212
- .describe("Explicit replacement body applied to every listed key. Omit to generate " +
213
- "'[absorbed→Evermind vN] <first line>' from each entry's own first line."),
214
- version: z
215
- .number()
216
- .int()
217
- .min(0)
218
- .optional()
219
- .describe("Version of the model that absorbed these facts; appears in the generated stub."),
220
- maxChars: z
221
- .number()
222
- .int()
223
- .min(20)
224
- .max(500)
225
- .optional()
226
- .describe(`Max characters of the generated pointer line (default ${DEFAULT_STUB_CHARS}).`),
227
- },
228
- handler: async (args) => {
229
- try {
230
- const raw = args["keys"];
231
- const keys = Array.isArray(raw) ? raw.map((k) => String(k)).filter(Boolean) : [];
232
- if (keys.length === 0)
233
- return fail("keys is required.");
234
- // ONE read pass: the hit carries both the body the plan reasons about
235
- // and the tags/importance the rewrite must preserve.
236
- const hits = new Map();
237
- for (const key of keys) {
238
- const hit = await backend.get(key);
239
- if (hit)
240
- hits.set(key, hit);
241
- }
242
- const plan = planCompaction(keys.map((key) => ({ key, content: hits.get(key)?.content })), {
243
- stub: typeof args["stub"] === "string" ? args["stub"] : undefined,
244
- version: args["version"] == null ? undefined : Number(args["version"]),
245
- maxChars: args["maxChars"] == null ? undefined : Number(args["maxChars"]),
246
- });
247
- // Preserve tags/importance — compaction shortens a body, it does not
248
- // reclassify the fact.
249
- const writes = plan.writes.map((w) => {
250
- const prev = hits.get(w.key);
251
- return { key: w.key, content: w.content, tags: prev?.tags, importance: prev?.importance };
252
- });
253
- if (writes.length > 0) {
254
- if (backend.rememberMany)
255
- await backend.rememberMany(writes);
256
- else
257
- for (const w of writes)
258
- await backend.remember(w);
259
- }
260
- return ok(renderCompaction(plan.writes.length, plan.bytesSaved, plan.skipped));
261
- }
262
- catch (err) {
263
- return fail(`compact failed: ${String(err)}`);
264
- }
265
- },
266
- });
267
- }
186
+ // memory_compact + memory_restore — the lossless compaction pair (compaction-tools.ts).
187
+ if (writable && backend.remember)
188
+ appendCompactionTools(tools, backend, opts);
268
189
  if (writable && backend.forget) {
269
190
  tools.push({
270
191
  name: "memory_forget",
package/dist/tools.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seanhogg/builderforce-memory-mcp",
3
- "version": "2026.10.2",
3
+ "version": "2026.10.22",
4
4
  "mcpName": "io.github.SeanHogg/builderforce-memory",
5
5
  "description": "BuilderForce Agent Memory — MCP transport. Exposes @seanhogg/builderforce-memory to any MCP client (Claude Agent SDK in-process, stdio, or HTTP) over a pluggable MemoryBackend, with token-saving fetch-on-demand recall.",
6
6
  "type": "module",
@@ -56,8 +56,8 @@
56
56
  },
57
57
  "peerDependencies": {
58
58
  "@anthropic-ai/claude-agent-sdk": ">=0.1.0",
59
- "@seanhogg/builderforce-memory": "^2026.10.2",
60
- "@seanhogg/builderforce-memory-engine": "^2026.10.2",
59
+ "@seanhogg/builderforce-memory": "^2026.10.22",
60
+ "@seanhogg/builderforce-memory-engine": "^2026.10.22",
61
61
  "fake-indexeddb": "^6.0.0"
62
62
  },
63
63
  "peerDependenciesMeta": {
@@ -83,8 +83,8 @@
83
83
  "fake-indexeddb": "^6.0.0",
84
84
  "typescript": "^6.0.3",
85
85
  "@typescript/native-preview": "7.0.0-dev.20260627.2",
86
- "@seanhogg/builderforce-memory": "2026.10.2",
87
- "@seanhogg/builderforce-memory-engine": "2026.10.2"
86
+ "@seanhogg/builderforce-memory": "2026.10.22",
87
+ "@seanhogg/builderforce-memory-engine": "2026.10.22"
88
88
  },
89
89
  "engines": {
90
90
  "node": ">=18.0.0"
@@ -94,7 +94,7 @@
94
94
  },
95
95
  "scripts": {
96
96
  "build": "tsc",
97
- "test": "tsc && node --test tests/install.test.mjs tests/tools.test.mjs tests/http.test.mjs tests/compaction.test.mjs tests/recall-method.test.mjs tests/experience.test.mjs",
97
+ "test": "tsc && node --test tests/install.test.mjs tests/tools.test.mjs tests/http.test.mjs tests/compaction.test.mjs tests/recall-method.test.mjs tests/experience.test.mjs tests/lossless.test.mjs",
98
98
  "lint": "eslint src/",
99
99
  "typecheck:native": "tsgo --noEmit"
100
100
  }
package/server.json CHANGED
@@ -8,14 +8,14 @@
8
8
  "source": "github",
9
9
  "subfolder": "packages/memory-mcp"
10
10
  },
11
- "version": "2026.10.2",
11
+ "version": "2026.10.22",
12
12
  "websiteUrl": "https://builderforce.ai",
13
13
  "packages": [
14
14
  {
15
15
  "registryType": "npm",
16
16
  "registryBaseUrl": "https://registry.npmjs.org",
17
17
  "identifier": "@seanhogg/builderforce-memory-mcp",
18
- "version": "2026.10.2",
18
+ "version": "2026.10.22",
19
19
  "transport": {
20
20
  "type": "stdio"
21
21
  },
package/src/backend.ts CHANGED
@@ -8,6 +8,8 @@
8
8
  * transports.
9
9
  */
10
10
 
11
+ import type { ArchivedFact } from "./compaction.js";
12
+
11
13
  /** A single recalled memory, normalised across backends. */
12
14
  export interface RecallHit {
13
15
  /** Stable identifier for the memory. */
@@ -26,6 +28,18 @@ export interface RecallHit {
26
28
  importance?: number;
27
29
  /** Unix-ms write time. */
28
30
  timestamp?: number;
31
+ /**
32
+ * Set when the stored body is a compaction stub that was resolved to its
33
+ * archived original: `content` is then the FULL original and this is the stub
34
+ * actually stored. Absent for an ordinary (uncompacted) memory.
35
+ */
36
+ stub?: string;
37
+ /**
38
+ * True when the stored body is a compaction stub with NO archived original — the
39
+ * text is gone and only the one-line pointer remains. Readers must label it
40
+ * (`CONTENT_LOST_LABEL`) and treat it as unverified; `memory_restore` clears it.
41
+ */
42
+ contentLost?: boolean;
29
43
  }
30
44
 
31
45
  /**
@@ -99,4 +113,19 @@ export interface MemoryBackend {
99
113
 
100
114
  /** Delete a memory by key. Optional — read-only backends omit it. */
101
115
  forget?(key: string): Promise<void>;
116
+
117
+ /**
118
+ * Durably store the full originals of facts about to be compacted. Optional —
119
+ * but `memory_compact` stubs NOTHING on a backend without it, because a stub
120
+ * whose original was never kept is lost content. Must be durable before it
121
+ * resolves: the compactor writes the stubs only afterwards.
122
+ */
123
+ archive?(facts: ArchivedFact[]): Promise<void>;
124
+
125
+ /**
126
+ * Keys whose stored body is a compaction stub with no archived original
127
+ * (`contentLost`). Optional; `memory_restore` uses it to match restore records
128
+ * by text, and falls back to key-only matching without it.
129
+ */
130
+ lostKeys?(): Promise<string[]>;
102
131
  }
@@ -12,10 +12,20 @@
12
12
  * The embedder does NOT have to be a GPU runtime: `EvermindTextEmbedder` from the
13
13
  * engine is a pure-CPU `EvermindLM`, which is what lets the headless stdio server
14
14
  * rank recall semantically (see ./evermind-embedder.ts).
15
+ *
16
+ * Ranking signals: recall also weights each fused score by the fact's importance
17
+ * (x(0.5+importance), the cloud recall's factor) and a half-life recency decay —
18
+ * both ON by default here ({@link DEFAULT_RECALL_RANKING}).
19
+ *
20
+ * Compaction stubs: a stored body that is an `[absorbed→Evermind …]` stub is
21
+ * resolved to its ARCHIVED original (../persistence/fact-archive.ts) on every read,
22
+ * so recall returns the full text; a stub with no archive is flagged `contentLost`.
15
23
  */
16
24
 
17
25
  import type { MemoryBackend, RankedRecall, RecallHit, RememberInput } from "../backend.js";
26
+ import { defaultArchiveFile, isContentLost, isStub, type ArchivedFact } from "../compaction.js";
18
27
  import { dynamicImport } from "../dynamic-import.js";
28
+ import { FileFactArchive, MemoryFactArchive, type FactArchive } from "../persistence/fact-archive.js";
19
29
  import { SharedJsonFile, type SharedFileFs } from "../persistence/shared-json-file.js";
20
30
 
21
31
  // Structural views of the @seanhogg/builderforce-memory surface we use, so this package
@@ -28,8 +38,29 @@ interface MemoryEntryLike {
28
38
  importance?: number;
29
39
  }
30
40
 
41
+ /**
42
+ * Recall ranking signals — the subset of the store's `HybridRetrieveOptions` this
43
+ * backend sets. Structural, so this package needs no type import from the runtime.
44
+ */
45
+ export interface RecallRanking {
46
+ /** Weight each fused score by `0.5 + importance`. */
47
+ importanceWeight?: boolean;
48
+ /** Half-life (days) of the recency decay over each fact's write time; 0 = off. */
49
+ recencyHalfLifeDays?: number;
50
+ }
51
+
52
+ /** Recall ranking defaults: importance ON, 90-day half-life recency decay ON. */
53
+ export const DEFAULT_RECALL_RANKING: Readonly<Required<RecallRanking>> = Object.freeze({
54
+ importanceWeight: true,
55
+ recencyHalfLifeDays: 90,
56
+ });
57
+
31
58
  interface MemoryStoreLike {
32
- remember(key: string, content: string, opts?: { ttlMs?: number; tags?: string[]; importance?: number }): Promise<void>;
59
+ remember(
60
+ key: string,
61
+ content: string,
62
+ opts?: { ttlMs?: number; tags?: string[]; importance?: number; timestamp?: number },
63
+ ): Promise<void>;
33
64
  recall(key: string): Promise<MemoryEntryLike | undefined>;
34
65
  recallAll(): Promise<MemoryEntryLike[]>;
35
66
  recallByTag(tag: string): Promise<MemoryEntryLike[]>;
@@ -38,12 +69,18 @@ interface MemoryStoreLike {
38
69
  query: string,
39
70
  topK: number,
40
71
  runtime?: unknown,
72
+ opts?: RecallRanking,
41
73
  ): Promise<{ hits: Array<{ entry: MemoryEntryLike; score: number }>; method: "embedding" | "lexical" }>;
42
74
  forget(key: string): Promise<void>;
43
75
  }
44
76
 
45
- function toHit(e: MemoryEntryLike, score?: number): RecallHit {
46
- return {
77
+ /**
78
+ * Normalise a stored entry into a hit, resolving a compaction stub: with an archived
79
+ * original the hit carries the FULL text (and the stored stub in `stub`); without one
80
+ * it keeps the stub and is flagged `contentLost`.
81
+ */
82
+ function toHit(e: MemoryEntryLike, archived: ArchivedFact | undefined, score?: number): RecallHit {
83
+ const base: RecallHit = {
47
84
  key: e.key,
48
85
  content: e.content,
49
86
  ...(score === undefined ? {} : { score }),
@@ -51,14 +88,31 @@ function toHit(e: MemoryEntryLike, score?: number): RecallHit {
51
88
  importance: e.importance,
52
89
  timestamp: e.timestamp,
53
90
  };
91
+ if (!isStub(e.content)) return base;
92
+ if (archived) return { ...base, content: archived.content, stub: e.content };
93
+ return { ...base, contentLost: true };
94
+ }
95
+
96
+ export interface MemoryStoreBackendOptions {
97
+ /** Where compacted originals are kept. Default: an in-process archive. */
98
+ archive?: FactArchive;
99
+ /** Recall ranking signals. Default {@link DEFAULT_RECALL_RANKING}; `false` = fusion alone. */
100
+ ranking?: RecallRanking | false;
54
101
  }
55
102
 
56
103
  export class MemoryStoreBackend implements MemoryBackend {
104
+ private readonly facts: FactArchive;
105
+ private readonly ranking: RecallRanking | undefined;
106
+
57
107
  constructor(
58
108
  private readonly store: MemoryStoreLike,
59
109
  /** Optional SSMRuntime; enables embedding-based recall when present. */
60
110
  private readonly runtime?: unknown,
61
- ) {}
111
+ opts: MemoryStoreBackendOptions = {},
112
+ ) {
113
+ this.facts = opts.archive ?? new MemoryFactArchive();
114
+ this.ranking = opts.ranking === false ? undefined : { ...DEFAULT_RECALL_RANKING, ...opts.ranking };
115
+ }
62
116
 
63
117
  /** Plain recall — {@link recallRanked} with the ranker's name dropped. ONE path. */
64
118
  async recall(query: string, topK: number): Promise<RecallHit[]> {
@@ -66,18 +120,35 @@ export class MemoryStoreBackend implements MemoryBackend {
66
120
  }
67
121
 
68
122
  async recallRanked(query: string, topK: number): Promise<RankedRecall> {
69
- const ranked = await this.store.recallRanked(query, topK, this.runtime);
70
- return { hits: ranked.hits.map((h) => toHit(h.entry, h.score)), method: ranked.method };
123
+ const ranked = await this.store.recallRanked(query, topK, this.runtime, this.ranking);
124
+ const rows = this.facts.all();
125
+ return { hits: ranked.hits.map((h) => toHit(h.entry, rows[h.entry.key], h.score)), method: ranked.method };
71
126
  }
72
127
 
73
128
  async get(key: string): Promise<RecallHit | undefined> {
74
129
  const e = await this.store.recall(key);
75
- return e ? toHit(e) : undefined;
130
+ return e ? toHit(e, this.facts.get(key)) : undefined;
76
131
  }
77
132
 
78
133
  async recallByTag(tag: string, limit: number): Promise<RecallHit[]> {
79
134
  const entries = await this.store.recallByTag(tag);
80
- return entries.slice(0, limit).map(toHit);
135
+ const rows = this.facts.all();
136
+ return entries.slice(0, limit).map((e) => toHit(e, rows[e.key]));
137
+ }
138
+
139
+ async archive(facts: ArchivedFact[]): Promise<void> {
140
+ this.facts.putMany(facts);
141
+ }
142
+
143
+ /** Keys whose stored body is a stub with no archived original. */
144
+ async lostKeys(): Promise<string[]> {
145
+ const rows = this.facts.all();
146
+ return (await this.store.recallAll()).filter((e) => isContentLost(e.content, rows[e.key])).map((e) => e.key);
147
+ }
148
+
149
+ /** Every archived row, read once — the snapshot writer's `contentLost` source. */
150
+ archivedRows(): Readonly<Record<string, ArchivedFact>> {
151
+ return this.facts.all();
81
152
  }
82
153
 
83
154
  async remember(input: RememberInput): Promise<void> {
@@ -144,6 +215,18 @@ export interface LocalBackendOptions {
144
215
  * when `BUILDERFORCE_MEMORY_MODEL` is set, so this is mostly for tests.
145
216
  */
146
217
  semanticRecall?: false;
218
+ /**
219
+ * Recall ranking signals (importance weighting, half-life recency decay).
220
+ * Default {@link DEFAULT_RECALL_RANKING} — both on; `false` ranks by fusion alone.
221
+ */
222
+ ranking?: RecallRanking | false;
223
+ /**
224
+ * Where compacted originals are archived. Default: beside `persistFile`
225
+ * (`memory.archive.json`) when there is one, else in-process.
226
+ */
227
+ archiveFile?: string;
228
+ /** Diagnostic sink (stderr by default — stdout is the MCP stdio channel). */
229
+ log?: (line: string) => void;
147
230
  }
148
231
 
149
232
  /**
@@ -159,6 +242,14 @@ interface SnapshotEntry {
159
242
  content: string;
160
243
  tags?: string[];
161
244
  importance?: number;
245
+ /** Unix-ms write time — persisted so recency ranking survives a respawn. */
246
+ timestamp?: number;
247
+ /**
248
+ * Written as true for a stub with no archived original, so dependency-free
249
+ * readers (the Claude Code hook) can label it without reading the archive.
250
+ * Derived on every write — never read back as truth; the archive decides.
251
+ */
252
+ contentLost?: true;
162
253
  }
163
254
 
164
255
  type FsLike = SharedFileFs & { mkdirSync(path: string, opts: { recursive: boolean }): void };
@@ -269,17 +360,41 @@ class DiskPersistedBackend implements MemoryBackend {
269
360
  if (!wanted.has(existing.key)) await this.store.forget(existing.key);
270
361
  }
271
362
  for (const raw of entries) {
272
- await this.store.remember(raw.key, raw.content, { tags: raw.tags, importance: raw.importance });
363
+ await this.store.remember(raw.key, raw.content, {
364
+ tags: raw.tags,
365
+ importance: raw.importance,
366
+ ...(typeof raw.timestamp === "number" && Number.isFinite(raw.timestamp) ? { timestamp: raw.timestamp } : {}),
367
+ });
273
368
  }
274
369
  }
275
370
 
371
+ /**
372
+ * Archive first — durable before the caller writes the stubs. When the rows
373
+ * RESTORE lost stubs (memory_restore), the snapshot is rewritten too, so its
374
+ * derived `contentLost` flags stop naming them.
375
+ */
376
+ async archive(facts: ArchivedFact[]): Promise<void> {
377
+ await this.ensureFresh();
378
+ const lostBefore = new Set(await this.inner.lostKeys());
379
+ await this.inner.archive(facts);
380
+ if (facts.some((f) => lostBefore.has(f.key))) await this.snapshot();
381
+ }
382
+
383
+ async lostKeys(): Promise<string[]> {
384
+ await this.ensureFresh();
385
+ return this.inner.lostKeys();
386
+ }
387
+
276
388
  private async snapshot(): Promise<void> {
277
389
  const entries = await this.store.recallAll();
390
+ const rows = this.inner.archivedRows();
278
391
  const out: SnapshotEntry[] = entries.map((e) => ({
279
392
  key: e.key,
280
393
  content: e.content,
281
394
  tags: e.tags,
282
395
  importance: e.importance,
396
+ timestamp: e.timestamp,
397
+ ...(isContentLost(e.content, rows[e.key]) ? { contentLost: true as const } : {}),
283
398
  }));
284
399
  this.file.write(JSON.stringify(out, null, 2));
285
400
  }
@@ -321,9 +436,9 @@ export async function createLocalMemoryStoreBackend(opts: LocalBackendOptions =
321
436
  }
322
437
 
323
438
  const store = new MemoryStore({ idbFactory, dbName: opts.dbName, maxEntries });
324
- const backend = new MemoryStoreBackend(store, runtime);
439
+ const log = opts.log ?? ((line: string) => void globalThis.process?.stderr?.write(`${line}\n`));
325
440
 
326
- if (!opts.persistFile) return backend;
441
+ if (!opts.persistFile) return new MemoryStoreBackend(store, runtime, { ranking: opts.ranking });
327
442
 
328
443
  // Disk-mirror requested. node:fs/path are loaded indirectly so a browser
329
444
  // bundle of this module never statically pulls in Node builtins.
@@ -332,8 +447,23 @@ export async function createLocalMemoryStoreBackend(opts: LocalBackendOptions =
332
447
  const dir = path.dirname(opts.persistFile);
333
448
  if (dir && !fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
334
449
 
450
+ // The archive sits beside the snapshot, OUTSIDE it: it must survive the snapshot
451
+ // being rebuilt, rewritten by another process, or capped — see fact-archive.ts.
452
+ const archive = new FileFactArchive(opts.archiveFile ?? defaultArchiveFile(opts.persistFile), fs);
453
+ const backend = new MemoryStoreBackend(store, runtime, { archive, ranking: opts.ranking });
335
454
  const persisted = new DiskPersistedBackend(backend, store, new SharedJsonFile(opts.persistFile, fs));
336
455
  // Boot hydration IS the freshness check with no stamp yet — see ensureFresh().
337
456
  await persisted.ensureFresh();
457
+
458
+ // Facts compacted before archiving existed are stubs whose text is gone. Every
459
+ // read flags them `contentLost` (and so does the next snapshot); say so once at
460
+ // boot so the loss is visible, with the way back.
461
+ const lost = await persisted.lostKeys();
462
+ if (lost.length > 0) {
463
+ log(
464
+ `[builderforce-memory] ${lost.length} memory(ies) are compaction stubs with no archived original ` +
465
+ `(content lost — re-verify before relying on them). Recover the text with memory_restore.`,
466
+ );
467
+ }
338
468
  return persisted;
339
469
  }
package/src/bin/http.ts CHANGED
@@ -24,9 +24,12 @@ import { createLocalMemoryStoreBackend } from "../backends/memory-store.js";
24
24
  import { createRecallEmbedder } from "../embedding/index.js";
25
25
  import { createExperienceHost } from "../experience/host.js";
26
26
  import { resolveMemoryFile } from "../install/server-spec.js";
27
+ import { lazyRecallProbe } from "../model/recall-probe.js";
27
28
  import { createMemoryHttpHandler } from "../transports/http.js";
28
29
 
29
- const memoryFile = resolveMemoryFile();
30
+ const memoryFile = resolveMemoryFile(process.env, undefined, {
31
+ log: (line) => void process.stderr.write(`${line}\n`),
32
+ });
30
33
 
31
34
  const backend = await createLocalMemoryStoreBackend({
32
35
  dbName: process.env["BUILDERFORCE_MEMORY_DB"],
@@ -46,6 +49,9 @@ const handler = createMemoryHttpHandler(backend, {
46
49
  gatewayUrl: process.env["BUILDERFORCE_GATEWAY_URL"] ?? "https://api.builderforce.ai",
47
50
  gatewayApiKey: process.env["BUILDERFORCE_API_KEY"],
48
51
  experience: await createExperienceHost({ memoryFile }),
52
+ recallProbe: lazyRecallProbe(),
53
+ // No readRestoreFile: a networked server never reads a caller-named path —
54
+ // memory_restore takes the export inline.
49
55
  });
50
56
 
51
57
  if (process.env["BUILDERFORCE_MEMORY_EXPERIENCE"] === "1" && !process.env["BUILDERFORCE_MEMORY_TOKEN"]) {
@@ -22,7 +22,7 @@ import nodeFs from "node:fs";
22
22
  import { HOSTS } from "../install/hosts.js";
23
23
  import { installMemoryServer, type HostSelector } from "../install/install.js";
24
24
  import { installClaudeCombo } from "../install/claude-hooks.js";
25
- import { defaultMemoryFile } from "../install/server-spec.js";
25
+ import { resolveMemoryFile } from "../install/server-spec.js";
26
26
 
27
27
  function argValue(name: string): string | undefined {
28
28
  const hit = process.argv.find((a) => a.startsWith(`--${name}=`));
@@ -55,7 +55,11 @@ const hosts: HostSelector =
55
55
  ? "all"
56
56
  : hostArg.split(",").map((s) => s.trim()).filter(Boolean);
57
57
 
58
- const memoryFile = argValue("memory-file") ?? defaultMemoryFile();
58
+ // The SAME resolver the servers and the hook use — so an install on a machine whose
59
+ // live store sits at a legacy location bakes THAT path, not an empty new one.
60
+ const memoryFile =
61
+ argValue("memory-file") ??
62
+ resolveMemoryFile(process.env, undefined, { log: (line) => process.stderr.write(`${line}\n`) });
59
63
 
60
64
  let results;
61
65
  try {
@@ -112,6 +116,6 @@ if (results.length === 0) {
112
116
  );
113
117
  } else {
114
118
  process.stdout.write(
115
- `\nDone — ${wrote} config(s) written. Store: ${memoryFile}\nRestart the agent(s) to connect. Tools: memory_recall · memory_remember · memory_get · memory_recall_by_tag · memory_forget · memory_compact\n`,
119
+ `\nDone — ${wrote} config(s) written. Store: ${memoryFile}\nRestart the agent(s) to connect. Tools: memory_recall · memory_remember · memory_get · memory_recall_by_tag · memory_forget · memory_compact · memory_restore\n`,
116
120
  );
117
121
  }