Skip to content

releasetools/release

v0.3.0Apache-2.0

Cut a release: prechecks, notes, version bump, pull request, merge, tag, publish

release, as an agent plugin

Runs the steps a release takes, in order, stopping at the first refusal. What each step needs comes from .releasetools.yaml, so the same command releases a Python package, a Rust crate and a monorepo's one plugin.

Installing

claude plugin marketplace add releasetools/agent-plugins --scope project
claude plugin install release@release-tools --scope project
codex plugin add release@release-tools

--scope project declares it in the repository rather than in whoever ran it, so the next person to cut a release is offered the same plugin.

What it needs

releasetools/cli v0.4.0 or newer for the checks and the bump (brew install releasetools/tap/releasetools-cli), gh authenticated for the pull request and the workflows, and the release-notes plugin for the changelog entry.

What it reads

projects:
  - path: ./
    manifest: pyproject.toml
    changelog: CHANGELOG.md
    bump: uv version {version}

release:
  branch: main
  merge: squash
  checks: tests.yml
  publish: publish.yml
  trigger: tag
  registry: https://pypi.org/pypi/my-package/{version}/json
keywhat it isdefault
branchwhat a release is cut fromthe remote's default branch
mergehow the pull request lands: squash, rebase or mergesquash
checksthe workflow that must be green on the release commitnone, and the wait is skipped
publishthe workflow that publishes, watched to the endnone, and it stops at the push
triggerwhat starts publish: tag, dispatch, or a list of bothtag
registrya URL that must 404 before releasingnone

Under tag the plugin pushes the signed tag and the push starts publish. Under dispatch it runs publish with the version and the release commit, and the workflow creates the tag. /release:setup declares which, and changes the publish workflow to match.

The release tag is v<version>, as defined by the conventions. There is no tag-shape setting in .releasetools.yaml.

bump is the command the project declares for setting its version, which every ecosystem ships: uv version {version}, npm version {version} --no-git-tag-version, cargo set-version {version}. Nothing here parses or rewrites a manifest.

The steps

Release preparation runs in a linked worktree and branch owned by this release. The main checkout stays clean on the remote's default branch. One operator owns its updates through publication; other agents work in their own linked checkouts. A release from another branch uses a separate publication worktree too, and its preparation branch starts at that release branch's fetched tip.

1reserve the main checkout, synchronize it, then run rt release::prechecks in the publication checkout
2create a linked release worktree, prepare the notes and version, review the files, commit and push
3the pull request, with the changelog entry as its body, and its checks watched
4merge the recorded PR, synchronize main and verify the exact merged commit
5under tag, sign and push a tag naming that commit; under dispatch, run the workflow that tags it

The release tag leads back to the PR's merged commit even if the default branch advances during verification. Under dispatch it names that commit, or a built commit whose Source-Commit trailer does. The version and required checks are verified at that SHA. Local builds and tests use a linked checkout at the verified release commit, and artifacts are built from that checkout.

What it will not do

Move a tag, force anything, stash your work, delete an unmerged branch, retry a failed check in the hope that it passes, or release a version nobody named.

Where a publish workflow fails after it has already uploaded, the answer is to re-run that workflow, not to re-tag.

License

Apache-2.0. See LICENSE.