@ssheleg/agent-stack 0.15.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,80 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.16.1 — the installers refuse the shadow, and the pack stops mis-selling itself
4
+
5
+ - **Both installers refuse to write plain copies over an installed plugin.** The family
6
+ audit of 2026-08-29 reproduced the shadow live: a bare `npx @ssheleg/telegram-dev`
7
+ created three plain copies in `~/.claude/skills/` while that plugin was enabled — and
8
+ this member had **no plugin check at all**, in either installer, so a bare
9
+ `npx @ssheleg/agent-stack` on a machine with the plugin would have shipped **four**
10
+ shadows, one per skill, each serving its frozen version forever. `bin/agent-stack.js`
11
+ and `install.sh` now implement make-skill v0.25.0's canon (`distribution.md`, "The
12
+ installer must refuse the shadow it documents"): detect from the TARGET home's
13
+ `installed_plugins.json` (keys are `<name>@<marketplace>`, and the two names differ
14
+ often), keep the `marketplaces/` dir read only as the fallback signal, refuse with
15
+ exit **3** and a remedy that names the spec read from the JSON
16
+ (`claude plugin marketplace update agent-stack` + `claude plugin update
17
+ agent-stack@<marketplace>`, plus the family launcher), offer `--force` as the recorded
18
+ deliberate override, fail open on a missing or corrupt JSON, and gate only the
19
+ `~/.claude` write — no other agent has plugins.
20
+ - **`test/installer_test.js` joins `npm test` and CI** — 11 cases against throwaway
21
+ HOMEs: fresh / rerun-skip / `--force` / unknown-arg, plugin-present refusal (exit
22
+ code, remedy text, nothing written — all three asserted), a differently-named
23
+ marketplace in the remedy spec, corrupt JSON failing open, no false refusal on other
24
+ plugins or an `agent-stack-extra` prefix-collider, the marketplaces-dir fallback, and
25
+ the same matrix for `install.sh`. Watched failing before trusted: **7 of 11 red**
26
+ against the pre-fix installers (`git stash` the two, run, pop). The suite follows the
27
+ house residue rule — a failing case keeps its HOME, and the run ends by saying what it
28
+ left. It replaces the inline fresh-HOME-only step in `validate.yml`, which is the CI
29
+ shape that let the plugin-present case go unrun everywhere.
30
+ - **A successful install now says how the next version arrives** — the last line names
31
+ `npx @ssheleg/agent-stack@latest --force` and the family launcher, in both installers.
32
+ - **AST-01: the plugin stops selling itself as two skills.** `plugin.json` and
33
+ `marketplace.json` both opened with "Two skills: agent-orchestrator … and agent-evals"
34
+ while the pack ships **four** — `agent-interop` and `agent-harness` were invisible in
35
+ `claude plugin details` and on the marketplace. Both descriptions now name all four
36
+ skills with what each covers.
37
+
38
+ ## v0.16.0 — the whole survey, not just its taxonomy
39
+
40
+ v0.15.0 took the taxonomy and the named failure modes. This takes the rest: the write
41
+ path and the landscape, as two references under the spine that already exists.
42
+
43
+ - **`memory-lifecycle.md` — how an entry is made, changed and thrown away.** Five formation
44
+ operations with the cost of each stated rather than implied: semantic summarization is
45
+ *lossy by design* and wrong for evidence-critical tasks; structured construction buys
46
+ multi-hop and pays schema rigidity; latent is a black box; parametric cannot be precisely
47
+ removed. Summarization's two shapes fail differently — incremental drifts because each
48
+ summary is built from the last, partitioned loses cross-partition dependencies — and
49
+ **summarizing by fixed window is partitioned summarization with the worst partition rule**.
50
+ - **Updating is not consolidation.** One resolves conflict, the other abstracts, and a
51
+ system needs both. The field's own trajectory is worth copying rather than rediscovering:
52
+ early systems deleted the superseded entry and broke temporal continuity; the better
53
+ pattern is **temporal annotation** — mark a validity window instead — which also makes the
54
+ stability–plasticity decision reversible, and it has no general answer.
55
+ - **Consolidation has a cost this pack did not state**: it risks information smoothing, and
56
+ the outlier it smooths away is often the entry worth keeping.
57
+ - **`memory-landscape.md` — build or adopt, measure, and what is not practice yet.** Around
58
+ twenty-five open-source frameworks give you an index and leave you the judgement: what
59
+ becomes a memory, when to retrieve, what to abstain on, what to demote. **Adopt for the
60
+ index, not for the judgement.** Frameworks are compared by the axes that separate them
61
+ rather than by a list that expires.
62
+ - Benchmarks are split into memory-oriented and long-horizon-that-stresses-memory, and the
63
+ first question is neither: it is `agent-evals`' question — **what fails if memory is
64
+ silently disabled?** A memory never queried and a memory that is empty score identically
65
+ on every benchmark; only the retrieval log separates them.
66
+ - Frontiers are marked as frontiers, with one exception acted on: **expose memory operations
67
+ as tools the agent calls.** It makes every memory decision legible in the trace, including
68
+ the decision NOT to retrieve — which is the silent failure this whole subject is about,
69
+ and which a background memory module cannot show you.
70
+ - Three things the pack deliberately does NOT implement are named as absent rather than
71
+ quietly added: frequency-based forgetting, temporal annotation, dual-phase updating. Each
72
+ is a real change to a mechanism in production, and a reference's job is to say what the
73
+ options are, not to rewrite `patterns.md` from a survey.
74
+ - The citation now has **one home**. The member's own validator refused three files each
75
+ repeating the pinned source — "a fact with two homes disagrees with itself on the first
76
+ edit" — so the spine holds it and the siblings name it.
77
+
3
78
  ## v0.15.0 — memory architecture, and the axes the layer table does not have
