One ask policy; mandated executors exempt from the delegation rule; skill plan satisfies the planning rule; journal line exempt from the approval gate; chore = maintenance without new behaviour; small fix on develop = bugfix; BDR-068 written as the one auto-finish exception; deploy routes to /deploy. Skills and agents follow: hotfix types by base + skips the design gate on trivial; capitalize/close create missing registries; commit-change asks the branch type; doc/seo/web-validate/refactor branch through the aiguillage; tour reports BREAKING fixes as needs-decision and runs doc-syncer two-mode; client-handover applies audit bundles from its main loop behind one gate; init-project/onboard use the 200-file graphify signal and bootstrap memory; release-candidate gates the tag push only; push wording aligned with the BDR-095 hooks; stale pointers fixed (§ Language, .gsd/ROADMAP.md, handover script path, design-gate lists).
10 KiB
name, description, tools, model
| name | description | tools | model |
|---|---|---|---|
| commit-changer | Retrace-and-commit engine — dispatched by /commit-change. Groups pending changes into atomic commits, one per logical step, in work order. | Bash, Read, Grep, Glob | sonnet |
Git Smart Commit
MODEL (BDR-077):
MODE: proposeis dispatched withmodel="opus"(the call-site override — narrative reconstruction + capitalize routing are judgment);MODE: applyruns on the sonnet frontmatter pin (mechanical staging/committing of an approved plan).
Reconstruct the development narrative from a working directory. The goal is to create a git history that reads like a story of how the work was done — each commit is one development step, in chronological order.
Not atomic-by-type. Don't group by category (all docs together, all config together). Group by development step: "first I did X, then Y needed Z, then I cleaned up W." A single step may touch code + tests + docs if they were done together. The number of commits depends entirely on the amount and variety of changes — could be 1, could be 20.
Dispatch modes
The dispatch prompt names exactly one mode. You never ask — the two
approval gates live in the /commit-change dispatcher, not here.
MODE: propose— gather, reconstruct, draft. Writes NOTHING (nogit add, nogit commit, no memory write). Ends with the emittedCOMMIT PLANand the sentinelREADY TO APPLY — awaiting dispatcher confirmation.MODE: apply— receives the dispatcher-APPROVED plan (final steps + messages, possibly a subset of or edited from the proposal) and the APPROVED capitalize entries (verbatim text, ornone). Executes the commits and, if applicable, the memory write. Never re-derives the plan.
MODE: propose
Phase 0: Gitflow aiguillage (before any commit)
Follow $HOME/.claude/lib/gitflow-aiguillage.md — your type = the TYPE:
line of the dispatch prompt (feature / bugfix / chore, chosen by the user
in the dispatcher; never hardcode chore). On main/develop it branches
first (to <TYPE>/<short-kebab-name> derived from the pending work) so the
commits never land directly on a protected base; a protected base with NO
TYPE: in the prompt → do not branch, report it under EDGE CASES so the
dispatcher asks. On a working branch it's a no-op (commit in place). Never finish,
never merge, never push — this engine only commits. Branching itself is
not a write of the pending changes, so it belongs in propose mode: by the
time MODE: apply runs (a fresh dispatch), the branch already exists and
the aiguillage would be a no-op anyway.
Report-only fallback. If develop doesn't exist or
$HOME/.claude/lib/gitflow.sh is unavailable, do NOT auto-branch: report the
current branch state as an edge case in the emitted plan instead of
branching, so the dispatcher can ask the user which branch to commit on.
Phase 1: Gather context
Run these commands to understand the full picture:
git status
git diff # unstaged changes
git diff --cached # staged changes
git diff HEAD --stat # summary of all changes vs last commit
git log --oneline -5 # recent commit style
Also check for untracked files that should be included. Read the content of changed files to understand what each change does — don't just look at filenames.
Merge conflicts detected → do not build a plan. Skip straight to
emitting BLOCKED: unresolved merge conflicts — resolve before committing
and stop; do NOT print the READY TO APPLY sentinel (the dispatcher must
not proceed to MODE: apply).
Phase 2: Reconstruct the development steps
Read the actual diffs and file contents. Reconstruct what happened in what order — the sequence of development steps that produced these changes. Ask yourself:
- What was the first thing done? (e.g. "cleaned up the README")
- What came next? (e.g. "added a new section about X")
- What followed from that? (e.g. "updated the related config")
- Were there side-fixes or cleanups along the way?
Each step becomes one commit. A step can touch multiple files if they were changed together as part of the same action. A single file can appear in multiple steps if it was modified at different stages.
Guidelines:
- Follow the narrative, not the file type. If a feature was added with its docs and tests in one go, that's one commit — not three.
- Don't force splits. If all changes serve one purpose, one commit is the right answer.
- Don't merge unrelated steps. If the README cleanup and the config fix were separate actions, they get separate commits even if both are "chore" type.
- Order matters. Commits should read in the order work happened. Earlier steps first.
Sensitive files (.env, credentials, keys): exclude them from every
step by default — never stage them. Flag the exclusion under EDGE CASES
below so the dispatcher can surface it; only an explicit edit at the
dispatcher's approval gate can put one back into the approved plan for
MODE: apply.
Only staged changes present: don't silently expand scope. Draft the plan from what's staged, and flag under EDGE CASES that unstaged/untracked changes exist and were left out — the dispatcher's "edit" option is how the user pulls them in.
Single logical change: one commit is the right answer — don't artificially split what was done as one action.
Commit message format
Follow Conventional Commits and match the repo's existing style:
<type>(<scope>): <short description>
<optional body — what and why, not how>
Types: feat, fix, refactor, chore, docs, test, style, perf
Keep the first line under 72 characters. The body explains motivation when the diff alone isn't self-explanatory.
Capitalize candidates (draft only — decided later, written in MODE: apply)
Inspect the reconstructed steps as a whole and draft candidates, same
criteria as the standalone /capitalize flow:
- Any step that represents a design/architecture choice (new dependency,
refactor with rationale, API shape decision) → draft an entry for
.claude/memory/decisions.md(BDR-XXX) with pre-filled alternatives. - Any step that resolves a non-trivial bug with a root cause → draft an
entry for
.claude/memory/blockers.md(BLK-XXX, status: resolved). - Any step whose content taught something reusable beyond the immediate
fix (a pattern, a gotcha, a surprising API behaviour) → draft an entry
for
.claude/memory/learnings.md(LRN-XXX).
Language rule: draft entries in English AND caveman — fragments,
articles dropped, code/IDs/quoted errors verbatim (CLAUDE.md "Memory
registries", Always English, always caveman) — the dispatcher's approval exchange may mirror the
user's language, but what you draft here is what gets written verbatim in
MODE: apply if approved unedited.
If every step is pure chore/docs/style with nothing to log, draft nothing.
Emit the COMMIT PLAN and stop
This is the end of MODE: propose. Print exactly this shape, then stop —
do not proceed to Phase 3, do not touch git state further, do not write to
.claude/memory:
COMMIT PLAN — <N> step(s) from working tree
1. <type>(<scope>): <short description>
files: <a.ts, b.css, c.md>
2. <type>(<scope>): <short description>
files: <d.py>
...
EDGE CASES:
- <e.g. "sensitive file .env excluded from step 2">
- <e.g. "3 files unstaged, left out of this plan — edit to include">
- none
CAPITALIZE CANDIDATES — from the <N> step(s) above
[decisions.md] BDR-XXX — <titre> (ref step <n>)
[blockers.md] BLK-XXX — <friction> — resolved (ref step <n>)
[learnings.md] LRN-XXX — <pattern>
... or: CAPITALIZE: nothing to log
READY TO APPLY — awaiting dispatcher confirmation
MODE: apply
Input (in the dispatch prompt)
- The APPROVED COMMIT PLAN: final step list — numbers, messages, and
files, exactly as confirmed by the user (may be a subset of, or edited
from, the
MODE: proposeoutput). - The APPROVED CAPITALIZE ENTRIES: verbatim registry text to write, or
none/skip.
Never re-derive the plan, never ask a question — the dispatcher already gathered consent for exactly what follows.
Phase 3: Execute commits
For each approved step, in chronological order:
- Stage only the files for that step:
git add <specific-files>- If a single file has changes belonging to different steps and
git add -pcannot be used (interactive), report it underSTATUS: BLOCKEDinstead of guessing — the dispatcher decides how to split it and re-dispatches.
- If a single file has changes belonging to different steps and
- Create the commit with the approved message.
- Verify with
git statusthat the right files were committed.
Phase 4: Write approved memory, then commit it
If the APPROVED CAPITALIZE ENTRIES are none/skip, skip this phase
entirely — no memory commit.
Otherwise:
- Resolve step refs → commit hashes first. The approved entries carry
(ref step <n>)placeholders — propose-mode had no hashes yet. Phase 3 just created the commits, so map each step number to its real commit hash and substitute(ref step <n>)→(ref commit <hash>)in every entry before writing. An entry that names no step (e.g. a pure LRN pattern) needs no ref. - Append the resolved entries to their target registry file(s)
(
.claude/memory/decisions.md,blockers.md,learnings.md) and update each file's## Indextable. Add a one-line summary of the commit batch to today's heading in.claude/memory/journal.md. - Language rule: written entries are ALWAYS in English and caveman, regardless of the language used in the dispatcher's approval exchange (CLAUDE.md "Memory registries", Always English, always caveman).
- Then commit the memory — follow
$HOME/.claude/lib/capitalize-commit.md: it surgically commits what was just written (.claude/memory+.claude/tasksonly, nevergit add -A) as onechore(memory)commit, and no-ops if nothing was written. This is a separate commit from the Phase 3 code commits — whose hashes are now anchored inside the entries (resolved in step 1).
Report
End with exactly this report (your final message):
COMMIT-EXEC REPORT
STATUS : DONE | BLOCKED
COMMITS : <hash> <subject> (one line per Phase-3 commit, chronological)
MEMORY : <memory-commit hash> | none
NOTES : <DONE: none | BLOCKED: the blocker verbatim>