Skip to content

Commit Messages

Commit messages drive release behavior, changelogs, and audit search. Because merges are squash-only, the PR title becomes the commit on main; write PR titles and commit subjects with the same grammar.

Required format

type(optional-scope): short imperative subject
optional body that explains why
optional footer with refs, closes, incident ids, or breaking-change notes

Good one-line examples:

feat(profile): add language selector
fix(api): reject duplicate permit submissions
infra(argocd): add preview namespace controls
docs(gitops): clarify release tag promotion

The subject is mandatory. Use imperative present tense, lowercase unless a proper noun requires it, and no ending period.

Release impact

TypeUse forRelease impact
featNew user-visible behaviorMinor
fixBug fixPatch
securitySecurity hardening or vulnerability fixPatch
perfPerformance improvementPatch
feat!, fix!, security!Backward-incompatible changeMajor
docs, test, ci, style, chore, build, infra, refactorNon-product or internal workNone by itself
revertReverse a previous changeMatches reverted impact

Use ! or a BREAKING CHANGE: footer when callers, data, APIs, or operational behavior must change.

Write a body when context matters: motivation, previous behavior, user impact, rollout notes, migration notes, or rollback notes. The body should answer, “Why did this change need to happen?”

Use the footer for machine-readable references:

Refs: ADR-070
Closes: PROJ-2211
BREAKING CHANGE: API session token exchange now requires `aud`.

Do not put issue IDs in the scope. Use scopes for stable system areas such as auth, profile, api, ci, release-prod, or docs.

Full examples

feat(profile): add language selector
Allow residents to choose a portal language from the header.
Default remains English for compatibility with existing bookmarks.
Refs: ADR-070
Closes: PROJ-2211
feat(auth)!: migrate login flow to OIDC bearer assertions
The previous cookie-based session format is removed.
Clients must use the new token exchange endpoint before this release.
BREAKING CHANGE: API session token exchange now requires `aud` to match the target client id.
Refs: ADR-112
Closes: SEC-4412
infra(ci): tighten release pipeline timeout defaults
Lower the default timeout from 45m to 30m for LaunchPad dispatch jobs.
Retries remain in place for the same failure classes.
Refs: OPS-771

Exceptions

These generated Git forms are allowed:

chore: init
Merge branch 'branch-name'
Revert "reverted commit subject line"

Do not rewrite Git-generated merge or revert subjects into artificial Conventional Commits unless you are creating a normal human-authored commit.

Enforcement

Commit messages are enforced by the conventional-commits GitHub ruleset on all branches with no bypass actors. PR titles are checked by the central governance workflow because the squash commit uses the title.

Run or inspect the enforcement script at templates/governance/enforce-commit-messages.sh.

Terminal window
ORG=mdds bash templates/governance/enforce-commit-messages.sh

Review rule

If validation fails, fix the title or commit before merge. Do not bypass the grammar during incidents; emergency changes need good release metadata more than routine changes do.

See also