claude/skills/capitalize/SKILL.md
Bastien Chanot e8807a7333 feat(gitflow): chore branch type + aiguillage for standalone memory/doc skills
Standalone /capitalize /close /prune-memory /reconcile no longer lean on the .claude/** hook exemption when run on main/develop: the aiguillage branches them to chore/* off develop before writing. New chore type (base develop, finish->develop) added to the lib; hook unchanged (chore/* non-protected). Closes the leak where standalone memory work (memory IS the work, no code branch to follow) landed direct on a protected base. 64/64 gitflow-test green, shellcheck clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RNaYKPEkjH1jbgoX1TwKMX
2026-07-01 13:25:36 +02:00

427 lines
21 KiB
Markdown

---
name: capitalize
description: |
Use when about to /clear or /compact, or when closing a session, and the
conversation holds decisions, learnings, blockers, eval results, or
finished/new TODO items not yet written to `.claude/memory/` or
`.claude/tasks/TODO.md`. Plain invocation = pre-wipe flush; `--ritual` (or the
word "close"/"ritual" in the request) = end-of-session reflection mode. NOT
registry curation (that is /prune-memory).
Triggers: "capitalize", "capitalise", "before clear", "before compact",
"save before clear", "flush memory", "don't lose this", "what's not logged
yet", "avant de clear", "avant compact", "sauvegarde avant clear",
"capitalise ce qui manque", "close", "end session", "session close",
"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:
- Read
- Edit
- Write
- Bash
- Grep
- Glob
- AskUserQuestion
---
# /capitalize — Flush uncapitalized context (two modes)
Salvage the registry-worthy insights from **this conversation** that were never
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 + the
TODO. Does NOT re-read source code.
## Modes
| Mode | How triggered | Adds |
|------|---------------|------|
| **default** (pre-wipe flush) | plain `/capitalize`, "before clear", "flush memory" | auto-scan + dedup + TODO reconcile |
| **--ritual** (session-close) | `--ritual` flag, OR `$ARGUMENTS` contains "close"/"ritual", OR invoked via `/close` | everything above **+ STEP 1B** 3-question reflection |
Detect the mode first. Both modes share the SAME dedup (STEP 2), TODO reconcile
(STEP 2B), and approval gate (STEP 3). The signature move is **STEP 2 — DEDUP**:
every candidate is checked against what is already in the registries, and
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.
## Gitflow aiguillage (before any write)
Before STEP 4 writes anything, follow `$HOME/.claude/lib/gitflow-aiguillage.md`
— this skill's TYPE = `chore`. On `main`/`develop` it branches to `chore/<name>`
off develop, so the memory commit lands on a branch, never direct on a protected
base; on a working branch it proceeds in place. Never `gitflow finish` (human-gated).
## STEP 0 — PRECHECK
```bash
ls .claude/memory/decisions.md .claude/memory/learnings.md \
.claude/memory/blockers.md .claude/memory/evals.md \
.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 —
that is `/onboard` / `/init-project` responsibility):
```
⚠️ .claude/memory/ absent. Lance `/onboard` (ou `/init-project`) pour créer
les registres avant de capitaliser.
```
- Some registry files missing → name them, create each from
`~/.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
Mine the conversation (and git, for grounding) for capitalize-worthy items.
Route each by the CLAUDE.md "Memory registries" rules:
| Found in conversation | Registry | Prefix |
|-----------------------|----------|--------|
| Choice with tradeoffs you'd defend (framework, scope, naming, architecture) | `decisions.md` | BDR |
| Reusable pattern / gotcha / "don't do X" / surprising API behavior | `learnings.md` | LRN |
| Dead end with identified root cause, friction > 15 min, upstream bug | `blockers.md` | BLK |
| Quality verdict on something Claude produced (report, plan, generated code) | `evals.md` | EVAL |
| One-line timeline of the session | `journal.md` | (date) |
Grounding scan (do not re-read code):
```bash
git log --oneline -10
git diff HEAD --stat
git status --short
date +%Y-%m-%d
```
For each candidate, draft the fields the target registry's schema expects (read
the YAML header of that file if unsure).
**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 pattern,
it is not a learning. Noise hurts the every-session re-read.
**One incident → one primary registry.** Do not fan a single event across
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
unresolved, or when the friction itself (not the lesson) is the durable record.
The same event written to two registries is a near-duplicate in the
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
For every candidate from STEP 1 (and STEP 1B), check whether it is already
captured before proposing it. Pull the distinctive keyword(s) of the candidate
and grep the relevant registry (Index + bodies):
```bash
# Example: candidate is a learning about "cd -P symlink resolution"
grep -niE 'symlink|cd -P|BASH_SOURCE' .claude/memory/learnings.md
```
Also scan the journal tail for `<ID> capitalized` lines — the session may have
already logged it earlier:
```bash
grep -nE '(BDR|LRN|BLK|EVAL)-[0-9]+ capitalized' .claude/memory/journal.md | tail -20
```
Classify each candidate:
- **ALREADY CAPTURED** — strong match on an existing entry → drop it silently,
remember the existing ID (shown in the report footer, not proposed).
- **POSSIBLE DUP** — partial / uncertain overlap with `<ID>` → propose it but
flag `⚠ maybe dup of <ID> — confirm or skip`.
- **NEW** — no match → propose it normally.
Dedup is **semantic, not string-equality**. The same insight reworded with
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).** Detection is free — a capable
agent already spots the finished tasks from the STEP 1 git scan. The only rule
worth stating is **restraint**: flip `- [ ]``- [x]` ONLY when the task maps
cleanly to a commit/diff that did exactly it. Partial / umbrella tasks
("harden X" when 1 of 3 parts shipped) and vague tasks ("Commit", "Deploy",
"test it") with no precise git evidence stay unchecked. Never check 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)
One compact screen. Pre-filled drafts — registry bodies in caveman-English, TODO
lines in plain prose. Group by registry, then a **SEPARATE TODO.md block**. Mark
dup flags inline.
```
═══ CAPITALIZE — <pre-wipe flush | session-close ritual> ═══
decisions.md
▸ NEW BDR-019 <title>
decision: <1 line> | why: <1 line> | alts: <if any>
⚠ DUP? BDR-0NN <title> (maybe dup of BDR-012 — confirm)
learnings.md
▸ NEW LRN-026 <pattern> — <context> — <future use>
blockers.md
(rien de neuf — tout déjà capitalisé)
evals.md
▸ 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
Ignored as noise: "push branch + tag v0.3.0" (systematic action)
Action ? (all / pick <IDs> / edit <ID> / skip-all)
```
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).
## STEP 4 — WRITE APPROVED ENTRIES
Registries first (in registry order), then the TODO.
Registry entries — for each approved:
1. Read the target registry file.
2. Next sequential ID = scan existing `## <PREFIX>-NNN` body headings, take max,
+1 (e.g. last `## BDR-018``BDR-019`). Never reuse, never renumber.
3. Append the full entry at the **end** of the body (never rewrite existing
entries — append-only).
4. Add one row to the `## Index` table at the top: `| <ID> | <date> | <title>
| <status> |` (column set varies per file — match that file's header row).
5. Body in **caveman English** per CLAUDE.md memory format: drop articles +
filler, fragments OK, short synonyms. Keep code/URLs/error-quotes/IDs/dates
verbatim. Entries are ALWAYS English even if the STEP 3 prompt mirrored the
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)
Write one timeline line under today's `## YYYY-MM-DD` heading — even if every
candidate was skipped or already captured.
- Heading exists → append a bullet.
- Missing → create `## YYYY-MM-DD` and write 3-5 bullets summarizing the session.
Reference any IDs written this run AND the TODO ops:
`BDR-019 + LRN-026 capitalized; checked 1 done, added 1 task.`
## STEP 5B — COMMIT THE CAPITALIZED MEMORY (coupled)
Once the approved entries (STEP 4) and the journal line (STEP 5) are written,
commit them — surgically, via the shared include, exactly like the 6 dev flows.
This closes a wiring gap: `/capitalize` and `/close` predate
`lib/capitalize-commit.md` and never called it, so a flush left memory written
but **uncommitted** (BDR-037). STEP 3 already approved the CONTENT; only the
COMMIT of those approved entries is automated here (the BDR-034 contract).
Follow `~/.claude/lib/capitalize-commit.md`:
1. Compose the message from the IDs just written + the mode:
- `chore(memory): <IDs> — capitalize` (pre-wipe flush)
- `chore(memory): <IDs> — close ritual` (ritual mode, via /close)
- `chore(memory): journal — capitalize` (journal-only — see note)
2. Commit via the helper, capturing the hash:
mem_hash=$(bash "$HOME/.claude/lib/memory-commit.sh" commit "<message>")
rc=$?
3. Report by (rc, mem_hash):
- **rc 0, hash non-empty** → committed; surface `<mem_hash>` in STEP 6. This
is the only success path here (see the invariant below).
- **rc 3** → unsafe git state (detached / merge / rebase) or not a git repo:
memory stays in the working tree, surface the helper's stderr, do NOT retry.
The flush is safe on disk; STEP 6 must say NOT committed, not ✅-all.
- **rc 0, hash EMPTY → must NOT happen from this step.** STEP 5 always writes
the journal line, so memory is ALWAYS pending at 5B → the helper always has
≥1 change → the hash is non-empty by construction. An empty hash here means
the STEP 5 journal write silently failed upstream — treat it as a bug to
investigate, not a normal "nothing to commit" branch.
**Journal-only commit is DESIRED, not a side effect.** On `skip-all` (no registry
entries approved) STEP 5 still writes the journal line, so 5B commits
`chore(memory): journal — capitalize`. The journal IS memory; a session-timeline
line is worth committing on its own — intended, mirroring the include's own
journal-only example.
Surgical scope is the helper's (stages ONLY `.claude/memory` + `.claude/tasks`,
changed-paths-filtered, never `git add -A`). Do NOT hand-roll git here.
## STEP 6 — FINAL OUTPUT + HANDOFF
```
CAPITALIZE COMPLETE — <YYYY-MM-DD> (<pre-wipe flush | session-close>)
decisions.md : +<N> (BDR-019) | 0
learnings.md : +<N> (LRN-026) | 0
blockers.md : 0 — already up to date
evals.md : +<N> (EVAL-003) | 0
TODO.md : checked <N>, added <M>
journal.md : +1 line under ## <date>
committed : <mem_hash> (chore(memory): …) | ⚠️ NOT committed (rc 3 — see closing line)
dropped as already-captured: LRN-023, BLK-006
ignored as noise: push/tag release
```
Then the mode-specific closing line:
- **pre-wipe flush** → `✅ Context flushed + committed <mem_hash>. Safe to /clear or /compact now.`
- **session-close ritual** → `✅ Session closed + committed <mem_hash>. Next session: read .claude/memory/ at startup.`
- **commit skipped (rc 3)** → keep the ✅ on the FLUSH but make the gap loud, never
buried: `✅ Context flushed — ⚠️ NOT committed (<reason: detached/merge/non-git>); entries safe on disk, commit manually.`
The ✅ covers the write (entries on disk); the ⚠️ marks the commit gap so it is
not read as "all committed".
The closing line matters — confirm the wipe is safe (default) or the session is
checkpointed (ritual), AND whether the memory was committed (5B) or left for a
manual commit (rc 3).
## Rules
- **Never invent.** Every entry grounded in this conversation or git history. No
fabricated "lessons" to fill the screen, no invented TODO subtasks.
- **Dedup before proposing.** Re-logging an existing entry is the #1 failure mode.
When in doubt, flag as `⚠ DUP?` and let the user decide. Dedup is semantic —
a reworded dup is still a dup. Applies to ritual answers too.
- **Append-only.** Never overwrite or renumber existing registry entries.
- **Caveman English** registry bodies, always English. **The TODO is plain
prose, never caveman** — caveman is registries-only.
- **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`.
- **Commit the flush (STEP 5B)** — content gate (STEP 3) first, then the commit of
approved entries is automated via `lib/capitalize-commit.md` (BDR-034 contract).
The journal always writes → memory is always pending at 5B, so a successful run
always produces a commit; only an unsafe git state (rc 3) skips it.
- **Skip trivial** for the 4 ID registries; journal excepted.
- `.claude/memory/` missing → STOP at STEP 0, do not create the structure here.
## Common mistakes
| Mistake | Fix |
|---------|-----|
| Proposing items already in the registries | STEP 2 dedup is mandatory. Grep keywords + read entries + journal `capitalized` lines first. |
| 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. |
| 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. |
| 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. |
| Folding push / tag / release / deploy into the TODO | Anti-noise filter. Those are systematic actions, not tracked work — drop them, even phrased as tasks. |
| 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
- **The STEP 3 gate STOP has never been exercised in test** (the build harness
was non-interactive — it printed the gate then proceeded as "all approved").
On the FIRST real run, confirm STEP 3 halts and waits for approval BEFORE any
file write. If anything is written before you answer, the gate is broken —
stop and fix it. This is the skill's #1 guarantee; it is currently unverified.
- About to append a registry entry without having grepped + read the registry
for it → dedup skipped.
- About to treat a reworded item as new without checking meaning → semantic
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)
Baseline (RED, 2026-06-19): a no-skill agent on a pressured fixture deduped
correctly (incl. a reworded semantic dup), routed an architecture directive to
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.
GREEN re-run on the same fixture confirmed: drops both dups (footer shows
existing IDs), logs jigsaw as ONE learning, checks only the cleanly-done task,
leaves the umbrella "harden" task unchecked, adds only the explicit README
to-do, ignores the push/tag parasite, routes the GraphQL directive to BDR.
**Caveat — gate not exercised:** the STEP 3 STOP itself was NOT tested. The
harness is non-interactive — GREEN printed the gate then proceeded as "all
approved", so the halt-before-write behavior is unverified. See the first
Red flag; confirm it on first real use.