feat(capitalize): merge /close into /capitalize + TODO reconcile

Two-mode capitalize: default pre-wipe flush, --ritual adds the 3-question
end-of-session reflection (now deduped, unlike legacy /close). New STEP 2B
reconciles .claude/tasks/TODO.md — PASS A done-detection (only on an
unambiguous task<->commit map), PASS B explicit-only capture with an
anti-noise filter (never track commit/deploy/push/release/tag) and BDR
routing for orientation directives. STEP 3 gate gains a separate TODO block;
journal/handoff report TODO ops. /close becomes a thin alias for
/capitalize --ritual (zero duplicated logic).

Built via superpowers:writing-skills TDD: RED baseline (no skill) folded a
push/tag parasite into the TODO, invented a subtask, and wrote with no gate;
GREEN re-run on the same fixture stops at the gate, drops both dups (footer
shows existing IDs), logs one learning, checks only the cleanly-done task,
ignores the parasite, and routes the GraphQL directive to BDR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X3e8LaH2vymmxyh36h3jFU
This commit is contained in:
Bastien Chanot 2026-06-19 18:00:51 +02:00
parent a4e0425581
commit 9dc2b83f0e
3 changed files with 209 additions and 263 deletions

View File

@ -1,61 +0,0 @@
$ClaudeDir = if ($env:CLAUDE_CONFIG_DIR) { $env:CLAUDE_CONFIG_DIR } else { Join-Path $HOME ".claude" }
$Flag = Join-Path $ClaudeDir ".caveman-active"
if (-not (Test-Path $Flag)) { exit 0 }
# Refuse reparse points (symlinks / junctions) and oversized files. Without
# this, a local attacker could point the flag at a secret file and have the
# statusline render its bytes (including ANSI escape sequences) to the terminal
# every keystroke.
try {
$Item = Get-Item -LiteralPath $Flag -Force -ErrorAction Stop
if ($Item.Attributes -band [System.IO.FileAttributes]::ReparsePoint) { exit 0 }
if ($Item.Length -gt 64) { exit 0 }
} catch {
exit 0
}
$Mode = ""
try {
$Raw = Get-Content -LiteralPath $Flag -TotalCount 1 -ErrorAction Stop
if ($null -ne $Raw) { $Mode = ([string]$Raw).Trim() }
} catch {
exit 0
}
# Strip anything outside [a-z0-9-] — blocks terminal-escape and OSC hyperlink
# injection via the flag contents. Then whitelist-validate.
$Mode = $Mode.ToLowerInvariant()
$Mode = ($Mode -replace '[^a-z0-9-]', '')
$Valid = @('off','lite','full','ultra','wenyan-lite','wenyan','wenyan-full','wenyan-ultra','commit','review','compress')
if (-not ($Valid -contains $Mode)) { exit 0 }
$Esc = [char]27
if ([string]::IsNullOrEmpty($Mode) -or $Mode -eq "full") {
[Console]::Write("${Esc}[38;5;172m[CAVEMAN]${Esc}[0m")
} else {
$Suffix = $Mode.ToUpperInvariant()
[Console]::Write("${Esc}[38;5;172m[CAVEMAN:$Suffix]${Esc}[0m")
}
# Savings suffix: on by default. Opt out via CAVEMAN_STATUSLINE_SAVINGS=0.
# Reads a pre-rendered string written by caveman-stats.js. Refuses reparse
# points and strips control bytes (matches statusline.sh hardening). Until
# /caveman-stats has run at least once, the suffix file is absent and nothing
# is rendered — safe default for fresh installs.
if ($env:CAVEMAN_STATUSLINE_SAVINGS -ne "0") {
$SavingsFile = Join-Path $ClaudeDir ".caveman-statusline-suffix"
if (Test-Path $SavingsFile) {
try {
$SavingsItem = Get-Item -LiteralPath $SavingsFile -Force -ErrorAction Stop
if (-not ($SavingsItem.Attributes -band [System.IO.FileAttributes]::ReparsePoint) -and
$SavingsItem.Length -le 64) {
$Savings = (Get-Content -LiteralPath $SavingsFile -Raw -ErrorAction Stop).TrimEnd()
$Savings = ($Savings -replace '[\x00-\x1F]', '')
if ($Savings.Length -gt 0) {
[Console]::Write(" ${Esc}[38;5;172m$Savings${Esc}[0m")
}
}
} catch {}
}
}

View File

