Skip to content

Conventional Commits & AI Coding: A Trending Critique, Explained

Conventional Commits encourages focus on the wrong things, says a viral post. Here's what it means for your AI coding workflow - and how to fix CLAUDE.md.

8 min readBeginner

The number one mistake people are making with the trending Conventional Commits debate: arguing about whether feat: or refactor: is the right prefix, instead of asking whether the prefix matters at all. A post from Sumner Evans titled Stop Using Conventional Commits blew up on Hacker News in early 2025, and the comment section is split down the middle. If you use Claude Code, Copilot, Cursor, or any AI assistant that writes your commit messages, this is your problem now – whether you wanted it or not.

Here’s the part most write-ups missed. Evans points out that Conventional Commits has become popular enough that AIs default to it for commit messages, propagating anti-pattern-ridden commit messages across projects that never opted into the format. The critique isn’t academic anymore. It’s a prompt-engineering issue baked into your tooling defaults.

The trending claim, in one paragraph

Evans’ argument: the format puts type before scope, which is exactly backwards. Scope – the subject of the change – is what actually orients a reader. Per the official spec (v1.0.0, current as of mid-2025), the structure is <type>[optional scope]: <description>. Note the word optional. Evans is blunt about it: a commit without a scope is like a sentence without a subject, yet the spec treats scope as decoration while fix: or feat: is required – even though those types are usually obvious from the description anyway.

The top HN comment thread (January 2025) goes further: the only thing actually missing from most commits is a link or ID to the relevant change request – the context about why. Conventional Commits doesn’t require that. It requires a category prefix.

Why existing advice falls short

Every other tutorial on this trend tells you the same three things: pick a type, write in imperative mood, keep commits atomic. Useful, but it dodges the real issue. Most of those guides also miss a quiet fact buried in the spec.

Only fix and feat are formally defined by the spec itself – everything else (chore, refactor, docs, style) comes from commitlint’s defaults, not from conventionalcommits.org. So when you and a teammate argue whether something is a chore or a refactor, you’re arguing about a third-party convention, not the standard. That’s real cognitive overhead for a tag the description usually makes obvious anyway.

There’s a second gap nobody flags during setup. Changelogs are mainly for users of the software – they care about what changed for them. Commit messages serve developers – they care about why the code moved. Auto-generating a changelog from feat: lines conflates the two audiences (this argument appears in detail at beyermatthias.de). Developer-facing artifacts repurposed as user-facing artifacts is a category error, and it’s baked into the standard setup.

The recommended approach: stop arguing, configure your AI

If an AI writes most of your commits now, the debate moves into your config file. Here’s a pragmatic stance that takes the critique seriously without throwing out tooling that already works.

  1. Make scope mandatory in your CLAUDE.md, not optional. Evans’ core complaint disappears if scope is required. One line in your config file, done.
  2. Cut types down to feat, fix, and chore. The spec formally defines only feat (maps to MINOR) and fix (maps to PATCH). chore is a pragmatic addition for housekeeping – keep it, but drop refactor, docs, style, and the rest. You’re eliminating the arguments, not the format.
  3. Require a body that answers why, with an issue link. The Hacker News consensus: missing context, not missing classification, is the real problem with most commit histories.
  4. Decide on co-authorship before you turn on auto-commit. See the note below – this one bites teams silently.

A minimal CLAUDE.md block that implements this:

## Commit conventions
- Format: type(scope): description
- type: ONLY one of feat, fix, or chore. Never refactor, never docs, never style.
- scope: REQUIRED. Use the directory or module touched (e.g. auth, billing/api).
- description: imperative, < 60 chars, no period.
- Body: REQUIRED for any non-trivial change. Explain WHY.
 End body with "Refs: #issue-number" when applicable.
- Breaking changes: add "BREAKING CHANGE:" footer with migration notes.
- Do NOT add Co-Authored-By trailers (our commitlint rejects them).

The point isn’t that this is the One True Format. The point is that you’ve made the actual decisions – scope priority, type minimalism, why-not-what – instead of letting Anthropic’s defaults make them for you.

