Conventional Commits
Conventional Commits is a specification for git commit messages that makes history machine-readable and human-scannable. The format:
<type>(<optional scope>): <subject>
<optional body>
<optional footer(s)>
Example: fix(parser): handle captions with no timestamps
Why the format exists
A git log is the only complete history a project has, and free-form messages (“fixed stuff”, “wip”) make it write-only. With typed commits:
git log --onelinebecomes scannable — you can see at a glance which commits changed behavior vs. housekeeping.- Changelogs generate themselves — tooling groups
feat:andfix:commits into release notes. - Version bumps can be automated (semantic versioning):
fix:→ patch release,feat:→ minor,BREAKING CHANGE→ major. - Reviewers and future debuggers can filter: “show me every
fix:touching the parser this month.”
The types
The two the spec defines, plus the conventional extended set:
| Type | Means | Version signal |
|---|---|---|
feat | New capability visible to users of the code | minor |
fix | Corrects wrong behavior | patch |
docs | Documentation only | — |
refactor | Restructures code, behavior identical | — |
test | Adds or fixes tests only | — |
chore | Maintenance that touches no production code behavior: dependency bumps, config, tooling, cleanup | — |
build / ci | Build system / CI pipeline changes | — |
perf | Performance improvement (behavior same, faster) | patch |
style | Formatting, whitespace — no logic change | — |
chore vs fix vs refactor — the common confusion: if user-visible
behavior was wrong and now is right → fix. If behavior is unchanged but the
code is structured differently → refactor. If no production code changed at
all (deps, configs, housekeeping) → chore.
Subject-line rules
- Imperative mood: “add retry logic”, not “added” or “adds” — read it as “if applied, this commit will add retry logic”.
- Keep it ≈50 characters (hard ceiling ~72); no trailing period.
- The scope in parentheses names the area touched:
feat(auth):,chore(deps):. Optional; use it when the repo is big enough to need it.
Body and footers
- The body explains why, not what — the diff already shows what.
BREAKING CHANGE: <description>in the footer (or!after the type:feat!:) marks a compatibility break → major version bump.- Footers carry structured trailers:
Fixes #42,Co-Authored-By: ....
Good and bad, side by side
BAD: update stuff
BAD: Fixed the bug where it crashed sometimes.
GOOD: fix(fetch): handle videos with no caption tracks
BAD: changes to README and also retry logic and tests
GOOD: feat(client): retry failed requests with backoff
(separate commit) docs: document retry behavior
One logical change per commit — if the subject needs “and”, split it.
Ecosystem
The spec: conventionalcommits.org. Enforcement/automation tooling:
commitlint (lints messages in CI or a git hook), semantic-release /
release-please (automate versioned releases from the commit stream).
[!note] In your repos (internal — remove this section before sharing) House style adds an agent tag before the type:
[CASE] feat(scope): subject. Every agent (CASE, TARS, Friday, Sheldon, KIPP) commits as the same git author, so the bracket tag is the only attribution that exists —git blamecan’t tell agents apart without it. Claude Code commits also carry aCo-Authored-By: Claude ...footer — a standard trailer marking machine co-authorship.