Prepare release
Development tools backing a-novel and a-novel-kit. Home of a-novel CLI and AI skills.
npx -y skills add a-novel-kit/stack --skill prepare-releaseAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Run BEFORE cutting a release: it reads the commits since the last tag, proposes the version bump (`fix`/`chore`→patch, `feat` or an absorbable breaking change→minor; a major is never derived from commits — it is a planned `vX`-line initiative), and drafts the per-version migration guide (`docs/migrations/vX.Y.Z.md`) when consumers must act. Use it when asked "is this patch / minor / major?", "what changed since the last release?", or "does this need a migration guide?". ADVISORY — the human cuts the release; this never tags, pushes, or publishes.
SKILL.md
9.9 KB, as published. Nobody here has run it
Prepare a release — size it, and write its migration guide
A release has two questions this skill answers before anyone clicks "Run":
- 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.) - 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. The human reviews and cuts 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):
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.mdas a table, newest-first, linking each guide. - Linked from the release. The release notes for
vX.Y.Zshould 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
# 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. The human cuts 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
featmislabeledfix), 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
vXbranch 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; the human releases.
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.