conventional-commits
Write, review, or fix git commit messages that follow the Conventional Commits 1.0.0 spec. Use when composing a commit message, squash/merge message, or PR title, when asked to lint or rewrite commit
SKILL.mdtemplate/.claude/skills/conventional-commits/SKILL.md
GitHubConventional Commits 1.0.0
Spec source: https://www.conventionalcommits.org/en/v1.0.0/ (licensed CC BY 3.0).
Message format
<type>[optional scope][!]: <description>
[optional body]
[optional footer(s)]
- Header (first line):
type, optional(scope), optional!, then a colon and a single space, then the description. - Body: optional, starts after exactly one blank line following the header. Free-form, any number of paragraphs.
- Footers: optional, start after one blank line following the body (or header if no body).
Rules (normative)
- The header MUST start with a type (a noun like
feat,fix), followed by optional scope, optional!, and a REQUIRED:(colon + space). - Use
featwhen the commit adds a new feature. - Use
fixwhen the commit fixes a bug. - A scope MAY follow the type, as a noun naming a part of the codebase, in parentheses:
fix(parser):. - The description MUST come immediately after
:and briefly summarize the change. - The body MAY be added and MUST begin one blank line after the description.
- The body is free-form; multiple newline-separated paragraphs are fine.
- One or more footers MAY follow one blank line after the body. Each footer is a word token, then
:or#, then a value (git-trailer style), e.g.Reviewed-by: Z,Refs #123. - Footer tokens MUST use
-instead of spaces (Acked-by). Exception:BREAKING CHANGEmay contain a space. - Footer values MAY contain spaces and newlines; a value ends when the next valid
token:/token #pair appears. - Breaking changes MUST be marked either with
!in the header or with a footer. - A breaking-change footer MUST be uppercase
BREAKING CHANGE: <description>. - With
!(placed right before the:), the footer MAY be omitted; the header description then describes the break. - Other types beyond
feat/fixMAY be used. - Parsers MUST treat all elements as case-insensitive, except
BREAKING CHANGE, which MUST be uppercase. BREAKING-CHANGEis equivalent toBREAKING CHANGEas a footer token.
Common types
Only feat and fix are defined by the spec. The widely used set (from @commitlint/config-conventional, Angular convention):
| Type | Use for |
|---|---|
feat |
New user-facing feature |
fix |
Bug fix |
docs |
Documentation only |
style |
Formatting, whitespace, semicolons — no behavior change |
refactor |
Code change that neither fixes a bug nor adds a feature |
perf |
Performance improvement |
test |
Adding or correcting tests |
build |
Build system or external dependencies |
ci |
CI configuration and scripts |
chore |
Maintenance that doesn't touch src or tests |
revert |
Reverting previous commit(s) |
If the repo has its own config (commitlint.config.*, .commitlintrc*, .czrc, package.json → commitlint/config.commitizen, release-please, semantic-release config), follow its allowed types and scopes over this table. Also check git log --oneline -20 to match existing scope names and casing.
SemVer mapping
fix→ PATCHfeat→ MINOR- Any commit with
!or aBREAKING CHANGEfooter, regardless of type → MAJOR - Other types → no release on their own (unless breaking)
To compute a bump over a range, take the highest of these across all commits.
How to write a message
- Inspect the change (
git diff --staged, or the diff provided). - If it mixes unrelated concerns (e.g. a feature plus an unrelated fix), recommend splitting into separate commits rather than picking one type.
- Pick the type by intent, not by file: a bug fix in docs tooling is
fix, a typo fix in README isdocs. - Add a scope only if it adds clarity and matches the repo's existing scopes.
- Description: imperative mood ("add", not "added"/"adds"), lowercase start, no trailing period, aim for ≤ 72 chars in the full header. (These are conventions, not spec requirements — defer to the repo's style.)
- Body: explain what and why, not how; wrap at ~72 columns.
- If any public API or behavior changes incompatibly, mark it: add
!and/or aBREAKING CHANGE:footer explaining what breaks and how to migrate. - Reference issues in footers:
Refs: #123,Closes #45.
How to review/lint a message
Check in order and report each violation with a corrected version:
- Header matches
^[a-zA-Z]+(\([^()\r\n]+\))?!?: \S.*$ - Exactly one blank line between header and body, and between body and footers
- Footer tokens are hyphenated (except
BREAKING CHANGE) and use:or# BREAKING CHANGEis uppercase;!sits directly before:- Type is in the repo's allowed list (or the common list above)
- Type matches the actual change (e.g. a new capability labeled
fixshould befeat)
Examples
Breaking change via footer:
feat: allow provided config object to extend other configs
BREAKING CHANGE: `extends` key in config file is now used for extending other config files
Breaking change via ! with scope:
feat(api)!: send an email to the customer when a product is shipped
Both ! and footer:
feat!: drop support for Node 6
BREAKING CHANGE: use JavaScript features not available in Node 6.
No body:
docs: correct spelling of CHANGELOG
Multi-paragraph body and multiple footers:
fix: prevent racing of requests
Introduce a request id and a reference to latest request. Dismiss
incoming responses other than from latest request.
Remove timeouts which were used to mitigate the racing issue but are
obsolete now.
Reviewed-by: Z
Refs: #123
Revert (spec suggests, doesn't mandate):
revert: let us never again speak of the noodle incident
Refs: 676104e, a215868
Edge cases (from the spec FAQ)
- Early development: write commits as if already released — someone is consuming the changes.
- Type casing: any case works; be consistent (lowercase is the norm).
- Wrong type used, not yet merged/released: fix with
git rebase -i(reword). Never rewrite history that's already pushed to a shared branch without the user's explicit OK. - Non-spec type (typo like
feet): not fatal, but tooling will ignore that commit. - Squash workflows: only the final squash/merge message needs to conform; PR titles often become that message, so apply the same format to PR titles.
- Reverts: not defined by the spec; use
revert:with aRefs:footer listing SHAs unless the repo's tooling says otherwise.