From cdf63d00244aa4e99aee08743e112ba634d39d93 Mon Sep 17 00:00:00 2001 From: Dotta Date: Thu, 5 Mar 2026 11:21:44 -0600 Subject: [PATCH] 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 --- releases/.gitkeep | 0 skills/release-changelog/SKILL.md | 331 ++++++++++++++++++++++++++++++ 2 files changed, 331 insertions(+) create mode 100644 releases/.gitkeep create mode 100644 skills/release-changelog/SKILL.md diff --git a/releases/.gitkeep b/releases/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/skills/release-changelog/SKILL.md b/skills/release-changelog/SKILL.md new file mode 100644 index 00000000..b5a57bba --- /dev/null +++ b/skills/release-changelog/SKILL.md @@ -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 +```