Skip to main content

release-workflow

Cut a release: version task, CHANGELOG, clean-tree gate, push then tag, gh release create, check the publish trigger, install the released build. Use when cutting or publishing a version.

Source facts

Repository
xberg-io/agent-conventions
Last source activity
October 30, 2026 at 05:04
Detected SKILL.md language
English
Stars
8
Forks
2

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
release-workflow
description
Cut a release: version task, CHANGELOG, clean-tree gate, push then tag, gh release create, check the publish trigger, install the released build. Use when cutting or publishing a version.
# Release Workflow (shared) Canonical publish sequence for a repo that tags versioned releases. One manifest (`Cargo.toml` in a Rust repo) is the single source of truth for the version, and the repo's version task syncs it to every other manifest. Task names differ per repo: find it with `mise tasks | grep -i version`. ## 1. Set the version Run the repo's version task. Some take the version as a `--` positional argument (`mise run <version-task> -- X.Y.Z`), others bump one part (`major`, `minor`, `patch`); read its description in `mise tasks`. The task rewrites the source manifest, syncs the version to every other manifest and pinned version constant, and refreshes lock files. Never hand-edit a manifest's `version` — use the task so everything stays in lockstep. Verify with `grep -m1 '^version' Cargo.toml` (or the repo's source manifest). ## 2. Update the CHANGELOG `CHANGELOG.md` follows Keep a Changelog. Entries land under `## [Unreleased]` between releases, never under an already-released section. At release, move every `[Unreleased]` bullet into a new `## [X.Y.Z] - YYYY-MM-DD` section (grouped Added / Changed / Deprecated / Removed / Fixed / Security), highlight breaking changes, and re-create an empty `[Unreleased]`. Never tag an empty section. ## 3. Clean-tree precondition (hard gate) Never release a dirty or failing tree. ```bash poly lint . # lint clean poly fmt --check . # formatting clean ``` The repo's test task must pass too (find it with `mise tasks | grep -i test`). Apply formatting with `poly fmt --fix .` and re-stage. Fix any lint or test failure at its source — do not release past a failure. If the repo carries a coding-agent plugin with its own version pin (`plugin/.ai-rulez/config.plugins.toml` `[plugin].version`, checked by its version-sync script), run its `--check` mode here too, against the version set in step 1: ```bash python3 scripts/sync_plugin_version.py --check # or the repo's equivalent ``` Step 1's version task already chains this sync — but a narrower, similarly-named task that syncs only some manifests is an easy trap, and running it instead silently leaves the plugin pin behind. This is not hypothetical: it produced a real drift (`[plugin].version` vs `Cargo.toml`) in two sibling repos on the same release day. Whatever CI runs post-tag as `--expect <version>` to gate `publish.yaml`, run here as `--check` before you tag — a gate that can only fire after the tag is cut turns every drift into a full re-run of the publish flow. ## 4. Commit, tag, and publish the GitHub release Push the default branch before creating the tag, not after — tagging first and pushing second risks the tag pointing at a commit the default branch never contains if the push is rejected or rebased in between. The default branch is not always `main`: ```bash default=$(git symbolic-ref --short refs/remotes/origin/HEAD | sed 's|^origin/||') git add CHANGELOG.md <each manifest and lock file the version task changed> git commit -m "chore(release): X.Y.Z" git push origin "HEAD:$default" git tag -a vX.Y.Z -m "vX.Y.Z" git push origin vX.Y.Z gh release create vX.Y.Z --title "vX.Y.Z" --generate-notes ``` Add `--prerelease` for RC/beta tags. Prefer `--notes-file` built from the new CHANGELOG section when the entry is rich. A bare `git tag` is not a release — always run `gh release create`. Stage the paths the version task reported (`git status --porcelain` lists them), never `git add -A`: another agent's work in the tree would ship in the release commit. **Do not assume what triggers your repo's publish workflow — check it.** Repos are not uniform: some publish on the GitHub release (`on: release: types: [published]`), some require an explicit `workflow_dispatch` with no automatic trigger at all, and at least one fires on a tag push (`on: push: tags:`). Read your own `.github/workflows/publish*.yaml` `on:` block before relying on any one of these — assuming the wrong mechanism is how a tagged, pushed release silently never reaches its registry. ## 5. Install the released build locally For a repo that ships a Rust CLI: ```bash cargo install --path . # CLI crate at a subpath: cargo install --path crates/<cli-crate> ``` Installs the released binary from the workspace so it shadows any crates.io copy on `$PATH`. Confirm `which <binary>` and `<binary> --version` reflect X.Y.Z. ## 6. Clean up build artifacts ```bash mise run clean # runs cargo clean (removes target/) plus repo-specific cleanup ``` Reclaims disk by removing build output and generated caches (`target/`, `dist/`). Where no `clean` task exists, run the toolchain's own clean (`cargo clean`). ## Anti-patterns - Hand-editing a manifest's `version` instead of the version task. - `git add -A` in the release commit. - Releasing a dirty or lint/test-failing tree. - Tagging without `gh release create`. - AI attribution in commit/tag/release text.
View on GitHub