4
79
 
5
80
  - **`agent-orchestrator/references/memory-architecture.md`** — form, function and dynamics
@@ -16,6 +16,44 @@ const os = require('os');
16
16
 
17
17
  const ROOT = path.resolve(__dirname, '..');
18
18
  const REPO = 'ssheleg/agent-stack';
19
+ const PLUGIN = 'agent-stack';
20
+
21
+ // Exit codes are the contract: 0 installed or skipped, 1 corrupted package,
22
+ // 2 usage error, 3 refused — the plugin channel owns this agent (--force overrides).
23
+ const EXIT_PLUGIN_PRESENT = 3;
24
+
25
+ /**
26
+ * The plugin spec (`<name>@<marketplace>`) installed for `name` in this home,
27
+ * or null.
28
+ *
29
+ * `installed_plugins.json` is the record of what is actually installed. The
30
+ * `plugins/marketplaces/<name>` directory under-reports: a marketplace added
31
+ * from a local `directory` source has no dir there at all, and plugin names
32
+ * differ from marketplace names, so a check keyed on it stays green while the
33
+ * shadow lands. Absence and corruption both read as "no plugin": the fresh
34
+ * HOME is the common case, and an installer that crashes on a parse error
35
+ * refuses the machines that need it most.
36
+ */
37
+ function installedPluginSpec(home, name) {
38
+ try {
39
+ const raw = fs.readFileSync(
40
+ path.join(home, '.claude', 'plugins', 'installed_plugins.json'), 'utf8');
41
+ const parsed = JSON.parse(raw);
42
+ const plugins =
43
+ parsed && typeof parsed === 'object' &&
44
+ parsed.plugins && typeof parsed.plugins === 'object'
45
+ ? parsed.plugins
46
+ : parsed;
47
+ if (!plugins || typeof plugins !== 'object') return null;
48
+ for (const spec of Object.keys(plugins)) {
49
+ if (spec === name) return `${name}@${name}`;
50
+ if (spec.startsWith(name + '@')) return spec;
51
+ }
52
+ } catch {
53
+ // missing or corrupt = no plugin — fail open on absence, never crash
54
+ }
55
+ return null;
56
+ }
19
57
 
