---
name: conventional-commits-changelog
description: Writes Conventional Commits from staged changes, splits mixed diffs into atomic commits, and generates changelogs and release notes from commit history with correct semantic versioning. Use when committing work, preparing a release, tagging a version, or when asked for a changelog, release notes or a "what changed" summary.
license: MIT
compatibility: Git repository. Optional - gh CLI for GitHub releases, and a version file (package.json, pyproject.toml, Cargo.toml) for bumps.
metadata:
  category: devops
  version: "1.0.0"
---

# Conventional Commits and Changelog

Commit messages are the only documentation guaranteed to survive. Write them so a release note can be generated from them and a future engineer can `git blame` a line and understand *why*.

## Part A — Committing

### 1. Inspect before writing
```bash
git status --short
git diff --staged            # what will be committed
git diff                     # what is not yet staged
git log --oneline -15        # match the repo's existing style and scopes
```
Check for a `commitlint` config, `.gitmessage`, `CONTRIBUTING.md` or `cliff.toml` — follow local rules over this skill when they conflict.

### 2. Split mixed changes
If the staged diff contains more than one logical change (a bug fix plus a refactor plus formatting), split it: `git add -p` for hunks, then commit each separately. Never bundle formatting with behaviour changes. Never commit generated files, secrets, `.env`, or debug logging.

### 3. Write the message

```
<type>(<scope>): <imperative summary, ≤72 chars, no trailing period>

<why this change, what was wrong before, what trade-off was made — wrapped at 72>

BREAKING CHANGE: <what breaks and the migration path>
Refs: #123
```

Types: `feat` (user-visible capability), `fix` (bug), `perf`, `refactor` (no behaviour change), `docs`, `test`, `build` (deps, build system), `ci`, `chore` (nothing else fits), `revert`.

Rules:
- Summary in imperative mood: "add retry to webhook delivery", not "added" or "adds".
- Scope is the module or package, consistent with history (`auth`, `billing`, `cli`).
- Body explains *why*; the diff already shows *what*. Skip the body only for trivial changes.
- `!` after the type/scope (`feat(api)!:`) plus a `BREAKING CHANGE:` footer for incompatible changes.
- Reference issues in footers, not in the summary.

### 4. Verify
```bash
git commit -F msg.txt
git log -1 --format=%B        # re-read it
npx commitlint --last          # if configured
```

## Part B — Releasing

### 1. Determine the version
From commits since the last tag (`git log $(git describe --tags --abbrev=0)..HEAD --format='%s%n%b'`):
- any `BREAKING CHANGE` or `!` → **major** (or minor while still 0.x, if the project follows that convention);
- any `feat` → **minor**;
- only `fix`/`perf`/others → **patch**.
Confirm the proposed version with the user before tagging.

### 2. Generate the changelog
Prefer an existing tool if configured (`git-cliff`, `conventional-changelog`, `changesets`, `release-please`, `semantic-release`). Otherwise produce this in `CHANGELOG.md`, newest first, Keep-a-Changelog style:

```
## [2.3.0] - 2026-09-01
### Breaking
- api: remove deprecated `/v1/users` endpoint; use `/v2/users` (#410)
### Added
- billing: support partial refunds (#402)
### Fixed
- auth: session cookie not refreshed on token rotation (#415)
### Performance
- ...
[2.3.0]: https://github.com/org/repo/compare/v2.2.1...v2.3.0
```

Group by type, drop `chore`/`ci`/`test` unless notable, link PR numbers, and rewrite entries in user language (what changed for them), not commit jargon.

### 3. Write release notes (for humans)
Above the changelog detail, add three to six sentences: the theme of the release, the one or two highlights, upgrade steps for breaking changes, and thanks to external contributors (`git shortlog -sn <range>`).

### 4. Cut the release
```bash
# bump version file(s) per ecosystem, then:
git commit -am "chore(release): v2.3.0"
git tag -a v2.3.0 -m "v2.3.0"
git push --follow-tags
gh release create v2.3.0 --title "v2.3.0" --notes-file RELEASE_NOTES.md
```
Only push and publish when the user has asked for it.

## Output format

For commits: the list of commits created (hash + summary). For releases: proposed version with reasoning, the changelog section, the release notes, and the exact commands run or proposed.

## Checklist

- [ ] One logical change per commit; formatting-only commits separate.
- [ ] Summary ≤72 chars, imperative, typed and scoped like the repo's history.
- [ ] Breaking changes flagged with `!` and a migration note.
- [ ] Version bump derived from commits and confirmed.
- [ ] Changelog entries readable by a user, linked to PRs.
- [ ] No secrets or generated artefacts committed.

## Pitfalls

- "fix: fix bug" and "chore: updates" are useless; if you cannot name the change, you do not understand it yet.
- Squash merges lose individual commits; write the PR title in Conventional format so the squash commit is correct.
- Do not rewrite public history (`--amend`, rebase) on shared branches to fix messages; add a follow-up commit.
- Changelogs copied straight from commit subjects read as noise; edit for the audience.
- Tagging before CI passes on the release commit ships broken versions.
