From fd619f5f9a37d1a8d206b3de80166da1e1c3e9b6 Mon Sep 17 00:00:00 2001 From: bastien Date: Mon, 11 May 2026 16:24:16 +0200 Subject: [PATCH] =?UTF-8?q?feat(skills):=20add=20/prune-memory=20=E2=80=94?= =?UTF-8?q?=20curate=20.claude/memory/=20registries?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New personal skill to maintain memory registry hygiene. Gap identified between existing tools: - /caveman:compress — text-compresses one file, no curation - /close — appends new entries end-of-session, doesn't prune - /prune-memory (new) — audits, classifies, applies user-approved cleanup Operations: - Mark obsolete entries `status: superseded by ` or `status: deprecated` (no hard delete — append-only per CLAUDE.md memory rule). - Merge similar entries (new ID, sources marked superseded). - Caveman-compress bloated prose-heavy entries inline. - Repair Index drift (missing rows, orphaned rows). Workflow: STEP 0 precheck (refuses dirty working tree, git = backup) → STEP 1 audit (A obsolete / B similar / C bloated / D drift) → STEP 2 plan + mandatory user approval → STEP 3 apply safe→destructive → STEP 4 verify Index sanity + line-count report. Follows superpowers:writing-skills CSO conventions: "Use when..." trigger description (under 1024-char spec), Quick Reference table, Common Mistakes table, Failure Paths table. v1 ships without baseline TDD test (noted in skill body); STEP 2 approval gate is the safety net. Co-Authored-By: Claude --- skills/prune-memory/SKILL.md | 241 +++++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 skills/prune-memory/SKILL.md diff --git a/skills/prune-memory/SKILL.md b/skills/prune-memory/SKILL.md new file mode 100644 index 0000000..2cf900e --- /dev/null +++ b/skills/prune-memory/SKILL.md @@ -0,0 +1,241 @@ +--- +name: prune-memory +description: | + Use when .claude/memory/ registries grow too large or noisy — superseded + entries verbose, similar entries cluttering, journal stale, caveman style + drifted. Curates the 5 registries via mark-superseded + merge + inline + caveman compression. Append-only safe (no hard delete). Git is the backup. + Triggers: "prune memory", "compact memory", "clean memory", "memory + hygiene", "trier memoire", "nettoyer memoire", "registres trop longs", + "compresse les memoires". +argument-hint: [optional: decisions|learnings|blockers|journal|evals — default all 5] +disable-model-invocation: false +allowed-tools: + - Read + - Edit + - Write + - Bash + - Grep + - Glob + - AskUserQuestion +--- + +# /prune-memory — Memory registry curation + +Operates on `.claude/memory/` in the current project (CWD). Curates the +5 registries: `decisions.md`, `learnings.md`, `blockers.md`, `journal.md`, +`evals.md`. + +## Core principles + +- **Git is the backup.** Skill writes in-place. PRECHECK refuses to run + if working tree dirty on registry files. +- **Append-only friendly.** Marks entries `status: superseded by ` + or `status: deprecated` instead of deleting. Body of old entry stays + for history. +- **IDs stable.** Never renumber. Merges create a new ID; sources keep + their ID with superseded status. +- **Caveman style enforced.** Per CLAUDE.md memory rule, all writes are + caveman-style English. Compression rewrites prose to fragments. +- **User approves every category.** No silent changes. + +## Quick reference + +| When | Use | +|------|-----| +| Add new entry this session | `/close` | +| Token-compress one file (not curating) | `/caveman:compress ` | +| Curate: obsolete + merge + caveman | `/prune-memory` (this skill) | + +## STEP 0 — PRECHECK + +```bash +test -d .claude/memory/ || { echo "no .claude/memory/ in $(pwd)"; exit 1; } +git status --short .claude/memory/ 2>/dev/null +``` + +If working tree is dirty on any registry file → STOP with: "Commit or +stash pending changes in `.claude/memory/` first. Skill writes in-place. +Git is the only backup." + +## STEP 1 — AUDIT (per registry) + +For each target registry (filter by `$ARGUMENTS` or all 5): + +Read file. Classify candidates into A/B/C/D below. Use today's date for +age comparisons. Today's date is in the system context. + +### A. Obsolete — mark-superseded candidates +- Decisions `status: proposed` older than 90 days → propose + `status: deprecated` (no follow-up). +- Decisions whose body contains "superseded by " but Index row still + says `accepted` → propose Index row fix to + `superseded by `. +- Blockers `status: open` whose root cause matches a commit in last 30 + days (grep `git log --since=30.days --grep=`) → propose + `status: resolved` with commit ref. +- Journal entries older than 180 days with zero cross-reference from + later entries → propose collapse into 1-line month summary + (`## YYYY-MM` heading replaces detail). + +### B. Similar — merge candidates +- Two+ entries sharing root keyword in title (e.g. `pandoc`, + `client-handover`, `CSS overlay`). +- Shared file paths in `**Reference**:` lines. +- Same week + adjacent IDs + same domain. +- Use semantic judgment on overlap; don't merge complementary entries + that cover different angles of one concept. + +### C. Bloated — inline caveman-rewrite candidates +- Body > 150 words AND prose-heavy. +- Detect filler density: count `\b(the|a|an|just|really|basically|actually|simply)\b` + matches; if > 5% of word count → bloated. + +### D. Index drift +- Body `## (BDR|LRN|BLK|EVAL)-NNN` heading exists but no matching row + in `## Index` table → propose Index backfill. +- Index row exists but body entry missing → propose `status: deleted + (orphaned)` tombstone or removal of Index row (user decides). + +## STEP 2 — PRESENT PLAN ★ MANDATORY STOP + +Print one block per registry. Example: + +``` +PRUNE PLAN — decisions.md (N entries → M after if approved) + +[A. Obsolete — mark superseded] + BDR-003 — Gitignore wildcard pattern — status: proposed since 2026-03-12 + → mark: status: deprecated (no follow-up after 90 days) + BDR-011 — Client handover 4-chapter — body says superseded by BDR-013 + → fix Index: status = "superseded by BDR-013" + +[B. Similar — merge] + LRN-014 + LRN-016 — both pandoc rendering quirks + → propose: merge into NEW LRN-017 ("Pandoc rendering quirks") + with both bodies appended + caveman pass; sources marked + status: superseded by LRN-017 + +[C. Bloated — inline caveman rewrite] + BDR-011 — body 612 words, filler density 7.2% → ~380 expected (-38%) + +[D. Index drift] + (none) + +Approve per category? (all / a / b / c / d / edit / skip) +``` + +Wait for user input. Default = nothing applied. + +## STEP 3 — APPLY APPROVED CHANGES + +Order: safe → destructive. + +1. **Index drift fixes** — no body changes. Backfill missing rows, mark + orphans. +2. **Status flag updates** — Index row status field only. Body untouched. +3. **Merges** — write new merged entry (next-free ID); source IDs marked + `status: superseded by ` in Index (body kept verbatim for + history). Merged body: + - Preserves all `**Reference**:` lines (dedupe identical paths). + - Caveman pass on prose during merge. + - Keeps frontmatter fields: id (new), date (today), title, status + (accepted), references (union). +4. **Inline caveman compression** — preserve frontmatter exactly (id, + date, title, status, references). Rewrite prose body to fragments: + - Drop articles (`a`, `an`, `the`). + - Drop filler (`just`, `really`, `basically`, `actually`, `simply`). + - Short synonyms (`big` not `extensive`, `fix` not `implement a solution for`). + - Keep code blocks, URLs, error messages, file paths VERBATIM. + - Keep IDs (BDR-XXX, LRN-XXX, commit hashes) verbatim. + +After each write, regenerate Index from body when rows changed. + +## STEP 4 — VERIFY + +```bash +# All body entries have Index rows; no orphans +for f in .claude/memory/decisions.md .claude/memory/learnings.md .claude/memory/blockers.md; do + prefix=$(basename "$f" .md | tr a-z A-Z | cut -c1-3) + /usr/bin/grep -oE "^## (${prefix})-[0-9]+" "$f" | while read marker; do + id="${marker##\#\# }" + /usr/bin/grep -q "^| ${id} " "$f" || echo "MISSING INDEX: $id in $f" + done + /usr/bin/grep -oE "^\| (${prefix})-[0-9]+ " "$f" | while read row; do + id=$(echo "$row" | awk '{print $2}') + /usr/bin/grep -q "^## ${id} " "$f" || echo "ORPHAN INDEX: $id in $f" + done +done + +wc -l .claude/memory/*.md +``` + +Report: + +``` +PRUNE COMPLETE + decisions.md : 226 → 184 lines (-19%) + learnings.md : 190 → 165 lines (-13%) + blockers.md : no candidates + journal.md : 88 → 62 lines (-30%) + evals.md : no candidates + +INDEX SANITY: OK +NEXT: review `git diff .claude/memory/`, then `/commit-change` +``` + +## What NOT to prune + +- Journal entries < 30 days old. +- Decisions / learnings with commit references < 14 days old. +- Entries the user marked `status: accepted` in the current session. +- The current session's just-capitalized entries (read `journal.md` + tail to identify them). + +## Common mistakes + +| Mistake | Fix | +|---------|-----| +| Renumbering IDs after a merge | IDs are stable. Sources keep their ID + `status: superseded`. New merged entry gets next-free ID. | +| Hard-deleting "obsolete" entries | Forbidden by append-only rule. Use `status: deprecated`. Body stays. | +| Compressing code blocks / URLs / error messages | Caveman compression touches PROSE only. Code, URLs, IDs, error quotes stay verbatim. | +| Running on a dirty working tree | PRECHECK blocks this. Commit first. | +| Compressing the current session's journal entry | Excluded by "What NOT to prune" — current session capitalization is still useful. | +| Merging complementary entries that cover different angles | Merge only when same concept, same scope. Different angles = keep separate. | + +## Failure paths + +| Situation | Behavior | +|---|---| +| `.claude/memory/` missing | STOP: `no .claude/memory/ in current directory; run from project root` | +| Working tree dirty on registry files | STOP per PRECHECK; tell user to commit/stash first | +| User says `skip` at STEP 2 | Exit cleanly, no writes | +| Merge produces an entry > 600 words | Re-split — merge was too greedy. Re-prompt user to keep separate. | +| Index sanity FAILED at STEP 4 | Print exact missing/orphan IDs. Do NOT auto-fix — user re-runs or hand-edits. | +| Caveman compression result < 20% of original AND original had code blocks | Revert that entry's compression — flag as needing manual rewrite (likely stripped technical detail). | +| Same file already compressed in same session (e.g. via `/caveman:compress`) | Skip C-category for that file; warn user that double-pass risks technical drift. | + +## Rules + +- No silent writes — every change goes through STEP 2 approval gate. +- No renumbering — IDs are stable across all operations. +- No hard delete in v1 — only mark superseded. (Hard delete opt-in may + arrive in v2 if explicit demand surfaces.) +- Working tree must be clean before any write — git is the only backup. +- Caveman compression touches prose only; code/URLs/error quotes + verbatim per CLAUDE.md memory format rule. + +## TDD note (skill itself) + +v1 ships without baseline test scenarios per superpowers:writing-skills +Iron Law. Recommended before relying on the skill in production: + +1. RED: spawn subagent, give it a real `.claude/memory/` snapshot, ask + "prune obsolete entries". Document what it does naturally. +2. GREEN: invoke `/prune-memory` on the same snapshot. Verify it + follows STEP 0–4 + respects append-only rule. +3. REFACTOR: log any new rationalizations the subagent finds; add + counters to the "Common mistakes" / "Failure paths" tables. + +Until TDD is done, the skill is v1-untested. STEP 2 approval gate is +the human safety net.