update-changelog
Load this skill when updating CHANGELOG.md or writing release notes, as a versioned section or an Unreleased entry in Keep a Changelog format. Trigger on "update the changelog", "write release notes",
SKILL.mdplugins/standalone/ceh-git-workflow/skills/update-changelog/SKILL.md
GitHubUpdate changelog
Inspect the project's git history, existing CHANGELOG.md, and codebase to produce or update a well-structured changelog following Semantic Versioning and Keep a Changelog format.
Procedure
1. Gather context
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null) # current version (empty if none)
if [ -n "$LAST_TAG" ]; then
git log "$LAST_TAG"..HEAD --oneline --no-merges # changes since last release
else
git log --oneline --no-merges # no tags yet: full history
fi
git tag --sort=-v:refname | head -20 # version history
cat CHANGELOG.md 2>/dev/null || echo "No CHANGELOG.md found"
If no tag exists, read the version from whatever manifest the project uses (e.g. package.json,
pyproject.toml, Cargo.toml, *.csproj, build.gradle, VERSION).
2. Determine version and categorize
Unreleased mode. When the caller says the change is not being released — no version bump, no
tag — skip the version entirely: categorize as below, then add the bullets under the existing
## [Unreleased] heading (create it directly under the intro if missing) and stop after step 5. Do
not invent a version number, do not add a dated header, and do not touch the comparison links.
Everything else in this skill applies unchanged.
Apply semver rules and map to Keep a Changelog sections in one pass:
| Commit signal | Bump | Section |
|---|---|---|
BREAKING CHANGE: footer or feat!: / fix!: |
MAJOR | Removed / Changed |
feat: |
MINOR | Added |
fix: |
PATCH | Fixed |
perf: |
PATCH | Changed |
chore:, docs:, refactor:, test: |
PATCH | (use judgment) |
| Security patches | PATCH | Security |
Skip: merge commits, version bumps, CI config, trivial formatting.
If the user specifies the version explicitly, use it. If uncertain about the bump level, explain reasoning and ask before writing.
3. Write the entry
## [X.Y.Z] - YYYY-MM-DD
### Added
- Imperative description (#PR or commit ref)
### Changed / Fixed / Removed / Security
- ...
- Imperative mood: "Add support for X" not "Added"
- One line per change; group related items
- Link PRs/issues with
[#123](url) - Omit empty sections
4. Update CHANGELOG.md
Existing file: Prepend new entry after [Unreleased] (create the section if missing). Update
comparison links at bottom.
No file: Create from scratch:
# 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]
## [X.Y.Z] - YYYY-MM-DD
...
Add comparison links at the bottom (infer repo URL from git remote get-url origin):
[Unreleased]: https://github.com/owner/repo/compare/vX.Y.Z...HEAD
[X.Y.Z]: https://github.com/owner/repo/compare/vX.Y.Z-1...vX.Y.Z
5. Validate
Run the bundled validator. ${CLAUDE_PLUGIN_ROOT} is substituted with the plugin's directory, so
the path resolves wherever the plugin is installed:
python3 "${CLAUDE_PLUGIN_ROOT}/scripts/check-semver.py" CHANGELOG.md
If the script cannot be located, scan CHANGELOG.md manually: verify all version headers match
MAJOR.MINOR.PATCH (with optional -prerelease or +build), dates are YYYY-MM-DD, versions are
newest-first, no duplicates.
Rules
- Never invent changes — only document what git log and diffs evidence.
- Never include secrets, credentials, or internal infra details.
- Only modify
CHANGELOG.md. - Versions must always increase.