Commit
How to use
Use this when you are ready to commit your changes.
Prompt
Produce the smallest valid Conventional Commit sequence from staged changes. One intent per commit. Every intermediate tree must be valid.
CRITICAL CONSTRAINTS (FAIL-CLOSED)
- Pre-
YES: read-only. No git write operations. YESin the same session authorises the latest proposal only.- NEVER: amend, rebase, push,
git commit -a, bypass hooks, or touch unstaged hunks. - STOP on conflicts or an active Git operation.
1. Evidence
Run once. Do not repeat.
git -c core.quotePath=false status --short --untracked-files=no
git -c core.quotePath=false diff --staged --name-status
git -c core.quotePath=false diff --staged --numstat
git log -n 20 --pretty=format:%s
git diff --staged --binary --no-ext-diff --no-textconv | git hash-object --stdinLast hash = proposal fingerprint.
Gate: staging area is empty → STOP: staging area is empty. Do nothing else.
Read history for style reference only; do not generate commits from it.
Account every staged path. No full diff by default. Per text path:
git -c core.quotePath=false diff --staged --no-ext-diff --no-textconv --unified=3 -- '<path>' | sed -n '1,300p'Gate: read the next 300 lines only if the slice is truncated AND at least one of: diff contains BREAKING CHANGE, path name matches auth|crypto|secret|token|key, or intent cannot be determined from the first 300 lines.
Binary/generated/snapshot/lockfiles: metadata only.
2. Atomicity
Split by intent, never by directory. Keep implementation with its required tests, migrations, generated files, and lockfiles. Order: producer before consumer, only when the consumer compiles against the produced artefact in the same commit. Each path appears in exactly one commit.
Gate: auto-split only when all three hold: (a) all paths are fully staged, (b) no unstaged hunks in any listed path, (c) one clear intent per path. If any condition fails: list all paths, label those without a clear group as UNCLASSIFIED, output Verification: N/N staged paths accounted for, then STOP and request a manual grouping decision.
Multiple commits: use ordered messages with shell-quoted paths. Output Verification: N/N staged paths accounted for.
3. Message
Format: <type>(<scope>): <subject> or <type>: <subject>.
Mandatory
- Type: MUST be one of:
feat|fix|docs|refactor|perf|test|build|ci|chore|style|revert. - Subject: Imperative mood, lowercase start, ≤60 characters, no trailing period.
- Content: Behaviour and user-facing rationale only. No file list. No implementation mechanics. Staged facts only.
- Breaking change: MUST use
!suffix AND includeBREAKING CHANGE: <impact and migration>as a body footer. - Body: MANDATORY (never subject-only) for: breaking changes, security fixes, data migrations, reverts.
Scope
Gate 1: Run ls pnpm-workspace.yaml 2>/dev/null || grep '"workspaces"' package.json 2>/dev/null. If output is non-empty → monorepo mode:
- Scope = workspace directory name (
packages/ui→ui,sites/prompts-library→prompts-library,tools/repo-manager→repo-manager). - Use
repofor repository-root configs, global workflows, or multi-workspace changes.
Gate 2: Else run ls src/modules/ 2>/dev/null || ls src/domain/ 2>/dev/null. If output is non-empty → DDD mode:
- Scope = bounded context / domain name (e.g.
auth,billing,cart,catalog,customer).
Gate 3: Else → architectural layer mode:
- Scope = layer or subsystem (e.g.
api,ui,db,cli,config,middleware). - Cross-cutting / infra:
deps,ci,test,security,perf,i18n.
Omit scope only when the change is cross-cutting across all applicable scopes simultaneously.
Body & Footers
- Body: REQUIRED for breaking changes, security fixes, data migrations, reverts. Use only when motivation cannot fit in the subject line.
- Use bullet points starting with
-; each bullet ≤72 characters, one line. - Footers: issue references (
Closes #123),BREAKING CHANGE:note.
Prohibited
This commit does X,I,we,now,currently— the diff says what.As requested by …— useCo-authored-by:trailer instead.- AI attribution of any kind.
- Emoji.
- The file name when the scope already names it.
Examples: @.agents/skills/cebreus-commit/COMMIT-EXAMPLES.md
4. Output
Return one separate bash block per proposed commit. No prose before the first block.
Rules:
- Start every block:
# Commit N/M — <message>. - Use literal paths/messages only. No placeholders.
- Each block: list paths, then multi-line command:
git add -- \, one shell-quoted path per line,&& \, thengit commit -m '<message>'. - For multiple commits: put
git restore --staged -- <all-paths>at the start of the first block only. - Commands must exactly match proposed paths/messages. Preview only; execute only after
YES.
Required multi-commit shape:
# Commit 1/2 — feat(cli): add review command
git restore --staged -- 'src/cli/review.ts' 'tests/cli/review.test.ts' 'docs/review.md'
git add -- \
'src/cli/review.ts' \
'tests/cli/review.test.ts' && \
git commit -m 'feat(cli): add review command'# Commit 2/2 — docs: document review command
git add -- \
'docs/review.md' && \
git commit -m 'docs: document review command'End only with:
Commit this proposal? YES / NO / EDIT
5. Confirm
Gate: YES — do not rerun Evidence or show another proposal. Use exactly one shell invocation: check for an active Git operation, compare the current staged fingerprint with the proposal fingerprint, then execute the approved commit commands. Never invoke a standalone safety/hash command first. A mismatch stops with no commit and requires a new proposal/YES. For multiple groups: unstage all proposed paths once, then stage and commit groups in order. Run hooks; report hashes/subjects.
Gate: NO → Cancelled. Stop.
Gate: EDIT → ask for the change. Stop.
Gate: other → repeat choices. Stop.
Failure: report state. Stop. Never bypass hooks.
Attachments
# Commit Message Examples
## Regular commit with body
❌ `feat: added a new endpoint to get user profile information from the database`
— past tense, verbose, no scope
✅
```
feat(api): add GET /users/:id/profile
- Fetch minimal profile payload to cut cold-launch bandwidth
Closes #128
```
## Breaking change
❌ `fix(auth): fix login` — breaking change hidden, no body
✅
```
fix(auth)!: reject tokens signed before the key rotation
- Invalidate legacy tokens to block replay attacks after key compromise
BREAKING CHANGE: sessions issued before 2026-08-01 stop working.
Clients must re-authenticate; there is no migration path.
```
## Scope selection
❌ `fix: update packages/ui/src/button.ts` — file path in message
✅ `fix(ui): correct focus ring on Button in high-contrast mode`
## Monorepo multi-package change
❌ `chore: update configs` — no scope, vague subject
✅
```
chore(repo): align ESLint configs across all workspaces
- Centralise ESLint rules in root to eliminate workspace drift
- Remove local overrides so all packages share identical quality gates
```