Changelog and Release Notes skill for Claude Code
Tell users what changed for them, not what you typed. Claude collects merged PRs and commits since the last tag, drops internal noise like refactors and CI tweaks, and rewrites each remaining change as its effect on the user. Entries land in Keep a Changelog sections, the version bump follows from the highest-impact change, and every breaking change gets a before and after example plus migration steps. Separate benefit-led notes can be written for end users.
- name
changelog-release-notes - size198 lines · ≈1,900 tokens
- files1
- licenseMIT
- updated
What Claude sees before loading it
This description is the only part of the skill that sits in context all the time. Claude reads it to decide when to load the full playbook below.
description: Writes changelogs in Keep a Changelog format and user-facing release notes from commits and merged PRs — grouped by impact, written as what changed for the user rather than what the developer did, with breaking changes and deprecations called out with migration steps, and semver-consistent versions. Use when preparing a release, updating CHANGELOG.md, writing release notes or a GitHub release, announcing breaking changes, or setting up changesets, git-cliff, or release-please. Try asking
- Write the changelog for v3.0.0 from everything merged since v2.8.1
- Turn these release PRs into customer-facing release notes for our blog
- We're changing the default timeout. Write the breaking change notice and migration steps
Use it when
- Preparing a release or GitHub release
- CHANGELOG.md is missing, stale, or just a git log
- Announcing breaking changes or deprecations
- Choosing between changesets, release-please, and git-cliff
Skip it when
- You need the tagging, branching and release process itself, use release-management instead
- You want better commit messages at the source, use commit-craft instead
How to check the result
Every PR merged since the last tag is listed or deliberately excluded, the semver bump matches the highest-impact section, and each breaking change has followable migration steps.
The common mistake it prevents
Filing a behavior change under Fixed because the old behavior was a bug, which still breaks every client that depended on it without warning.
A changelog entry is done when a user can tell, without reading code, whether the
release affects them and what to do about it. Breaking changes are impossible to miss
and come with migration steps. A pasted git log is not a changelog.
Two documents, two readers
| CHANGELOG.md | Release notes | |
|---|---|---|
| Reader | Developers upgrading the package or service | Users or customers of the product |
| Scope | Every user-visible change, including small fixes | Highlights that change what people can do |
| Tone | Terse, factual | Benefit-led, plain language, can include visuals |
| Format | Keep a Changelog sections per version | Headline + highlights + improvements + fixes |
| Where | Repo root, GitHub Releases | Blog, in-app “What’s new”, email, docs |
Ground rules
- Write for the reader’s impact: “Exports no longer drop rows with empty dates”, not “Fix null check in ExportService”.
- Exclude internal noise: refactors, CI changes, dependency bumps with no user effect, test changes.
- Breaking changes first, in their own section, each with a before/after and migration steps.
- Version numbers follow semver for libraries: breaking → major, feature → minor, fix → patch. (Pre-1.0: breaking → minor is common; say so in the README.)
- Every entry links to its PR or issue for detail.
- Keep an
## [Unreleased]section updated in each PR; release day is then a rename.
Workflow
- [ ] 1. List changes since the last release
- [ ] 2. Filter out non-user-facing changes
- [ ] 3. Classify (Added, Changed, Deprecated, Removed, Fixed, Security) and spot breaking ones
- [ ] 4. Rewrite each entry for user impact
- [ ] 5. Decide the version number
- [ ] 6. Write breaking-change and migration notes
- [ ] 7. Produce release notes for end users if needed
- [ ] 8. Verify links, versions, and dates
1. Collect
LAST=$(git describe --tags --abbrev=0)
git log "$LAST"..HEAD --no-merges --pretty='%h %s (%an)'
gh pr list --state merged --search "merged:>=$(git log -1 --format=%cs "$LAST")" --limit 200 \
--json number,title,labels --jq '.[] | "#\(.number) \(.title) [\(.labels|map(.name)|join(","))]"'
git log "$LAST"..HEAD --grep='BREAKING CHANGE' -i --pretty='%h %s'
git log "$LAST"..HEAD --pretty='%h %s' | grep -E '^\w+ \w+(\(.+\))?!:' # conventional "feat!:" markers
PR descriptions are better input than commit subjects; read them for the user-facing effect.
3. Classify (Keep a Changelog 1.1.0)
| Section | Use for |
|---|---|
| Added | New features, endpoints, options |
| Changed | Changes in existing behavior (mark breaking ones) |
| Deprecated | Features that still work but will be removed; say when |
| Removed | Features removed in this release |
| Fixed | Bug fixes users could have noticed |
| Security | Vulnerability fixes; include CVE/GHSA ID and affected versions |
4. Rewrite for impact
| Before (commit-speak) | After (user impact) |
|---|---|
| “refactor date parsing” | (omit, unless behavior changed) |
| “fix: handle null in exporter” | “CSV export no longer skips rows that have an empty due date (#412).” |
| “feat: add retry option” | “client.send() accepts retries (default 0) to retry on 5xx and network errors (#398).” |
| “bump axios to 1.7” | (omit) or under Security if it fixes a CVE that affected users |
| “change default timeout” | “Breaking: default request timeout is now 10s (was unlimited). Pass timeout: 0 to restore the old behavior (#401).” |
Style: one line per entry when possible, past tense or present-tense description used consistently, code identifiers in backticks, PR link at the end.
5. Version
- Any entry in Removed, or a breaking Changed → major (≥ 1.0).
- Any Added or Deprecated → minor.
- Only Fixed/Security → patch.
- Use
npx semveror the release tool to compute; never reuse a published version.
6. Breaking change block
### Breaking changes
#### `createClient()` now requires `region`
Previously `region` defaulted to `us-east-1`, which sent EU customers' data to the US.
Before:
const client = createClient({ apiKey });
After:
const client = createClient({ apiKey, region: "eu-west-1" });
Migration: add `region` to every `createClient()` call. A codemod is available:
`npx @example/codemods v3/region .` (#455)
Deprecations: say what replaces it and the removal version or date: “listAll() is
deprecated and will be removed in 4.0 (no earlier than 2027-04). Use list({ autoPaginate: true }).”
CHANGELOG.md format
# Changelog
All notable changes to this project are documented here. The format follows
[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]
## [3.0.0] - 2026-10-19
### Breaking changes
- `createClient()` requires `region`; see migration notes below (#455).
### Added
- `client.send()` accepts `retries` to retry on 5xx and network errors (#398).
### Fixed
- CSV export no longer skips rows with an empty due date (#412).
### Security
- Signed URLs now expire after 15 minutes instead of 7 days (GHSA-xxxx-xxxx-xxxx).
[Unreleased]: https://github.com/acme/sdk/compare/v3.0.0...HEAD
[3.0.0]: https://github.com/acme/sdk/compare/v2.8.1...v3.0.0
Dates are ISO 8601 (YYYY-MM-DD). Newest version first.
7. Release notes for users
# October release: scheduled exports and faster search
**Scheduled exports.** Set any report to export to CSV or Google Sheets daily or weekly.
Find it under Reports → Schedule. [Screenshot]
**Search is 3× faster** on workspaces with more than 10,000 documents.
### Improvements
- Invoices show the payment method used.
- You can now reorder dashboard widgets by dragging.
### Fixes
- Exports no longer skip rows with an empty due date.
### Heads-up
- On November 15 we're retiring the legacy API v1. If you use it, see the migration guide.
Lead with the benefit, name where to find it, show it. Skip internal jargon and ticket numbers.
Tooling (pick one; do not mix)
| Tool | Model | Command |
|---|---|---|
| Changesets (JS monorepos) | Each PR adds a .changeset/*.md describing impact and bump | npx changeset in the PR; npx changeset version at release |
| release-please | Parses conventional commits, opens a release PR | GitHub Action googleapis/release-please-action@v4 |
| git-cliff | Generates from conventional commits via a template | git cliff --tag v3.0.0 -o CHANGELOG.md |
Generated changelogs are drafts: still rewrite entries for impact and add migration notes by hand.
Gotchas
- Commit-derived changelogs leak internal phrasing and miss user impact; edit them.
- “Various bug fixes and improvements” tells users nothing; list them or say nothing.
- Hiding a breaking change in Fixed because “it was a bug” still breaks clients that relied on the behavior; call it out.
- Security entries must not include exploit details before users can upgrade; give affected versions and the fixed version.
- Comparison links at the bottom must be updated each release or they point to the wrong range.
Verification
- Every PR merged since the last tag is either in the changelog or deliberately excluded
(cross-check the
gh pr listoutput). - The version bump matches the highest-impact section.
- Each breaking change has before/after and migration steps; someone can follow them.
- Links resolve (
lychee CHANGELOG.mdor click through), dates are ISO, newest first.
About this skill
Written and maintained by the Claude Skills editors to the same editorial standard as every skill in the directory: a selective trigger, a real workflow, known pitfalls and a verification step. First published , last updated . MIT licensed.