ADR-0033: Write commit messages as Conventional Commits, checked in pull requests
Proposed
Status: proposed · 2026-11-04
Context
The history mixes styles: most commits are plain sentences ("Plan the vault with agent skills through the vault tools"), a few use a type prefix ("feat: add checkModel configuration …"). Nothing says which is right, so neither humans nor agents can rely on it. A typed history can be read at a glance (what was a fix, what only touched docs or CI) and is what release tooling such as nx release reads to write changelogs and pick versions.
Decision
- Every commit message is a Conventional Commit:
type(scope): subject, an optional body, optional footers. - Types:
feat(a new ability for the user),fix(a bug fix),docs,refactor,perf,test,build(dependencies, Nx, packaging),ci,chore,styleandrevert. - The scope is optional and names the Nx project the change is about (
domain,application,adapter-ollama,cli,docs, …). A change across projects leaves it out. - The subject is imperative, starts lower-case, has no full stop, and the header stays within 100 characters. The body says why, in prose.
- A breaking change adds
!after the type or scope and aBREAKING CHANGE:footer saying what the user must do. - CI enforces it: on every pull request,
commitlint(with@commitlint/config-conventionaland the type list above, incommitlint.config.mjs) checks each commit between the base and the head, and fails the run on a bad message. There is no local hook;npx commitlint --from origin/mainchecks a branch before it is pushed. - Commits already on
mainare not rewritten.
Consequences
- The type of each change is visible in
git log --oneline, andnx releasecan derive changelogs and versions later without a new convention. - A pull request with a badly worded commit fails until the commit is reworded, which means rewriting the branch's history and force-pushing it.
- Agents working in the repository read the rule from
CLAUDE.mdandAGENTS.md. @commitlint/cliand@commitlint/config-conventionaljoin the root dev dependencies.