Files
msd-core/commands/gsd/mempalace-capture.md
Tom Boucher 903182fed3 fix(#2414): mempalace-capture rooms example must be dicts with name key (#2464)
* fix(#2414): mempalace-capture rooms example must be dicts with name key

The skill's Step 3 'Add the drawer (verbatim)' example wrote a flat list
of bare strings under rooms: in the embedded mempalace.yaml. mempalace's
miner (detect_room + _mine_impl) indexes room["name"] — a bare-string
list crashes the first 'mempalace mine' invocation with

  TypeError: string indices must be integers, not 'str'

Following the documented example verbatim and running the capture crashed
every time, before any file was routed. The bug shipped in #2220's fix
(commit d8af61be4) — the same commit that replaced the invalid --room
flag with detect_room() staging also introduced this rooms: block with
the wrong (string, not dict) entry shape.

Fix: convert each '- <room>' to '- name: <room>' in both shipped source
files (skills/gsd-mempalace-capture/SKILL.md and commands/gsd/mempalace-capture.md).
The two files are byte-for-byte duplicates of the broken block; both are
corrected in lockstep so the installer regenerates consistent copies into
the user's runtime config dir (gsd-pristine/ and gsd-local-patches/ are
install-time-generated, no separate edit needed).

Tests: tests/mempalace-capture-headless-invocation.test.cjs gains a #2414
describe block that extracts the YAML block from each file, parses it with
js-yaml, and asserts every entry under rooms: is a dict carrying a
non-empty 'name' string. A second belt-and-suspenders check forbids any
bare '- <word>' line under rooms: so a future reversion can't slip back in
silently if the YAML parser is ever removed/refactored.

References: #2414; #2220 (same origin commit, distinct failure mode);
mempalace's miner dict-shape contract (miner.py:1708 built-in default
uses [{"name": "general", "description": "All project files"}]).

* chore(#2414): backfill pr:2464 in .changeset/eager-pandas-jump.md
2026-07-20 16:52:34 -04:00

5.7 KiB

name, description, argument-hint, allowed-tools, requires
name description argument-hint allowed-tools requires
gsd:mempalace-capture File a phase artifact into MemPalace; mirror decision facts into its temporal KG [CONTEXT.md|PLAN.md|SUMMARY.md]
Read
Bash
config

STOP -- DO NOT READ THIS FILE. You are already reading it. This prompt was injected into your context by the command system. Using the Read tool on this file wastes tokens. Begin executing Step 0 immediately.

Step 0 -- Banner

Before ANY tool calls, display this banner:

GSD > MEMPALACE CAPTURE

Then proceed to Step 1.

Step 1 -- Config Gate

Check whether the MemPalace capability is enabled by reading .planning/config.json directly with the Read tool.

  1. Read .planning/config.json with the Read tool.
  2. If the file does not exist, or config.mempalace is absent, or config.mempalace.enabled !== true, or config.mempalace.capture_artifacts !== true: display the disabled message and STOP.
  3. Otherwise proceed to Step 2.

Disabled message:

GSD > MEMPALACE CAPTURE

MemPalace capture is disabled (mempalace.enabled / mempalace.capture_artifacts).
Nothing was filed; the loop proceeds normally.

This step is onError: skip at discuss:post / plan:post / verify:post -- capture never fails a phase.

Step 2 -- Resolve target

  1. Artifact. Take the artifact from $ARGUMENTS. If absent, infer from the loop point: discuss:post → CONTEXT.md, plan:post → PLAN.md, verify:post → SUMMARY.md.
  2. Room. Map artifact → room:
    • CONTEXT.md → decisions
    • PLAN.md → planning
    • SUMMARY.md → milestones (Confirmed problem→fix pairs go to problems — see the capture-problems fragment used at execute:wave:post.)
  3. Wing. config.mempalace.wing if non-empty, else config.project_code, else the repo directory name.
  4. Mode / transport. Read config.mempalace.memory_mode. Prefer MCP (mempalace_*) when your MemPalace MCP server is registered and your runtime permits those tools; otherwise use the mempalace CLI (covered by this skill's Bash allow-tool), as in mempalace-recall.

Step 3 -- File verbatim (idempotent)

On any error or timeout, stop and let the phase continue -- capture is best-effort.

  1. Dedup first. Interactive: mempalace_check_duplicate on the artifact's deterministic drawer id. Headless: rely on mempalace mine's content-hash idempotency.

  2. Add the drawer (verbatim). File the exact artifact text into room: <room> of wing: <wing> with provenance (source_file, phase id). Interactive: mempalace_add_drawer. Headless: see below.

    mempalace mine has no --room flag — only search accepts --room (CLI reference: https://mempalaceofficial.com/reference/cli.html). Room assignment is driven by detect_room() matching folder-path segments against the rooms: list in mempalace.yaml (mining guide: https://mempalaceofficial.com/guide/mining.html — "Rooms are auto-detected from your folder structure"; config reference: https://mempalaceofficial.com/guide/configuration.html). Stage the artifact under a room-named folder so detect_room() assigns it correctly:

    STAGE=".planning/.mempalace-stage"
    # One-time: declare the GSD room taxonomy so detect_room() recognizes these folders
    mkdir -p "$STAGE"
    [ -f "$STAGE/mempalace.yaml" ] || cat > "$STAGE/mempalace.yaml" <<'YAML'
    # Each entry MUST be a dict with a `name` key (the miner's detect_room()
    # indexes room["name"] — a bare-string list crashes _mine_impl with
    # TypeError: string indices must be integers, not 'str'). Optional fields:
    # `description`, `keywords` (matched against folder-path segments).
    rooms:
      - name: decisions
      - name: planning
      - name: milestones
      - name: problems
      - name: general
    YAML
    # Suppress MemPalace cache artifacts written into the scanned tree
    [ -f "$STAGE/.gitignore" ] || echo "mempalace_embedder.json" > "$STAGE/.gitignore"
    # Stage under <room>/<phase-id>/<basename> — stable path so mine's content-hash
    # idempotency (file_already_mined keys on absolute source_file + mtime) deduplicates
    # instead of creating duplicate drawers on re-runs.
    ROOM_DIR="$STAGE/<room>/<phase-id>"
    mkdir -p "$ROOM_DIR"
    cp "<artifact-path>" "$ROOM_DIR/<basename>"
    # Mine with --wing only — no --room flag; detect_room() assigns from the folder path
    mempalace mine "$STAGE" --wing <wing>
    
  3. Mirror KG facts when config.mempalace.mirror_kg is true: extract decision/delivery facts and mempalace_kg_add them with valid_from = the phase date (e.g. (<project>, decided, <decision>) from CONTEXT; (<phase>, delivered, <capability>) from SUMMARY). Under augment these are an additive mirror of GSD's native .planning/graphs/. Under kg_backend/replace the palace KG is the authoritative fact store — GSD still produces .planning/graphs/ through its normal graphify, so an unreachable palace never loses a fact.

  4. Re-running a phase MUST NOT create duplicate drawers (deterministic ids + check_duplicate).

Step 4 -- Report

Print a one-line summary: Filed <artifact> → <wing>/<room> (<n> KG facts) or MemPalace unavailable — capture skipped.

Anti-Patterns

  1. DO NOT let any MemPalace error fail the step -- capture is onError: skip.
  2. DO NOT write lossy summaries -- store the verbatim artifact text (AAAK compression is a separate, optional index).
  3. DO NOT prune or delete drawers here -- pruning (sync --apply) is the curator agent's job at ship:post, wing-scoped only.
  4. DO NOT skip the config gate or the dedup check.