Note on Co-Authored-By trailers: Claude Code adds a Co-Authored-By: Claude trailer by default (behavior as of mid-2025). Per the DeployHQ writeup on Claude Code git workflow, strict commit conventions may not accommodate those attribution lines – the extra text can conflict with tooling that parses commit messages. If you run commitlint with a footer-tokens rule, those trailers will fail CI. Decide once: allow them and add Co-Authored-By to your commitlint footer whitelist, or tell Claude in CLAUDE.md to skip them entirely.

A real example: the same change, three ways

You fixed a bug where namespaced SVG <style> elements were being stripped by the compiler. Here’s how the same commit looks under three regimes.

Default AI output (Conventional Commits, type-first):

fix: prevent SVG style elements from being stripped

Evans-style (scope-first, prose):

compiler: stop stripping namespaced SVG <style> elements

The pragmatic middle, with the why:

fix(compiler): preserve namespaced SVG <style> elements

The SVG sanitizer was treating xmlns-prefixed style nodes as
unknown and dropping them. Production users hit this when
embedding inline SVG icons from Figma exports.

Refs: #4821

The third one survives git log --oneline, gives a maintainer the why on the second line, and still bumps SemVer correctly. That’s what most teams actually want.

But here’s an open question the debate hasn’t really answered: when AI agents write dozens of checkpoint commits per session, is commit history even the right artifact to care about anymore? Maybe the unit of communication shifts to the PR description – and commits become scaffolding you collapse before merge rather than a log you read later. That framing changes what “good commit discipline” means entirely.

Pro tips the trending discussion exposed

A few things the debate surfaced that don’t fit neatly into the format-vs-no-format argument:

Commit granularity is the real upstream problem. Per a Lobsters thread on the topic, a single feature often spans multiple commits and a single commit might touch more than one thing – so the commit-to-changelog mapping was always broken, independent of prefix format. If your AI auto-commits per file edit, you’ve already lost the granularity battle. Squash before merge, or use Claude’s Stop hook instead of PostToolUse for the commit step.

Repo context beats general rules. Tell the model what matters in this specific repo, not what matters in general. CLI repo? Scope is the subcommand. Monorepo? Scope is the package. Don’t let Claude guess – it will guess “conventional commits defaults” every time.

Generate release notes from PRs, not commits. PR descriptions already speak the user’s language. Commits speak the developer’s language. Use the right artifact for each audience. Audit your last 50 AI-written commits: count how many have a meaningful scope and a body explaining why. That number is your real signal.

So is Conventional Commits actually wrong?

Honestly, the spec isn’t the villain. The defaults are. The spec gives you optional scope, optional body, optional footer, two required types – and then AI tooling fills the gaps with whatever’s most common in its training data. That’s how a format meant to be minimal becomes a noisy ritual.

The takeaway from the trending post isn’t “delete commitlint”. It’s that the prefix war is a distraction from the question that matters: does your commit history tell the next engineer why the code looks the way it does?

FAQ

Should I rip Conventional Commits out of my project this week?

No. Churning your team’s workflow costs more than suboptimal prefixes.

My team uses semantic-release. Doesn’t that force me to keep type-first commits?

Yes, and that’s the genuine constraint behind the format’s stickiness. If you ship via semantic-release, you need feat: and fix: for version bumps to work. The compromise: keep those two prefixes for tooling, but make scope mandatory in your CLAUDE.md and require a body that answers why. You get the SemVer automation without the “is this a chore or a refactor” arguments that eat 10 minutes per PR review.

What about commits Claude makes in agent mode while it’s iterating?

Those are checkpoints, not communication. A common workaround (not officially documented, but widely used as of early 2025): let Claude use wip: messages during the loop, then ask it to interactive-rebase and rewrite history before you push. Keeps your main branch readable without interrupting the agent mid-task.

Next action: open your project’s CLAUDE.md (or .cursorrules, or Copilot instructions file). Find the commit section. If scope is optional, make it required. If you allow more than three types, cut it to feat, fix, chore. Commit that change with a meaningful body. That’s the whole tutorial.