Add release-changelog skill and releases/ directory
Introduces the release-changelog skill (skills/release-changelog/SKILL.md) that teaches agents to generate user-facing changelogs from git history, changesets, and merged PRs. Includes breaking change detection, categorization heuristics, and structured markdown output template. Also creates the releases/ directory convention for storing versioned release notes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
0
releases/.gitkeep
Normal file
0
releases/.gitkeep
Normal file
331
skills/release-changelog/SKILL.md
Normal file
331
skills/release-changelog/SKILL.md
Normal file
@@ -0,0 +1,331 @@
|
||||
---
|
||||
name: release-changelog
|
||||
description: >
|
||||
Generate user-facing release changelogs for Paperclip. Reads git history,
|
||||
merged PRs, and changeset files since the last release tag. Detects breaking
|
||||
changes, categorizes changes, and outputs structured markdown to
|
||||
releases/v{version}.md. Use when preparing a release or when asked to
|
||||
generate a changelog.
|
||||
---
|
||||
|
||||
# Release Changelog Skill
|
||||
|
||||
Generate a user-facing changelog for a new Paperclip release. This skill reads
|
||||
the commit history, changeset files, and merged PRs since the last release tag,
|
||||
detects breaking changes, categorizes everything, and writes a structured
|
||||
release notes file.
|
||||
|
||||
**Output:** `releases/v{version}.md` in the repo root.
|
||||
**Review required:** Always present the draft for human sign-off before
|
||||
finalizing. Never auto-publish.
|
||||
|
||||
---
|
||||
|
||||
## Step 1 — Determine the Release Range
|
||||
|
||||
Find the last release tag and the planned version:
|
||||
|
||||
```bash
|
||||
# Last release tag (most recent semver tag)
|
||||
git tag --sort=-version:refname | head -1
|
||||
# e.g. v0.2.7
|
||||
|
||||
# All commits since that tag
|
||||
git log v0.2.7..HEAD --oneline --no-merges
|
||||
```
|
||||
|
||||
If no tag exists yet, use the initial commit as the base.
|
||||
|
||||
The new version number comes from one of:
|
||||
- An explicit argument (e.g. "generate changelog for v0.3.0")
|
||||
- The bump type (patch/minor/major) applied to the last tag
|
||||
- The version already set in `cli/package.json` if `scripts/release.sh` has been run
|
||||
|
||||
---
|
||||
|
||||
## Step 2 — Gather Raw Change Data
|
||||
|
||||
Collect changes from three sources, in priority order:
|
||||
|
||||
### 2a. Git Commits
|
||||
|
||||
```bash
|
||||
git log v{last}..HEAD --oneline --no-merges
|
||||
git log v{last}..HEAD --format="%H %s" --no-merges # full SHAs for file diffs
|
||||
```
|
||||
|
||||
### 2b. Changeset Files
|
||||
|
||||
Look for unconsumed changesets in `.changeset/`:
|
||||
|
||||
```bash
|
||||
ls .changeset/*.md | grep -v README.md
|
||||
```
|
||||
|
||||
Each changeset file has YAML frontmatter with package names and bump types
|
||||
(`patch`, `minor`, `major`), followed by a description. Parse these — the bump
|
||||
type is a strong categorization signal, and the description may contain
|
||||
user-facing summaries.
|
||||
|
||||
### 2c. Merged PRs (when available)
|
||||
|
||||
If GitHub access is available via `gh`:
|
||||
|
||||
```bash
|
||||
gh pr list --state merged --search "merged:>={last-tag-date}" --json number,title,body,labels
|
||||
```
|
||||
|
||||
PR titles and bodies are often the best source of user-facing descriptions.
|
||||
Prefer PR descriptions over raw commit messages when both are available.
|
||||
|
||||
---
|
||||
|
||||
## Step 3 — Detect Breaking Changes
|
||||
|
||||
Scan for breaking changes using these signals. **Any match flags the release as
|
||||
containing breaking changes**, which affects version bump requirements and
|
||||
changelog structure.
|
||||
|
||||
### 3a. Migration Files
|
||||
|
||||
Check for new migration files since the last tag:
|
||||
|
||||
```bash
|
||||
git diff --name-only v{last}..HEAD -- packages/db/src/migrations/
|
||||
```
|
||||
|
||||
- **New migration files exist** = DB migration required in upgrade.
|
||||
- Inspect migration content: look for `DROP`, `ALTER ... DROP`, `RENAME` to
|
||||
distinguish destructive vs. additive migrations.
|
||||
- Additive-only migrations (new tables, new nullable columns, new indexes) are
|
||||
safe but should still be mentioned.
|
||||
- Destructive migrations (column drops, type changes, table drops) = breaking.
|
||||
|
||||
### 3b. Schema Changes
|
||||
|
||||
```bash
|
||||
git diff v{last}..HEAD -- packages/db/src/schema/
|
||||
```
|
||||
|
||||
Look for:
|
||||
- Removed or renamed columns/tables
|
||||
- Changed column types
|
||||
- Removed default values or nullable constraints
|
||||
- These indicate breaking DB changes even if no explicit migration file exists
|
||||
|
||||
### 3c. API Route Changes
|
||||
|
||||
```bash
|
||||
git diff v{last}..HEAD -- server/src/routes/ server/src/api/
|
||||
```
|
||||
|
||||
Look for:
|
||||
- Removed endpoints
|
||||
- Changed request/response shapes (removed fields, type changes)
|
||||
- Changed authentication requirements
|
||||
|
||||
### 3d. Config Changes
|
||||
|
||||
```bash
|
||||
git diff v{last}..HEAD -- cli/src/config/ packages/*/src/*config*
|
||||
```
|
||||
|
||||
Look for renamed, removed, or restructured configuration keys.
|
||||
|
||||
### 3e. Changeset Severity
|
||||
|
||||
Any `.changeset/*.md` file with a `major` bump = explicitly flagged breaking.
|
||||
|
||||
### 3f. Commit Conventions
|
||||
|
||||
Scan commit messages for:
|
||||
- `BREAKING:` or `BREAKING CHANGE:` prefix
|
||||
- `!` after the type in conventional commits (e.g. `feat!:`, `fix!:`)
|
||||
|
||||
### Version Bump Rules
|
||||
|
||||
| Condition | Minimum Bump |
|
||||
|---|---|
|
||||
| Destructive migration (DROP, RENAME) | `major` |
|
||||
| Removed API endpoints or fields | `major` |
|
||||
| Any `major` changeset or `BREAKING:` commit | `major` |
|
||||
| New (additive) migration | `minor` |
|
||||
| New features (`feat:` commits, `minor` changesets) | `minor` |
|
||||
| Bug fixes only | `patch` |
|
||||
|
||||
If the planned bump is lower than the minimum required, **warn the reviewer**
|
||||
and recommend the correct bump level.
|
||||
|
||||
---
|
||||
|
||||
## Step 4 — Categorize Changes
|
||||
|
||||
Assign every meaningful change to one of these categories:
|
||||
|
||||
| Category | What Goes Here | Shows in User Notes? |
|
||||
|---|---|---|
|
||||
| **Breaking Changes** | Anything requiring user action to upgrade | Yes (top, with warning) |
|
||||
| **Highlights** | New user-visible features, major behavioral changes | Yes (with 1-2 sentence descriptions) |
|
||||
| **Improvements** | Enhancements to existing features | Yes (bullet list) |
|
||||
| **Fixes** | Bug fixes | Yes (bullet list) |
|
||||
| **Internal** | Refactoring, deps, CI, tests, docs | No (dev changelog only) |
|
||||
|
||||
### Categorization Heuristics
|
||||
|
||||
Use these signals to auto-categorize. When signals conflict, prefer the
|
||||
higher-visibility category and flag for human review.
|
||||
|
||||
| Signal | Category |
|
||||
|---|---|
|
||||
| Commit touches migration files, schema changes | Breaking Change (if destructive) |
|
||||
| Changeset marked `major` | Breaking Change |
|
||||
| Commit message has `BREAKING:` or `!:` | Breaking Change |
|
||||
| New UI components, new routes, new API endpoints | Highlight |
|
||||
| Commit message starts with `feat:` or `add:` | Highlight or Improvement |
|
||||
| Changeset marked `minor` | Highlight |
|
||||
| Commit message starts with `fix:` or `bug:` | Fix |
|
||||
| Changeset marked `patch` | Fix or Improvement |
|
||||
| Commit message starts with `chore:`, `refactor:`, `ci:`, `test:`, `docs:` | Internal |
|
||||
| PR has detailed body with user-facing description | Use PR body as the description |
|
||||
|
||||
### Writing Good Descriptions
|
||||
|
||||
- **Highlights** get 1-2 sentence descriptions explaining the user benefit.
|
||||
Write from the user's perspective ("You can now..." not "Added a component that...").
|
||||
- **Improvements and Fixes** are concise bullet points.
|
||||
- **Breaking Changes** get detailed descriptions including what changed,
|
||||
why, and what the user needs to do.
|
||||
- Group related commits into a single changelog entry. Five commits implementing
|
||||
one feature = one Highlight entry, not five bullets.
|
||||
- Omit purely internal changes from user-facing notes entirely.
|
||||
|
||||
---
|
||||
|
||||
## Step 5 — Write the Changelog
|
||||
|
||||
Output the changelog to `releases/v{version}.md` using this template:
|
||||
|
||||
```markdown
|
||||
# v{version}
|
||||
|
||||
> Released: {YYYY-MM-DD}
|
||||
|
||||
{If breaking changes detected, include this section:}
|
||||
|
||||
## Breaking Changes
|
||||
|
||||
> **Action required before upgrading.** Read the Upgrade Guide below.
|
||||
|
||||
- **{Breaking change title}** — {What changed and why. What the user needs to do.}
|
||||
|
||||
## Highlights
|
||||
|
||||
- **{Feature name}** — {1-2 sentence description of what it does and why it matters.}
|
||||
|
||||
## Improvements
|
||||
|
||||
- {Concise description of improvement}
|
||||
|
||||
## Fixes
|
||||
|
||||
- {Concise description of fix}
|
||||
|
||||
---
|
||||
|
||||
{If breaking changes detected, include this section:}
|
||||
|
||||
## Upgrade Guide
|
||||
|
||||
### Before You Update
|
||||
|
||||
1. **Back up your database.**
|
||||
- SQLite: `cp paperclip.db paperclip.db.backup`
|
||||
- Postgres: `pg_dump -Fc paperclip > paperclip-pre-{version}.dump`
|
||||
2. **Note your current version:** `paperclip --version`
|
||||
|
||||
### After Updating
|
||||
|
||||
{Specific steps: run migrations, update configs, etc.}
|
||||
|
||||
### Rolling Back
|
||||
|
||||
If something goes wrong:
|
||||
1. Restore your database backup
|
||||
2. `npm install @paperclipai/server@{previous-version}`
|
||||
```
|
||||
|
||||
### Template Rules
|
||||
|
||||
- Omit any empty section entirely (don't show "## Fixes" with no bullets).
|
||||
- The Breaking Changes section always comes first when present.
|
||||
- The Upgrade Guide always comes last when present.
|
||||
- Use `**bold**` for feature/change names, regular text for descriptions.
|
||||
- Keep the entire changelog scannable — a busy user should get the gist from
|
||||
headings and bold text alone.
|
||||
|
||||
---
|
||||
|
||||
## Step 6 — Present for Review
|
||||
|
||||
After generating the draft:
|
||||
|
||||
1. **Show the full changelog** to the reviewer (CTO or whoever triggered the release).
|
||||
2. **Flag ambiguous items** — commits you weren't sure how to categorize, or
|
||||
items that might be breaking but aren't clearly signaled.
|
||||
3. **Flag version bump mismatches** — if the planned bump is lower than what
|
||||
the changes warrant.
|
||||
4. **Wait for approval** before considering the changelog final.
|
||||
|
||||
If the reviewer requests edits, update `releases/v{version}.md` accordingly.
|
||||
|
||||
Do not proceed to publishing, website updates, or social announcements. Those
|
||||
are handled by the `release` coordination skill (separate from this one).
|
||||
|
||||
---
|
||||
|
||||
## Directory Convention
|
||||
|
||||
Release changelogs live in `releases/` at the repo root:
|
||||
|
||||
```
|
||||
releases/
|
||||
v0.2.7.md
|
||||
v0.3.0.md
|
||||
...
|
||||
```
|
||||
|
||||
Each file is named `v{version}.md` matching the git tag. This directory is
|
||||
committed to the repo and serves as the source of truth for release history.
|
||||
|
||||
The `releases/` directory should be created with a `.gitkeep` if it doesn't
|
||||
exist yet.
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
```bash
|
||||
# Full workflow summary:
|
||||
|
||||
# 1. Find last tag
|
||||
LAST_TAG=$(git tag --sort=-version:refname | head -1)
|
||||
|
||||
# 2. Commits since last tag
|
||||
git log $LAST_TAG..HEAD --oneline --no-merges
|
||||
|
||||
# 3. Files changed (for breaking change detection)
|
||||
git diff --name-only $LAST_TAG..HEAD
|
||||
|
||||
# 4. Migration changes specifically
|
||||
git diff --name-only $LAST_TAG..HEAD -- packages/db/src/migrations/
|
||||
|
||||
# 5. Schema changes
|
||||
git diff $LAST_TAG..HEAD -- packages/db/src/schema/
|
||||
|
||||
# 6. Unconsumed changesets
|
||||
ls .changeset/*.md | grep -v README.md
|
||||
|
||||
# 7. Merged PRs (if gh available)
|
||||
gh pr list --state merged --search "merged:>=$(git log -1 --format=%aI $LAST_TAG)" \
|
||||
--json number,title,body,labels
|
||||
```
|
||||
Reference in New Issue
Block a user