SuperAPI AI Directory

changelog-quality-pass

Writing & research

View repository

Updated 10-15 17:29

About this skill

Changelog Workmanship

Use this skill to write or repair a CHANGELOG.md so a user deciding whether to upgrade can read one section and know what changed, what broke, and what to do. A changelog is a product surface, not a git log dump.

⚠️ Critical Constraints

  • Write user-facing change, not commit subjects. A changelog answers "what does this mean for me?", not "what did the author touch." Why: raw commit messages describe implementation; users need outcomes.
    • WRONG: - refactor auth middleware to use jwt-decode v4 (a1b2c3d)
    • CORRECT: - Fixed: expired sessions now log out cleanly instead of looping
  • Never invent or backdate entries. Every entry must trace to real shipped change. Why: a fabricated history is worse than none — it destroys trust and misleads upgraders.
  • Keep an ## [Unreleased] section at the top, always. Why: the file stays current only if entries land with the change, not at release time when context is gone.
    • WRONG: writing the whole changelog the day you cut the release from git log.
    • CORRECT: each PR adds its line to [Unreleased]; release moves the block.
  • Version headings must match real tags and semver. Why: a user pins a version and expects the heading, the tag, and the breaking-change signal to agree; a Patch bump that hides a breaking change is a workmanship failure.

Why This Exists

Most projects either have no changelog or have an autogenerated commit dump that no human reads. Both fail the one job: helping a person decide whether and how to upgrade. Generation defaults to either over-terse ("bug fixes") or commit-shaped noise. This skill is the forcing function for the disciplined middle: structured, grouped, audience-facing, semver-aligned, and maintained continuously.

Quick Start

  1. Locate or create CHANGELOG.md at the repo root.
  2. Reconstruct history from tags + the commits/PRs/issues between them:
    git tag --sort=-creatordate
    git log --oneline v1.1.0..v1.2.0
    
  3. For each release, group changes under the standard headings (below).
  4. Translate each entry from commit language into user-facing language.
  5. Confirm version order, dates, and semver alignment.
  6. Run bash scripts/validate.sh and report the verdict.

The Keep-a-Changelog Structure

A conforming file has this shape:

# Changelog

All notable changes to this project are documented here.
The format is based on Keep a Changelog, and this project adheres to
Semantic Versioning.

## [Unreleased]

### Added
- New thing users can now do.

## [1.2.0] - 2026-06-06

### Added
- ...
### Changed
- ...
### Fixed
- ...

## [1.1.0] - 2026-05-01

### Removed
- ...

[Unreleased]: https://example.com/compare/v1.2.0...HEAD
[1.2.0]: https://example.com/compare/v1.1.0...v1.2.0

Rules that hold every time:

  • Releases are listed newest first, each with ## [version] - YYYY-MM-DD.
  • [Unreleased] sits at the top with no date.
  • Dates are ISO 8601 (YYYY-MM-DD), unambiguous across locales.

The Six Groups

Group every entry under exactly one of these standard headings, omitting any group with no entries:

  • Added — new features or capabilities.
  • Changed — changes to existing behavior.
  • Deprecated — soon-to-be-removed features (warn before removal).
  • Removed — features taken out this release.
  • Fixed — bug fixes.
  • Security — vulnerability fixes (call these out explicitly).

Semver Alignment

The release type the changelog implies must match the version bump:

  • Anything under Removed, or a breaking Changed entry → Major bump.
  • Anything under Added (backward-compatible) → Minor bump.
  • Only Fixed / Security → Patch bump.

Mark breaking changes loudly — a **BREAKING:** prefix on the entry, plus the Major bump. A changelog that buries a breaking change under a Patch heading is the most damaging failure mode.

Audit Flow (for an existing changelog)

  1. Confirm the structural skeleton: title, [Unreleased], newest-first releases, dated headings, comparison links.
  2. Read each entry as a user: does it describe an outcome, or an implementation detail / bare commit subject? Rewrite the latter.
  3. Check grouping: is every entry under a correct standard heading? Are empty groups omitted?
  4. Cross-check each version heading against the real tag and the bump type the entries imply.
  5. Verify comparison/diff links resolve and the [Unreleased] link points at the latest tag.
  6. Confirm the maintenance discipline exists (a CONTRIBUTING note or release step that adds to [Unreleased]); if not, recommend one.

Keeping It Current (the release flow)

The changelog stays good only if it is edited continuously, not reconstructed:

  • Every change-bearing PR adds a line under the right group in [Unreleased].
  • Cutting release X.Y.Z is a mechanical move: rename [Unreleased] to [X.Y.Z] - <today>, add a fresh empty [Unreleased], update the diff links, tag the commit.
  • Never let "write the changelog" become a release-day archaeology task.

Output Specification

Return a workmanship report (also written to CHANGELOG.md when repairing):

  • Verdict: pass, needs work, or blocked.
  • Findings: ordered by severity, each tied to a changelog property.
  • Changes: what was edited and why.
  • Verification: commands run and their results.
  • Residual risk: history gaps, unverifiable entries, missing tags.

Quality Rubric

  • Every entry reads as a user-facing outcome, with zero raw commit hashes or subjects left in prose form.
  • Every entry sits under a correct standard group; no empty groups are emitted; releases are newest-first with ISO dates.
  • The latest release heading matches a real tag, and the implied bump type (Major/Minor/Patch) matches the actual version, with breaking changes marked.

Examples

Rewriting a commit dump into a release entry:

  • Input commits: fix: npe in retry, chore: bump deps, feat: add --json.
  • Output:
    ## [2.3.0] - 2026-06-06
    ### Added
    - `--json` flag for machine-readable output.
    ### Fixed
    - No longer crashes when a request is retried after a timeout.
    
    (chore: bump deps is dropped — not user-facing unless it changes behavior.)

Troubleshooting

Symptom Likely cause Fix
Changelog is a commit dump Generated from git log at release time Adopt the [Unreleased] continuous-edit flow; rewrite entries as outcomes.
Users surprised by a breaking change Breaking change under a Patch/Minor bump Re-bump to Major; add **BREAKING:** prefix and a migration note.
Dates ambiguous or missing Locale-specific or absent dates Use ISO 8601 YYYY-MM-DD on every dated release.
Comparison links 404 Stale diff links after a tag Update [version]: <compare-url> and the [Unreleased] link to the latest tag.
Empty headings everywhere Boilerplate template not pruned Omit any group (Added/Changed/...) with no entries this release.

See Also

  • Keep a Changelog conventions (structure + group names).
  • Semantic Versioning (Major/Minor/Patch bump rules).
  • scripts/validate.sh — structural self-check for this skill.