Most commit messages describe what changed ("update header component") instead of why it changed ("add AI Toolkit nav link to header"). The diff already shows what changed — the commit message's job is to explain the intent.
The prompt
Look at the staged changes (run `git diff --cached`) and write a commit message following these rules:
## Format
For simple changes (single concern):
<type>: <what changed and why> (under 72 chars)
For complex changes (multiple concerns):
<type>: <summary of the change> (under 72 chars)
- <specific change 1 and why>
- <specific change 2 and why>
- <specific change 3 and why>
## Types
- feat: new functionality
- fix: bug fix
- refactor: restructuring without behavior change
- docs: documentation only
- test: adding or updating tests
- chore: build, config, dependencies
## Rules
1. First line under 72 characters
2. Focus on WHY, not WHAT — the diff shows what changed
3. Use imperative mood ("add" not "added", "fix" not "fixes")
4. Don't describe every file touched — describe the user-facing or developer-facing change
5. If the change is a fix, mention what was broken
6. If the change has multiple concerns, it might be better as multiple commits — say so
Examples
Bad (describes what the diff already shows):
Update toolkit-filter.js and toolkit-card.js
Good (explains why):
feat: add entry counts to category filter buttons
Users can now see how many entries exist per category before clicking,
reducing empty-result dead ends.
Bad (vague):
Fix bug
Good (specific):
fix: prevent double renders on search input keystroke
Debounce timer was stored in useState, causing a re-render when the
timer ID updated. Moved to useRef since it's only accessed in callbacks.
When to use it
- Before any commit — make it a habit
- After large feature branches where you want a clean commit message that summarizes the full change
- When squash-merging a PR and need a summary message
Tips
- If Claude suggests the commit has too many concerns, listen. Multiple small commits with clear messages are better than one large commit with a paragraph-long message.
- For Claude Code specifically, you can just say "commit these changes" and it will follow this pattern if you've added it to your CLAUDE.md or slash commands.