Plannotator release-plannotator
Prepare and execute a Plannotator release — draft release notes with full contributor credit, bump versions across all package files, build in dependency order, and kick off the tag-driven release pipeline. Use this skill whenever the user mentions preparing a release, bumping versions, writing release notes, tagging a release, or publishing. Also trigger when the user says things like "let's ship", "prep a release", "what's changed since last release", or "time to cut a new version".
git clone https://github.com/backnotprop/plannotator
T=$(mktemp -d) && git clone --depth=1 https://github.com/backnotprop/plannotator "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.agents/skills/release" ~/.claude/skills/backnotprop-plannotator-release-plannotator && rm -rf "$T"
.agents/skills/release/SKILL.mdPlannotator Release
The process has four phases. Phase 1 (release notes) is where most of the work happens — present the draft for review before proceeding to later phases.
Phase 1: Draft Release Notes
This is the most important phase. The release notes are the public face of each version and the primary way the community sees their contributions recognized.
Step 1: Determine scope
- Find the latest release tag:
git tag --sort=-v:refname | head -1 - Determine the new version number. Ask the user if unclear (patch, minor, or major).
- Gather all changes since the last tag:
for commit historygit log --oneline <last-tag>..HEAD
for merged PRsgit log --merges --oneline <last-tag>..HEAD
- For each PR, use
to get details.gh pr view <number> --json title,author,body,closedIssues,labels
Step 2: Research contributors
This is critical. Every person who participated in the release gets credit — not just PR authors.
For each PR and linked issue, collect:
- PR authors — the person who wrote the code
- Issue reporters — who filed the bug or feature request
- Issue commenters — who participated in the discussion with useful context
- Discussion creators — who started relevant GitHub Discussions
- Feature requestors — check the linked "closes #N" issues and their authors
Use the GitHub API via
gh:
# Get issue details including author gh issue view <number> --json author,title,body # Get issue comments to find participants gh api repos/backnotprop/plannotator/issues/<number>/comments --jq '.[].user.login' # Get PR review comments gh api repos/backnotprop/plannotator/pulls/<number>/comments --jq '.[].user.login'
Step 3: Write the release notes
Read the reference release notes in
references/ for the canonical template structure. These are real release notes from previous versions — match their tone, structure, and level of detail.
— large release, 14 PRs, 3 first-time contributors, "New Contributors" + narrative "Contributors" sectionrelease-notes-v0.13.0.md
— large community release, 14 PRs, 10 external, detailed narrative "Contributors" sectionrelease-notes-v0.12.0.md
— small patch release, 2 PRs, no external authors, "Community" section focused on issue reportersrelease-notes-v0.13.1.md
Pay attention to how each reference handles contributor crediting differently. Pick the pattern that fits the release's contributor profile — a release with many external PRs warrants a narrative "Contributors" section; a patch driven by issue reports uses a lighter "Community" section.
Write the file to the repo root as
RELEASE_NOTES_v<VERSION>.md.
Structure
-
X/Twitter follow link — first line, always the same:
Follow [@plannotator](https://x.com/plannotator) on X for updates -
"Missed recent releases?" collapsible table — copy from the previous release's notes, then:
- Add the previous release (the one you're succeeding) as the newest row
- Keep roughly 10-12 rows; drop the oldest if needed
- Each row: version link + comma-separated feature highlights (short phrases)
-
"What's New in vX.Y.Z" — the heart of the notes
- Open with 1-3 sentences summarizing the release theme and scope. Mention how many PRs, how many from external contributors, any first-timers.
- Each major feature/fix gets its own
subsection with:###- A descriptive heading (not the PR title verbatim — rephrase for clarity)
- 1-4 paragraphs explaining what changed and why it matters. Be specific and concrete. Describe the problem that existed before, what the change does, and how users experience it.
- Credit line at the bottom: PR link, linked issues with
, and contributor attributionclosing [#N]
- Minor changes go under
as bold-titled bullets### Additional Changes
-
Install / Update — standard block, read from the previous release notes and reuse verbatim
-
"What's Changed" — bullet list of every PR in the release:
- feat: descriptive PR title by @author in [#N](url) -
"New Contributors" — if any first-time contributors:
- @username made their first contribution in [#N](url) -
"Contributors" or "Community" — narrative section recognizing everyone who participated:
- PR authors get a sentence about what they built
- Issue reporters and commenters get listed with what they reported/discussed
- Group community issue reporters in a bullet list at the end
-
Full Changelog link:
**Full Changelog**: https://github.com/backnotprop/plannotator/compare/<prev-tag>...<new-tag>
Writing guidelines
- Narrative over noise. Write in clear, readable prose. Not marketing-speak, not changelog-dump. Explain what changed and why someone should care, in plain language.
- Bullets where they help. Use bullet lists for enumerating discrete items (additional changes, contributor lists). Use paragraphs for explaining features.
- No cliches or buzzwords. Don't say "exciting", "game-changing", "seamless", "powerful". Just describe what happened.
- No punchlines. Don't end sections with a clever quip or a summary zinger. Let the feature speak for itself.
- Speak through practical benefit. Describe what changed and what it means for the user in concrete, reliable terms. Not aspirational, not hype — just what it does.
- Don't overuse em dashes. One or two per release is fine. If you notice them stacking up, restructure the sentence instead.
- Grammatical structure matters. Vary sentence structure. Active voice. Concrete subjects and verbs.
- Contributor tags. Use
— bare at-mentions, not markdown links like@username
. GitHub renders bare[@user](url)
with avatar icons in release notes. This is important for community recognition.@mentions - Every contributor counts. Everyone who filed an issue, left a comment that shaped a decision, or participated in a discussion gets mentioned. This project's community is its lifeblood.
Step 4: Present for review
Write the draft to
RELEASE_NOTES_v<VERSION>.md in the repo root and tell the user it's ready for review. Do not git add or commit this file — release notes are kept untracked by design. Wait for their feedback before proceeding to Phase 2.
Phase 2: Version Bump
Bump the version string in these 7 files (and only these — other package.json files use stub versions):
| File | Field |
|---|---|
(root) | |
| |
| |
| |
| |
(root) | |
| |
Read each file, confirm the current version matches expectations, then update all 7 atomically.
Do not bump the VS Code extension (
apps/vscode-extension/package.json) — it has independent versioning.
Phase 3: Build
Run builds in dependency order:
bun run build:review # 1. Code review editor (standalone Vite build) bun run build:hook # 2. Plan review + hook server (copies review's built HTML into hook dist) bun run build:opencode # 3. OpenCode plugin (copies built HTML from hook + review) bun run build:pi # 4. Pi extension (chains review → hook → pi internally, safe to run after 1-2)
build:pi chains review and hook internally, so after steps 1-2 it only runs the pi-specific build.
Verify all builds succeed before proceeding.
Pi Parity Gate
After builds pass, audit the Pi extension to ensure all server-side imports resolve in the published package. This catches missing files before they reach npm.
-
Check imports vs
array. Trace all local imports (starting withfiles
or./
) from../
,index.ts
,server.ts
, and every file intool-scope.ts
. Verify each target is covered by a pattern in theserver/
array offiles
.apps/pi-extension/package.json -
Check
covers all shared/ai imports. Everyvendor.sh
import in the server files must have a corresponding entry in../generated/*.js
's copy loops. If a new shared module or AI module was added tovendor.sh
orpackages/shared/
and is imported by Pi's server code, it must be added topackages/ai/
.vendor.sh -
Dry-run the pack. Run
and verify the output includes every file the server imports. Look specifically for any newly added files since the last release.cd apps/pi-extension && bun pm pack --dry-run -
Quick smoke test. Confirm
contains all expected files after build, especially any new ones (e.g., a new shared module added in this release cycle).generated/
If anything is missing, fix it before proceeding to Phase 4. Common fixes:
- Add the file to
's copy loopvendor.sh - Add the file or directory to the
array infilespackage.json - Add an import path fix (Pi uses
not../generated/
or@plannotator/shared
)@plannotator/ai
Phase 4: Commit, Tag, and Release
-
Commit the version bump:
chore: bump version to X.Y.ZStage only the 7 version-bumped files. Do not stage the release notes file (it's untracked by design).
-
Create and push the tag:
git tag vX.Y.Z git push origin main git push origin vX.Y.ZThe
tag push triggers the release pipeline (v*
)..github/workflows/release.yml -
The pipeline handles everything else:
- Runs tests
- Cross-compiles binaries for 6 platforms (macOS ARM64/x64, Linux x64/ARM64, Windows x64/ARM64)
- Compiles paste service binaries (same 6 platforms)
- Generates SLSA build provenance attestations for all 12 binaries via
(signed through Sigstore, recorded in Rekor)actions/attest-build-provenance - Creates the GitHub Release with all binaries attached
- Publishes
and@plannotator/opencode
to npm with provenance@plannotator/pi-extension
Note on immutable releases: The repo has GitHub Immutable Releases enabled, so once the
tag is pushed and the release is created, the tag→commit and tag→asset bindings are permanent. You cannot delete and re-create a tag to "fix" a bad release — you must ship a new version. Release notes remain editable (see step 5), but everything else is locked.v* -
Monitor the pipeline: Watch the release workflow run until it completes:
gh run list --workflow=release.yml --limit=1 gh run view <run-id> --logVerify:
- All jobs pass (test, build, release, npm-publish)
- The GitHub Release was created with all binary artifacts
- npm packages published successfully (check with
andnpm view @plannotator/opencode version
)npm view @plannotator/pi-extension version
If anything fails, investigate the logs and report to the user before retrying.
-
Replace the release notes: Once the release is live and verified, replace the auto-generated notes body with the drafted release notes:
gh release edit vX.Y.Z --notes-file RELEASE_NOTES_v<VERSION>.md
Checklist
Before tagging, verify:
- All 7 version files bumped consistently
- Release notes drafted and reviewed
-
succeededbun run build:review -
succeededbun run build:hook -
succeededbun run build:opencode -
succeeded (or pi-specific build step)bun run build:pi - Version bump committed
- Pi parity gate passed (imports, vendor.sh, dry-run pack)
- No stale build artifacts (clean builds, no cache issues — run
first if dependencies changed)bun install
After tagging, verify:
- Release workflow completed (all 4 jobs green)
- GitHub Release created with all binaries
- npm packages published at correct version
- Release notes replaced via
gh release edit