agent-working-memory 0.13.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +200 -238
  2. package/dist/adapters/common.d.ts +6 -0
  3. package/dist/adapters/common.d.ts.map +1 -1
  4. package/dist/adapters/common.js +457 -362
  5. package/dist/adapters/common.js.map +1 -1
  6. package/dist/api/routes.d.ts.map +1 -1
  7. package/dist/api/routes.js +24 -8
  8. package/dist/api/routes.js.map +1 -1
  9. package/dist/core/alias-map.d.ts +16 -0
  10. package/dist/core/alias-map.d.ts.map +1 -0
  11. package/dist/core/alias-map.js +102 -0
  12. package/dist/core/alias-map.js.map +1 -0
  13. package/dist/core/embeddings.d.ts +17 -0
  14. package/dist/core/embeddings.d.ts.map +1 -1
  15. package/dist/core/embeddings.js +50 -1
  16. package/dist/core/embeddings.js.map +1 -1
  17. package/dist/core/recall-config.d.ts +52 -0
  18. package/dist/core/recall-config.d.ts.map +1 -0
  19. package/dist/core/recall-config.js +110 -0
  20. package/dist/core/recall-config.js.map +1 -0
  21. package/dist/core/rerank-window.d.ts +61 -0
  22. package/dist/core/rerank-window.d.ts.map +1 -0
  23. package/dist/core/rerank-window.js +153 -0
  24. package/dist/core/rerank-window.js.map +1 -0
  25. package/dist/core/rerank2.d.ts +62 -0
  26. package/dist/core/rerank2.d.ts.map +1 -0
  27. package/dist/core/rerank2.js +75 -0
  28. package/dist/core/rerank2.js.map +1 -0
  29. package/dist/core/retrieval-text.d.ts +55 -0
  30. package/dist/core/retrieval-text.d.ts.map +1 -0
  31. package/dist/core/retrieval-text.js +87 -0
  32. package/dist/core/retrieval-text.js.map +1 -0
  33. package/dist/core/temporal-query.d.ts +61 -0
  34. package/dist/core/temporal-query.d.ts.map +1 -0
  35. package/dist/core/temporal-query.js +168 -0
  36. package/dist/core/temporal-query.js.map +1 -0
  37. package/dist/core/token-budget.d.ts +75 -0
  38. package/dist/core/token-budget.d.ts.map +1 -0
  39. package/dist/core/token-budget.js +136 -0
  40. package/dist/core/token-budget.js.map +1 -0
  41. package/dist/core/whoami.d.ts +11 -0
  42. package/dist/core/whoami.d.ts.map +1 -1
  43. package/dist/core/whoami.js +10 -0
  44. package/dist/core/whoami.js.map +1 -1
  45. package/dist/core/write-pipeline.d.ts.map +1 -1
  46. package/dist/core/write-pipeline.js +6 -3
  47. package/dist/core/write-pipeline.js.map +1 -1
  48. package/dist/engine/activation.d.ts.map +1 -1
  49. package/dist/engine/activation.js +135 -32
  50. package/dist/engine/activation.js.map +1 -1
  51. package/dist/hooks/prime.d.ts +77 -0
  52. package/dist/hooks/prime.d.ts.map +1 -0
  53. package/dist/hooks/prime.js +92 -0
  54. package/dist/hooks/prime.js.map +1 -0
  55. package/dist/hooks/sidecar.d.ts.map +1 -1
  56. package/dist/hooks/sidecar.js +39 -0
  57. package/dist/hooks/sidecar.js.map +1 -1
  58. package/dist/mcp.js +134 -102
  59. package/dist/mcp.js.map +1 -1
  60. package/dist/storage/pglite.d.ts.map +1 -1
  61. package/dist/storage/pglite.js +10 -2
  62. package/dist/storage/pglite.js.map +1 -1
  63. package/dist/storage/postgres.d.ts.map +1 -1
  64. package/dist/storage/postgres.js +10 -2
  65. package/dist/storage/postgres.js.map +1 -1
  66. package/dist/storage/sqlite.d.ts.map +1 -1
  67. package/dist/storage/sqlite.js +12 -2
  68. package/dist/storage/sqlite.js.map +1 -1
  69. package/dist/types/engram.d.ts +7 -0
  70. package/dist/types/engram.d.ts.map +1 -1
  71. package/package.json +3 -2
  72. package/src/adapters/common.ts +666 -567
  73. package/src/api/routes.ts +1015 -999
  74. package/src/core/alias-map.ts +97 -0
  75. package/src/core/embeddings.ts +172 -115
  76. package/src/core/recall-config.ts +115 -0
  77. package/src/core/rerank-window.ts +158 -0
  78. package/src/core/rerank2.ts +82 -0
  79. package/src/core/retrieval-text.ts +82 -0
  80. package/src/core/temporal-query.ts +193 -0
  81. package/src/core/token-budget.ts +160 -0
  82. package/src/core/whoami.ts +110 -92
  83. package/src/core/write-pipeline.ts +6 -3
  84. package/src/engine/activation.ts +1568 -1468
  85. package/src/hooks/prime.ts +136 -0
  86. package/src/hooks/sidecar.ts +43 -0
  87. package/src/mcp.ts +1422 -1387
  88. package/src/storage/pglite.ts +10 -2
  89. package/src/storage/postgres.ts +10 -2
  90. package/src/storage/sqlite.ts +12 -2
  91. package/src/types/engram.ts +7 -0
