Move maintainer skills into .agents/skills

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Dotta
2026-03-12 07:36:14 -05:00
parent 397e6d0915
commit 01180d3027
6 changed files with 4 additions and 4 deletions

View File

@@ -0,0 +1,202 @@
---
name: pr-report
description: >
Review a pull request or contribution deeply, explain it tutorial-style for a
maintainer, and produce a polished report artifact such as HTML or Markdown.
Use when asked to analyze a PR, explain a contributor's design decisions,
compare it with similar systems, or prepare a merge recommendation.
---
# PR Report Skill
Produce a maintainer-grade review of a PR, branch, or large contribution.
Default posture:
- understand the change before judging it
- explain the system as built, not just the diff
- separate architectural problems from product-scope objections
- make a concrete recommendation, not a vague impression
## When to Use
Use this skill when the user asks for things like:
- "review this PR deeply"
- "explain this contribution to me"
- "make me a report or webpage for this PR"
- "compare this design to similar systems"
- "should I merge this?"
## Outputs
Common outputs:
- standalone HTML report in `tmp/reports/...`
- Markdown report in `report/` or another requested folder
- short maintainer summary in chat
If the user asks for a webpage, build a polished standalone HTML artifact with
clear sections and readable visual hierarchy.
Resources bundled with this skill:
- `references/style-guide.md` for visual direction and report presentation rules
- `assets/html-report-starter.html` for a reusable standalone HTML/CSS starter
## Workflow
### 1. Acquire and frame the target
Work from local code when possible, not just the GitHub PR page.
Gather:
- target branch or worktree
- diff size and changed subsystems
- relevant repo docs, specs, and invariants
- contributor intent if it is documented in PR text or design docs
Start by answering: what is this change *trying* to become?
### 2. Build a mental model of the system
Do not stop at file-by-file notes. Reconstruct the design:
- what new runtime or contract exists
- which layers changed: db, shared types, server, UI, CLI, docs
- lifecycle: install, startup, execution, UI, failure, disablement
- trust boundary: what code runs where, under what authority
For large contributions, include a tutorial-style section that teaches the
system from first principles.
### 3. Review like a maintainer
Findings come first. Order by severity.
Prioritize:
- behavioral regressions
- trust or security gaps
- misleading abstractions
- lifecycle and operational risks
- coupling that will be hard to unwind
- missing tests or unverifiable claims
Always cite concrete file references when possible.
### 4. Distinguish the objection type
Be explicit about whether a concern is:
- product direction
- architecture
- implementation quality
- rollout strategy
- documentation honesty
Do not hide an architectural objection inside a scope objection.
### 5. Compare to external precedents when needed
If the contribution introduces a framework or platform concept, compare it to
similar open-source systems.
When comparing:
- prefer official docs or source
- focus on extension boundaries, context passing, trust model, and UI ownership
- extract lessons, not just similarities
Good comparison questions:
- Who owns lifecycle?
- Who owns UI composition?
- Is context explicit or ambient?
- Are plugins trusted code or sandboxed code?
- Are extension points named and typed?
### 6. Make the recommendation actionable
Do not stop at "merge" or "do not merge."
Choose one:
- merge as-is
- merge after specific redesign
- salvage specific pieces
- keep as design research
If rejecting or narrowing, say what should be kept.
Useful recommendation buckets:
- keep the protocol/type model
- redesign the UI boundary
- narrow the initial surface area
- defer third-party execution
- ship a host-owned extension-point model first
### 7. Build the artifact
Suggested report structure:
1. Executive summary
2. What the PR actually adds
3. Tutorial: how the system works
4. Strengths
5. Main findings
6. Comparisons
7. Recommendation
For HTML reports:
- use intentional typography and color
- make navigation easy for long reports
- favor strong section headings and small reference labels
- avoid generic dashboard styling
Before building from scratch, read `references/style-guide.md`.
If a fast polished starter is helpful, begin from `assets/html-report-starter.html`
and replace the placeholder content with the actual report.
### 8. Verify before handoff
Check:
- artifact path exists
- findings still match the actual code
- any requested forbidden strings are absent from generated output
- if tests were not run, say so explicitly
## Review Heuristics
### Plugin and platform work
Watch closely for:
- docs claiming sandboxing while runtime executes trusted host processes
- module-global state used to smuggle React context
- hidden dependence on render order
- plugins reaching into host internals instead of using explicit APIs
- "capabilities" that are really policy labels on top of fully trusted code
### Good signs
- typed contracts shared across layers
- explicit extension points
- host-owned lifecycle
- honest trust model
- narrow first rollout with room to grow
## Final Response
In chat, summarize:
- where the report is
- your overall call
- the top one or two reasons
- whether verification or tests were skipped
Keep the chat summary shorter than the report itself.