@ -1,17 +1,19 @@
--- ---
name: capitalize name: capitalize
description: | description: |
Use when about to /clear or /compact and the current conversation holds Use when about to /clear or /compact, or when closing a session, and the
decisions, learnings, blockers, or eval results that were never written to conversation holds decisions, learnings, blockers, eval results, or
`.claude/memory/`. Use to flush important uncapitalized context before it is finished/new TODO items not yet written to `.claude/memory/` or
wiped, or when unsure whether the session's insights already reached the `.claude/tasks/TODO.md`. Plain invocation = pre-wipe flush; `--ritual` (or the
registries. NOT the fresh end-of-session ritual (that is /close) and NOT word "close"/"ritual" in the request) = end-of-session reflection mode. NOT
registry curation (that is /prune-memory). registry curation (that is /prune-memory).
Triggers: "capitalize", "capitalise", "before clear", "before compact", Triggers: "capitalize", "capitalise", "before clear", "before compact",
"save before clear", "flush memory", "don't lose this", "what's not logged "save before clear", "flush memory", "don't lose this", "what's not logged
yet", "avant de clear", "avant compact", "sauvegarde avant clear", yet", "avant de clear", "avant compact", "sauvegarde avant clear",
"capitalise ce qui manque". "capitalise ce qui manque", "close", "end session", "session close",
argument-hint: (none — scans the current conversation against .claude/memory/) "ferme la session", "checkpoint memory", "what did we learn", "retro rapide",
"fin de journée".
argument-hint: "[--ritual] (scans conversation + git + TODO against .claude/memory/; --ritual adds the 3-question reflection)"
allowed-tools: allowed-tools:
- Read - Read
- Edit - Edit
@ -22,27 +24,31 @@ allowed-tools:
- AskUserQuestion - AskUserQuestion
--- ---
# /capitalize — Flush uncapitalized context before a wipe # /capitalize — Flush uncapitalized context (two modes)
Salvage the registry-worthy insights from **this conversation** that were Salvage the registry-worthy insights from **this conversation** that were never
never written down, right before `/clear` or `/compact` destroys them. written down — before `/clear` or `/compact` destroys them, or as a deliberate
end-of-session ritual. Also reconciles `.claude/tasks/TODO.md` against what
actually shipped.
Operates on conversation memory + git state + the existing registries. Does Operates on conversation memory + git state + the existing registries + the
NOT re-read source code. TODO. Does NOT re-read source code.
## What makes this different from /close ## Modes
| Situation | Skill | | Mode | How triggered | Adds |
|-----------|-------| |------|---------------|------|
| About to `/clear` or `/compact` — salvage what the session produced but never logged | **/capitalize** (this) | | **default** (pre-wipe flush) | plain `/capitalize`, "before clear", "flush memory" | auto-scan + dedup + TODO reconcile |
| Deliberate end-of-session ritual, fresh 3-question prompt | `/close` | | **--ritual** (session-close) | `--ritual` flag, OR `$ARGUMENTS` contains "close"/"ritual", OR invoked via `/close` | everything above **+ STEP 1B** 3-question reflection |
| Registries too long / noisy — curate, merge, compress | `/prune-memory` |
| Token-compress one registry file | `/caveman:compress <file>` |
The signature move of THIS skill is **STEP 2 — DEDUP**: every candidate is Detect the mode first. Both modes share the SAME dedup (STEP 2), TODO reconcile
checked against what is already in the registries, and anything already (STEP 2B), and approval gate (STEP 3). The signature move is **STEP 2 — DEDUP**:
captured is dropped silently. `/close` does not dedup; it asks fresh. Running every candidate is checked against what is already in the registries, and
`/capitalize` right after a `/close` should propose (near) nothing. anything already captured is dropped (its existing ID shown in the footer).
Running `/capitalize` right after a ritual should propose (near) nothing.
This skill is NOT `/prune-memory` (registry curation — merge, compress,
mark-superseded). It only appends.
## STEP 0 — PRECHECK ## STEP 0 — PRECHECK
@ -50,6 +56,7 @@ captured is dropped silently. `/close` does not dedup; it asks fresh. Running
ls .claude/memory/decisions.md .claude/memory/learnings.md \ ls .claude/memory/decisions.md .claude/memory/learnings.md \
.claude/memory/blockers.md .claude/memory/evals.md \ .claude/memory/blockers.md .claude/memory/evals.md \
.claude/memory/journal.md 2>/dev/null .claude/memory/journal.md 2>/dev/null
ls .claude/tasks/TODO.md 2>/dev/null
``` ```
- `.claude/memory/` missing entirely → print and STOP (do NOT create here — - `.claude/memory/` missing entirely → print and STOP (do NOT create here —
@ -58,8 +65,11 @@ ls .claude/memory/decisions.md .claude/memory/learnings.md \
⚠️ .claude/memory/ absent. Lance `/onboard` (ou `/init-project`) pour créer ⚠️ .claude/memory/ absent. Lance `/onboard` (ou `/init-project`) pour créer
les registres avant de capitaliser. les registres avant de capitaliser.
``` ```
- Some files missing → name them, create each from - Some registry files missing → name them, create each from
`~/.claude/templates/memory/<name>.md`, continue. `~/.claude/templates/memory/<name>.md`, continue.
- `.claude/tasks/TODO.md` missing → the TODO reconcile volet (STEP 2B) is
**skipped**. Do NOT create it (same posture as the registries). Registries
still run.
## STEP 1 — SCAN THE CONVERSATION ## STEP 1 — SCAN THE CONVERSATION
@ -83,34 +93,50 @@ git status --short
date +%Y-%m-%d date +%Y-%m-%d
``` ```
For each candidate, draft the fields the target registry's schema expects For each candidate, draft the fields the target registry's schema expects (read
(read the YAML header of that file if unsure — e.g. decisions need the YAML header of that file if unsure).
decision/why/alternatives; blockers need friction/real_cause/solution/status).
**Skip the trivial.** If it is reversible in under 10 min with no cross-file **Skip the trivial.** If it is reversible in under 10 min with no cross-file
impact, it is not a decision. If it is a one-shot fact, not a reusable impact, it is not a decision. If it is a one-shot fact, not a reusable pattern,
pattern, it is not a learning. Noise hurts the every-session re-read. it is not a learning. Noise hurts the every-session re-read.
**One incident → one primary registry.** Do not fan a single event across **One incident → one primary registry.** Do not fan a single event across
registries. A resolved gotcha that cost time is a *learning* (the reusable registries. A resolved gotcha that cost time is a *learning* (the reusable
pattern) — not *also* a blocker. Open a blocker only when the friction is pattern) — not *also* a blocker. Open a blocker only when the friction is
unresolved, or when the friction itself (not the lesson) is the durable unresolved, or when the friction itself (not the lesson) is the durable record.
record. The same event written to two registries is a near-duplicate in the The same event written to two registries is a near-duplicate in the
every-session re-read. every-session re-read.
## STEP 1B — RITUAL REFLECTION (only in --ritual mode)
Default mode skips this entirely. In ritual mode, after the auto-scan, force the
end-of-session reflection — three questions that surface what the scan may have
missed:
1. **What did you decide?** → decisions.md (BDR)
2. **What did you learn?** → learnings.md (LRN)
3. **What blocked you?** → blockers.md (BLK)
Each answer becomes an additional candidate. It does NOT bypass dedup: every
ritual answer flows into STEP 2 exactly like an auto-scanned candidate. A
reflection answer that is already captured is **dropped, and its existing
`<ID>` is shown in the footer** — same as any other dup, never re-logged. This
is the key difference from the legacy `/close`, which wrote ritual answers fresh
with no dedup.
## STEP 2 — DEDUP AGAINST THE REGISTRIES ★ the whole point ## STEP 2 — DEDUP AGAINST THE REGISTRIES ★ the whole point
For every candidate from STEP 1, check whether it is already captured before For every candidate from STEP 1 (and STEP 1B), check whether it is already
proposing it. Pull the distinctive keyword(s) of the candidate and grep the captured before proposing it. Pull the distinctive keyword(s) of the candidate
relevant registry (Index + bodies): and grep the relevant registry (Index + bodies):
```bash ```bash
# Example: candidate is a learning about "cd -P symlink resolution" # Example: candidate is a learning about "cd -P symlink resolution"
grep -niE 'symlink|cd -P|BASH_SOURCE' .claude/memory/learnings.md grep -niE 'symlink|cd -P|BASH_SOURCE' .claude/memory/learnings.md
``` ```
Also scan the journal tail for `<ID> capitalized` lines — the session may Also scan the journal tail for `<ID> capitalized` lines — the session may have
have already logged it earlier: already logged it earlier:
```bash ```bash
grep -nE '(BDR|LRN|BLK|EVAL)-[0-9]+ capitalized' .claude/memory/journal.md | tail -20 grep -nE '(BDR|LRN|BLK|EVAL)-[0-9]+ capitalized' .claude/memory/journal.md | tail -20
@ -124,16 +150,55 @@ Classify each candidate:
flag `⚠ maybe dup of <ID> — confirm or skip`. flag `⚠ maybe dup of <ID> — confirm or skip`.
- **NEW** — no match → propose it normally. - **NEW** — no match → propose it normally.
Dedup is semantic, not string-equality. Same root cause described two ways is Dedup is **semantic, not string-equality**. The same insight reworded with
still a dup. different vocabulary is still a dup — read the registry entries and reason about
meaning, do not rely on keyword grep alone. (A reworded "Tailwind classes built
by concatenation get purged at build" still matches an existing "purge strips
concatenated class names" entry.)
## STEP 2B — TODO RECONCILE (both modes)
Runs only if `.claude/tasks/TODO.md` exists (STEP 0). Two passes.
**PASS A — done-detection (TODO → reality).** For each unchecked `- [ ]`, decide
whether the session actually finished it, grounding on git (`git log`,
`git diff HEAD`, `git show`) AND the conversation. Propose `[x]` ONLY when the
task ↔ commit/code map is unambiguous (task "add retry-with-backoff" ↔ a commit
that adds exactly that).
- Partial / umbrella tasks ("harden X" covering 3 things when only 1 shipped) →
leave unchecked.
- Vague tasks ("Commit", "Deploy", "test it") with no precise git evidence →
leave unchecked. Never check on assumption or on a guess.
**PASS B — capture (conversation → TODO).** Spot explicit to-dos voiced in the
session ("il faut X", "TODO Y", "à corriger Z", new directives) that are absent
from the TODO → propose adding them as `- [ ]`. Dedup semantically against
existing items first. Capture ONLY what was explicitly stated — do not invent,
expand, or decompose a task into subtasks the user never named.
**Anti-noise filter (PASS B).** NEVER add — or fold into an existing item —
commit / deploy / push / release / tag actions. These are systematic steps the
user performs every session, not tracked work. "push la branche + tag v0.3.0" is
noise even when phrased with action verbs. If such an item ALREADY exists in the
TODO, PASS A may check it when proven done, but PASS B never creates it nor
enriches one with session-derived push/tag/release detail.
**Routing.** A directive that changes the project's ORIENTATION (a policy /
architecture choice, e.g. "GraphQL for all new endpoints from now on") is a
DECISION, not a task → it flows through STEP 1 into decisions.md (BDR), never
into the TODO. Don't confuse an actionable task with an architecture decision.
**Language.** The TODO is **NOT caveman**. Tasks stay in readable, actionable
prose. Caveman is reserved for the `.claude/memory/` registries (STEP 4).
## STEP 3 — PRESENT PLAN ★ MANDATORY STOP (approval gate) ## STEP 3 — PRESENT PLAN ★ MANDATORY STOP (approval gate)
One compact screen. Pre-filled drafts, caveman-English bodies (registry rule). One compact screen. Pre-filled drafts — registry bodies in caveman-English, TODO
Group by registry. Mark dup flags inline. lines in plain prose. Group by registry, then a **SEPARATE TODO.md block**. Mark
dup flags inline.
``` ```
═══ CAPITALIZE — uncapitalized context before wipe ═══ ═══ CAPITALIZE — <pre-wipe flush | session-close ritual> ═══
decisions.md decisions.md
▸ NEW BDR-019 <title> ▸ NEW BDR-019 <title>
@ -149,17 +214,28 @@ blockers.md
evals.md evals.md
▸ NEW EVAL-003 <output><method><anomalies> — action: <keep|correct|deprecate> ▸ NEW EVAL-003 <output><method><anomalies> — action: <keep|correct|deprecate>
TODO.md
☑ check "<task>" (done @ <hash> | conversation)
+ add "[ ] <new task>" (said in session, absent)
Already captured this session (dropped): LRN-023, BLK-006 Already captured this session (dropped): LRN-023, BLK-006
Ignored as noise: "push branch + tag v0.3.0" (systematic action)
Action ? (all / pick <IDs> / edit <ID> / skip-all) Action ? (all / pick <IDs> / edit <ID> / skip-all)
``` ```
If a registry has zero NEW + zero DUP → print `(rien de neuf — déjà à jour)`. The **TODO.md block is approved / edited / skipped INDEPENDENTLY** of the
registry blocks. If a section has zero NEW + zero DUP → print
`(rien de neuf — déjà à jour)`. If a dup was dropped (incl. a ritual answer),
name its existing ID on the `Already captured` line. If the anti-noise filter
dropped a parasite, name it on the `Ignored as noise` line (no silent drops).
Wait for input. Default = nothing written (journal line still goes in STEP 5). Wait for input. Default = nothing written (journal line still goes in STEP 5).
## STEP 4 — WRITE APPROVED ENTRIES ## STEP 4 — WRITE APPROVED ENTRIES
For each approved entry, in registry order: Registries first (in registry order), then the TODO.
Registry entries — for each approved:
1. Read the target registry file. 1. Read the target registry file.
2. Next sequential ID = scan existing `## <PREFIX>-NNN` body headings, take max, 2. Next sequential ID = scan existing `## <PREFIX>-NNN` body headings, take max,
@ -173,6 +249,12 @@ For each approved entry, in registry order:
verbatim. Entries are ALWAYS English even if the STEP 3 prompt mirrored the verbatim. Entries are ALWAYS English even if the STEP 3 prompt mirrored the
user's language. user's language.
TODO — for each approved:
- **Check**: flip the exact `- [ ]` line to `- [x]`, leaving the text unchanged.
- **Add**: append `- [ ] <task>` under the right `##` section (create a section
only if none fits). Plain readable prose, NOT caveman.
## STEP 5 — JOURNAL LINE (always) ## STEP 5 — JOURNAL LINE (always)
Write one timeline line under today's `## YYYY-MM-DD` heading — even if every Write one timeline line under today's `## YYYY-MM-DD` heading — even if every
@ -181,36 +263,49 @@ candidate was skipped or already captured.
- Heading exists → append a bullet. - Heading exists → append a bullet.
- Missing → create `## YYYY-MM-DD` and write 3-5 bullets summarizing the session. - Missing → create `## YYYY-MM-DD` and write 3-5 bullets summarizing the session.
Reference any IDs written this run: `BDR-019 + LRN-026 capitalized before /clear.` Reference any IDs written this run AND the TODO ops:
`BDR-019 + LRN-026 capitalized; checked 1 done, added 1 task.`
## STEP 6 — FINAL OUTPUT + HANDOFF ## STEP 6 — FINAL OUTPUT + HANDOFF
``` ```
CAPITALIZE COMPLETE — <YYYY-MM-DD> (pre-wipe flush) CAPITALIZE COMPLETE — <YYYY-MM-DD> (<pre-wipe flush | session-close>)
decisions.md : +<N> (BDR-019) | 0 decisions.md : +<N> (BDR-019) | 0
learnings.md : +<N> (LRN-026) | 0 learnings.md : +<N> (LRN-026) | 0
blockers.md : 0 — already up to date blockers.md : 0 — already up to date
evals.md : +<N> (EVAL-003) | 0 evals.md : +<N> (EVAL-003) | 0
TODO.md : checked <N>, added <M>
journal.md : +1 line under ## <date> journal.md : +1 line under ## <date>
dropped as already-captured: LRN-023, BLK-006 dropped as already-captured: LRN-023, BLK-006
ignored as noise: push/tag release
✅ Context flushed. Safe to /clear or /compact now.
``` ```
The closing line matters — this skill exists to make the wipe safe, so confirm Then the mode-specific closing line:
it explicitly.
- **pre-wipe flush**`✅ Context flushed. Safe to /clear or /compact now.`
- **session-close ritual**`✅ Session closed. Next session: read .claude/memory/ at startup.`
The closing line matters — confirm the wipe is safe (default) or the session is
checkpointed (ritual).
## Rules ## Rules
- **Never invent.** Every entry grounded in this conversation or git history. - **Never invent.** Every entry grounded in this conversation or git history. No
No fabricated "lessons" to fill the screen. fabricated "lessons" to fill the screen, no invented TODO subtasks.
- **Dedup before proposing.** Re-logging an existing entry is the #1 failure - **Dedup before proposing.** Re-logging an existing entry is the #1 failure mode.
mode of this skill. When in doubt, flag as `⚠ DUP?` and let the user decide — When in doubt, flag as `⚠ DUP?` and let the user decide. Dedup is semantic —
never silently create a near-duplicate. a reworded dup is still a dup. Applies to ritual answers too.
- **Append-only.** Never overwrite or renumber existing entries. - **Append-only.** Never overwrite or renumber existing registry entries.
- **Caveman English** bodies, always English, per CLAUDE.md memory format. - **Caveman English** registry bodies, always English. **The TODO is plain
- **Journal always writes**, even on `skip-all` — timeline logging is cheap and prose, never caveman** — caveman is registries-only.
noise-tolerant. - **TODO reconcile runs only if TODO.md exists.** Never create it (STEP 0).
- **PASS A checks only on an unambiguous task↔code/commit map.** Partial /
umbrella / vague → leave unchecked. Never on assumption.
- **PASS B captures only explicit to-dos**, deduped — never invented or
decomposed.
- **Anti-noise**: never track commit / deploy / push / release / tag.
- **Orientation directive → decisions.md (BDR)**, not the TODO.
- **Journal always writes**, even on `skip-all`.
- **Skip trivial** for the 4 ID registries; journal excepted. - **Skip trivial** for the 4 ID registries; journal excepted.
- `.claude/memory/` missing → STOP at STEP 0, do not create the structure here. - `.claude/memory/` missing → STOP at STEP 0, do not create the structure here.
@ -218,35 +313,48 @@ it explicitly.
| Mistake | Fix | | Mistake | Fix |
|---------|-----| |---------|-----|
| Proposing items already in the registries | STEP 2 dedup is mandatory. Grep keywords + journal `capitalized` lines first. | | Proposing items already in the registries | STEP 2 dedup is mandatory. Grep keywords + read entries + journal `capitalized` lines first. |
| Re-running after `/close` and re-logging the same items | Expected output after `/close` is `(rien de neuf)`. If it proposes the just-closed items, dedup failed. | | Re-running after a ritual and re-logging the same items | Expected output after a ritual is `(rien de neuf)`. If it proposes the just-closed items, dedup failed. |
| Treating a reworded insight as new | Dedup is semantic, not lexical. Read the entry's meaning, not just its keywords. |
| Renumbering or reusing an ID | IDs are stable + sequential. Max existing +1. | | Renumbering or reusing an ID | IDs are stable + sequential. Max existing +1. |
| Writing prose bodies | Registries are caveman-English. Fragments, no articles/filler. | | Writing prose registry bodies | Registries are caveman-English. Fragments, no articles/filler. (TODO stays prose.) |
| Logging a trivial reversible tweak as a decision | Decision = tradeoff you'd defend, cross-file or >10 min to reverse. Else skip. | | Logging a trivial reversible tweak as a decision | Decision = tradeoff you'd defend, cross-file or >10 min to reverse. Else skip. |
| Fanning one incident across registries (e.g. a resolved gotcha as both LRN and BLK) | One incident → one primary registry. Reusable pattern → LRN. Unresolved friction / the friction itself → BLK. Don't write the same event twice. | | Fanning one incident across registries (a resolved gotcha as both LRN and BLK) | One incident → one primary registry. Reusable pattern → LRN. Unresolved friction / the friction itself → BLK. |
| French/English entry text | Prompt may be French; written entry is always English. | | Folding push / tag / release / deploy into the TODO | Anti-noise filter. Those are systematic actions, not tracked work — drop them, even phrased as tasks. |
| Creating `.claude/memory/` when absent | Not this skill's job — STOP and point to `/onboard`. | | Checking an umbrella/partial task because "some of it shipped" | PASS A needs the WHOLE task proven done with a clear git map. Partial → leave unchecked. |
| Inventing a subtask the user never voiced | PASS B captures only explicit to-dos. No decomposition, no expansion. |
| Dumping an architecture directive as a TODO task | Route orientation/policy directives to decisions.md (BDR), not the TODO. |
| Writing a ritual answer fresh without dedup | Ritual answers go through STEP 2 like any candidate; a dup shows its existing ID. |
| French/English entry text | Prompt may be French; written registry entry is always English. |
| Creating `.claude/memory/` or `.claude/tasks/TODO.md` when absent | Not this skill's job — registries STOP and point to `/onboard`; TODO volet is skipped. |
## Red flags — STOP ## Red flags — STOP
- About to append an entry without having grepped the registry for it → dedup skipped. - About to append a registry entry without having grepped + read the registry
- Proposing 6+ entries from a short conversation → over-capturing noise; keep only what you'd defend. for it → dedup skipped.
- Rewriting an existing entry "to update it" → append-only violation; add a new entry with `supersedes`. - About to treat a reworded item as new without checking meaning → semantic
- Same incident headed for two registries (LRN + BLK for one event) → pick the one primary registry. dedup skipped.
- Proposing 6+ entries from a short conversation → over-capturing noise.
- Rewriting an existing entry "to update it" → append-only violation; add a new
entry with `supersedes`.
- Same incident headed for two registries (LRN + BLK for one event) → pick one.
- About to add / relabel a TODO item with push / tag / release / deploy → noise.
- About to check a `- [ ]` with no commit/code proving the WHOLE task done → stop.
- About to write a TODO item the user never explicitly asked for → stop.
- Writing the TODO in caveman → TODO is plain prose.
## TDD note (skill itself) ## TDD note (skill itself)
v1 ships without baseline pressure tests per superpowers:writing-skills Iron Baseline (RED, 2026-06-19): a no-skill agent on a pressured fixture deduped
Law. The STEP 3 approval gate is the human safety net (same posture as correctly (incl. a reworded semantic dup), routed an architecture directive to
`/prune-memory` v1). Recommended baseline before relying on it: BDR, and checked a cleanly-done task — but (a) folded a "push branch + tag
release" parasite into the TODO, (b) invented a subtask the user never voiced,
(c) wrote everything with no approval stop, and (d) fanned one incident across
two registries on an earlier run (non-deterministic). This skill's mandatory
gate (STEP 3), anti-noise filter (STEP 2B), explicit-only capture, and
one-incident-one-registry rule make those deterministic.
1. **RED** — give a subagent a synthetic transcript containing 2 GREEN re-run on the same fixture must: stop at the gate, drop both dups (footer
already-captured insights + 1 genuinely new learning, plus a registry shows existing IDs), log jigsaw as ONE learning, check only the cleanly-done
snapshot. Ask it to "save what matters before /clear" WITHOUT this skill. task, leave the umbrella "harden" task unchecked, add only the explicit README
Document whether it re-logs the captured ones (no dedup) or misses the new one. to-do, ignore the push/tag parasite, and route the GraphQL directive to BDR.
2. **GREEN** — invoke `/capitalize` on the same inputs. Verify STEP 2 drops the
2 dups and proposes only the 1 new entry.
3. **REFACTOR** — log any new rationalization (e.g. "it's basically the same so
I'll just append anyway") and add a counter to Common mistakes / Red flags.
Until done, treat as v1-untested; the approval gate gates every write.

View File

@ -1,13 +1,14 @@
--- ---
name: close name: close
description: | description: |
End-of-session ritual — capitalize the 3 registry questions: what was End-of-session ritual — flush what was decided, learned, and blocked into
decided, what was learned, what was blocked. Writes approved entries `.claude/memory/`, reconcile `.claude/tasks/TODO.md`, and log a journal line.
into `.claude/memory/decisions.md`, `.claude/memory/learnings.md`, and Alias for `/capitalize --ritual`: same dedup + TODO-reconcile + approval-gate
`.claude/memory/blockers.md`, plus a timeline line in `.claude/memory/journal.md`. pipeline, plus the explicit 3-question reflection. NOT registry curation
Trigger: "close", "end session", "ferme la session", "session close", (that is /prune-memory).
Triggers: "close", "end session", "ferme la session", "session close",
"checkpoint memory", "what did we learn", "retro rapide", "fin de journée". "checkpoint memory", "what did we learn", "retro rapide", "fin de journée".
argument-hint: (none — operates on the current conversation context) argument-hint: (none — runs capitalize in ritual mode on the current conversation)
allowed-tools: allowed-tools:
- Read - Read
- Edit - Edit
@ -15,124 +16,22 @@ allowed-tools:
- Bash - Bash
- Grep - Grep
- Glob - Glob
- AskUserQuestion
--- ---
# CLOSE — Session-Close Ritual # /close — Session-close ritual (alias)
Capture the 3 registry-worthy outputs from the current session before losing context. Operates entirely on conversation memory + git state — does NOT re-read code. `/close` is an alias for **`/capitalize --ritual`**. All logic lives in the
**capitalize** skill — nothing is duplicated here.
## STEP 0 — PRECHECK Invoke the `capitalize` skill now and run it in **ritual mode**: the full
pipeline (STEP 0 precheck → STEP 1 auto-scan → STEP 2 dedup → STEP 2B TODO
reconcile → STEP 3 approval gate → STEP 4 write → STEP 5 journal → STEP 6
handoff), PLUS STEP 1B's explicit 3-question reflection (what did you decide /
learn / block).
Verify the registry files exist: Ritual answers are deduped like any other candidate — a dup is dropped and its
existing ID shown, not re-logged. This is the upgrade over the legacy `/close`,
which wrote ritual answers fresh with no dedup.
```bash → Use the Skill tool to launch `capitalize` with argument `--ritual`.
ls .claude/memory/decisions.md .claude/memory/learnings.md .claude/memory/blockers.md .claude/memory/journal.md 2>/dev/null
```
- If `.claude/memory/` is missing entirely → print:
```
⚠️ .claude/memory/ absent. Lance d'abord `/onboard` (ou `/init-project` pour un nouveau repo)
pour créer la structure des registres.
```
STOP.
- If some files are missing → print which, create them from `~/.claude/templates/memory/<name>.md`, continue.
## STEP 1 — GATHER SESSION CONTEXT
Collect the raw material without re-reading code:
```bash
git log --oneline -10
git diff HEAD --stat
git status --short
date +%Y-%m-%d
```
Extract from current conversation:
- Any decision made (framework pick, refactor scope, architecture choice, naming convention).
- Any learning surfaced (surprising API behaviour, reusable pattern, gotcha, "don't do X").
- Any blocker encountered (dead end, friction > 15 min wasted, upstream bug).
## STEP 2 — THE 3 QUESTIONS
Present the ritual compactly — one screen, 3 questions, pre-filled draft answers from STEP 1:
```
═══ SESSION-CLOSE RITUAL — 3 QUESTIONS ═══
1⃣ Qu'est-ce que tu as décidé ?
Proposition BDR-XXX :
Titre : <extrait de la conversation>
Décision: <1 phrase>
Pourquoi: <1-2 phrases>
Alts rejetées: <si captable>
→ (accept / edit / skip / add another)
2⃣ Qu'est-ce que tu as appris ?
Proposition LRN-XXX :
Pattern : <extrait abstrait>
Contexte: </quand>
Future : <quand s'en rappeler>
→ (accept / edit / skip / add another)
3⃣ Sur quoi es-tu bloqué ?
Proposition BLK-XXX :
Friction : <extrait>
Cause : <si identifiée sinon "à investiguer">
Solution : <workaround si déjà trouvé sinon "open">
Statut : open | resolved | upstream
→ (accept / edit / skip / add another)
Action globale ? (all / pick <numbers> / edit / skip-all)
```
If nothing notable to propose for a given question → say `(rien à logger cette session)` for that question.
## STEP 3 — WRITE APPROVED ENTRIES
For each approved entry:
1. Read the target registry file.
2. Append the new entry at the end (never rewrite existing entries).
3. Add a line to the Index table at the top with the new ID, date, short title, status.
4. Generate next sequential ID by scanning existing IDs (e.g., if `BDR-007` exists, next is `BDR-008`).
## STEP 4 — JOURNAL ENTRY
Always write one line in `.claude/memory/journal.md` under today's heading — even if all 3 questions were skipped:
- If today's heading exists → append a new bullet under it.
- If not → create `## YYYY-MM-DD` heading and write 3-5 bullets summarising the session.
Template:
```markdown
## YYYY-MM-DD
- <what was done 1 line from conversation>
- <what was decided link to BDR-XXX if logged>
- <what was learned link to LRN-XXX if logged>
- <what's blocked link to BLK-XXX if logged>
- <commit hashes if any `<hash1>..<hashN>`>
```
## STEP 5 — FINAL OUTPUT
```
CLOSE COMPLETE — session <YYYY-MM-DD>
decisions.md : +<N> entries (BDR-XXX, BDR-YYY) | 0 entries
learnings.md : +<N> entries (LRN-XXX) | 0 entries
blockers.md : +<N> entries (BLK-XXX) | 0 entries
journal.md : +1 line under ## <date>
Prochaine session : lire `.claude/memory/` au démarrage pour rappel.
```
---
## RULES
- Never invent content. Every entry must be grounded in the current conversation or git history — no fabricated "lessons".
- Skip silently rather than log a trivial entry. Journal excepted (timeline logging is cheap, noise is fine).
- Never overwrite existing entries — append-only.
- If the user says `skip-all` → still write the journal line and exit.
- If `.claude/memory/` is missing → STOP at STEP 0, do not create it here (onboard / init-project responsibility).
- **Language rule**: written entries are ALWAYS in English (see CLAUDE.md "Memory registries" § Language). The 3-question prompt may mirror the user's language; the appended entries must not.