@@ -126,22 +126,46 @@ export function homedir() {
126
126
  *
127
127
  * Returns a short human-readable status string for the setup command output.
128
128
  */
129
+ /** Opening marker for the generated block. Everything between the markers is replaced
130
+ * on upgrade; anything outside them is preserved. The text is deliberately addressed to
131
+ * whoever opens the file, because that is who needs to know. */
132
+ export const AWM_GEN_BEGIN = '<!-- AWM:GENERATED:BEGIN — this block is REPLACED by `awm setup`. ' +
133
+ 'Put your own notes OUTSIDE these markers and they will survive upgrades. -->';
134
+ export const AWM_GEN_END = '<!-- AWM:GENERATED:END -->';
135
+ /** Wrap generated content in the markers. */
136
+ function wrapGenerated(content) {
137
+ return `${AWM_GEN_BEGIN}\n${content.trim()}\n${AWM_GEN_END}`;
138
+ }
129
139
  export function upsertAwmSection(filePath, newContent, options = {}) {
130
140
  const fname = basename(filePath);
131
141
  const suffix = options.suffix ?? '';
142
+ const force = options.force ?? false;
132
143
  if (!existsSync(filePath)) {
133
144
  const title = options.titleIfNew ?? `# ${basename(dirname(filePath))}`;
134
145
  mkdirSync(dirname(filePath), { recursive: true });
135
- writeFileSync(filePath, `${title}\n\n${newContent}${suffix}`);
146
+ writeFileSync(filePath, `${title}\n\n${wrapGenerated(newContent)}${suffix}`);
136
147
  return `${fname}: created with AWM workflow section`;
137
148
  }
138
149
  const existing = readFileSync(filePath, 'utf-8');
150
+ // ---- Preferred path: the file already carries generated markers, so the boundary
151
+ // between "ours" and "theirs" is explicit and only our block is touched.
152
+ const gb = existing.indexOf(AWM_GEN_BEGIN);
153
+ const ge = existing.indexOf(AWM_GEN_END);
154
+ if (gb !== -1 && ge > gb) {
155
+ const current = existing.slice(gb, ge + AWM_GEN_END.length);
156
+ const desired = wrapGenerated(newContent);
157
+ if (current.trimEnd() === desired.trimEnd()) {
158
+ return `${fname}: AWM section already up-to-date (skipped)`;
159
+ }
160
+ writeFileSync(filePath, existing.slice(0, gb) + desired + existing.slice(ge + AWM_GEN_END.length));
161
+ return `${fname}: AWM generated block updated (content outside the markers preserved)`;
162
+ }
139
163
  // Find section bounds: `## Memory (AWM)` (possibly with ` — MANDATORY` etc.) until next `## ` or EOF
140
164
  const startRegex = /^## Memory \(AWM\)[^\n]*$/m;
141
165
  const startMatch = startRegex.exec(existing);
142
166
  if (!startMatch) {
143
167
  // Section not present — append
144
- writeFileSync(filePath, existing.trimEnd() + '\n\n' + newContent + suffix);
168
+ writeFileSync(filePath, existing.trimEnd() + '\n\n' + wrapGenerated(newContent) + suffix);
145
169
  return `${fname}: appended AWM workflow section`;
146
170
  }
147
171
  // Find end: next `## ` heading after the section start, or EOF
@@ -156,371 +180,442 @@ export function upsertAwmSection(filePath, newContent, options = {}) {
156
180
  if (currentSection === desiredSection) {
157
181
  return `${fname}: AWM section already up-to-date (skipped)`;
158
182
  }
183
+ // ---- LEGACY, UNMARKED SECTION.
184
+ // Written before generated markers existed, so hand-added notes inside it are
185
+ // indistinguishable from generated text. Replacing would silently delete them — on a
186
+ // real install this measured 169 of 381 lines (44%), every one an operational finding
187
+ // that cost real debugging. Back up and refuse; the caller opts in explicitly.
188
+ if (!force) {
189
+ const stamp = new Date().toISOString().replace(/[:.]/g, '-').replace('Z', '');
190
+ const backup = `${filePath}.awm-backup-${stamp}`;
191
+ try {
192
+ writeFileSync(backup, existing);
193
+ }
194
+ catch {
195
+ return `${fname}: AWM section is out of date, but it has no generated markers and the ` +
196
+ `backup could not be written — REFUSING to touch it. Copy the file yourself, then re-run.`;
197
+ }
198
+ return `${fname}: NOT updated — the AWM section predates generated markers, so your own ` +
199
+ `notes inside it cannot be told apart from generated text and would be lost. ` +
200
+ `Backup written to ${basename(backup)}. To upgrade: move any notes you want to keep ` +
201
+ `ABOVE the '## Memory (AWM)' heading (content outside the section is always preserved), ` +
202
+ `then re-run with force. Nothing has been changed.`;
203
+ }
159
204
  const before = existing.slice(0, startMatch.index).trimEnd();
160
205
  const after = existing.slice(sectionEnd).replace(/^\s*\n/, '');
161
206
  const rebuilt = (before ? before + '\n\n' : '') +
162
- desiredSection +
207
+ wrapGenerated(newContent) + suffix +
163
208
  (after ? '\n\n' + after : '\n');
164
209
  writeFileSync(filePath, rebuilt);
165
- return `${fname}: AWM section updated (preserved surrounding content)`;
210
+ return `${fname}: AWM section replaced with a marked generated block (force)`;
166
211
  }
167
- export const AWM_INSTRUCTION_CONTENT = `
168
- ## Memory (AWM) — MANDATORY
169
-
170
- **AWM is THE memory system.** Use it via the \`agent-working-memory\` MCP server
171
- (preferred) or HTTP at \`http://127.0.0.1:8400\` (fallback). The file-based
172
- auto-memory at \`~/.claude/projects/.../memory/*.md\` is a LEGACY bootstrap path —
173
- **do not write new memories to it.** All persistent knowledge goes through AWM.
174
-
175
- If MCP tools aren't loaded at session start, use ToolSearch with
176
- \`select:mcp__agent-working-memory__memory_recall,mcp__agent-working-memory__memory_write\`
177
- to load them. If the MCP server isn't responsive, restart with \`/mcp\` or use
178
- the HTTP endpoints (\`POST /memory/write-batch\`, \`POST /memory/activate\`)
179
- directly — but **DO NOT fall back to markdown files**. Files drift the moment
180
- you write them; AWM stays current because every agent reads + writes the same store.
181
-
182
- ### Lifecycle (always do these, in this order)
183
- 1. **Session start**: call \`memory_restore\` to recover previous context. If it reports the
184
- store is empty/new (or recall keeps returning nothing), **warm-start first**: recall the
185
- \`onboard a new project\` skill and follow it — or call \`onboard_scan\` on the project's
186
- docs/repo, refine the candidates, run \`onboard_questions\`, and save the good ones with
187
- \`memory_write\` (canonical). A cold store is nearly useless until it's seeded.
188
- 2. **Starting a task**: call \`memory_task_begin\` (checkpoints + recalls relevant memories).
189
- 3. **During work**: call \`memory_recall\` BEFORE stating any fact, BEFORE searching
190
- the filesystem, BEFORE making architectural decisions. Recall is ~300ms — cheaper
191
- than one filesystem search.
192
- 4. **As you learn things**: call \`memory_write\` proactively. Don't batch.
193
- 5. **Finishing a task**: call \`memory_task_end\` with a summary.
194
- 6. **Auto-checkpoint** is handled by hooks (compaction, session-end, 15-min timer). No action needed.
195
-
196
- ### Write memory when:
197
- - A project decision is made or changed
198
- - A root cause is discovered after debugging
199
- - A reusable implementation pattern is established
200
- - A user preference, constraint, or requirement is clarified
201
- - A prior assumption is found to be wrong
202
- - A significant piece of work is completed
203
-
204
- ### Writing for recall (the highest-leverage section)
205
- A memory's recall quality is set the moment you write it. AWM is fast at
206
- finding what's findable — but if the write is shaped wrong, no retriever
207
- can rescue it. Be slightly more verbose at the front than feels natural:
208
- the first 1-2 sentences are what BM25, the embedding model, and concept
209
- extraction all see most strongly.
210
-
211
- - **Lead with the rule or fact.** Don't open with context or backstory.
212
- "Don't mock the database in integration tests." comes first; the reason
213
- comes second. Recall scans the head of the body, not the tail.
214
- - **Pick the most specific topic.** Not \`auth\` — \`auth-magic-link-rate-limit\`.
215
- Topic is a hard filter at recall time. Generic topics hide the memory in
216
- a noisy bucket where it competes with everything else in the area.
217
- - **Include 2+ retrievable identifiers.** File paths, function names, table
218
- columns, ticket IDs, exact error strings, the literal terms a future query
219
- will use. \`AccountingService.closePeriod()\` beats "the accounting code."
220
- \`tblMemberDetails.activation_date\` beats "the activation column."
221
- \`schema/072-period-close.sql\` beats "the migration."
222
- - **Write in the vocabulary of the future question.** When you imagine asking
223
- this in three months, what nouns will you use? Use those nouns. Don't
224
- paraphrase the user's domain language into your own neutral summary.
225
- - **Reserve canonical for stable invariants.** Decisions, requirements,
226
- hard facts, cross-agent shared context. Working class (default) is correct
227
- for findings, observations, and progress notes. The canonical floor is
228
- 0.7 salience overusing it pollutes the canonical layer and the floor
229
- loses meaning.
230
- - **Include the why for feedback memories.** A rule without a reason can't
231
- be applied to edge cases. "Don't mock the database" is brittle. "Don't
232
- mock the database last quarter mocked tests masked a broken migration"
233
- is portable to new situations.
234
-
235
- ### Tagging rules (REQUIRED AWM's prefix-tag retrieval boost depends on these)
236
-
237
- Every \`memory_write\` should pass these structured fields. AWM stores each as a
238
- prefix-tag like \`proj=\`, \`topic=\`, \`intent=\`, etc. and uses them for BM25
239
- and entity-bridge boosts at recall time.
240
-
241
- | Field | Required? | Format | Example |
242
- |---|---|---|---|
243
- | \`project\` | **YES** | one short word matching the current project | \`"EquiHub"\`, \`"AWM"\`, \`"USEA-Agent"\` |
244
- | \`topic\` | **YES** | one or more lowercase area words | \`"database-migration"\`, \`"benchmarks"\` |
245
- | \`intent\` | **YES** | one of: \`decision\` / \`finding\` / \`todo\` / \`question\` / \`context\` | \`"finding"\` |
246
- | \`confidence_level\` | **YES** | \`verified\` (tested) / \`observed\` (read in code) / \`assumed\` (reasoning) | \`"verified"\` |
247
- | \`source\` | recommended | \`code-reading\` / \`debugging\` / \`discussion\` / \`research\` / \`testing\` / \`observation\` | \`"testing"\` |
248
- | \`memory_class\` | when stable | \`canonical\` (source-of-truth, 0.7 floor, never staged) / \`working\` (default) / \`ephemeral\` | \`"canonical"\` |
249
- | \`session_id\` | recommended | current conversation ID for entity-bridge boost | autogenerated |
250
- | \`tags\` | when applicable | extra prefix-tags for IDs and dates | \`["ticket=18360", "date=2026-05-11"]\` |
251
-
252
- **Always add identifier tags when present in the content:**
253
- - \`ticket=<id>\` for Freshdesk tickets
254
- - \`member=<id>\` for member IDs
255
- - \`horse=<id>\` for horse_member_id
256
- - \`usef=<id>\` for USEF lookups
257
- - \`date=YYYY-MM-DD\` for temporal anchoring (ISO format)
258
- - \`person=<Name>\` for stakeholder quotes / decisions
259
- - \`version=<X.Y.Z>\` for release-specific findings
260
-
261
- ### Entity index — exact-match recall for named things (default off)
262
- Structured identifier tags (\`ticket=\`, \`person=\`, \`horse=\`, \`member=\`, bare 4+ digit
263
- ids, etc.) feed a dedicated entity inverted index, separate from BM25/embedding scoring.
264
- A query naming an entity ("ticket 19252", "Kaleigh Collett") can reach the memory through
265
- this index even when the wording doesn't lexically match it's a deterministic exact
266
- lookup, immune to vocabulary mismatch. Keep identifier tags exact and consistent for
267
- this reason, not just for the BM25 boost described above.
268
-
269
- Off by default; opt in with \`AWM_ENTITY_INDEX_FETCH=1\` (bounded by
270
- \`AWM_ENTITY_INDEX_CAP\`, default 12). Matched entities get no score boost — they're
271
- guaranteed a reranker audition instead, so the cross-encoder alone decides whether they
272
- surface. Worth trialing on identifier-heavy workloads (ticket/event numbers, named
273
- people/things you refer to by name often); not yet the default pending evaluation.
274
-
275
- ### Temporal validity memories that expire or start in the future
276
- \`memory_write\` accepts \`valid_from\` / \`valid_to\` (ISO dates). Use \`valid_to\` on
277
- **operational** facts with a real shelf life — a deploy state, "waiting on X's reply",
278
- a ticket status so the memory expires instead of relying on you to remember it's
279
- stale. Recall renders \`[valid until …]\` on results carrying this field. Use
280
- \`valid_from\` for a fact that becomes true on a known future date (a policy change, a
281
- season that hasn't started yet). Don't set either for durable facts — most memories
282
- don't need them.
283
-
284
- ### Memory classes (controls how strictly the salience filter gates the write)
285
- - \`memory_class: canonical\` source-of-truth memories. Floor 0.7 salience, never staged.
286
- Use for: user-stated decisions, project requirements, verified architectural facts,
287
- cross-agent shared context. **In a hive (multi-agent) setup, always use \`canonical\`
288
- for writes that other agents must be able to recall** — the default \`working\` class
289
- may get filtered.
290
- - \`memory_class: working\` (default) observations and findings. Salience-gated.
291
- - \`memory_class: ephemeral\` short-lived context that should decay quickly.
292
-
293
- ### Salience auto-promotion (defense in depth)
294
- The salience filter automatically promotes certain content patterns even if you forget
295
- to set \`memory_class\` explicitly:
296
- - **User feedback** content starting with "Robert said…", "Katherine directed…",
297
- "Nancy decided…" etc. auto-promotes to canonical. So quoting the user verbatim
298
- always preserves the decision.
299
- - **Verified operational records** content with an action verb (Submitted, Finalized,
300
- Completed, Reconciled, Triaged, Posted, Resolved, Stamped, Pushed, Deployed, Migrated,
301
- Imported, Exported, Backfilled) plus 2+ concrete identifiers (ISO date \`YYYY-MM-DD\`,
302
- or contextual numeric IDs like "event 18969", "ticket #18330", "USEF 341980") gets
303
- a 0.45 salience floor. So batch summaries with real IDs survive even when topic
304
- terms repeat.
305
-
306
- If neither pattern applies and you want a memory to definitely survive, set
307
- \`memory_class: canonical\` explicitly. Don't rely on auto-promotion for important writes.
308
-
309
- ### Recall memory when:
310
- - **BEFORE stating ANY fact about how a system works** — recall first; if AWM doesn't
311
- have it, read the code. Never guess and present it as fact.
312
- - **BEFORE searching the filesystem** — recall first; AWM is faster and has cross-session
313
- knowledge that file search doesn't.
314
- - Starting work on a new task or subsystem
315
- - Re-entering code you haven't touched recently
316
- - After a failed attempt check if there's prior knowledge
317
- - Before refactoring or making architectural changes
318
- - When a topic comes up that you might have prior context on
319
-
320
- Recall is fast (~300ms typical). Use it freely.
321
-
322
- ### Recall strategy (when one query isn't enough)
323
- AWM's adaptive retrieval handles most query variations natively — synonym
324
- expansion, multi-channel scoring, embedding + BM25 + reranker agreement.
325
- A single recall is usually enough.
326
-
327
- When it isn't:
328
- - **If the first recall returns nothing or returns the wrong things, reformulate.**
329
- Try a second query with different phrasingsynonyms, more specific nouns,
330
- the exact identifier from the code rather than the conceptual name. Two or
331
- three recalls cost less than one filesystem search.
332
- - **Use the words a domain expert would use, not generic English.** "Period
333
- close lock" not "accounting feature"; "magic link rate limit" not "auth issue."
334
- - **For broad exploration, pass \`mode: "exploratory"\`** — wider candidate
335
- pool, lower precision floor. For specific lookups, leave mode unset (auto).
336
- - **Don't ensemble more than 3 reformulations.** If three different phrasings
337
- return nothing, the memory probably isn't there read the code instead of
338
- burning more recalls.
339
-
340
- ### Recall tuning (0.8.x — opt-in parameters for higher-quality recall)
341
- Default \`memory_recall\` is tuned for the common case. The 0.8.x recall pipeline
342
- exposes four opt-in parameters that change the cost/quality tradeoff. Use them
343
- when the default doesn't match what you actually need.
344
-
345
- - **\`granularity: 'compact'\`**every result carries a 200-char \`summary\`
346
- field with a query-aware snippet (the densest window of query terms in the
347
- content). Use this when you expect to scan 5+ results to find one — saves
348
- ~70% of recall output tokens. The full content stays available in
349
- \`engram.content\` if you want to drill into a specific result.
350
- - **\`granularity: 'auto'\`** — confidence-adaptive. If the top result is a clear
351
- winner, it gets a longer summary while the rest are compact. If confidence
352
- is uniform across results, everything is compact. Use when you don't know
353
- in advance whether one result will dominate.
354
- - **\`require_confidence: 0.10 | 0.25 | 0.40\`** — opt-in abstention. AWM
355
- returns \`[]\` instead of low-confidence noise. Use when you're about to ACT
356
- on the recalled fact (grounding a decision, citing the memory verbatim,
357
- contradicting a prior assumption). Thresholds: \`0.10\` strict only abstain
358
- on garbage; \`0.25\` balanced; \`0.40\` aggressive — prefer "I don't know"
359
- over "best of bad." When abstention fires (empty result), treat it as a
360
- signal either the memory genuinely isn't there (read the code) or your
361
- query missed (reformulate). Don't retry without the threshold.
362
- - **\`workspace: "<name>"\`** hive-mode recall across all agents in the
363
- workspace. Use when other agents may have written canonical knowledge you
364
- need. Default is agent-scoped (your own memories only). Can also be set
365
- globally via the \`AWM_WORKSPACE\` env var.
366
-
367
- ### Keep memory fresh
368
- - After recalling a memory, if you observe the real state is different → call
369
- \`memory_supersede\` immediately with the corrected version.
370
- - After using a recalled memory: call \`memory_feedback\` (useful/not-useful) so the
371
- activation engine learns what's valuable.
372
- - If you discover a memory is factually wrong: \`memory_retract\` to remove it.
373
- - **If you bypass AWM (file-memory, in-context notes, "I'll just remember"), the memory
374
- drifts out of date. The system relies on you to keep it current. This is the #1
375
- failure mode.**
376
-
377
- ### Cognition recipes — YOU do the thinking, AWM keeps the result (0.11.x)
378
- AWM contains no LLM. When memory needs real thinking distilling a repeatable
379
- procedure, reflecting on a failure AWM hands YOU a versioned recipe (prompt +
380
- strict output shape) and you run it as a SEPARATE focused pass, then write the
381
- result back as an ordinary memory with provenance.
382
-
383
- - \`memory_task_end\` responses include the recipe invitations. Honor the gates:
384
- skill-derivation only after a genuinely procedural task (3+ tool calls or a
385
- delegated sub-task); friction-lesson only after a failure/retry/wrong assumption.
386
- - Run each recipe as its own focused pass do NOT bundle it with other
387
- reasoning; bundled passes reliably drop the output.
388
- - Write back exactly per the recipe's contract: \`origin_class: 'recipe'\` +
389
- \`recipe_id\` (e.g. \`skill-derivation@1\`), concept prefixed \`skill: \` or
390
- \`lesson: \`. AWM validates the shape and rejects malformed or unknown-recipe
391
- writes with the contract echoed back fix and retry, don't drop the insight.
392
- - Re-deriving the same skill name reinforces the existing memory instead of
393
- duplicating it, so don't fear writing a skill you may have written before.
394
-
395
- ### Content fadewrite-and-forget is safe (0.8.x)
396
- Un-recalled engrams gradually fade their content while preserving cue pathways
397
- (concept + tags + embedding stay intact). This is Paper 1storage
398
- degradation. Practical implications:
399
-
400
- - **Don't manually purge memories** to "save space." The system already
401
- compresses unused content. Old memories stay findable via cue match even
402
- when their body has decayed.
403
- - **Don't over-pin with \`memory_class: canonical\`** to fight fade. Canonical
404
- only changes salience gating at write time, not fade behavior. Fade
405
- affects un-recalled engrams of any class.
406
- - **Recall keeps content alive.** Every recall touches the engram and resets
407
- its fade clock. Frequently-recalled memories stay full-fidelity automatically.
408
- - **Supersede is the right tool for stale facts.** When you observe a memory
409
- is outdated, call \`memory_supersede\` the new version inherits the old
410
- one's coherent associations (counter-narrative replacement, 0.8.x) so cue
411
- pathways carry forward to the replacement.
412
-
413
- ### Example good vs bad memory_write
414
-
415
- **BAD** (no prefix tags, vague concept, can't be recalled by future queries):
416
- \`\`\`
417
- memory_write(
418
- concept="found a bug",
419
- content="The thing I was looking at was broken so I fixed it."
420
- )
421
- \`\`\`
422
-
423
- **GOOD** (rich identifiers, structured metadata, prefix tags):
424
- \`\`\`
425
- memory_write(
426
- concept="EquiHub period-close BLOCKED check missing server-side",
427
- content="apps/web/app/(accounting)/accounting/period-close/page.tsx had client-only BLOCKED enforcement. Fixed by adding server-side check in AccountingService.closePeriod() per schema/072-period-close.sql. Without server-side check a malicious request could bypass via direct API call.",
428
- project="EquiHub",
429
- topic="accounting",
430
- intent="finding",
431
- confidence_level="verified",
432
- source="debugging",
433
- memory_class="canonical",
434
- tags=["ticket=18360", "person=Robert", "date=2026-05-11", "topic=period-close", "topic=security"]
435
- )
436
- \`\`\`
437
-
438
- ### Also:
439
- - To track work items: memory_task_add, memory_task_update, memory_task_list, memory_task_next
440
- - \`memory_whoami\` (MCP tool) / \`GET /whoami\` identify the instance you're actually
441
- talking to: agent id, workspace, mode, backend, store path, code provenance, sibling
442
- agent spaces sharing the store. Call this FIRST whenever you're unsure which store,
443
- which agent identity, or which running code you're dealing with before reasoning
444
- about AWM's own state from a stale memory or an assumed port number.
445
- - AWM is shared across all agents in real time. When any agent writes or supersedes a
446
- memory, every other agent can recall it immediately but only within the same
447
- workspace and agent scope.
448
-
449
- ### Output compression (token efficiency, output-only)
450
- When a tool returns a LARGE STRUCTURED result you need to keep in context a JSON
451
- array of records, query rows, a log dump, an API response — pass it through
452
- \`compress_output\` first. It re-encodes the data as TOON (a compact, lossless,
453
- schema-aware tabular form of JSON), cutting ~50-65% of the tokens at no
454
- comprehension cost. This is output-only: it never changes the data or your memories.
455
- - Use it on big STRUCTURED outputs, not on prose. Prose is returned unchanged —
456
- for trimming memory prose, use recall \`granularity: 'compact'\` instead.
457
- - It returns a \`ref\`; call \`retrieve_original(ref)\` if you later need the exact
458
- verbatim source (e.g. to hand it to another tool unchanged).
459
- - Don't bother for small outputs it only compresses when the saving is worthwhile
460
- and falls back to plain JSON if TOON wouldn't reproduce the data exactly.
461
-
462
- ### Backend (SQLite vs PGlite, 0.8.x)
463
- AWM ships two storage backends. The installer picks SQLite by default; both
464
- are functionally equivalent for cognitive workloads, but differ in operational
465
- guarantees:
466
-
467
- - **SQLite** (default) — embedded, **multi-process safe** via WAL mode. Best
468
- for single-machine setups and MCP scenarios where multiple Claude Code
469
- sessions may open the same database concurrently.
470
- - **PGlite** — embedded Postgres (WASM) with pgvector. **Single-process only**
471
- — two MCP processes against the same \`memory-pglite/\` directory will
472
- abort the second. Pick via \`AWM_STORE_BACKEND=pglite\` and
473
- \`AWM_DB_PATH=path/to/memory-pglite\`.
474
- - **Auto-detect** — if \`AWM_DB_PATH\` points to a directory that already
475
- exists, AWM detects PGlite; a file → SQLite. No explicit
476
- \`AWM_STORE_BACKEND\` needed when an existing DB is present.
477
-
478
- For the comparison table (recall quality parity, BM25 vs \`ts_rank_cd\`,
479
- multi-process guarantees), see \`docs/pglite-feature-parity.md\`.
480
-
481
- ### Diagnostics / escape hatches (env vars, only if you know why)
482
- The 0.7.6→0.7.14 work cut recall latency from 11s to ~300ms. The 0.8.x work
483
- added the write-path rewrite (per-write 300+ ms → under 10ms) and PGlite
484
- parity tuning. Each optimization is gated by an env-var so it can be disabled
485
- for A/B testing if a regression appears in your workload:
486
-
487
- Recall pipeline (0.7.x):
488
- - \`AWM_DISABLE_POOL_FILTER=1\` — disables the candidate pool reduction
489
- pre-filter in recall. Reverts to scoring all active candidates.
490
- - \`AWM_ENTITY_INDEX_FETCH=1\` see "Entity index" above (0.12.x, default off).
491
- - \`AWM_DISABLE_SLIM_CACHE=1\` disables the in-memory slim cache.
492
- Reverts to per-recall SQL fetch + Buffer→Float32Array conversion.
493
- - \`AWM_DISABLE_RERANK_SKIP=1\` disables the cross-encoder skip on
494
- clear-winner queries. Forces every recall through the reranker.
495
- - \`AWM_DISABLE_EXPANSION_CACHE=1\` disables the query expansion skip
496
- heuristic + LRU cache. Forces every recall through flan-t5-small.
497
-
498
- Write pipeline + lifecycle (0.8.x, plus 0.12.x telemetry):
499
- - \`AWM_SLOW_WRITE_MS=250\` (0.12.x) any write slower than this logs one stderr
500
- line with a phase-time breakdown (embed/novelty/persist, event-loop lag,
501
- embed-model cold-load ms). \`0\` disables. Useful for diagnosing why a session's
502
- first write/recall feels slow.
503
- - \`AWM_REINFORCE_MAX_CONTENT_LEN=1500\` max chars an engram's content
504
- can grow to via merge-on-reinforce (drop-oldest on overflow). Higher =
505
- preserves more reinforced detail; lower = leaner recall output.
506
- - \`AWM_REINFORCE_MERGE_CONTENT=0\` disable content merge on reinforce.
507
- Reverts to pre-0.8.5 behavior (discard new content, only bump confidence).
508
- - \`AWM_NOVELTY_EMBED=0\` disable the cosine channel in novelty
509
- computation. BM25-only fallback. Reverts to pre-0.8.5 novelty.
510
- - \`AWM_GRANULARITY_COMPACT_LEN=200\` char budget for query-aware snippet
511
- in \`granularity: 'compact'\` mode.
512
- - \`AWM_GRANULARITY_FULL_LEN=1000\` char budget for the top result in
513
- \`granularity: 'auto'\` mode when there's a clear winner.
514
-
515
- PGlite backend (0.8.x):
516
- - \`AWM_PGLITE_BM25_M=1\` — multiplier on PGlite \`ts_rank_cd\` to calibrate
517
- against SQLite FTS5 BM25 distribution. M=1 (default) is passthrough;
518
- higher M boosts PGlite scores at the cost of recall-ranking precision
519
- (see CHANGELOG 0.8.5 follow-up).
520
- - \`AWM_IVFFLAT_PROBES=5\`pgvector ivfflat probes per query. Higher =
521
- more accurate, slower.
522
-
523
- In production, leave these all unset. Use only when diagnosing a suspected
524
- recall-quality regression.
212
+ export const AWM_INSTRUCTION_CONTENT = `
213
+ ## Memory (AWM) — MANDATORY
214
+
215
+ **AWM is THE memory system.** Use it via the \`agent-working-memory\` MCP server
216
+ (preferred) or HTTP at \`http://127.0.0.1:8400\` (fallback). The file-based
217
+ auto-memory at \`~/.claude/projects/.../memory/*.md\` is a LEGACY bootstrap path —
218
+ **do not write new memories to it.** All persistent knowledge goes through AWM.
219
+
220
+ If MCP tools aren't loaded at session start, use ToolSearch with
221
+ \`select:mcp__agent-working-memory__memory_recall,mcp__agent-working-memory__memory_write\`
222
+ to load them. If the MCP server isn't responsive, restart with \`/mcp\` or use
223
+ the HTTP endpoints (\`POST /memory/write-batch\`, \`POST /memory/activate\`)
224
+ directly — but **DO NOT fall back to markdown files**. Files drift the moment
225
+ you write them; AWM stays current because every agent reads + writes the same store.
226
+
227
+ ### Lifecycle (always do these, in this order)
228
+ 1. **Session start**: call \`memory_restore\` to recover previous context. If it reports the
229
+ store is empty/new (or recall keeps returning nothing), **warm-start first**: recall the
230
+ \`onboard a new project\` skill and follow it — or call \`onboard_scan\` on the project's
231
+ docs/repo, refine the candidates, run \`onboard_questions\`, and save the good ones with
232
+ \`memory_write\` (canonical). A cold store is nearly useless until it's seeded.
233
+ 2. **Starting a task**: call \`memory_task_begin\` (checkpoints + recalls relevant memories).
234
+ 3. **During work**: call \`memory_recall\` BEFORE stating any fact, BEFORE searching
235
+ the filesystem, BEFORE making architectural decisions. Recall is ~300ms — cheaper
236
+ than one filesystem search.
237
+ 4. **As you learn things**: call \`memory_write\` proactively. Don't batch.
238
+ 5. **Finishing a task**: call \`memory_task_end\` with a summary.
239
+ 6. **Auto-checkpoint** is handled by hooks (compaction, session-end, 15-min timer). No action needed.
240
+
241
+ ### Write memory when:
242
+ - A project decision is made or changed
243
+ - A root cause is discovered after debugging
244
+ - A reusable implementation pattern is established
245
+ - A user preference, constraint, or requirement is clarified
246
+ - A prior assumption is found to be wrong
247
+ - A significant piece of work is completed
248
+
249
+ ### Writing for recall (the highest-leverage section)
250
+ A memory's recall quality is set the moment you write it. AWM is fast at
251
+ finding what's findable — but if the write is shaped wrong, no retriever
252
+ can rescue it. Be slightly more verbose at the front than feels natural:
253
+ the first 1-2 sentences are what BM25, the embedding model, and concept
254
+ extraction all see most strongly.
255
+
256
+ - **Lead with the rule or fact.** Don't open with context or backstory.
257
+ "Don't mock the database in integration tests." comes first; the reason
258
+ comes second. Recall scans the head of the body, not the tail.
259
+ - **Pick the most specific topic.** Not \`auth\` — \`auth-magic-link-rate-limit\`.
260
+ Topic is a hard filter at recall time. Generic topics hide the memory in
261
+ a noisy bucket where it competes with everything else in the area.
262
+ - **Include 2+ retrievable identifiers.** File paths, function names, table
263
+ columns, ticket IDs, exact error strings, the literal terms a future query
264
+ will use. \`AccountingService.closePeriod()\` beats "the accounting code."
265
+ \`tblMemberDetails.activation_date\` beats "the activation column."
266
+ \`schema/072-period-close.sql\` beats "the migration."
267
+ - **Write in the vocabulary of the future question.** When you imagine asking
268
+ this in three months, what nouns will you use? Use those nouns. Don't
269
+ paraphrase the user's domain language into your own neutral summary.
270
+ - **Name the CATEGORY as well as the specifics — both, always.** Specifics
271
+ make a memory precise; category words make it *reachable*. A memory that
272
+ says "private plan memory peaked 88%, scale P1v3 -> P2v3" never says
273
+ "Azure" or "App Service Plan", so a question asked in those words cannot
274
+ find it — measured on a real store, that memory was not in the top 40
275
+ candidates for "azure app service plan capacity increase". Write the
276
+ system / product / domain nouns (Azure App Service Plan, Freshdesk ticket,
277
+ MySQL connection pool, ShowConnect scoring) NEXT TO the identifiers.
278
+ Note this cuts against "pick the most specific topic" above: that rule is
279
+ about the \`topic\` TAG, not a licence to omit the category from the body.
280
+ Measured on an 11k-engram store: 94% of tagged memories are missing at
281
+ least one of their own topical terms from the body, and 66% of those
282
+ terms never appear in the text at all.
283
+ - **Tags are NOT a substitute for body text.** Only BM25 indexes tags. The
284
+ embedding is built from \`concept + content\` and the cross-encoder rerank
285
+ passage is built from \`concept + content\` — neither sees tags. So a word
286
+ that exists only as a tag is invisible to two of the three retrieval
287
+ channels, including the one that decides final ordering. Tag it *and*
288
+ write it.
289
+ - **Reserve canonical for stable invariants.** Decisions, requirements,
290
+ hard facts, cross-agent shared context. Working class (default) is correct
291
+ for findings, observations, and progress notes. The canonical floor is
292
+ 0.7 salience overusing it pollutes the canonical layer and the floor
293
+ loses meaning.
294
+ - **Include the why for feedback memories.** A rule without a reason can't
295
+ be applied to edge cases. "Don't mock the database" is brittle. "Don't
296
+ mock the database — last quarter mocked tests masked a broken migration"
297
+ is portable to new situations.
298
+
299
+ ### Tagging rules (REQUIRED — AWM's prefix-tag retrieval boost depends on these)
300
+
301
+ Every \`memory_write\` should pass these structured fields. AWM stores each as a
302
+ prefix-tag like \`proj=\`, \`topic=\`, \`intent=\`, etc. and uses them for BM25
303
+ and entity-bridge boosts at recall time.
304
+
305
+ | Field | Required? | Format | Example |
306
+ |---|---|---|---|
307
+ | \`project\` | **YES** | one short word matching the current project | \`"EquiHub"\`, \`"AWM"\`, \`"USEA-Agent"\` |
308
+ | \`topic\` | **YES** | one or more lowercase area words | \`"database-migration"\`, \`"benchmarks"\` |
309
+ | \`intent\` | **YES** | one of: \`decision\` / \`finding\` / \`todo\` / \`question\` / \`context\` | \`"finding"\` |
310
+ | \`confidence_level\` | **YES** | \`verified\` (tested) / \`observed\` (read in code) / \`assumed\` (reasoning) | \`"verified"\` |
311
+ | \`source\` | recommended | \`code-reading\` / \`debugging\` / \`discussion\` / \`research\` / \`testing\` / \`observation\` | \`"testing"\` |
312
+ | \`memory_class\` | when stable | \`canonical\` (source-of-truth, 0.7 floor, never staged) / \`working\` (default) / \`ephemeral\` | \`"canonical"\` |
313
+ | \`session_id\` | recommended | current conversation ID for entity-bridge boost | autogenerated |
314
+ | \`tags\` | when applicable | extra prefix-tags for IDs and dates | \`["ticket=18360", "date=2026-05-11"]\` |
315
+
316
+ **Always add identifier tags when present in the content:**
317
+ - \`ticket=<id>\` for Freshdesk tickets
318
+ - \`member=<id>\` for member IDs
319
+ - \`horse=<id>\` for horse_member_id
320
+ - \`usef=<id>\` for USEF lookups
321
+ - \`date=YYYY-MM-DD\` for temporal anchoring (ISO format)
322
+ - \`person=<Name>\` for stakeholder quotes / decisions
323
+ - \`version=<X.Y.Z>\` for release-specific findings
324
+
325
+ ### Entity index exact-match recall for named things (default off)
326
+ Structured identifier tags (\`ticket=\`, \`person=\`, \`horse=\`, \`member=\`, bare 4+ digit
327
+ ids, etc.) feed a dedicated entity inverted index, separate from BM25/embedding scoring.
328
+ A query naming an entity ("ticket 19252", "Kaleigh Collett") can reach the memory through
329
+ this index even when the wording doesn't lexically match it's a deterministic exact
330
+ lookup, immune to vocabulary mismatch. Keep identifier tags exact and consistent for
331
+ this reason, not just for the BM25 boost described above.
332
+
333
+ Off by default; opt in with \`AWM_ENTITY_INDEX_FETCH=1\` (bounded by
334
+ \`AWM_ENTITY_INDEX_CAP\`, default 12). Matched entities get no score boost — they're
335
+ guaranteed a reranker audition instead, so the cross-encoder alone decides whether they
336
+ surface. Worth trialing on identifier-heavy workloads (ticket/event numbers, named
337
+ people/things you refer to by name often); not yet the default pending evaluation.
338
+
339
+ ### Temporal validity memories that expire or start in the future
340
+ \`memory_write\` accepts \`valid_from\` / \`valid_to\` (ISO dates). Use \`valid_to\` on
341
+ **operational** facts with a real shelf life — a deploy state, "waiting on X's reply",
342
+ a ticket status so the memory expires instead of relying on you to remember it's
343
+ stale. Recall renders \`[valid until …]\` on results carrying this field. Use
344
+ \`valid_from\` for a fact that becomes true on a known future date (a policy change, a
345
+ season that hasn't started yet). Don't set either for durable facts — most memories
346
+ don't need them.
347
+
348
+ ### Memory classes (controls how strictly the salience filter gates the write)
349
+ - \`memory_class: canonical\` — source-of-truth memories. Floor 0.7 salience, never staged.
350
+ Use for: user-stated decisions, project requirements, verified architectural facts,
351
+ cross-agent shared context. **In a hive (multi-agent) setup, always use \`canonical\`
352
+ for writes that other agents must be able to recall** — the default \`working\` class
353
+ may get filtered.
354
+ - \`memory_class: working\` (default) — observations and findings. Salience-gated.
355
+ - \`memory_class: ephemeral\` short-lived context that should decay quickly.
356
+
357
+ ### Salience auto-promotion (defense in depth)
358
+ The salience filter automatically promotes certain content patterns even if you forget
359
+ to set \`memory_class\` explicitly:
360
+ - **User feedback** content starting with "Robert said…", "Katherine directed…",
361
+ "Nancy decided…" etc. auto-promotes to canonical. So quoting the user verbatim
362
+ always preserves the decision.
363
+ - **Verified operational records** content with an action verb (Submitted, Finalized,
364
+ Completed, Reconciled, Triaged, Posted, Resolved, Stamped, Pushed, Deployed, Migrated,
365
+ Imported, Exported, Backfilled) plus 2+ concrete identifiers (ISO date \`YYYY-MM-DD\`,
366
+ or contextual numeric IDs like "event 18969", "ticket #18330", "USEF 341980") gets
367
+ a 0.45 salience floor. So batch summaries with real IDs survive even when topic
368
+ terms repeat.
369
+
370
+ If neither pattern applies and you want a memory to definitely survive, set
371
+ \`memory_class: canonical\` explicitly. Don't rely on auto-promotion for important writes.
372
+
373
+ ### Recall memory when:
374
+ - **BEFORE stating ANY fact about how a system works** recall first; if AWM doesn't
375
+ have it, read the code. Never guess and present it as fact.
376
+ - **BEFORE searching the filesystem** recall first; AWM is faster and has cross-session
377
+ knowledge that file search doesn't.
378
+ - Starting work on a new task or subsystem
379
+ - Re-entering code you haven't touched recently
380
+ - After a failed attempt check if there's prior knowledge
381
+ - Before refactoring or making architectural changes
382
+ - When a topic comes up that you might have prior context on
383
+
384
+ Recall is fast (~300ms typical). Use it freely.
385
+
386
+ ### Chain recalls one hop per call
387
+
388
+ AWM returns what matches your query. It does **not** walk from that answer to the next
389
+ fact, and it is not meant to: it is active memory, holding what you need right now.
390
+ Following a chain to the next thing is **your** job recall, read, recall again, each
391
+ result becoming the cue for the next query.
392
+
393
+ So when a question refers to something **by its role instead of its name**, you have a
394
+ chain, not a query:
395
+
396
+ > *"What is the codename of the project owned by my scheduler?"*
397
+
398
+ That is three lookups, not one:
399
+
400
+ 1. recall \`who is my scheduler\` a name
401
+ 2. recall \`what project does <that name> own\` a project
402
+ 3. recall \`<that project> codename\` the answer
403
+
404
+ **The failure mode is answering from the first recall.** A single query blending all
405
+ three terms returns the most *salient* related memory, not the correct one — measured,
406
+ that returns the main project's codename with complete confidence, and it is wrong.
407
+ Each hop on its own is an ordinary, reliable recall; the chain only breaks when you stop
408
+ asking.
409
+
410
+ Tells that you are looking at a chain: a possessive or relative clause naming an entity
411
+ by role rather than identity (\`my scheduler\`, \`the owner of X\`, \`whoever signed
412
+ off on Y\`), or a rule that operates on an attribute you have not looked up yet (\`the
413
+ release tag of the project we discussed\` needs that project's codename first). If
414
+ resolving the question requires a fact you would have to *derive*, recall the fact
415
+ instead.
416
+
417
+ ### Recall strategy (when one query isn't enough)
418
+ AWM's adaptive retrieval handles most query variations natively synonym
419
+ expansion, multi-channel scoring, embedding + BM25 + reranker agreement.
420
+ A single recall is usually enough.
421
+
422
+ When it isn't:
423
+ - **If the first recall returns nothing or returns the wrong things, reformulate.**
424
+ Try a second query with different phrasing synonyms, more specific nouns,
425
+ the exact identifier from the code rather than the conceptual name. Two or
426
+ three recalls cost less than one filesystem search.
427
+ - **Use the words a domain expert would use, not generic English.** "Period
428
+ close lock" not "accounting feature"; "magic link rate limit" not "auth issue."
429
+ - **For broad exploration, pass \`mode: "exploratory"\`** wider candidate
430
+ pool, lower precision floor. For specific lookups, leave mode unset (auto).
431
+ - **Don't ensemble more than 3 reformulations.** If three different phrasings
432
+ return nothing, the memory probably isn't there — read the code instead of
433
+ burning more recalls.
434
+
435
+ ### Recall tuning (0.8.x opt-in parameters for higher-quality recall)
436
+ Default \`memory_recall\` is tuned for the common case. The 0.8.x recall pipeline
437
+ exposes four opt-in parameters that change the cost/quality tradeoff. Use them
438
+ when the default doesn't match what you actually need.
439
+
440
+ - **\`granularity: 'compact'\`**every result carries a 200-char \`summary\`
441
+ field with a query-aware snippet (the densest window of query terms in the
442
+ content). Use this when you expect to scan 5+ results to find one saves
443
+ ~70% of recall output tokens. The full content stays available in
444
+ \`engram.content\` if you want to drill into a specific result.
445
+ - **\`granularity: 'auto'\`** confidence-adaptive. If the top result is a clear
446
+ winner, it gets a longer summary while the rest are compact. If confidence
447
+ is uniform across results, everything is compact. Use when you don't know
448
+ in advance whether one result will dominate.
449
+ - **\`require_confidence: 0.10 | 0.25 | 0.40\`** opt-in abstention. AWM
450
+ returns \`[]\` instead of low-confidence noise. Use when you're about to ACT
451
+ on the recalled fact (grounding a decision, citing the memory verbatim,
452
+ contradicting a prior assumption). Thresholds: \`0.10\` strict only abstain
453
+ on garbage; \`0.25\` balanced; \`0.40\` aggressive prefer "I don't know"
454
+ over "best of bad." When abstention fires (empty result), treat it as a
455
+ signal — either the memory genuinely isn't there (read the code) or your
456
+ query missed (reformulate). Don't retry without the threshold.
457
+ - **\`workspace: "<name>"\`** — hive-mode recall across all agents in the
458
+ workspace. Use when other agents may have written canonical knowledge you
459
+ need. Default is agent-scoped (your own memories only). Can also be set
460
+ globally via the \`AWM_WORKSPACE\` env var.
461
+
462
+ ### Keep memory fresh
463
+ - After recalling a memory, if you observe the real state is different → call
464
+ \`memory_supersede\` immediately with the corrected version.
465
+ - After using a recalled memory: call \`memory_feedback\` (useful/not-useful) so the
466
+ activation engine learns what's valuable.
467
+ - If you discover a memory is factually wrong: \`memory_retract\` to remove it.
468
+ - **If you bypass AWM (file-memory, in-context notes, "I'll just remember"), the memory
469
+ drifts out of date. The system relies on you to keep it current. This is the #1
470
+ failure mode.**
471
+
472
+ ### Cognition recipes YOU do the thinking, AWM keeps the result (0.11.x)
473
+ AWM contains no LLM. When memory needs real thinking — distilling a repeatable
474
+ procedure, reflecting on a failure — AWM hands YOU a versioned recipe (prompt +
475
+ strict output shape) and you run it as a SEPARATE focused pass, then write the
476
+ result back as an ordinary memory with provenance.
477
+
478
+ - \`memory_task_end\` responses include the recipe invitations. Honor the gates:
479
+ skill-derivation only after a genuinely procedural task (3+ tool calls or a
480
+ delegated sub-task); friction-lesson only after a failure/retry/wrong assumption.
481
+ - Run each recipe as its own focused pass — do NOT bundle it with other
482
+ reasoning; bundled passes reliably drop the output.
483
+ - Write back exactly per the recipe's contract: \`origin_class: 'recipe'\` +
484
+ \`recipe_id\` (e.g. \`skill-derivation@1\`), concept prefixed \`skill: \` or
485
+ \`lesson: \`. AWM validates the shape and rejects malformed or unknown-recipe
486
+ writes with the contract echoed back fix and retry, don't drop the insight.
487
+ - Re-deriving the same skill name reinforces the existing memory instead of
488
+ duplicating it, so don't fear writing a skill you may have written before.
489
+
490
+ ### Content fade write-and-forget is safe (0.8.x)
491
+ Un-recalled engrams gradually fade their content while preserving cue pathways
492
+ (concept + tags + embedding stay intact). This is Paper 1 — storage
493
+ degradation. Practical implications:
494
+
495
+ - **Don't manually purge memories** to "save space." The system already
496
+ compresses unused content. Old memories stay findable via cue match even
497
+ when their body has decayed.
498
+ - **Don't over-pin with \`memory_class: canonical\`** to fight fade. Canonical
499
+ only changes salience gating at write time, not fade behavior. Fade
500
+ affects un-recalled engrams of any class.
501
+ - **Recall keeps content alive.** Every recall touches the engram and resets
502
+ its fade clock. Frequently-recalled memories stay full-fidelity automatically.
503
+ - **Supersede is the right tool for stale facts.** When you observe a memory
504
+ is outdated, call \`memory_supersede\`the new version inherits the old
505
+ one's coherent associations (counter-narrative replacement, 0.8.x) so cue
506
+ pathways carry forward to the replacement.
507
+
508
+ ### Example good vs bad memory_write
509
+
510
+ **BAD** (no prefix tags, vague concept, can't be recalled by future queries):
511
+ \`\`\`
512
+ memory_write(
513
+ concept="found a bug",
514
+ content="The thing I was looking at was broken so I fixed it."
515
+ )
516
+ \`\`\`
517
+
518
+ **GOOD** (rich identifiers, structured metadata, prefix tags):
519
+ \`\`\`
520
+ memory_write(
521
+ concept="EquiHub period-close BLOCKED check missing server-side",
522
+ content="apps/web/app/(accounting)/accounting/period-close/page.tsx had client-only BLOCKED enforcement. Fixed by adding server-side check in AccountingService.closePeriod() per schema/072-period-close.sql. Without server-side check a malicious request could bypass via direct API call.",
523
+ project="EquiHub",
524
+ topic="accounting",
525
+ intent="finding",
526
+ confidence_level="verified",
527
+ source="debugging",
528
+ memory_class="canonical",
529
+ tags=["ticket=18360", "person=Robert", "date=2026-05-11", "topic=period-close", "topic=security"]
530
+ )
531
+ \`\`\`
532
+
533
+ ### Also:
534
+ - To track work items: memory_task_add, memory_task_update, memory_task_list, memory_task_next
535
+ - \`memory_whoami\` (MCP tool) / \`GET /whoami\` identify the instance you're actually
536
+ talking to: agent id, workspace, mode, backend, store path, code provenance, sibling
537
+ agent spaces sharing the store. Call this FIRST whenever you're unsure which store,
538
+ which agent identity, or which running code you're dealing with — before reasoning
539
+ about AWM's own state from a stale memory or an assumed port number.
540
+ - AWM is shared across all agents in real time. When any agent writes or supersedes a
541
+ memory, every other agent can recall it immediately — but only within the same
542
+ workspace and agent scope.
543
+
544
+ ### Output compression (token efficiency, output-only)
545
+ When a tool returns a LARGE STRUCTURED result you need to keep in context — a JSON
546
+ array of records, query rows, a log dump, an API response — pass it through
547
+ \`compress_output\` first. It re-encodes the data as TOON (a compact, lossless,
548
+ schema-aware tabular form of JSON), cutting ~50-65% of the tokens at no
549
+ comprehension cost. This is output-only: it never changes the data or your memories.
550
+ - Use it on big STRUCTURED outputs, not on prose. Prose is returned unchanged —
551
+ for trimming memory prose, use recall \`granularity: 'compact'\` instead.
552
+ - It returns a \`ref\`; call \`retrieve_original(ref)\` if you later need the exact
553
+ verbatim source (e.g. to hand it to another tool unchanged).
554
+ - Don't bother for small outputs — it only compresses when the saving is worthwhile
555
+ and falls back to plain JSON if TOON wouldn't reproduce the data exactly.
556
+
557
+ ### Backend (SQLite vs PGlite, 0.8.x)
558
+ AWM ships two storage backends. The installer picks SQLite by default; both
559
+ are functionally equivalent for cognitive workloads, but differ in operational
560
+ guarantees:
561
+
562
+ - **SQLite** (default) embedded, **multi-process safe** via WAL mode. Best
563
+ for single-machine setups and MCP scenarios where multiple Claude Code
564
+ sessions may open the same database concurrently.
565
+ - **PGlite**embedded Postgres (WASM) with pgvector. **Single-process only**
566
+ two MCP processes against the same \`memory-pglite/\` directory will
567
+ abort the second. Pick via \`AWM_STORE_BACKEND=pglite\` and
568
+ \`AWM_DB_PATH=path/to/memory-pglite\`.
569
+ - **Auto-detect** — if \`AWM_DB_PATH\` points to a directory that already
570
+ exists, AWM detects PGlite; a file → SQLite. No explicit
571
+ \`AWM_STORE_BACKEND\` needed when an existing DB is present.
572
+
573
+ For the comparison table (recall quality parity, BM25 vs \`ts_rank_cd\`,
574
+ multi-process guarantees), see \`docs/pglite-feature-parity.md\`.
575
+
576
+ ### Diagnostics / escape hatches (env vars, only if you know why)
577
+ The 0.7.6→0.7.14 work cut recall latency from 11s to ~300ms. The 0.8.x work
578
+ added the write-path rewrite (per-write 300+ ms → under 10ms) and PGlite
579
+ parity tuning. Each optimization is gated by an env-var so it can be disabled
580
+ for A/B testing if a regression appears in your workload:
581
+
582
+ Recall pipeline (0.7.x):
583
+ - \`AWM_DISABLE_POOL_FILTER=1\` — disables the candidate pool reduction
584
+ pre-filter in recall. Reverts to scoring all active candidates.
585
+ - \`AWM_ENTITY_INDEX_FETCH=1\` — see "Entity index" above (0.12.x, default off).
586
+ - \`AWM_DISABLE_SLIM_CACHE=1\` — disables the in-memory slim cache.
587
+ Reverts to per-recall SQL fetch + Buffer→Float32Array conversion.
588
+ - \`AWM_DISABLE_RERANK_SKIP=1\` — disables the cross-encoder skip on
589
+ clear-winner queries. Forces every recall through the reranker.
590
+ - \`AWM_DISABLE_EXPANSION_CACHE=1\` — disables the query expansion skip
591
+ heuristic + LRU cache. Forces every recall through flan-t5-small.
592
+
593
+ Write pipeline + lifecycle (0.8.x, plus 0.12.x telemetry):
594
+ - \`AWM_SLOW_WRITE_MS=250\` (0.12.x) — any write slower than this logs one stderr
595
+ line with a phase-time breakdown (embed/novelty/persist, event-loop lag,
596
+ embed-model cold-load ms). \`0\` disables. Useful for diagnosing why a session's
597
+ first write/recall feels slow.
598
+ - \`AWM_REINFORCE_MAX_CONTENT_LEN=1500\` — max chars an engram's content
599
+ can grow to via merge-on-reinforce (drop-oldest on overflow). Higher =
600
+ preserves more reinforced detail; lower = leaner recall output.
601
+ - \`AWM_REINFORCE_MERGE_CONTENT=0\` — disable content merge on reinforce.
602
+ Reverts to pre-0.8.5 behavior (discard new content, only bump confidence).
603
+ - \`AWM_NOVELTY_EMBED=0\` — disable the cosine channel in novelty
604
+ computation. BM25-only fallback. Reverts to pre-0.8.5 novelty.
605
+ - \`AWM_GRANULARITY_COMPACT_LEN=200\` — char budget for query-aware snippet
606
+ in \`granularity: 'compact'\` mode.
607
+ - \`AWM_GRANULARITY_FULL_LEN=1000\` — char budget for the top result in
608
+ \`granularity: 'auto'\` mode when there's a clear winner.
609
+
610
+ PGlite backend (0.8.x):
611
+ - \`AWM_PGLITE_BM25_M=1\` — multiplier on PGlite \`ts_rank_cd\` to calibrate
612
+ against SQLite FTS5 BM25 distribution. M=1 (default) is passthrough;
613
+ higher M boosts PGlite scores at the cost of recall-ranking precision
614
+ (see CHANGELOG 0.8.5 follow-up).
615
+ - \`AWM_IVFFLAT_PROBES=5\` — pgvector ivfflat probes per query. Higher =
616
+ more accurate, slower.
617
+
618
+ In production, leave these all unset. Use only when diagnosing a suspected
619
+ recall-quality regression.
525
620
  `.trimStart();
526
621
  //# sourceMappingURL=common.js.map