Skip to content
Back to skills

Prepare Release

ASecurity

Advise on release size, unpublished changes, and consumer migration guides. Use before a release or when asked about version bumps or migration needs; never tag, push, or publish.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
developmentgobashrailsgit

Works with

  • cli

Security analysis

A100/100

Scanned November 7, 2026

npx -y skills add a-novel-kit/stack --skill prepare-release --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Prepare Release?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Prepare Release
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/a-novel-kit-prepare-release/badge)](https://www.skillsdirectory.com/skills/a-novel-kit-prepare-release)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: prepare-release
description: >
  Advise on release size, unpublished changes, and consumer migration guides. Use before a release
  or when asked about version bumps or migration needs; never tag, push, or publish.
---

# Prepare a release — size it, and write its migration guide

A release has two questions this skill answers before anyone clicks "Run":

1. **How big is it?** — patch or minor, read from the commit history, not guessed. (A major is not sized
   here; it is a planned `vX`-line initiative — see step 2.)
2. **What must a consumer do to adopt it?** — captured as a **migration guide** that ships with the
   code and lives forever, so the answer is never lost in a PR description or a Slack thread.

You are advisory: read the diff, propose the version, draft the guide. Core or the repository's
`owners-<class>` review and cut the release from the Actions tab. You never tag, push, or publish —
releases are human-only (see `manage-versions`).

> This skill is the manual stand-in for a future agent that runs it automatically before every
> release. Until then, invoke it deliberately when a release is near.

---

## 1. Read the unpublished diff

Find the last release and everything since, on the branch you'll release from (the default branch):

```bash
git fetch --tags origin
last=$(git tag --list 'v*' --sort=-v:refname | head -1)   # or <subdir>/v* for a sub-dir module
git log --no-merges --pretty='%s' "$last..origin/master"
```

Read the **subjects** (the conventional-commit type/scope/`!`) and, for anything that might break or
deprecate, the **body/footers** (`BREAKING CHANGE:`). A squash-merge repo has one commit per PR, so the
subjects are the PR titles — usually enough; open the PR/diff when a subject is ambiguous about consumer
impact.

With **no prior tag**, this is the first release (`v0.1.0` or `v1.0.0` per the team's call) — there is
nothing to migrate _from_, so a guide is rarely needed.

---

## 2. Propose the bump

Apply this mapping — a **local variant** of Conventional Commits; the **highest** wins across the range:

| Commit signal                                                                      | Bump      |
| ---------------------------------------------------------------------------------- | --------- |
| any `feat:`, or a `!` / `BREAKING CHANGE:` too small for its own major (see below) | **minor** |
| only `fix:` / `perf:` / `refactor:` / `chore:`                                     | **patch** |

**A major is never derived from the commit history here.** This is the deliberate departure from stock
Conventional Commits: a `!` or `BREAKING CHANGE:` footer does **not** size a release to major. A major
is a **planned, initiative-led migration on its own `vX` release line** — a global sweep, a paradigm
shift, a change whose migration is large enough to track as its own initiative — and it is cut from that
line when it lands, not proposed by this pass. If the range you are sizing contains a `!` and you think
it warrants a major, that is a signal to **stop and raise an initiative**, not to bump the second digit.

So a **breaking change small enough to absorb in a normal release stays a minor**: removing a capability
(especially one that no longer works), dropping a dead action, tightening a validation. It ships as a
minor with a migration guide (below), because it still asks a consumer to act, but it does not touch the
major. Name it plainly in the proposal — _"minor, carries one small breaking change (#NNN removes the
dead `foo` action)"_ — so the operator sees the break without a version jump implying a bigger one.

The **highest across the range is therefore minor** whenever any `feat:` or an absorbable break is
present, else patch. Docs/CI-only ranges (`docs:`, `ci:`, `chore:`) are a **patch** (still a release if
you want the notes), or skip the release entirely.

(There is no pre-1.0 special case: majors are initiative-gated regardless of the current major digit.)

State the proposed version plainly — e.g. _"`v1.0.3` → `v1.1.0` (minor: three `feat:`, no breaking
footer)"_ — and name the one or two commits that drove it. That version is also the **release-type the
human picks in the release workflow** and the **filename of the guide**.

---

## 3. Decide whether a migration guide is needed

A guide documents **consumer action**, not a changelog. Use this gate:

| Release shape                                                                              | Guide?          |
| ------------------------------------------------------------------------------------------ | --------------- |
| A major (the planned `vX`-line migration)                                                  | **Required**    |
| Minor carrying an absorbable breaking change (a removal, a tightened validation)           | **Required**    |
| Minor that **deprecates** a path, adds a **preferred** alternative, or recommends a change | **Recommended** |
| Minor that is purely additive (new optional thing, no consumer change)                     | No (notes only) |
| Patch (bug/perf/internal)                                                                  | No              |

The middle row is the subtle one: a backward-compatible release can still _ask_ consumers to move
(a new recommended input, a renamed-but-aliased field, a new pattern). Nothing forces the change, but
the migration is real and worth writing down once. When in doubt for a minor, ask: _"is there anything
a consumer should change to fully benefit, even though nothing breaks?"_ If yes, write the guide.

---

## 4. Write the guide

**One immutable file per version**, never a single growing `UPGRADING.md` — the convention every mature
migration system uses (Flyway `V1__…`, Rails / GitLab timestamped migrations). A single appended file is
a merge-conflict magnet across parallel release branches and blurs which change maps to which release;
per-version files are additive (no conflicts) and map 1:1 to a tag.

- **Path:** `docs/migrations/vX.Y.Z.md`, named by the version that introduces the change. (A sub-dir Go
  module — e.g. `cli/` — keys the file by its version too; a repo releases one module, so the version
  is unambiguous.)
- **Immutable once shipped.** Never edit a released guide; a correction goes in the _next_ version's
  guide, so history stays truthful.
- **Indexed.** Keep `docs/migrations/README.md` as a table, newest-first, linking each guide.
- **Linked from the release.** The release notes for `vX.Y.Z` should point at its guide (add the link
  to the generated notes / the GitHub Release body).
- **Committed _with_ the change**, before the release is cut — so the released tag already contains its
  own guide.

### Template

```markdown
# Upgrading to vX.Y.Z

One-line summary of what changed and why it matters to a consumer.

## Do I need to act?

**Required / Recommended / No** — and the one-sentence reason. If "No", say why the release is safe to
take as-is and stop here.

## <Change 1 — imperative title, e.g. "Switch bot inputs to client_id">

What changed and **why**. Then the concrete migration, before → after:

\`\`\`yaml

# before

app_id: ${{ vars.AGENT_BOT_ID }}

# after

client_id: ${{ vars.AGENT_BOT_CLIENT_ID }}
\`\`\`

Any **prerequisite** (a new variable, a new permission), whether the old path **still works**
(deprecated vs removed), and how to **verify** the migration landed.

## <Change 2 …>

…

## Notes

Anything optional, related follow-ups, or pointers to a larger effort this is part of.
```

Lead with **"Do I need to act?"** — most readers want exactly that, and a clear "No" for a safe minor is
a feature. Keep each change section to _what changed → why → before/after → caveats_.

---

## 5. Present — advisory only

Hand the operator: the **proposed version**, the **commits that drove it**, whether a **guide** was
written (and where), and the **release-type to pick** in the workflow. Then stop. Core or the
repository's owners cut the release (Actions ▸ `release` ▸ pick the bump); `release-core` stamps
versions, tags, and publishes.
You do not run it.

If the change ships in stages or spans repos, that ordering is a `manage-versions` concern — note it
and defer.

---

## Principles

- **The guide is consumer-facing.** Release notes list _what changed_; the guide says _what to do about
  it_. A change needing no consumer action belongs in the notes.
- **One file per version, immutable.** Additive, conflict-free, 1:1 with a tag.
- **Derive patch-vs-minor from the commit history.** If the history is wrong (a `feat` mislabeled
  `fix`), fix the discipline (`git-conventions`) rather than silently overriding the math.
- **A major is never derived; it is planned.** No commit range proposes a major. A major is an
  initiative with its own `vX` branch that becomes master when it lands. A `!` in an ordinary range is
  an absorbable breaking change (a minor with a guide), or a prompt to raise that initiative — never a
  second-digit bump on the current line.
- **Advisory, never the trigger.** You propose; core or the repository's owners release.

---

## How it composes

```
prepare-release ─ (reads the unpublished diff) ─> proposed bump + docs/migrations/vX.Y.Z.md
      │
      ├─ git-conventions  — the commit→bump mapping it applies
      ├─ manage-versions  — versioning mechanics, staged/cross-repo rollouts the guide may reference
      └─ release workflow — the human cuts the release with the proposed bump; the guide ships in the tag
```

A migration guide written here is the **instruction**; rolling it out across consumer repos is execution
(`implement-feature` / `manage-versions`), often tracked as its own follow-up issue.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.