release-notes · v1.0.0 · 2026-03-19 · sha256 1300c25eb756ab7b

release-notes v1.0.0A

Immutable. This exact content is served forever at /api/v1/blob/1300c25eb756ab7b.

---
name: release-notes
description: "Generate changelog entries and GitHub releases from git history. Categorizes commits into features, fixes, breaking changes, and docs. Supports conventional commits, PR-based grouping, and semantic versioning. Creates formatted CHANGELOG.md entries and GitHub releases."
license: MIT
origin: custom
author: Rebecca Rae Barton
author_url: https://github.com/thatrebeccarae
metadata:
  version: 1.0.0
  category: devops
  domain: git
  updated: 2026-03-19
  tested: 2026-03-19
  tested_with: "Claude Code v2.1"
---

# release-notes

Generate changelog entries and GitHub releases from git history.

## Install

```bash
claude skill add --from https://github.com/thatrebeccarae/claude-skills/release-notes
```

## When to Use

- **Cutting a release**: You have commits ready to ship and need a changelog entry and/or GitHub release.
- **Monthly changelog update**: You maintain a regular changelog cadence and need to capture everything since the last entry.
- **Retroactive changelog**: An existing project has no CHANGELOG.md and you want to generate one from the full git history.

## Usage

### Generate a changelog entry

```
/release-notes changelog [repo-path]
```

Reads commits since the last tag, categorizes them, and prepends a new entry to CHANGELOG.md.

### Create a changelog entry and GitHub release

```
/release-notes release [repo-path] [version]
```

Does everything `changelog` does, then creates a GitHub release via `gh release create`. If `version` is omitted, a version is suggested based on the changes detected.

### Retroactively generate a full changelog

```
/release-notes init [repo-path]
```

Walks the entire tag history (or full commit history if untagged) and generates a complete CHANGELOG.md from scratch.

## Procedure

### Step 1 — Find the last tag or release

Run `git describe --tags --abbrev=0` to find the most recent tag. If no tags exist, use the initial commit as the starting point. Cross-reference with `gh release list --limit 1` to check for GitHub releases that may differ from local tags.

### Step 2 — Collect commits since last tag

```bash
git log <last-tag>..HEAD --pretty=format:"%H %s" --no-merges
```

Parse each commit message for conventional commit prefixes (`type(scope): description`). Record the raw message for commits that do not follow conventional format.

### Step 3 — Check merged PRs

```bash
gh pr list --state merged --search "merged:>YYYY-MM-DD" --json number,title,labels,mergedAt --limit 200
```

Use the date of the last tag as the cutoff. Cross-reference PR titles with commit messages to avoid duplicates. PR titles often provide cleaner descriptions than commit messages — prefer the PR title when a commit is associated with a merged PR.

### Step 4 — Categorize changes

Map each commit or PR to a changelog category:

| Prefix / Signal | Category |
|---|---|
| `feat`, `feature` | **Added** |
| `fix` | **Fixed** |
| `BREAKING CHANGE` in body or `!` suffix (e.g., `feat!:`) | **Breaking Changes** |
| `docs` | **Documentation** |
| `refactor`, `perf` | **Changed** |
| `chore`, `ci`, `build` | **Maintenance** |
| `deprecate` | **Deprecated** |
| `remove` | **Removed** |
| `security` | **Security** |

**When conventional commits are not used**: Analyze commit message content to infer categories. Look for keywords like "add", "fix", "remove", "update", "refactor", "document". Group ambiguous commits under **Changed** and flag them for human review.

### Step 5 — Suggest version bump

Apply semantic versioning rules:

- **Major** bump if any Breaking Changes are present.
- **Minor** bump if any Added entries exist and no breaking changes.
- **Patch** bump if only Fixed, Changed, or Maintenance entries.

Present the suggestion with reasoning. The human decides the final version.

### Step 6 — Format the changelog entry

Use [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format:

```markdown
## [X.Y.Z] — YYYY-MM-DD

### Breaking Changes
- Description of breaking change (#PR)

### Added
- Description of new feature (#PR)

### Fixed
- Description of bug fix (#PR)

### Changed
- Description of refactor or improvement (#PR)

### Documentation
- Description of docs change (#PR)

### Maintenance
- Description of chore (#PR)
```

Omit empty categories. Order categories as shown above — Breaking Changes always first.

### Step 7 — Human review

Present the formatted entry and suggested version to the user. Wait for explicit approval before writing anything. Highlight any commits that were ambiguously categorized.

### Step 8 — Write to CHANGELOG.md

Prepend the new entry after the file header. Never overwrite or reorder existing entries. If CHANGELOG.md does not exist, create it with a standard header:

```markdown
# 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).
```

### Step 9 — Optionally create GitHub release

Only when the user invoked `/release-notes release` or explicitly requests it:

```bash
gh release create vX.Y.Z --title "vX.Y.Z" --notes "RELEASE_BODY"
```

Use the changelog entry as the release body. Never create a release without user confirmation.

## Key Principles

1. **Never auto-publish.** Every release and changelog write requires explicit human approval.
2. **Preserve existing entries.** Never modify, reorder, or delete previous changelog entries.
3. **Human-readable over machine-parseable.** Write descriptions that make sense to a person reading the changelog, not a parser. Prefer plain language over commit hashes.
4. **Attribute PRs and authors.** Include PR numbers as links. For multi-contributor projects, consider noting first-time contributors.
5. **When in doubt, ask.** If a commit is ambiguous, surface it to the user rather than guessing the category.