Generates and maintains CHANGELOG.md files following Keep a Changelog conventions — from git history, commit messages, or a description of changes. Use when asked to write a changelog, update release notes, or document what changed in a version.
Follow the Keep a Changelog convention:
one CHANGELOG.md at the repo root, entries in reverse chronological
order (newest first), each release tagged with a semantic version and
date, changes grouped under seven standard categories. Write for
humans, not machines — the reader is a developer evaluating whether
to upgrade.
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [1.2.0] — 2026-04-08
### Added
- ...
### Changed
- ...
### Deprecated
- ...
### Removed
- ...
### Fixed
- ...
### Security
- ...
[Unreleased]: https://github.com/org/repo/compare/v1.2.0...HEAD
[1.2.0]: https://github.com/org/repo/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/org/repo/releases/tag/v1.1.0
The [Unreleased] section accumulates changes since the last
release. On release, it becomes the new version block.
Use exactly these headings — no others:
| Category | What goes here |
|---|---|
| Added | New features, new endpoints, new configuration options |
| Changed | Changes to existing behavior, updated defaults, refactors that change observable behavior |
| Deprecated | Features that will be removed in a future version |
| Removed | Features removed in this version |
| Fixed | Bug fixes |
| Security | Vulnerability fixes — always include CVE IDs where available |
Omit sections that have no entries for a release. Do not use custom categories (e.g. "Performance", "Refactor") — map to the nearest standard one.
Use the git log to find changes since the last release:
# Changes since the last tag
git log v1.1.0..HEAD --oneline
# Changes between two tags
git log v1.1.0..v1.2.0 --oneline
# With full messages for detail
git log v1.1.0..HEAD --format="%h %s%n%b" | head -100
Then group commits by type:
feat: or add → Addedfix: → Fixedchore:, refactor:, perf: → Changed (if user-visible)BREAKING CHANGE: → Removed or Changed (prominently)security: or CVE mentions → SecurityDiscard: merge commits, version bumps, CI config changes, typo fixes in comments, and any change the end user will never notice.
Each entry is a single sentence describing the user-visible change. Format: verb phrase in past tense, describing the observable behavior change, not the implementation detail.
Good:
--dry-run flag to the sync command that previews changes without applying themBad:
Link to the relevant issue or PR for every entry where one exists:
Added dark mode support ([#142](https://github.com/org/repo/issues/142))
When releasing version 1.2.0:
## [Unreleased] with ## [1.2.0] — YYYY-MM-DD## [Unreleased] section at the top[1.2.0]: https://github.com/org/repo/compare/v1.1.0...v1.2.0[Unreleased] link:
[Unreleased]: https://github.com/org/repo/compare/v1.2.0...HEADBreaking changes deserve special treatment:
> **Breaking change:** blockquote before the entry### Changed
> **Breaking change:** The `auth` configuration key has been renamed
> to `authentication`. Update your config files before upgrading.
> See the [migration guide](docs/migration/v2.md).
- Renamed `config.auth` to `config.authentication` for clarity
Agent-specific failure modes — provider-neutral pause-and-self-check items:
[Unreleased] link and the new version link. Leaving them pointing to old tags makes the diff links wrong for everyone who clicks them.[Unreleased] section must always be the first entry, immediately after the file header. Entries below it are older releases in reverse chronological order. An [Unreleased] section buried below past versions is invisible to maintainers accumulating pre-release notes.If the project uses Conventional Commits:
| Commit prefix | Changelog category |
|---|---|
feat: | Added |
fix: | Fixed |
perf: | Changed |
refactor: (visible) | Changed |
docs: (user-facing) | Changed |
BREAKING CHANGE: footer | Changed or Removed (prominent) |
security: | Security |
chore:, test:, ci: | Omit |
deprecate: | Deprecated |
Tools that parse Conventional Commits and generate a draft changelog:
git-cliff — highly configurable, supports custom templatesconventional-changelog-cli — Node.js, many preset stylesrelease-please (Google) — GitHub Actions workflowThese produce a draft; always human-review before publishing. The agent's job when automation is available: review and edit the generated draft, not generate from scratch.
GitHub's "Generate release notes" button is not a substitute for CHANGELOG.md:
CHANGELOG.md is the authoritative, cumulative, human-readable record. GitHub release notes can be generated from it, not the other way around.
Never rewrite or delete old changelog entries, even when they are wrong about what a version contained. Old entries are part of the project's permanent history. If a past entry was incorrect, add a note in a later version's section that corrects the record.