changelog
GitHub根据 Git 历史自动生成 CHANGELOG.md,将提交按版本分类并格式化。
Trigger Scenarios
Install
npx skills add David-Crty/databasement --skill changelog -g -y
SKILL.md
Frontmatter
{
"name": "changelog",
"agent": "general-purpose",
"context": "fork",
"background": false,
"description": "Write the CHANGELOG.md entries for a release from git history. Reads the commits since the last tag, turns them into Keep a Changelog entries filed under their minor version, commits and pushes. Takes the version being released, `x.y.z`. Run by `make release`; run it by hand to review the entries before tagging.",
"allowed-tools": "Bash(git *), Bash(gh *), Bash(date *), Read, Edit, Write",
"argument-hint": "x.y.z",
"disable-model-invocation": true
}
Changelog
You maintain CHANGELOG.md at the repository root: the commits since the last
tag go in as entries an operator understands, filed under the minor version of
the release being cut. Nothing else in the repository may change.
Context
- Version being released:
$ARGUMENTS(required,x.y.z) - Branch: !
git branch --show-current - Last tag: !
git describe --tags --abbrev=0 --match 'v*' - Working tree (empty means clean): !
git status --porcelain - Today: !
date +%Y-%m-%d - Commits since the last tag (empty means there is nothing to release):
!git log HEAD --not --tags --no-merges --format='%h %s%n%b%n---'
If $ARGUMENTS is empty or is not an x.y.z version, stop and say
Usage: /changelog x.y.z. There is no other mode.
File format
One section per minor version, not per patch. Every entry is prefixed with the patch release that shipped it, in backticks. Entries are grouped by section, newest patch first inside each:
## [1.7] - 2026-09-05
### Added
- `1.7.9` Snapshots can carry a free-text comment ([#522](https://github.com/David-Crty/databasement/pull/522))
- `1.7.0` A backup configuration can target several storage volumes ([#478](https://github.com/David-Crty/databasement/pull/478))
### Fixed
- `1.7.10` A form that fails validation scrolls the first invalid field into view ([#598](https://github.com/David-Crty/databasement/pull/598))
The heading date is the date of the newest patch in that minor. There is no
## [Unreleased] section: the file only ever describes released versions.
Link references sit at the end of the file, one per minor spanning the previous minor's newest tag to this minor's newest tag:
[1.7]: https://github.com/David-Crty/databasement/compare/v1.6.12...v1.7.10
[1.6]: https://github.com/David-Crty/databasement/compare/v1.5.6...v1.6.12
The app renders this file as Markdown at /changelog and
docs/scripts/sync-changelog.js publishes it as a documentation page, so keep
the shape above: ## [minor] - date headings, ### Section groups,
- `x.y.z` entry bullets, and the link references (which turn each heading
into a link to the compare view).
Editorial rules
- Audience: people who run Databasement. Say what changed for them, not what changed in the code. Lead with the visible effect.
- One bullet per PR. GitHub appends
(#NNN)to the squash-merge subject; turn it into([#NNN](https://github.com/David-Crty/databasement/pull/NNN))at the end of the bullet. When several PRs ship one feature, merge them into one bullet and keep every link. - Drop refactors, CI, tests, docs-only, tooling and dependency bumps unless an operator would notice. A dependency bump that fixes a CVE goes under Security with the CVE id.
- Sections in this order, empty ones omitted: Added, Changed, Deprecated, Removed, Fixed, Security. PR titles are conventional commits, so
feat:starts in Added,fix:in Fixed,fix(security):in Security,perf:/refactor:in Changed, and a description starting with "remove"/"drop" or "deprecate" goes to Removed/Deprecated. The type is a hint, not a verdict: reclassify freely (a PR titled "Scope … to the current organization" is Security, "Allow choosing …" is Added). - Style: one bullet per entry, sentence case, no trailing period. The lead sentence is the visible effect; at most one or two more sentences for its limits or any action the operator must take. Describe the result ("Snapshots can carry a comment", "The Redis password is masked in logged commands"). Keep the terms Backup, Restore, Snapshot as they are. No em dashes. Backticks for env vars, flags and file names.
- Breaking changes (
feat!:,fix!:, aBREAKING CHANGE:footer) start with**Breaking:**after the patch prefix. - The commit bodies above explain the why, the subjects only the what; read both.
gh pr view <number>gives more context when a subject is opaque. - Never rewrite entries of already-released patches. Never touch any file other than
CHANGELOG.md. Never tag, never runmake release.
Steps
Stop with a clear message if any precondition fails:
- branch is
main, the working tree is clean, and aftergit fetch origin mainHEAD equalsorigin/main; git rev-parse -q --verify refs/tags/vx.y.zfinds nothing;x.y.zis greater than the last tag.- no commit since the last tag breaks agents on a patch release: if any subject has the
agentscope with a!(feat(agent)!:,fix(agent)!:, any type),x.y.zmust open a new minor or major (the patch is0andx.yis greater than the last tag's). Agents are only guaranteed to work with a server of the same minor, so otherwise stop, name the commits, and say to releasex.(y+1).0instead.
Then:
- Turn the commits since the last tag into polished entries, following the editorial rules.
- Insert each entry into the
## [x.y]section, prefixed with`x.y.z`, at the top of its### Section(newest patch first). Create the### Sectionin Keep a Changelog order if the minor has none yet.- If
## [x.y]does not exist (this release opens a new minor), insert a whole new section directly below the file header. - If nothing since the last tag is worth an entry, add a single
- `x.y.z` Maintenance release with no application changesunder Changed.
- If
- Set the
## [x.y]heading date to today. - Update the link references:
[x.y]: …/compare/v<newest tag of the previous minor>...vx.y.z. A new minor adds its own line above the previous one; an existing minor only has its end of the range bumped tovx.y.z. git add CHANGELOG.mdandgit commit --no-verify -m "Record the vx.y.z changelog". The hook is skipped on purpose: the preconditions guaranteemainis clean and already passed it, and its checks (Pint, PHPStan, tests) cover nothing inCHANGELOG.md. Check withgit show --stat HEADthat the commit touches only that file. No attribution lines or trailers.git push origin main.- Report the entries. If you were invoked by
make release, it tags right after you exit; when run by hand, the next step ismake release VERSION=x.y.z.
Version History
- 8052374 Current 2026-10-19 04:37