20
58
  function usage() {
21
59
  console.log(`agent-stack installer
@@ -25,6 +63,12 @@ Usage:
25
63
  into ~/.claude (skip existing unless --force)
26
64
  npx @ssheleg/agent-stack --help
27
65
 
66
+ Exit codes:
67
+ 0 installed or skipped 2 usage error
68
+ 1 corrupted package 3 refused: the agent-stack PLUGIN is installed in
69
+ this home — plain copies would shadow it (pass
70
+ --force to write them anyway)
71
+
28
72
  Other install paths:
29
73
  Claude Code plugin: /plugin marketplace add ${REPO}
30
74
  /plugin install agent-stack@agent-stack
@@ -86,6 +130,41 @@ function main(argv) {
86
130
  }
87
131
 
88
132
  const home = os.homedir();
133
+
134
+ // One channel per agent. A plain ~/.claude/skills/<name> beside the installed
135
+ // agent-stack plugin is two listings of the same skill per skill this pack
136
+ // ships, and the stale copy wins — the exact shadow make-skill's distribution
137
+ // canon forbids (§ "The installer must refuse the shadow it documents").
138
+ // Refuse rather than create it, and refuse LOUDLY: a presence check keyed on
139
+ // the marketplaces/ dir alone that exits 0 is the fail-open class — a
140
+ // directory-sourced marketplace has no dir there, plugin names differ from
141
+ // marketplace names, and exit 0 reads as success to every script above it.
142
+ // Reproduced live 2026-08-29: a bare `npx @ssheleg/telegram-dev` shipped
143
+ // three shadows past exactly this hole while the plugin was enabled. Only the
144
+ // ~/.claude write is gated — no other agent has plugins.
145
+ const spec = installedPluginSpec(home, PLUGIN);
146
+ const marketplace = path.join(home, '.claude', 'plugins', 'marketplaces', PLUGIN);
147
+ const viaMarketplaceDir = !spec && fs.existsSync(marketplace);
148
+ if ((spec || viaMarketplaceDir) && !force) {
149
+ const found = spec
150
+ ? `installed as the Claude Code plugin ${spec}\n` +
151
+ ' (declared in ~/.claude/plugins/installed_plugins.json)'
152
+ : `registered as a Claude Code marketplace\n (${marketplace})`;
153
+ console.error(
154
+ `refused: agent-stack is already ${found}.\n` +
155
+ ` Plain copies in ~/.claude/skills/ (${names.join(', ')})\n` +
156
+ ' would shadow the plugin and serve this frozen version forever.\n' +
157
+ ' Update the plugin channel instead:\n' +
158
+ ' claude plugin marketplace update agent-stack\n' +
159
+ ` claude plugin update ${spec || 'agent-stack@agent-stack'}\n` +
160
+ ' Family launcher (updates every member, prunes shadow copies):\n' +
161
+ ' npx --yes sshlg-skills@latest update\n' +
162
+ ' Pass --force to write the plain copies anyway — a deliberate choice\n' +
163
+ ' to run two channels, where the stale one wins.'
164
+ );
165
+ return EXIT_PLUGIN_PRESENT;
166
+ }
167
+
89
168
  for (const name of names) {
90
169
  installOne(
91
170
  `${name} skill`,
@@ -95,6 +174,15 @@ function main(argv) {
95
174
  force
96
175
  );
97
176
  }
177
+ // The last line says how the next version arrives — "Installed" is not a
178
+ // complete sentence. Auto-update is off on purpose: this member composes
179
+ // with its family, and per-marketplace autoUpdate moves each member on its
180
+ // own clock, into combinations nobody tested together.
181
+ console.log(
182
+ '\nUpdates: rerun `npx @ssheleg/agent-stack@latest --force`, or refresh the\n' +
183
+ 'whole family with `npx --yes sshlg-skills@latest update` (every channel,\n' +
184
+ 'and it prunes plain copies that would shadow a plugin).'
185
+ );
98
186
  return 0;
99
187
  }
100
188
 
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@ssheleg/agent-stack",
3
- "version": "0.15.0",
3
+ "version": "0.16.1",
4
4
  "scripts": {
5
- "test": "python3 test/validate.py && python3 test/plant_guard_test.py"
5
+ "test": "python3 test/validate.py && python3 test/plant_guard_test.py && node test/installer_test.js"
6
6
  },
7
7
  "description": "Production patterns for AI agent orchestrators — tool-calling loops, multi-stage pipelines with checkpoints, LLM provider routing with fallback, four-layer memory with confidence decay — plus the wallet side of reselling LLM access. This package is the installer CLI.",
8
8
  "bin": {
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "agent-stack",
3
3
  "displayName": "Agent Stack",
4
- "description": "Two skills: agent-orchestrator — tool-calling loops, multi-stage pipelines with checkpoints, provider routing with fallback, four-layer memory, context engineering, plus the wallet side of reselling LLM access; and agent-evals — run/trace/thread evals, judges, and fixtures grown from production.",
5
- "version": "0.15.0",
4
+ "description": "Four skills: agent-orchestrator — tool-calling loops, pipelines with checkpoints, provider routing with fallback, memory architecture, plus the wallet side of reselling LLM access; agent-evals — run/trace/thread evals, LLM judges, and fixtures grown from production; agent-interop — MCP servers and clients, A2A agent cards, the MCP Registry, and gateways; agent-harness — system prompts, tool shaping, workflow-vs-agent, and auditing an agent system.",
5
+ "version": "0.16.1",
6
6
  "author": {
7
7
  "name": "ssheleg",
8
8
  "url": "https://x.com/sshlg93"
@@ -244,7 +244,10 @@ answer built from nothing, in no error log.
244
244
 
245
245
  **Design a memory layer from
246
246
  [`references/memory-architecture.md`](references/memory-architecture.md)**, not from this
247
- table. It also carries the context-budget trap, layer 0 carryover and workspace scale.
247
+ table it also carries the context-budget trap, layer 0 carryover and workspace scale.
248
+ The write path is [`references/memory-lifecycle.md`](references/memory-lifecycle.md);
249
+ what to build on and measure with is
250
+ [`references/memory-landscape.md`](references/memory-landscape.md).
248
251
  ## 8. Self-Learning Feedback Loops
249
252
 
250
253
  Three cycles feed the memory layers, and they differ by what supplies the signal: a failed
@@ -30,6 +30,7 @@ the diversity and dynamics of contemporary agent memory systems."*
30
30
  - [8. Trustworthy memory](#8-trustworthy-memory)
31
31
  - [9. What this pack does NOT claim](#9-what-this-pack-does-not-claim)
32
32
  - [10. The checklist](#10-the-checklist)
33
+ - [11. The rest of it](#11-the-rest-of-it)
33
34
 
34
35
  ## The source, and what this file adds
35
36
 
@@ -306,3 +307,20 @@ made by accident:
306
307
  9. **Can a person see, correct and delete what is held about them?** (§8)
307
308
  10. **What eval fails if memory is silently disabled?** If none, the memory layer is
308
309
  unmeasured and its value is a belief. (`agent-evals`)
310
+
311
+ ## 11. The rest of it
312
+
313
+ This file is the decision spine and it deliberately stops at decisions. Two siblings carry
314
+ the depth, both pinned to the same survey and the same read date:
315
+
316
+ - [`memory-lifecycle.md`](memory-lifecycle.md) — the **write path**. Five ways to turn
317
+ experience into an entry and how each one fails, consolidation at three granularities,
318
+ why temporal annotation beats deletion when a fact is superseded, dual-phase updating,
319
+ and the three forgetting policies. It ends with a table of what this pack already
320
+ implements and three things it deliberately does not.
321
+ - [`memory-landscape.md`](memory-landscape.md) — **build or adopt**, the axes that actually
322
+ separate the twenty-odd open-source memory frameworks, which benchmarks measure what, and
323
+ which frontier ideas are directions rather than practice. Its last section is the one
324
+ frontier worth acting on now: exposing memory operations as tools the agent calls, which
325
+ makes every memory decision visible in the trace — including the decision not to
326
+ retrieve.
@@ -0,0 +1,128 @@
1
+ # Memory landscape — what exists to build on, what to measure with, where it is going
2
+
3
+ **Load this when** deciding whether to build a memory layer or adopt one, choosing what to
4
+ evaluate it against, or judging whether a technique somebody is proposing is settled
5
+ practice or a research direction.
6
+
7
+ **Source:** the survey pinned in [`memory-architecture.md`](memory-architecture.md)
8
+ — §6 resources, §7 positions and frontiers. That file is its one home; repeating the citation here would give it two.
9
+
10
+ **Read the dates on everything here.** This is the fastest-moving part of the subject, and
11
+ a landscape file is stale the day after it is written. What does not go stale is the
12
+ *shape*: which axes the frameworks differ on, and which of the frontier ideas is a
13
+ direction rather than a practice.
14
+
15
+ ## Contents
16
+
17
+ - [1. Build or adopt](#1-build-or-adopt)
18
+ - [2. Frameworks, by what actually separates them](#2-frameworks-by-what-actually-separates-them)
19
+ - [3. Evaluating a memory layer](#3-evaluating-a-memory-layer)
20
+ - [4. Frontiers — and which of them is not practice yet](#4-frontiers--and-which-of-them-is-not-practice-yet)
21
+ - [5. The one that changes how you build today](#5-the-one-that-changes-how-you-build-today)
22
+
23
+ ## 1. Build or adopt
24
+
25
+ An ecosystem of open-source memory frameworks exists — the survey tabulates around
26
+ twenty-five, including MemGPT, Mem0, Memobase, MemoryOS, MemOS, Zep, LangMem, Cognee,
27
+ Memary, MIRIX, and vector stores used as memory (Pinecone, Chroma, Weaviate).
28
+
29
+ **What most of them give you** is storage plus retrieval: a vector or graph database, an
30
+ API, a short/long-term split. **What most of them leave to you** is the part that decides
31
+ whether the memory works — *"they often leave agent behavior and evaluation protocols to
32
+ the application."*
33
+
34
+ So the honest framing of the choice:
35
+
36
+ | | Adopting a framework | Building on your own store |
37
+ |---|---|---|
38
+ | You get | schema, indexing, retrieval, a short/long split | nothing you did not write |
39
+ | You still own | formation policy, what enters at all, forgetting policy, retrieval timing, **evals** | the same list |
40
+ | Argues for it | not writing an index; graph or temporal support you would not build | your entries are few and structured, and a table plus a query is genuinely enough |
41
+
42
+ **The decision is usually smaller than it looks.** The parts that go wrong — deciding what
43
+ becomes a memory, when to retrieve, what to abstain on, what to demote — are yours in both
44
+ columns. Adopt for the index, not for the judgement.
45
+
46
+ ## 2. Frameworks, by what actually separates them
47
+
48
+ Rather than a list that expires, the axes that distinguish them — check a candidate on
49
+ these:
50
+
51
+ - **Does it model experiential memory, or only factual?** Several store facts well and have
52
+ no notion of a strategy learned from a trajectory. If the agent is supposed to improve,
53
+ this is the axis that matters.
54
+ - **What is the structure?** Hierarchical short/long-term, graph, temporal knowledge graph,
55
+ flat vectors, profile-based. This decides which queries are cheap. (§3 of
56
+ `memory-architecture.md`.)
57
+ - **Is temporal validity first-class?** A store that can express *"this was true until
58
+ March"* supports soft updating; one that cannot will make you delete history to stay
59
+ correct.
60
+ - **Does it report results on memory benchmarks at all?** Most do not. Absence is not
61
+ failure, but a framework with published LoCoMo or LongMemEval numbers has at least been
62
+ measured by someone.
63
+ - **Multimodal?** Most are text-only. The survey is explicit that **no system provides
64
+ truly omnimodal support** yet.
65
+
66
+ ## 3. Evaluating a memory layer
67
+
68
+ The survey groups benchmarks two ways, and the split is the useful part.
69
+
70
+ **Memory-oriented** — built to test memory directly. `LoCoMo` and `LongMemEval` are the two
71
+ most frequently reported and the closest thing to a common yardstick. `PersonaMem`,
72
+ `PrefEval`, `MemoryBank`, `PerLTQA`, `MPR` stress user modelling and preference tracking.
73
+ `StreamBench`, `LifelongAgentBench`, `MemoryAgentBench`, `Evo-Memory` test lifelong and
74
+ self-evolving behaviour — new information arriving while old information becomes obsolete
75
+ or conflicting. `HaluMem` targets memory-induced hallucination specifically.
76
+
77
+ **Long-horizon agent benchmarks that stress memory implicitly** — `SWE-Bench Verified`,
78
+ `GAIA`, `WebArena`, `ToolBench`, `ALFWorld`. Memory is not the measured target, but
79
+ performance depends on it.
80
+
81
+ **Which to use is not the first question.** The first question is the one `agent-evals`
82
+ asks: **what fails if memory is silently disabled?** A public benchmark measures a system
83
+ against a distribution that is not yours. A fixture built from your own traces, where the
84
+ answer is obtainable *only* from memory, catches the failure mode this whole subject is
85
+ about — the agent that skips retrieval and answers confidently from nothing
86
+ (`memory-architecture.md` §5.1). Build that fixture first; reach for a public benchmark
87
+ when you need to compare against somebody else's system.
88
+
89
+ **Instrument the negatives.** A memory never queried and a memory that is empty score
90
+ identically on every benchmark. Only the retrieval log separates them.
91
+
92
+ ## 4. Frontiers — and which of them is not practice yet
93
+
94
+ Marked plainly, because the risk with a survey's frontier section is building on a
95
+ direction as though it were a technique.
96
+
97
+ | Frontier | State | What it would change |
98
+ |---|---|---|
99
+ | **Memory generation** (over retrieval) | direction | memory synthesized on demand for the current task rather than fetched and concatenated. Two shapes: *retrieve-then-generate*, which is buildable now and is essentially §5.4 post-retrieval taken seriously; and *direct generation* with no retrieval step, which is research |
100
+ | **Automated memory management** | early | the agent reasons about its own memory through **explicit tool calls** — add/update/delete/retrieve as actions in its loop rather than a module beside it. See §5 |
101
+ | **RL-driven memory** | research | the progression is RL-free → RL for selected operations (reranking, the write policy) → fully learned. Most production systems are and will remain RL-free |
102
+ | **Multimodal memory** | partial | vision is furthest along, audio underexplored, and **no omnimodal system exists** |
103
+ | **Shared memory for multi-agent** | early | from isolated stores with message passing, through naive global stores, toward **role- and trust-aware** access. `memory-architecture.md` §7 |
104
+ | **Trustworthy memory** | **requirement, not frontier** | privacy, explainability, hallucination robustness. `memory-architecture.md` §8 |
105
+ | **Offline consolidation** ("sleep") | direction | a dedicated interval to reorganize, prune and replay, away from latency constraints. The buildable half of it is the **dual-phase update** in `memory-lifecycle.md` §4 |
106
+
107
+ ## 5. The one that changes how you build today
108
+
109
+ Of everything above, **automated memory management via explicit tool calls** is the item
110
+ worth acting on now, and it costs little.
111
+
112
+ Instead of a memory module that runs beside the agent — summarizing on a timer, evicting on
113
+ a policy, retrieving on every turn — expose memory operations as **tools the agent calls**:
114
+ `memory.search`, `memory.write`, `memory.update`, `memory.forget`. Three consequences, and
115
+ they are what make it worth doing rather than an aesthetic preference:
116
+
117
+ 1. **The decisions become legible.** Every memory operation is a tool call in the trace,
118
+ which means `agent-evals` can judge them and the retrieval log from
119
+ `memory-architecture.md` §5.1 exists for free — including the negatives, because a turn
120
+ with no `memory.search` call is visibly a turn that chose not to retrieve.
121
+ 2. **The agent can reason about them** — retrieve, find it insufficient, decompose and
122
+ retrieve again, which is the fast–slow pattern that the timing stage needs anyway.
123
+ 3. **They inherit everything the tool layer already has** — descriptions the model can act
124
+ on (`agent-harness`), error hierarchies, budgets and loop guards (`SKILL.md` §2).
125
+
126
+ **The cost, so it is a choice:** more model calls, and a model that can decline to use
127
+ memory at all. That second one is the silent failure mode again, which is why point 1
128
+ matters — with tool calls you can *see* it happen, and with a background module you cannot.
@@ -0,0 +1,154 @@
1
+ # Memory lifecycle — how an entry is made, changed and thrown away
2
+
3
+ **Load this when** writing the code that decides what becomes a memory, how a new entry
4
+ meets the ones already there, and what leaves. `memory-architecture.md` decides *what kind*
5
+ of memory is being built and owns retrieval; this file is the **write path**.
6
+
7
+ **Source:** the survey pinned in [`memory-architecture.md`](memory-architecture.md)
8
+ — §5.1 formation, §5.2 evolution. That file is its one home; repeating the citation here would give it two.
9
+
10
+ The three operators run at **different frequencies**, and that is the design. Formation can
11
+ run per turn, evolution per task boundary or offline, retrieval per call. Short- and
12
+ long-term behaviour is a consequence of those frequencies, not of separate boxes.
13
+
14
+ ## Contents
15
+
16
+ - [1. Formation — five ways to turn experience into an entry](#1-formation--five-ways-to-turn-experience-into-an-entry)
17
+ - [2. Choosing among them](#2-choosing-among-them)
18
+ - [3. Evolution — consolidation](#3-evolution--consolidation)
19
+ - [4. Evolution — updating, and the stability–plasticity dilemma](#4-evolution--updating-and-the-stabilityplasticity-dilemma)
20
+ - [5. Evolution — forgetting](#5-evolution--forgetting)
21
+ - [6. What this pack already implements](#6-what-this-pack-already-implements)
22
+
23
+ ## 1. Formation — five ways to turn experience into an entry
24
+
25
+ *"Instead of passively logging all interaction history, the memory system selectively
26
+ identifies information with long-term utility."* Five operations, and they compose — one
27
+ system commonly runs several.
28
+
29
+ | Operation | What it produces | Strength | The cost, stated |
30
+ |---|---|---|---|
31
+ | **Semantic summarization** | a compact narrative of a long stream | drastically shorter context; ideal for long dialogue | **lossy by design** — specific details and subtle cues get smoothed out, so it is wrong for evidence-critical tasks |
32
+ | **Knowledge distillation** | discrete reusable facts or strategies | fine-grained, function-specific | produces flat units with no relation between them |
33
+ | **Structured construction** | a graph or tree — entities, relations, hierarchy | explainability and multi-hop queries | **schema rigidity**; extraction and maintenance cost is high, and nuance that does not fit the schema is lost |
34
+ | **Latent representation** | vectors or KV states | high density, cross-modal, no decoding loss | **a black box** — cannot be inspected, edited or verified by a person |
35
+ | **Parametric internalization** | changed weights | zero retrieval cost, "instinctive" access | catastrophic forgetting, high update cost, and **cannot be precisely removed** |
36
+
37
+ ### Summarization has two shapes and they fail differently
38
+
39
+ - **Incremental** — fuse each new chunk into the running summary. Supports streaming and
40
+ avoids reprocessing the whole history. Fails by **semantic drift**: errors compound
41
+ across iterations, because each summary is built from the last one.
42
+ - **Partitioned** — summarize segments independently, then aggregate. Finer-grained and
43
+ parallelizable. Fails by **losing cross-partition dependencies**, and by cutting at
44
+ arbitrary boundaries unless segments are chosen semantically rather than by length.
45
+
46
+ If you summarize by fixed window size, you have chosen partitioned summarization with the
47
+ worst possible partition rule.
48
+
49
+ ### Distillation splits by what it is distilling
50
+
51
+ - **Factual** — dialogue turns into stated facts, user intent, environment state. Watch for
52
+ *goal drift*: separate confirmed constraints from unresolved intents, or the agent starts
53
+ treating a floated idea as a decision.
54
+ - **Experiential** — strategies from trajectories. **From contrast, not from success.** The
55
+ survey's own split confirms what §8 of `SKILL.md` already requires: success-only
56
+ distillation learns the agent's habits, and the systems that work compare successful and
57
+ failed runs, or reflect against ground truth.
58
+
59
+ ## 2. Choosing among them
60
+
61
+ The question is not which is best. It is **what the memory will be asked for later**:
62
+
63
+ | If the later question is… | Form it now with |
64
+ |---|---|
65
+ | "what happened, roughly" | semantic summarization |
66
+ | "what is true about X" | knowledge distillation, factual |
67
+ | "how do I do this kind of task" | knowledge distillation, experiential |
68
+ | "what connects to what" / multi-hop | structured construction |
69
+ | "match this to anything similar" at volume | latent |
70
+ | "behave this way, always, with no lookup" | parametric — and read §2 of `memory-architecture.md` on why this is rarely the answer |
71
+
72
+ **A schema chosen before this question has been asked is a guess.** The commonest and most
73
+ expensive version of that guess is a knowledge graph built because graphs sound thorough,
74
+ then maintained for multi-hop queries nobody runs.
75
+
76
+ ## 3. Evolution — consolidation
77
+
78
+ Merging new entries with existing ones so learning is cumulative rather than a growing pile
79
+ of near-duplicates. Three granularities:
80
+
81
+ - **Local** — a new entry retrieves its top-K nearest and a model decides whether to merge.
82
+ Cheapest, and the one to build first.
83
+ - **Cluster-level** — align a new cluster with similar existing clusters and fuse. Captures
84
+ regularities across instances that local merging cannot see.
85
+ - **Global integration** — periodically distil system-level insight from the whole store.
86
+
87
+ **The cost of consolidation, which is the reason not to run it aggressively:**
88
+ *"it risks information smoothing, where outlier events or unique exceptions are lost during
89
+ the abstraction process."* The exception is often the entry worth keeping — see §5.
90
+
91
+ ## 4. Evolution — updating, and the stability–plasticity dilemma
92
+
93
+ Updating resolves *conflict*; consolidation performs *abstraction*. They are different
94
+ operations and a system needs both.
95
+
96
+ **The trajectory the field took, and it is worth copying rather than rediscovering:**
97
+ early systems detected a conflict and **replaced or deleted** the old entry — destructive,
98
+ and it erased historical context and broke temporal continuity. The better pattern is
99
+ **temporal annotation**: mark the superseded fact with a validity window instead of
100
+ deleting it. Soft, time-aware updating keeps both semantic consistency and history.
101
+
102
+ **Dual-phase updating** is the shape that survives real load: a soft online update for
103
+ responsiveness, then an offline reflective pass that merges similar entries and resolves
104
+ conflicts properly. Eventual consistency, deliberately — because doing full reflective
105
+ consolidation inline puts a model call on the write path of every interaction.
106
+
107
+ **The dilemma has no general answer:** *"determining when to overwrite existing knowledge
108
+ versus when to treat new information as noise. Incorrect updates can overwrite critical
109
+ information."* What a system can do is make the decision **reversible** — which is the
110
+ argument for annotation over deletion, again.
111
+
112
+ ## 5. Evolution — forgetting
113
+
114
+ Three policies on three different signals — creation time, access frequency, judged
115
+ importance. They are orthogonal and most systems need more than one.
116
+
117
+ | Policy | Signal | Watch for |
118
+ |---|---|---|
119
+ | **Time-based** | age | evicting on age alone drops stable facts that were simply written early |
120
+ | **Frequency-based** | reads | **the long-tail trap** — see below |
121
+ | **Importance-driven** | a composite, increasingly a model's judgement of salience | the judge becomes a dependency, and an unaudited judge silently sets policy |
122
+
123
+ **The long-tail trap, stated because frequency-based eviction is the easy one to reach
124
+ for:** *"heuristic forgetting mechanisms like LRU may eliminate long-tail knowledge, which
125
+ is seldom accessed but essential for correct decision-making."* The entry read twice a year
126
+ is often the incident, the exception, the one customer whose setup differs — precisely the
127
+ entry that prevents an expensive mistake.
128
+
129
+ **The rule:** where storage is not the binding constraint, **demote rather than delete**.
130
+ Move it out of the default retrieval path, keep it reachable by explicit query. The survey
131
+ reports this is what many systems do in practice: *"when storage cost is not a critical
132
+ constraint, many memory systems avoid directly deleting certain memories."*
133
+
134
+ Deletion remains a **correctness and privacy** operation — a person asking to be forgotten
135
+ is not a capacity decision, and `memory-architecture.md` §8 covers it.
136
+
137
+ ## 6. What this pack already implements
138
+
139
+ Stated so this file is read as an extension and not as a replacement:
140
+
141
+ | Survey concept | Where it already lives here |
142
+ |---|---|
143
+ | Formation, experiential, from contrast | `SKILL.md` §8 · `patterns.md` → Learning Extraction Heuristics |
144
+ | Consolidation, local | `patterns.md` → Fuzzy Deduplication |
145
+ | Updating, conflict resolution | `patterns.md` → Conflict Resolution |
146
+ | Forgetting, time-based | `patterns.md` → Confidence Management |
147
+ | Global integration, cross-scope | `patterns.md` → Cross-Resource Learning Transfer |
148
+ | **Frequency-based forgetting** | **nowhere — and the long-tail trap above is why that is a deliberate omission rather than a gap to close carelessly** |
149
+ | **Temporal annotation instead of deletion** | **nowhere** — Conflict Resolution currently resolves rather than annotates |
150
+ | **Dual-phase updating** | **nowhere** — the pack updates inline |
151
+
152
+ The last three are named as absent rather than quietly added: each is a real change to a
153
+ mechanism that is in production, and this file's job is to say what the options are, not to
154
+ change `patterns.md` from a survey.