| name | commit |
| owner | baseline |
| description | Workflow Phase 11 — Commit Preparation and Execution. Stages and commits the work. Requires `/grant-commit` first (Git Commit Guard enforces a 5-min consent window). |
| argument-hint | [optional commit message; otherwise drafted from the spec/intake] |
Prereq: ALL of archive AND memory-flush in completed (Phase 10.5 archives slug artifacts; Phase 10.6 curates _pending.md) AND a valid consent token at .claude/state/commit_consent (the Git Commit Guard hook enforces this independently). On any workflow where memory-flush is in exceptions (e.g. non-git projects auto-except it), this skill SHALL refuse to proceed unless that exception is explicit in workflow.json.
Applicability. This skill applies only when the project is a git repository. Non-git projects auto-except commit at /triage time (CLAUDE.md Article IV); the workflow ends after /archive.
Steps:
- Git-repo precheck. Run
git rev-parse --is-inside-work-tree 2>/dev/null. If exit non-zero, exit cleanly with: "Not a git repository — /commit is inapplicable. Per CLAUDE.md Article IV, commit is auto-excepted on non-git projects; the workflow ended at /archive. Persistence outside git is your responsibility." Do not run any subsequent step.
- Archive
workflow.json itself. This is the final piece of the archival bundle, held back until now so phase-ordering checks worked up through this point. Read .claude/state/workflow.json to get the slug, then move the file into the already-existing archive bundle: docs/archive/<date>/<slug>/workflow.json. Use the bundle's <date> directory (the one /archive created — inspect docs/archive/ to find the most recent bundle matching the slug).
- Verify workflow prereq: memory-flush is the final non-commit entry in
completed; archive is the entry immediately before it; no open consent gates remain.
2.5. Branch topology (Art. VII). Read git.workflow_model. If it resolves to an enforced model (direct-to-main / github-flow), the commit SHALL land on a branch the model permits — git_commit_guard blocks anything else (under direct-to-main, commit on a release_branches member; do NOT reflexively create a feature branch). If it resolves to ask (default), the guard passes on topology grounds and the branch decision is YOURS to surface: ask the user which branch this commit belongs on rather than improvising one. Never create/switch branches to satisfy a model the project did not declare.
2.7. Stamp closure pre-stage (only when populated). Read source_backlog_keys from the archived copy docs/archive/<date>/<slug>/workflow.json (Step 1 moved the live file). If the array is absent OR empty, skip this step (back-compat — unchanged commit behavior). Otherwise run node .claude/skills/memory-flush/sweep.mjs --mode stamp-closure --memory-dir .claude/memory --backlog-keys <comma-separated keys>. This writes status: picked-up + superseded-at: <today> to .claude/memory/backlog.md BEFORE staging, so the closure stamp rides THIS commit (atomic). sweep.mjs is the sole writer to backlog.md — never edit it directly, and never add a commit-SHA provenance note (atomicity forbids a self-referential SHA).
2.8. Epic-child fold — close the epic when this is its last child (only on an epic-child track). Read workflow.json → track_id; if it is not epic-child, skip this step. Otherwise, BEFORE staging, flip this child's entry in .claude/state/epic/<epic>.json → children[] to status: "committed" (this is the pre-commit flip — it must precede the all-committed check so the close can ride THIS commit; the harness post-commit flip is now only an idempotent backstop). Then invoke node .claude/skills/commit/epic_close.mjs <epic> (where <epic> is workflow.json → epic). The helper no-ops while any sibling child is still open; once this flip makes every child committed, it git mvs the epic's discovery bundle into docs/archive/<date>/<epic>/ (staged) and merges closed:true + closed_at into the epic state file. The staged bundle move then rides the SAME commit produced below — no separate consent gate. (Run outside the harness, the same helper is the standalone recovery path: it stages the move and prints a /grant-commit + /commit prompt.)
git status + git diff --stat to confirm the change set. The diff now includes: production code changes + archive bundle additions + the workflow.json move + (when Step 2.7 stamped) the backlog.md closure stamp + (when Step 2.8 closed an epic) the epic discovery-bundle move into docs/archive/<date>/<epic>/. Stage named paths explicitly (never git add -A / git add . — seed.md forbids it). When Step 2.7 stamped, include git add .claude/memory/backlog.md so the closure rides this commit.
- Draft the commit message from the spec + diff. Conventional-style prefix (
feat: / fix: / refactor: / docs: / test:) followed by a 1-line summary and a short body explaining the WHY. The subject line is a fixed-register one-liner — leave it alone. The body is reviewer-facing prose — pass it through Skill(humanizer) before step 5 so AI-writing tells (em-dash overuse, rule of three, inflated verbs, vague attributions) get scrubbed. Keep the brief tight: tell humanizer the register is "factual reviewer-facing commit body — describe the diff faithfully, do not invent rationale, preserve any spec quotes verbatim".
4.5. Closure preflight (only when Step 2.7 stamped). Write the staged path list with git diff --cached --name-only > .claude/state/.closure-staged and the drafted message to a temp file, then run node .claude/skills/commit/closure-precommit-check.mjs --memory-dir .claude/memory --backlog-keys <comma-separated keys> --staged-file .claude/state/.closure-staged --message-file <message temp>. Exit 0 → proceed. Exit 1 → ABORT before git commit: the JSON report names what is unstamped/unstaged or which Closes <key> line is unreconciled; fix it and retry. This is the friendly pre-guard check — git_commit_guard independently re-verifies the same atomicity at commit time and will hard-block a split.
- Run
git commit with the message via HEREDOC. The Git Commit Guard hook will verify consent AND the closure obligation (a staged closing workflow.json requires the staged backlog.md stamps in the same commit). If consent is missing/expired, stop and ask the user to run /grant-commit.
- Post-commit clean-tree report (replaces the old post-commit stamp). Run
git status --porcelain. Because Step 2.7 stamped and Step 3 staged backlog.md, the closure stamp is now IN the commit — expect a clean tree. Report closure committed in <SHA>; tree clean alongside the commit SHA, plus the stamped key count. If .claude/memory/backlog.md is still dirty, surface WARN: closure residue left uncommitted <path> — the stamp did not ride the commit and must be investigated (it should not happen with Steps 2.7 + 3).
- Do NOT run
git push, git commit --amend, or pass --no-verify/--no-gpg-sign unless the user explicitly named the operation in their current request.
- Append
"commit" to completed — but note this only matters for logs; the workflow.json is now in the archive and the live .claude/state/workflow.json no longer exists. Report the commit SHA to the user.