Files
msd-core/docs/proposals/mempalace-capability-prd-adr.md
Tom Boucher e006ff74fd docs(#956): MemPalace capability pre-proposal (PRD/ADR draft) (#957)
Combined PRD + ADR for wiring MemPalace (local-first AI memory) into the
GSD loop as an ADR-857 feature capability. Bidirectional sync, three
selectable memory-relationship modes (augment/kg_backend/replace),
loop-point recall+capture map, opt-in tier:full, MCP-primary/CLI-fallback.

Marked Pre-Proposal: the first-party-plugin proposal standard is not yet
established and ADR-857 phase-6 loop wiring is pending. First of a planned
series; PRD/ADR format is provisional pending PM-method evaluation.

Refs #956

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 22:30:48 -04:00

27 KiB
Raw Blame History

PRD + ADR — MemPalace Capability

Status: Pre-Proposal (the stage before Proposed). The first-party-plugin proposal standard is not yet established; this is exploratory and intentionally not a formal ADR yet. Advancement Pre-Proposal → Proposed → Accepted happens once that standard exists. Tracking issue: #956 Type: Feature Capability (ADR-857 plug-in) ADR number: TBD — assign when advanced to Proposed, then promote to docs/adr/<issue>-mempalace-capability.md Format caveat: This is the first of a planned series of first-party-plugin proposals. The PRD/ADR-combined instrument used here is provisional — a better PM format (RFC, PR-FAQ, one-pager + spike, opportunity/solution tree, problem-framing doc) may be adopted as the standard and this doc retro-fitted to it. Depends on: ADR-857 (Capability System), capability-registry generation, federated config, loop-resolver (loop render-hooks) External dependency: MemPalace — local-first AI memory (ChromaDB + SQLite), MCP server + CLI + Claude Code hooks Format: Part I = PRD (problem, users, requirements, metrics). Part II = ADR (forks, decisions, manifest, rollout).


Part I — PRD

1. Problem

GSD's memory today is per-project and per-artifact: STATE.md, .planning/graphs/ (the gsd-graphify knowledge graph), phase CONTEXT.md/PLAN.md/SUMMARY.md, and gsd-extract-learnings output. These are excellent within a milestone but have three gaps:

  1. No durable cross-session recall. A decision made in phase 3 is re-derived in phase 9 because nothing surfaces it at the right moment. The learnings exist on disk but are not retrieved at discuss/plan time.
  2. No cross-project memory. A pattern learned in gsd-core is invisible when working in gsd-pi. There is no semantic search across the developer's whole body of work.
  3. No verbatim, time-aware decision graph. .planning/graphs/ is project-scoped and lacks temporal validity (when did a decision become true; when was it superseded?).

MemPalace solves exactly these: local-first verbatim storage (wings/rooms/drawers), semantic search, a temporal knowledge graph (subject→predicate→object with valid_from/valid_to), cross-project tunnels, and a ~600–900-token wake-up recall layer that "leaves 95%+ of context free."

The opportunity: wire MemPalace into the GSD loop's natural memory moments — recall before you think, capture after you decide — via the ADR-857 capability mechanism, so it is opt-in, declarative, and default-resilient (no behavior change when MemPalace is absent).

2. Users & personas

Persona Need What the capability gives them
Solo maintainer across many repos (the gsd-core author) "Why did I decide X three milestones ago?" answered without grep archaeology Cross-project recall at discuss/plan; temporal KG of decisions
Long-running autonomous runs (/gsd-autonomous, cron) Memory that survives context compaction and session boundaries precompact capture; diary journaling; CLI-path capture that works headless
Team onboarding (/gsd-milestone-summary consumer) A queryable narrative of how the project got here Verbatim drawers + KG timeline per wing
Privacy-sensitive users Memory that never leaves the machine MemPalace is local-first by construction; capability adds nothing cloud-bound

3. Goals

  • G1 — Deliberate recall. Surface relevant prior decisions, patterns, and surprises at discuss:pre and plan:pre, cheaply (wake-up + targeted search), so planning starts informed.
  • G2 — Deliberate capture. Persist phase artifacts and extracted learnings into the palace at discuss:post, plan:post, verify:post, and ship:post, mapped to a stable wing/room taxonomy.
  • G3 — Bidirectional KG sync. Mirror GSD's decisions/learnings into MemPalace's temporal KG, and (in the stronger modes) read them back.
  • G4 — Cross-project knowledge. Build tunnels between related wings so a pattern in one repo is reachable from another.
  • G5 — Session journaling. Write a per-agent diary entry at ship:post and on long-run boundaries.
  • G6 — Default-resilient & opt-in. tier: full, master toggle mempalace.enabled defaults off. Every hook is onError: skip. Absent MCP/CLI ⇒ loop proceeds unchanged.

4. Non-goals

  • N1 — Not replacing gsd-extract-learnings analysis; we feed it into the palace, not supersede it.
  • N2 — No third-party-code loading into gsd-core (ADR-857 §7 keeps that out of scope). Integration is via MemPalace's MCP tools + CLI only.
  • N3 — Not authoring a new MemPalace source-adapter (RFC-002); GSD ships text artifacts MemPalace already mines.
  • N4 — Not a blocking gate. Memory never halts the loop. (No blocking: true hooks.)
  • N5 — Not shipping MemPalace itself; the capability declares the dependency and wires it, but install/pip install mempalace is the user's action.

5. Functional requirements

5.1 Memory-relationship modes (selectable)

The capability exposes three modes via mempalace.memory_mode, so the user chooses how tightly MemPalace couples to GSD's native memory. All three are first-class and selectable (not a one-time design pick):

Mode .planning/graphs KG Learnings / STATE Recall source of truth Coupling
augment (default) stays native stays native GSD native; palace is an additional recall layer fed from artifacts lowest — palace is write-mostly, read-optional
kg_backend routed to mempalace_kg_* stays native KG queries hit MemPalace's temporal graph medium — graphify reads/writes the palace KG
replace backed by palace backed by palace palace is the durable store; GSD reads memory through it highest — MemPalace is a hard dependency

Mode is read at hook-render time and changes which MemPalace surfaces the rendered instructions invoke. Switching modes is a config change, not a reinstall.

5.2 Recall (read path)

  • FR-R1 At discuss:pre, inject a recall fragment instructing the orchestrator to run mempalace wake-up --wing <wing> (L0+L1, ~600–900 tokens) plus mempalace_search(query=<phase topic>, wing=<wing>) and surface the top drawers + any relevant mempalace_kg_query facts into discussion.
  • FR-R2 At plan:pre, a recall step (skill mempalace-recall) produces MEMORY-RECALL.md consuming CONTEXT.md: prior decisions, patterns, and surprises relevant to this plan, retrieved by semantic search + KG timeline, deduped.
  • FR-R3 Recall is read-only and side-effect-free; if MemPalace is unreachable, MEMORY-RECALL.md is written with an "unavailable" stub and the loop continues.

5.3 Capture (write path)

  • FR-C1 At discuss:post, file CONTEXT.md as a drawer in room: decisions (dedup via mempalace_check_duplicate), and extract decision facts into the KG (mempalace_kg_add with valid_from = phase date).
  • FR-C2 At plan:post, file PLAN.md as a drawer in room: planning.
  • FR-C3 At verify:post, file SUMMARY.md/UAT.md excerpts in room: milestones, and file confirmed problems→fixes in room: problems.
  • FR-C4 gsd-extract-learnings output (decisions, lessons, patterns, surprises) is mirrored into the KG and corresponding rooms, with provenance (source_file, source_drawer_id).
  • FR-C5 All captures are idempotent: re-running a phase re-files the same content without duplication (MemPalace deterministic drawer IDs + check_duplicate).

5.4 Cross-project & journaling

  • FR-X1 At ship:post, when mempalace.cross_project_tunnels = true, propose tunnels between this wing's rooms and related wings (mempalace_find_tunnels), creating those the user/agent confirms.
  • FR-X2 At ship:post, when mempalace.diary_journal = true, write a session-summary diary entry (mempalace_diary_write(agent_name, entry, topic="phase-ship", wing)).
  • FR-X3 At ship:post, optionally run mempalace sync --wing <wing> --apply to prune drawers whose source artifacts were archived/deleted (guarded: never global prune).

5.5 Passive auto-capture (optional, separate layer)

  • FR-P1 When mempalace.auto_capture_hooks = true, the capability's lifecycle hooks install MemPalace's native Claude Code hooks (session-start, stop @ every 15 human messages, precompact) so tool output and mid-session context are captured even between loop points. Default off (the deliberate loop hooks are the primary integration; this is belt-and-suspenders).

5.6 Transport selection (robustness)

  • FR-T1 Interactive runs prefer the MCP tools (rich, structured). Autonomous/headless/cron runs prefer the CLI (mempalace mine|search|wake-up|sync) because MCP servers may be absent in headless harness contexts. Rendered hook instructions name both and pick by run context.

6. Success metrics

Metric Target
Recall token cost at discuss/plan ≤ ~1k tokens (wake-up + one search)
Phases with artifacts captured ≥ 95% when enabled
Recall relevance (manual spot-check) top-5 drawers judged relevant ≥ 80% of phases
Loop overhead when MemPalace absent 0 (skip-on-error, no failures)
Cross-session decision reuse qualitative: maintainer reports "surfaced something I'd forgotten"
Duplicate drawers from re-runs ~0 (idempotent capture)

7. Risks & mitigations

Risk Mitigation
MCP server absent in headless/cron CLI fallback (FR-T1); never hard-depend on MCP
Phase-6 not yet wired — loop render-hooks is implemented but no workflow calls it yet Interim: invoke mempalace-recall/mempalace-capture skills manually or via MemPalace's native hooks; capability ships ready for phase-6 cutover
Palace noise/drift check_duplicate before file; mempalace sync prune; verbatim-only (no lossy summaries written)
AAAK is lossy (84% vs 96% R@5) Capture stores verbatim drawers, not AAAK; AAAK only as an optional index (compress)
Privacy Local-first by construction; capability adds no network egress
Over-capture cost Capture only at phase boundaries + bounded artifacts; not every message (that's the optional passive layer)
Mode replace makes MemPalace a hard dep Default augment; replace documented as opt-in with migration

Part II — ADR

8. Context

ADR-857 establishes the host/core vs Capability plug-in split: the five-step loop is the host; everything else is a Capability that contributes data (not control flow) at 12 stable Loop Extension Points via three hook kinds — step, contribution, gate. Capabilities are declared in capabilities/<id>/capability.json, compiled by scripts/gen-capability-registry.cjs into gsd-core/bin/lib/capability-registry.cjs, and resolved at runtime by loop render-hooks <point>. Config keys are federated (new keys flow without editing the central loadConfig whitelist).

MemPalace is a natural Capability: it adds memory recall/capture behavior at loop points, owns its own skills/agents/config slice, and degrades gracefully. It calls no gsd-core internals — only MemPalace's MCP tools and CLI — so it fits ADR-857's "declarative + first-party, third-party code deferred" decision (the integration glue is first-party; MemPalace runs out-of-process).

9. Decision drivers

  • Must be opt-in and default-resilient (G6) — memory is never load-bearing for the loop.
  • Must map cleanly onto MemPalace's existing taxonomy (wings/rooms/drawers/KG) — no new MemPalace adapter.
  • Must honor ADR-857's data-not-control-flow rule: hooks render instructions; the agent calls MemPalace.
  • Must let the user pick coupling depth (augment/kg_backend/replace) without reinstall.
  • Must work headless (CLI path), not just interactively (MCP path).

10. Resolved design forks

Mirroring ADR-857's "resolved decisions" structure:

  1. Capability role — feature. Owns skills + agents + hooks + config slice. (A future runtime-role descriptor is unnecessary; MemPalace is CLI-uniform across harnesses.)
  2. Tier — full. External dependency ⇒ opt-in only; never in core/standard profiles. Master toggle mempalace.enabled defaults off.
  3. Integration transport — MCP-primary, CLI-fallback. No code module in gsd-core; rendered hook markdown instructs the agent to call mempalace_* tools (interactive) or mempalace CLI (headless). Avoids the not-yet-existing gsd-tools runCommand registry (ADR-857 phase-6).
  4. Capture content — verbatim drawers, not AAAK. AAAK is lossy; we file exact artifact text. AAAK compress is offered only as an optional downstream index.
  5. Memory-relationship — three selectable modes, not one. mempalace.memory_mode ∈ {augment, kg_backend, replace}, default augment. Mode is read at render time; it changes which MemPalace surfaces the rendered instructions hit (§5.1). This is the direct realization of the user's "all three as selectable options" requirement.
  6. Failure policy — skip everywhere; no gate. Every hook is onError: skip; zero blocking: true. Memory failures never halt or fail a phase.
  7. Passive auto-capture is separate and off by default. MemPalace's native stop/precompact hooks are a belt-and-suspenders layer behind mempalace.auto_capture_hooks; the deliberate loop hooks are the contract.
  8. Wing/room taxonomy is fixed by GSD semantics. wing = project (from project_code/mempalace.wing); rooms = decisions | planning | milestones | problems | learnings; drawers = verbatim artifacts; KG = decision/relationship facts with phase-dated validity.

11. Loop Extension Point mapping

Using the 12 canonical points and per-step agentRoles from loop-host-contract.cjs. (into on a contribution must be a valid role at that point: discuss=[orchestrator], plan=[researcher,planner,checker], execute=[executor,verifier], verify=[orchestrator], ship=[orchestrator].)

Point Kind Ref / into produces consumes when Purpose
discuss:pre contribution into orchestrator — — mempalace.recall_on_discuss Inject wake-up + search recall into discussion
discuss:post step skill mempalace-capture — CONTEXT.md mempalace.capture_artifacts File CONTEXT → decisions; KG decision facts
plan:pre step skill mempalace-recall MEMORY-RECALL.md CONTEXT.md mempalace.recall_on_plan Retrieve prior decisions/patterns/surprises for the plan
plan:post step skill mempalace-capture — PLAN.md mempalace.capture_artifacts File PLAN → planning
execute:wave:post contribution into verifier — — mempalace.capture_artifacts Capture confirmed problems→fixes into problems
verify:post step skill mempalace-capture — SUMMARY.md mempalace.capture_artifacts File milestones; mirror extract-learnings → KG + learnings
ship:post step agent gsd-mempalace-curator — UAT.md mempalace.diary_journal Diary entry; cross-project tunnels; sync --apply

All steps/contributions are onError: skip. No gates.

Note on produces/consumes: these are the file-data spine the registry topo-sorts on. mempalace-recall produces MEMORY-RECALL.md so the planner can consume it; capture steps only consume (they emit to the palace, not to a tracked file artifact), which keeps them leaves in the topo-sort.

12. Palace mapping (GSD artifact → MemPalace)

GSD artifact / event Wing Room Stored as KG facts
CONTEXT.md <project> decisions drawer (verbatim) (<project>, decided, <decision>) valid_from=<phase date>
PLAN.md <project> planning drawer (<phase>, plans, <task>)
SUMMARY.md / UAT.md <project> milestones drawer excerpts (<phase>, delivered, <capability>)
confirmed bug→fix <project> problems drawer (<bug>, fixed_by, <fix>)
extract-learnings (decisions/lessons/patterns/surprises) <project> learnings drawer per item typed triples w/ provenance (source_drawer_id)
superseded decision — — — mempalace_kg_invalidate (sets valid_to)
cross-repo pattern two wings — — mempalace_create_tunnel(label=…)

Mode behavior on this table:

  • augment — all writes above happen; reads (recall) come from GSD native + palace search, palace is never required.
  • kg_backend — the KG columns route through mempalace_kg_*; gsd-graphify reads/writes the palace temporal graph instead of .planning/graphs/.
  • replace — drawer + KG columns become the durable store; GSD's learnings/graph reads resolve through the palace.

13. The capability.json manifest (concrete)

capabilities/mempalace/capability.json:

{
  "id": "mempalace",
  "role": "feature",
  "title": "MemPalace memory",
  "description": "Cross-session, cross-project memory: deliberate recall before discuss/plan and verbatim capture + temporal-KG sync at phase boundaries, via the MemPalace MCP server and CLI.",
  "tier": "full",
  "requires": [],
  "skills": ["mempalace-recall", "mempalace-capture"],
  "agents": ["gsd-mempalace-curator"],
  "hooks": [],
  "config": {
    "mempalace.enabled":                { "type": "boolean", "default": false, "description": "Master toggle for the MemPalace memory capability." },
    "mempalace.memory_mode":            { "type": "enum", "values": ["augment", "kg_backend", "replace"], "default": "augment", "description": "How MemPalace relates to GSD native memory: augment alongside, back the knowledge graph, or fully replace." },
    "mempalace.wing":                   { "type": "string", "default": "", "description": "Palace wing name; empty derives from project_code / project dir." },
    "mempalace.recall_on_discuss":      { "type": "boolean", "default": true, "description": "Inject wake-up + search recall at discuss:pre." },
    "mempalace.recall_on_plan":         { "type": "boolean", "default": true, "description": "Produce MEMORY-RECALL.md at plan:pre." },
    "mempalace.capture_artifacts":      { "type": "boolean", "default": true, "description": "File CONTEXT/PLAN/SUMMARY and learnings into the palace at phase boundaries." },
    "mempalace.mirror_kg":              { "type": "boolean", "default": true, "description": "Mirror decisions/learnings into MemPalace's temporal knowledge graph." },
    "mempalace.cross_project_tunnels":  { "type": "boolean", "default": false, "description": "Propose/create cross-wing tunnels at ship:post." },
    "mempalace.diary_journal":          { "type": "boolean", "default": true, "description": "Write a per-agent diary entry at ship:post." },
    "mempalace.auto_capture_hooks":     { "type": "boolean", "default": false, "description": "Install MemPalace's native stop/precompact Claude Code hooks for passive mid-session capture." }
  },
  "steps": [
    { "point": "discuss:post", "ref": { "skill": "mempalace-capture" }, "produces": [], "consumes": ["CONTEXT.md"], "when": "mempalace.capture_artifacts", "onError": "skip" },
    { "point": "plan:pre",     "ref": { "skill": "mempalace-recall" },  "produces": ["MEMORY-RECALL.md"], "consumes": ["CONTEXT.md"], "when": "mempalace.recall_on_plan", "onError": "skip" },
    { "point": "plan:post",    "ref": { "skill": "mempalace-capture" }, "produces": [], "consumes": ["PLAN.md"], "when": "mempalace.capture_artifacts", "onError": "skip" },
    { "point": "verify:post",  "ref": { "skill": "mempalace-capture" }, "produces": [], "consumes": ["SUMMARY.md"], "when": "mempalace.capture_artifacts", "onError": "skip" },
    { "point": "ship:post",    "ref": { "agent": "gsd-mempalace-curator" }, "produces": [], "consumes": ["UAT.md"], "when": "mempalace.diary_journal", "onError": "skip" }
  ],
  "contributions": [
    { "point": "discuss:pre",        "into": "orchestrator", "fragment": { "path": "fragments/recall-discuss.md" }, "when": "mempalace.recall_on_discuss", "onError": "skip" },
    { "point": "execute:wave:post",  "into": "verifier",     "fragment": { "path": "fragments/capture-problems.md" }, "when": "mempalace.capture_artifacts", "onError": "skip" }
  ],
  "gates": []
}

Validation notes (from the registry generator contract): id is kebab-case and equals the folder name; tier: full so requires may be empty; each when key exists in this capability's own config block; every contribution.into is a valid agent role at its point; fragment.path is relative with no ..; enum config carries values and a default in that set. Because all config keys are new (not in the central config-schema.manifest.json), they flow through the federated channel automatically — no loadConfig whitelist edit.

14. Skills & agent the capability owns

  • mempalace-recall (commands/gsd/mempalace-recall.md) — markdown skill. Reads CONTEXT.md, derives a search query, runs wake-up + mempalace_search + mempalace_kg_query/timeline, writes MEMORY-RECALL.md (or an "unavailable" stub). Branches on memory_mode for read source. Names MCP-primary / CLI-fallback per run context.
  • mempalace-capture (commands/gsd/mempalace-capture.md) — markdown skill. check_duplicate → add_drawer to the right room → kg_add facts (when mirror_kg). Idempotent. Branches on memory_mode for write target.
  • gsd-mempalace-curator (agents/gsd-mempalace-curator.md) — agent. Ship-time curation: diary write, tunnel proposal/creation, sync --apply (wing-scoped, never global), and extract-learnings → KG mirroring with provenance.

15. Rollout phases

Phase Deliverable Gate
0 — Spike mempalace init/mine/search/wake-up against gsd-core's own .planning/; confirm wing/room mapping feels right manual: recall surfaces real prior decisions
1 — Manifest + registry capabilities/mempalace/capability.json + gen-capability-registry.cjs --write; CI staleness gate green; consistency gate (id≠CLUSTERS collision) --check passes
2 — Skills + agent + fragments the two skills, the curator agent, two fragment files; augment mode only recall/capture work when invoked manually
3 — Config + federated flow all mempalace.* keys resolve via federated config; capability-state resolver reports the capability state resolver shows installed/surfaced + hook activity
4 — Modes kg_backend then replace; gsd-graphify routing seam each mode round-trips a decision
5 — Passive hooks + autonomous auto_capture_hooks installs native hooks; CLI-path capture verified headless (/gsd-autonomous, cron) headless run captures with no MCP
6 — Loop wiring (blocked on ADR-857 phase-6) loop render-hooks called from plan-phase.md/execute-phase.md/etc. so hooks auto-fire end-to-end auto recall/capture

Phases 1–5 ship value before ADR-857's phase-6 cutover (the skills are invocable directly). Phase 6 flips them to automatic.

16. Registration tax (per ADR-857 + repo checklists)

  1. capabilities/mempalace/capability.json (above).
  2. node scripts/gen-capability-registry.cjs --write → regenerates capability-registry.cjs (do not hand-edit).
  3. Add commands/gsd/mempalace-recall.md, commands/gsd/mempalace-capture.md.
  4. Add agents/gsd-mempalace-curator.md (+ ripple to scripts/research-profiles.cjs/docs/AGENTS.md only if it's a research-profile agent — the curator is not, so likely n/a).
  5. Add capabilities/mempalace/fragments/recall-discuss.md + fragments/capture-problems.md.
  6. Config keys: new ⇒ federated automatically; no loadConfig whitelist edit.
  7. Confirm id: mempalace does not collide with a CLUSTERS key in src/clusters.cts (HARD consistency gate) — if it does, match exactly or rename.
  8. Surface/profile: tier: full ⇒ only the full profile; no core/standard edits.
  9. CONTEXT.md glossary: add domain terms (Wing, Room, Drawer, Tunnel, Diary, AAAK, memory_mode) — glossary is a review gate.
  10. No new .cts source module ⇒ skip the new-CLI-module checklist (.gitignore/inventory/eslint). If kg_backend/replace need a routing seam in gsd-graphify, that does trigger the CLI-module checklist for that file.
  11. Docs: how-to ("Enable cross-session memory with MemPalace") + reference (config keys, modes) — missing docs is a PR blocker.

17. Open questions

  1. Wing identity — one wing per repo (project_code) vs one per milestone? Recommendation: per-repo wing, milestone/phase as KG validity windows + rooms; revisit if wings get too coarse.
  2. replace migration — do we backfill existing .planning/graphs/ into the palace KG, or only forward-fill? Recommendation: ship a one-shot mempalace mine .planning/ + KG import as part of mode switch.
  3. Curator agent tier — the curator is operational (branches, API calls, error recovery) ⇒ sonnet model. Confirm.
  4. Headless MCP availability — verify MemPalace's stdio MCP server is reachable under /gsd-autonomous/cron, or commit fully to the CLI path there (FR-T1).
  5. Phase-6 dependency — accept shipping 1–5 ahead of loop wiring, or hold until phase-6 lands? Recommendation: ship ahead; the manual-invocation value is real and de-risks phase-6.
  6. Diary agent_name — namespace per GSD role (gsd-orchestrator) or per repo? Recommendation: per repo+role so diaries don't collide across projects.

Appendix A — MemPalace surfaces used

  • MCP (interactive): mempalace_search, mempalace_check_duplicate, mempalace_add_drawer, mempalace_kg_add/kg_query/kg_invalidate/kg_timeline, mempalace_create_tunnel/find_tunnels, mempalace_diary_write/diary_read, mempalace_sync, mempalace_get_taxonomy/list_wings/list_rooms.
  • CLI (headless): mempalace wake-up --wing, mempalace search, mempalace mine, mempalace sync --wing --apply, mempalace hook run.
  • Native hooks (optional passive layer): session-start, stop (every 15 human messages; silent_save), precompact (captures pre-compaction tool output).
  • Retrieval cost: wake-up = L0 (identity, ~100 tok) + L1 (auto-summary, ~500–800 tok) ≈ 600–900 tokens.

Appendix B — Why this is a clean ADR-857 fit

  • Contributes data (rendered recall/capture instructions), not control flow.
  • One feature bundle: skills + agent + hooks + config slice + (no) requires.
  • Co-located manifest, generated registry, federated config.
  • Uses only the stable 12-point surface; additive-only.
  • Default-resilient: skip-on-error, opt-in, no gate ⇒ absent MemPalace = unchanged loop.
  • Calls no gsd-core internals ⇒ respects "third-party code deferred"; the glue is first-party, MemPalace runs out-of-process.