Voicebox draft-release-notes
Use this skill to draft or update the [Unreleased] section of CHANGELOG.md from the actual changes since the last tag. Run this at any point during development to keep a working copy of the release narrative. Does NOT bump versions or create tags.
install
source · Clone the upstream repo
git clone https://github.com/jamiepine/voicebox
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jamiepine/voicebox "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.agents/skills/draft-release-notes" ~/.claude/skills/jamiepine-voicebox-draft-release-notes && rm -rf "$T"
manifest:
.agents/skills/draft-release-notes/SKILL.mdsource content
Draft Release Notes
Goal
Update the
[Unreleased] section at the top of CHANGELOG.md with a narrative release story based on the real changes since the last tag. This is a non-destructive working copy — run it as many times as you want during development.
Workflow
-
Identify the last release tag and gather changes.
LAST_TAG=$(git tag --list "v*" --sort=-v:refname | head -n 1) echo "Last tag: $LAST_TAG"Then collect raw material from three sources:
a. Commit log since last tag:
git log --oneline "$LAST_TAG"..HEADb. GitHub-generated release notes preview (PR titles, new contributors):
gh api repos/:owner/:repo/releases/generate-notes \ -f tag_name="vNEXT" \ -f target_commitish="$(git rev-parse HEAD)" \ -f previous_tag_name="$LAST_TAG" \ --jq '.body'c. Diff stat for theme analysis:
git diff --stat "$LAST_TAG"..HEAD -
Draft the release narrative.
Write markdown for the
section following the format below. Do not include the[Unreleased]
heading itself — just the body content.## [Unreleased] -
Update CHANGELOG.md.
Replace everything between
and the next## [Unreleased]
heading with the new draft. Preserve the HTML comment header and all existing release sections below.## [The
section must always exist and always be the first section after the header comments.[Unreleased] -
Do NOT commit, tag, or bump versions. Just leave the file modified in the working tree.
Release Story Format
Structure the
[Unreleased] section like this:
## [Unreleased] <One strong opening paragraph: what this release is about and why it matters. Tie it to concrete shipped changes. No vague hype.> <One paragraph on major technical shifts, if applicable.> ### <Feature/Theme Group> - Bullet points with specifics - Reference PRs where available: ([#123](https://github.com/jamiepine/voicebox/pull/123)) ### <Another Group> - ... ### Bug Fixes - ...
Style Guidelines
- Factual and specific. Every claim should trace to a real commit or PR.
- Narrative over list. Lead with paragraphs that tell the story, then support with bullets.
- Group by theme, not by commit. Cluster related changes under descriptive headings.
- Reference PRs where they exist, but don't fabricate them.
- Skip trivial chores (typo fixes, CI tweaks) unless they're the bulk of the release.
- Match the voice of existing releases — look at the v0.2.1 and v0.2.3 entries in CHANGELOG.md for tone reference.
When There Are No Changes
If
git log "$LAST_TAG"..HEAD is empty, leave the [Unreleased] section empty (just the heading) and tell the user there's nothing to draft.
Notes
- This skill only touches the
section. It never modifies stamped release sections.[Unreleased] - The agent can be asked to run this skill at any point — mid-feature, before a PR, or right before cutting a release.
- The
skill depends on this draft being up to date before it finalizes.release-bump