View File

@@ -0,0 +1,426 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>PR Report Starter</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&family=Newsreader:opsz,wght@6..72,500;6..72,700&display=swap"
rel="stylesheet"
/>
<style>
:root {
--bg: #f4efe5;
--paper: rgba(255, 251, 244, 0.88);
--paper-strong: #fffaf1;
--ink: #1f1b17;
--muted: #6a6257;
--line: rgba(31, 27, 23, 0.12);
--accent: #9c4729;
--accent-soft: rgba(156, 71, 41, 0.1);
--good: #2f6a42;
--warn: #946200;
--bad: #8c2f25;
--shadow: 0 22px 60px rgba(52, 37, 19, 0.1);
--radius: 20px;
}
* {
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
}
body {
margin: 0;
color: var(--ink);
font-family: "IBM Plex Sans", sans-serif;
background:
radial-gradient(circle at top left, rgba(156, 71, 41, 0.12), transparent 34rem),
radial-gradient(circle at top right, rgba(47, 106, 66, 0.08), transparent 28rem),
linear-gradient(180deg, #efe6d6 0%, var(--bg) 48%, #ece5d8 100%);
}
.shell {
width: min(1360px, calc(100vw - 32px));
margin: 24px auto;
display: grid;
grid-template-columns: 280px minmax(0, 1fr);
gap: 24px;
}
.panel {
background: var(--paper);
backdrop-filter: blur(12px);
border: 1px solid var(--line);
border-radius: var(--radius);
box-shadow: var(--shadow);
}
.nav {
position: sticky;
top: 20px;
align-self: start;
padding: 22px;
}
.eyebrow {
letter-spacing: 0.12em;
text-transform: uppercase;
font-size: 11px;
font-weight: 700;
color: var(--accent);
}
.nav h1,
.hero h1,
h2,
h3 {
font-family: "Newsreader", serif;
line-height: 0.96;
margin: 0;
}
.nav h1 {
font-size: 2rem;
margin-top: 10px;
}
.nav p {
color: var(--muted);
font-size: 0.95rem;
line-height: 1.5;
}
.nav ul {
list-style: none;
padding: 0;
margin: 18px 0 0;
display: grid;
gap: 10px;
}
.nav a {
display: block;
color: var(--ink);
text-decoration: none;
padding: 10px 12px;
border-radius: 12px;
border: 1px solid transparent;
background: rgba(255, 255, 255, 0.35);
}
.nav a:hover {
border-color: var(--line);
background: rgba(255, 255, 255, 0.75);
}
.meta-block {
margin-top: 20px;
padding-top: 18px;
border-top: 1px solid var(--line);
color: var(--muted);
font-size: 0.86rem;
line-height: 1.5;
}
main {
display: grid;
gap: 24px;
}
section {
padding: 26px 28px 28px;
}
.hero {
padding: 28px;
overflow: hidden;
position: relative;
}
.hero::after {
content: "";
position: absolute;
inset: auto -3rem -6rem auto;
width: 18rem;
height: 18rem;
border-radius: 50%;
background: radial-gradient(circle, rgba(156, 71, 41, 0.14), transparent 68%);
pointer-events: none;
}
.hero h1 {
font-size: clamp(2.6rem, 5vw, 4.6rem);
max-width: 12ch;
margin-top: 12px;
}
.lede {
margin-top: 16px;
max-width: 70ch;
font-size: 1.05rem;
line-height: 1.65;
color: #2b2723;
}
.hero-grid,
.card-grid,
.two-col {
display: grid;
gap: 14px;
}
.hero-grid {
margin-top: 24px;
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.card-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.two-col {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.metric,
.card,
.finding {
padding: 18px;
background: rgba(255, 255, 255, 0.68);
border: 1px solid var(--line);
border-radius: 18px;
}
.metric .label {
color: var(--muted);
font-size: 0.82rem;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.metric .value {
margin-top: 8px;
font-size: 1.45rem;
font-weight: 700;
}
h2 {
font-size: 2rem;
margin-bottom: 16px;
}
h3 {
font-size: 1.3rem;
margin-bottom: 10px;
}
p {
margin: 0 0 14px;
line-height: 1.65;
}
ul,
ol {
margin: 0;
padding-left: 20px;
line-height: 1.65;
}
li + li {
margin-top: 8px;
}
.badge-row {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin: 18px 0 8px;
}
.badge {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 10px;
border-radius: 999px;
font-size: 0.82rem;
font-weight: 700;
border: 1px solid var(--line);
background: rgba(255, 255, 255, 0.68);
}
.badge.good {
color: var(--good);
}
.badge.warn {
color: var(--warn);
}
.badge.bad {
color: var(--bad);
}
.quote {
margin-top: 18px;
padding: 18px;
border-left: 4px solid var(--accent);
border-radius: 14px;
background: var(--accent-soft);
}
.severity {
display: inline-flex;
margin-bottom: 12px;
padding: 6px 10px;
border-radius: 999px;
font-size: 0.78rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
}
.severity.high {
background: rgba(140, 47, 37, 0.12);
color: var(--bad);
}
.severity.medium {
background: rgba(148, 98, 0, 0.12);
color: var(--warn);
}
.severity.low {
background: rgba(47, 106, 66, 0.12);
color: var(--good);
}
.ref {
color: var(--muted);
font-size: 0.82rem;
line-height: 1.5;
}
@media (max-width: 980px) {
.shell {
grid-template-columns: 1fr;
}
.nav {
position: static;
}
.hero-grid,
.card-grid,
.two-col {
grid-template-columns: 1fr;
}
.hero h1 {
max-width: 100%;
}
}
</style>
</head>
<body>
<div class="shell">
<aside class="panel nav">
<div class="eyebrow">Maintainer Report</div>
<h1>Report Title</h1>
<p>Replace this with a concise description of what the report covers.</p>
<ul>
<li><a href="#summary">Summary</a></li>
<li><a href="#tutorial">Tutorial</a></li>
<li><a href="#findings">Findings</a></li>
<li><a href="#recommendation">Recommendation</a></li>
</ul>
<div class="meta-block">
Replace with project metadata, review date, or scope notes.
</div>
</aside>
<main>
<section class="panel hero" id="summary">
<div class="eyebrow">Executive Summary</div>
<h1>Use the hero for the clearest one-line judgment.</h1>
<p class="lede">
Replace this with the short explanation of what the contribution does, why it matters,
and what the core maintainer question is.
</p>
<div class="badge-row">
<span class="badge good">Strength</span>
<span class="badge warn">Tradeoff</span>
<span class="badge bad">Risk</span>
</div>
<div class="hero-grid">
<div class="metric">
<div class="label">Overall Call</div>
<div class="value">Placeholder</div>
</div>
<div class="metric">
<div class="label">Main Concern</div>
<div class="value">Placeholder</div>
</div>
<div class="metric">
<div class="label">Best Part</div>
<div class="value">Placeholder</div>
</div>
<div class="metric">
<div class="label">Weakest Part</div>
<div class="value">Placeholder</div>
</div>
</div>
<div class="quote">
Use this block for the thesis, a sharp takeaway, or a key cited point.
</div>
</section>
<section class="panel" id="tutorial">
<h2>Tutorial Section</h2>
<div class="two-col">
<div class="card">
<h3>Concept Card</h3>
<p>Use cards for mental models, subsystems, or comparison slices.</p>
<div class="ref">path/to/file.ts:10</div>
</div>
<div class="card">
<h3>Second Card</h3>
<p>Keep cards fairly dense. This template is about style, not fixed structure.</p>
<div class="ref">path/to/file.ts:20</div>
</div>
</div>
</section>
<section class="panel" id="findings">
<h2>Findings</h2>
<article class="finding">
<div class="severity high">High</div>
<h3>Finding Title</h3>
<p>Use findings for the sharpest judgment calls and risks.</p>
<div class="ref">path/to/file.ts:30</div>
</article>
</section>
<section class="panel" id="recommendation">
<h2>Recommendation</h2>
<div class="card-grid">
<div class="card">
<h3>Path Forward</h3>
<p>Use this area for merge guidance, salvage plan, or rollout advice.</p>
</div>
<div class="card">
<h3>What To Keep</h3>
<p>Call out the parts worth preserving even if the whole proposal should not land.</p>
</div>
</div>
</section>
</main>
</div>
</body>
</html>

View File

@@ -0,0 +1,149 @@
# PR Report Style Guide
Use this guide when the user wants a report artifact, especially a webpage.
## Goal
Make the report feel like an editorial review, not an internal admin dashboard.
The page should make a long technical argument easy to scan without looking
generic or overdesigned.
## Visual Direction
Preferred tone:
- editorial
- warm
- serious
- high-contrast
- handcrafted, not corporate SaaS
Avoid:
- default app-shell layouts
- purple gradients on white
- generic card dashboards
- cramped pages with weak hierarchy
- novelty fonts that hurt readability
## Typography
Recommended pattern:
- one expressive serif or display face for major headings
- one sturdy sans-serif for body copy and UI labels
Good combinations:
- Newsreader + IBM Plex Sans
- Source Serif 4 + Instrument Sans
- Fraunces + Public Sans
- Libre Baskerville + Work Sans
Rules:
- headings should feel deliberate and large
- body copy should stay comfortable for long reading
- reference labels and badges should use smaller dense sans text
## Layout
Recommended structure:
- a sticky side or top navigation for long reports
- one strong hero summary at the top
- panel or paper-like sections for each major topic
- multi-column card grids for comparisons and strengths
- single-column body text for findings and recommendations
Use generous spacing. Long-form technical reports need breathing room.
## Color
Prefer muted paper-like backgrounds with one warm accent and one cool counterweight.
Suggested token categories:
- `--bg`
- `--paper`
- `--ink`
- `--muted`
- `--line`
- `--accent`
- `--good`
- `--warn`
- `--bad`
The accent should highlight navigation, badges, and important labels. Do not
let accent colors dominate body text.
## Useful UI Elements
Include small reusable styles for:
- summary metrics
- badges
- quotes or callouts
- finding cards
- severity labels
- reference labels
- comparison cards
- responsive two-column sections
## Motion
Keep motion restrained.
Good:
- soft fade/slide-in on first load
- hover response on nav items or cards
Bad:
- constant animation
- floating blobs
- decorative motion with no reading benefit
## Content Presentation
Even when the user wants design polish, clarity stays primary.
Good structure for long reports:
1. executive summary
2. what changed
3. tutorial explanation
4. strengths
5. findings
6. comparisons
7. recommendation
The exact headings can change. The important thing is to separate explanation
from judgment.
## References
Reference labels should be visually quiet but easy to spot.
Good pattern:
- small muted text
- monospace or compact sans
- keep them close to the paragraph they support
## Starter Usage
If you need a fast polished base, start from:
- `assets/html-report-starter.html`
Customize:
- fonts
- color tokens
- hero copy
- section ordering
- card density
Do not preserve the placeholder sections if they do not fit the actual report.

View File

@@ -0,0 +1,178 @@
---
name: release-changelog
description: >
Generate the stable Paperclip release changelog at releases/v{version}.md by
reading commits, changesets, and merged PR context since the last stable tag.
---
# Release Changelog Skill
Generate the user-facing changelog for the **stable** Paperclip release.
Output:
- `releases/v{version}.md`
Important rule:
- even if there are canary releases such as `1.2.3-canary.0`, the changelog file stays `releases/v1.2.3.md`
## Step 0 — Idempotency Check
Before generating anything, check whether the file already exists:
```bash
ls releases/v{version}.md 2>/dev/null
```
If it exists:
1. read it first
2. present it to the reviewer
3. ask whether to keep it, regenerate it, or update specific sections
4. never overwrite it silently
## Step 1 — Determine the Stable Range
Find the last stable tag:
```bash
git tag --list 'v*' --sort=-version:refname | head -1
git log v{last}..HEAD --oneline --no-merges
```
The planned stable version comes from one of:
- an explicit maintainer request
- the chosen bump type applied to the last stable tag
- the release plan already agreed in `doc/RELEASING.md`
Do not derive the changelog version from a canary tag or prerelease suffix.
## Step 2 — Gather the Raw Inputs
Collect release data from:
1. git commits since the last stable tag
2. `.changeset/*.md` files
3. merged PRs via `gh` when available
Useful commands:
```bash
git log v{last}..HEAD --oneline --no-merges
git log v{last}..HEAD --format="%H %s" --no-merges
ls .changeset/*.md | grep -v README.md
gh pr list --state merged --search "merged:>={last-tag-date}" --json number,title,body,labels
```
## Step 3 — Detect Breaking Changes
Look for:
- destructive migrations
- removed or changed API fields/endpoints
- renamed or removed config keys
- `major` changesets
- `BREAKING:` or `BREAKING CHANGE:` commit signals
Key commands:
```bash
git diff --name-only v{last}..HEAD -- packages/db/src/migrations/
git diff v{last}..HEAD -- packages/db/src/schema/
git diff v{last}..HEAD -- server/src/routes/ server/src/api/
git log v{last}..HEAD --format="%s" | rg -n 'BREAKING CHANGE|BREAKING:|^[a-z]+!:' || true
```
If the requested bump is lower than the minimum required bump, flag that before the release proceeds.
## Step 4 — Categorize for Users
Use these stable changelog sections:
- `Breaking Changes`
- `Highlights`
- `Improvements`
- `Fixes`
- `Upgrade Guide` when needed
Exclude purely internal refactors, CI changes, and docs-only work unless they materially affect users.
Guidelines:
- group related commits into one user-facing entry
- write from the user perspective
- keep highlights short and concrete
- spell out upgrade actions for breaking changes
### Inline PR and contributor attribution
When a bullet item clearly maps to a merged pull request, add inline attribution at the
end of the entry in this format:
```
- **Feature name** — Description. ([#123](https://github.com/paperclipai/paperclip/pull/123), @contributor1, @contributor2)
```
Rules:
- Only add a PR link when you can confidently trace the bullet to a specific merged PR.
Use merge commit messages (`Merge pull request #N from user/branch`) to map PRs.
- List the contributor(s) who authored the PR. Use GitHub usernames, not real names or emails.
- If multiple PRs contributed to a single bullet, list them all: `([#10](url), [#12](url), @user1, @user2)`.
- If you cannot determine the PR number or contributor with confidence, omit the attribution
parenthetical — do not guess.
- Core maintainer commits that don't have an external PR can omit the parenthetical.
## Step 5 — Write the File
Template:
```markdown
# v{version}
> Released: {YYYY-MM-DD}
## Breaking Changes
## Highlights
## Improvements
## Fixes
## Upgrade Guide
## Contributors
Thank you to everyone who contributed to this release!
@username1, @username2, @username3
```
Omit empty sections except `Highlights`, `Improvements`, and `Fixes`, which should usually exist.
The `Contributors` section should always be included. List every person who authored
commits in the release range, @-mentioning them by their **GitHub username** (not their
real name or email). To find GitHub usernames:
1. Extract usernames from merge commit messages: `git log v{last}..HEAD --oneline --merges` — the branch prefix (e.g. `from username/branch`) gives the GitHub username.
2. For noreply emails like `user@users.noreply.github.com`, the username is the part before `@`.
3. For contributors whose username is ambiguous, check `gh api users/{guess}` or the PR page.
**Never expose contributor email addresses.** Use `@username` only.
Exclude bot accounts (e.g. `lockfile-bot`, `dependabot`) from the list. List contributors
in alphabetical order by GitHub username (case-insensitive).
## Step 6 — Review Before Release
Before handing it off:
1. confirm the heading is the stable version only
2. confirm there is no `-canary` language in the title or filename
3. confirm any breaking changes have an upgrade path
4. present the draft for human sign-off
This skill never publishes anything. It only prepares the stable changelog artifact.

View File

@@ -0,0 +1,261 @@
---
name: release
description: >
Coordinate a full Paperclip release across engineering verification, npm,
GitHub, website publishing, and announcement follow-up. Use when leadership
asks to ship a release, not merely to discuss version bumps.
---
# Release Coordination Skill
Run the full Paperclip release as a maintainer workflow, not just an npm publish.
This skill coordinates:
- stable changelog drafting via `release-changelog`
- release-train setup via `scripts/release-start.sh`
- prerelease canary publishing via `scripts/release.sh --canary`
- Docker smoke testing via `scripts/docker-onboard-smoke.sh`
- stable publishing via `scripts/release.sh`
- pushing the stable branch commit and tag
- GitHub Release creation via `scripts/create-github-release.sh`
- website / announcement follow-up tasks
## Trigger
Use this skill when leadership asks for:
- "do a release"
- "ship the next patch/minor/major"
- "release vX.Y.Z"
## Preconditions
Before proceeding, verify all of the following:
1. `.agents/skills/release-changelog/SKILL.md` exists and is usable.
2. The repo working tree is clean, including untracked files.
3. There are commits since the last stable tag.
4. The release SHA has passed the verification gate or is about to.
5. If package manifests changed, the CI-owned `pnpm-lock.yaml` refresh is already merged on `master` before the release branch is cut.
6. npm publish rights are available locally, or the GitHub release workflow is being used with trusted publishing.
7. If running through Paperclip, you have issue context for status updates and follow-up task creation.
If any precondition fails, stop and report the blocker.
## Inputs
Collect these inputs up front:
- requested bump: `patch`, `minor`, or `major`
- whether this run is a dry run or live release
- whether the release is being run locally or from GitHub Actions
- release issue / company context for website and announcement follow-up
## Step 0 — Release Model
Paperclip now uses this release model:
1. Start or resume `release/X.Y.Z`
2. Draft the **stable** changelog as `releases/vX.Y.Z.md`
3. Publish one or more **prerelease canaries** such as `X.Y.Z-canary.0`
4. Smoke test the canary via Docker
5. Publish the stable version `X.Y.Z`
6. Push the stable branch commit and tag
7. Create the GitHub Release
8. Merge `release/X.Y.Z` back to `master` without squash or rebase
9. Complete website and announcement surfaces
Critical consequence:
- Canaries do **not** use promote-by-dist-tag anymore.
- The changelog remains stable-only. Do not create `releases/vX.Y.Z-canary.N.md`.
## Step 1 — Decide the Stable Version
Start the release train first:
```bash
./scripts/release-start.sh {patch|minor|major}
```
Then run release preflight:
```bash
./scripts/release-preflight.sh canary {patch|minor|major}
# or
./scripts/release-preflight.sh stable {patch|minor|major}
```
Then use the last stable tag as the base:
```bash
LAST_TAG=$(git tag --list 'v*' --sort=-version:refname | head -1)
git log "${LAST_TAG}..HEAD" --oneline --no-merges
git diff --name-only "${LAST_TAG}..HEAD" -- packages/db/src/migrations/
git diff "${LAST_TAG}..HEAD" -- packages/db/src/schema/
git log "${LAST_TAG}..HEAD" --format="%s" | rg -n 'BREAKING CHANGE|BREAKING:|^[a-z]+!:' || true
```
Bump policy:
- destructive migrations, removed APIs, breaking config changes -> `major`
- additive migrations or clearly user-visible features -> at least `minor`
- fixes only -> `patch`
If the requested bump is too low, escalate it and explain why.
## Step 2 — Draft the Stable Changelog
Invoke `release-changelog` and generate:
- `releases/vX.Y.Z.md`
Rules:
- review the draft with a human before publish
- preserve manual edits if the file already exists
- keep the heading and filename stable-only, for example `v1.2.3`
- do not create a separate canary changelog file
## Step 3 — Verify the Release SHA
Run the standard gate:
```bash
pnpm -r typecheck
pnpm test:run
pnpm build
```
If the release will be run through GitHub Actions, the workflow can rerun this gate. Still report whether the local tree currently passes.
The GitHub Actions release workflow installs with `pnpm install --frozen-lockfile`. Treat that as a release invariant, not a nuisance: if manifests changed and the lockfile refresh PR has not landed yet, stop and wait for `master` to contain the committed lockfile before shipping.
## Step 4 — Publish a Canary
Run from the `release/X.Y.Z` branch:
```bash
./scripts/release.sh {patch|minor|major} --canary --dry-run
./scripts/release.sh {patch|minor|major} --canary
```
What this means:
- npm receives `X.Y.Z-canary.N` under dist-tag `canary`
- `latest` remains unchanged
- no git tag is created
- the script cleans the working tree afterward
Guard:
- if the current stable is `0.2.7`, the next patch canary is `0.2.8-canary.0`
- the tooling must never publish `0.2.7-canary.N` after `0.2.7` is already stable
After publish, verify:
```bash
npm view paperclipai@canary version
```
The user install path is:
```bash
npx paperclipai@canary onboard
```
## Step 5 — Smoke Test the Canary
Run:
```bash
PAPERCLIPAI_VERSION=canary ./scripts/docker-onboard-smoke.sh
```
Confirm:
1. install succeeds
2. onboarding completes
3. server boots
4. UI loads
5. basic company/dashboard flow works
If smoke testing fails:
- stop the stable release
- fix the issue
- publish another canary
- repeat the smoke test
Each retry should create a higher canary ordinal, while the stable target version can stay the same.
## Step 6 — Publish Stable
Once the SHA is vetted, run:
```bash
./scripts/release.sh {patch|minor|major} --dry-run
./scripts/release.sh {patch|minor|major}
```
Stable publish does this:
- publishes `X.Y.Z` to npm under `latest`
- creates the local release commit
- creates the local git tag `vX.Y.Z`
Stable publish does **not** push the release for you.
## Step 7 — Push and Create GitHub Release
After stable publish succeeds:
```bash
git push public-gh HEAD --follow-tags
./scripts/create-github-release.sh X.Y.Z
```
Use the stable changelog file as the GitHub Release notes source.
Then open the PR from `release/X.Y.Z` back to `master` and merge without squash or rebase.
## Step 8 — Finish the Other Surfaces
Create or verify follow-up work for:
- website changelog publishing
- launch post / social announcement
- any release summary in Paperclip issue context
These should reference the stable release, not the canary.
## Failure Handling
If the canary is bad:
- publish another canary, do not ship stable
If stable npm publish succeeds but push or GitHub release creation fails:
- fix the git/GitHub issue immediately from the same checkout
- do not republish the same version
If `latest` is bad after stable publish:
```bash
./scripts/rollback-latest.sh <last-good-version>
```
Then fix forward with a new patch release.
## Output
When the skill completes, provide:
- stable version and, if relevant, the final canary version tested
- verification status
- npm status
- git tag / GitHub Release status
- website / announcement follow-up status
- rollback recommendation if anything is still partially complete