Writing Changelogs
Writing Changelogs
Turns git history into an accurate, user-friendly CHANGELOG.md entry after publishing a new version. Never invents changes — if something can't be verified from the diff or commits, it's either confirmed with the user or left out.
Run this skill after publishing a new version.
It will:
- Find the last documented change in CHANGELOG.md (or the beginning of history if the file doesn't exist)
- Diff from that point to HEAD
- Draft categorized entries
- Ask you to confirm anything ambiguous
- Write/update CHANGELOG.md
Progress:
- Step 1: Locate or create CHANGELOG.md
- Step 2: Determine the diff range
- Step 3: Gather evidence (diff + commits + PR titles)
- Step 4: Categorize changes
- Step 5: Ask clarifying questions for anything uncertain
- Step 6: Draft the entry
- Step 7: Write to CHANGELOG.md
Step 1: Locate or create CHANGELOG.md
- If
CHANGELOG.mdexists, read it. The most recent version heading marks the last documented point. - If it doesn't exist, create it with a
# Changelogheader and a note that it follows Keep a Changelog. Then generate an initial entry summarizing the current state of the project (from full git history or first commit to HEAD, whichever is feasible).
Step 2: Determine the diff range
- Find the git ref/tag/commit associated with the last changelog entry (look for a version tag matching the last heading, e.g.
## [1.2.0]). - If no matching tag exists, use the date of the last entry to find the nearest commit, or ask the user which commit/tag to diff from.
- Diff range =
last_ref..HEAD.
Step 3: Gather evidence
Collect, don't guess:
git log last_ref..HEAD --onelinefor commit messagesgit diff last_ref..HEADfor actual code changes- PR titles/descriptions if available (via
gh pr list --state mergedor similar) - The new version number (from
package.json,pyproject.toml, a git tag, or ask the user)
Only claim a change happened if it's visible in the diff or explicitly confirmed by the user. A commit message alone ("fix bug") is not enough evidence — look at the actual diff to describe what was fixed.
Step 4: Categorize changes
Sort findings into Keep a Changelog categories:
- Added — new features
- Changed — changes to existing functionality
- Fixed — bug fixes
- Removed — removed features
- Security — vulnerability fixes
- Deprecated — soon-to-be removed features
Skip internal-only changes users don't care about: refactors with no behavior change, test additions, CI config, formatting, dependency bumps with no user impact. When unsure if something is user-facing, ask.
Step 5: Ask clarifying questions
Ask only when the diff is genuinely ambiguous — e.g.:
- A diff touches auth code but the intent (bug fix vs. new restriction) isn't clear
- Multiple unrelated changes are bundled and you need a one-line description of the "why"
- The version number isn't obvious
Batch questions together instead of asking one at a time. If the user doesn't answer or says "skip," omit that item rather than guessing.
Step 6: Draft the entry
Write in plain, user-facing language, not commit-speak. Translate:
fix: null pointer in checkout flow→ "Fixed an issue where checkout could fail unexpectedly"feat: add CSV export→ "Added the ability to export data as CSV"
Use short bullets, bold the feature name when helpful, and keep one idea per bullet.
Step 7: Write to CHANGELOG.md
- Insert the new version section above the previous most-recent version, below the
# Changelogheader. - Format:
Markdownundefined
Added
- CSV Export: You can now export your data as a CSV file from the Reports page.
Fixed
- Fixed an issue where checkout could fail for users with saved payment methods.
Changed
- Search results now load faster for large datasets.
- Never duplicate entries already present. If a change was already logged (check by scanning existing bullets), skip it.
- Never delete or rewrite prior entries unless explicitly asked.
Example 1:
Input: Diff shows a null check added in checkout.js around payment processing, commit message says "fix: handle null payment method".
Output:
Markdown### Fixed - Fixed an issue where checkout could fail if a payment method wasn't fully loaded.
Example 2:
Input: Diff adds a new exportToCsv() function and a new "Export" button in the UI; no commit message context.
Output:
Markdown### Added - **CSV Export**: Added a new "Export" button to download your data as a CSV file.
(No clarifying question needed — the diff is self-explanatory.)
Example 3:
Input: Diff modifies rate-limiting thresholds in auth/middleware.js with no clear commit message or PR description.
Output: Ask the user: "I see the rate limit in auth/middleware.js changed from 100 to 50 requests/min. Was this a security fix, a bug fix, or a deliberate policy change? This affects how I categorize it."
- Ground every bullet in actual diff evidence — commit messages are hints, not proof.
- Prefer omission over speculation. An incomplete changelog is better than an inaccurate one.
- Write for the user reading the changelog, not for other developers.
- Keep categories consistent and always in the same order (Added, Changed, Fixed, Removed, Security, Deprecated).
- Batch clarifying questions; don't interrupt repeatedly.
- Use the actual release version and date, pulled from package metadata or git tags when possible.
- Don't invent a rationale for a change just to fill in a bullet — ask or omit.
- Don't include internal-only changes (refactors, tests, CI, formatting, dependency bumps without user impact).
- Don't copy raw commit messages verbatim — they're written for developers, not users.
- Don't re-summarize changes that are already documented in an earlier version entry.
- Don't guess the version number — check project metadata or ask.