| name | release |
| description | Cut a new `mind` release. Bump the version, update the changelog, verify CI, tag with `make release`, and confirm the GitHub release workflow builds and uploads the binaries. |
release
Cut a tagged release of mind. The version in Cargo.toml is the single source
of truth: make release tags v<version> and pushes it, and that tag push
triggers .github/workflows/release.yml, which builds the per-platform binaries,
publishes the GitHub Release with the tarballs, and regenerates the Homebrew
formula.
Releases are SemVer. Pick the bump from what landed since the last tag: a new
verb/flag or other backward-compatible feature is a minor bump; a bug-fix-only
batch is a patch; a breaking change to the CLI, config, on-disk layout, or
mind.toml schema is a major bump.
Steps
1. Confirm a clean, green starting point
Work from main with everything merged and pushed.
git switch main && git pull
test -z "$(git status --porcelain)" || echo "tree is dirty; commit or stash first"
make ci
2. Pick the version and survey the changes
git describe --tags --abbrev=0
git log "$(git describe --tags --abbrev=0)..HEAD" --format='%s'
Decide the new X.Y.Z from that list (see the SemVer note above).
3. Bump the version
Between releases main carries a pre-release version (X.Y.Z-dev) so a build
from main is distinguishable from the released binary. Drop the suffix here:
edit Cargo.toml [package].version to the new X.Y.Z, then sync the lockfile
so Cargo.lock's mind entry matches (the release build uses --locked, so a
stale lock fails CI):
cargo build
tests/changelog.rs only requires a matching ## [X.Y.Z] section once the
-dev suffix is gone, so this bump is what arms that check. Step 9 puts the
next -dev version back.
4. Update the changelog
Add a ## [X.Y.Z] - YYYY-MM-DD section at the top of CHANGELOG.md (Keep a
Changelog format), grouping the changes under Added / Changed / Fixed /
Removed. Describe user-facing behavior, not the commit workflow. Update the
link references at the bottom: point [Unreleased] at
.../compare/vX.Y.Z...HEAD and add [X.Y.Z]: .../compare/v<prev>...vX.Y.Z.
tests/changelog.rs enforces this (every version section needs a matching ref,
[Unreleased] must compare from the newest version, and each ref chains to the
next-older one), so make ci fails if a ref is missing or stale. Keep the voice
plain and factual (see ~/.local/share/agents/voice/voice-profile.md).
5. Commit the release prep
make ci
git add Cargo.toml Cargo.lock CHANGELOG.md
git commit -m "release 0.0.0"
git push origin main
The commit subject is release X.Y.Z (matches the repo's convention).
6. Tag and trigger the release workflow
make release requires a clean tree and an unused tag. It tags v<Cargo.toml version> and pushes the tag:
make release
7. Watch the GitHub workflow succeed
The tag push starts release.yml. It must finish green before the release is
real. Watch it:
gh run watch "$(gh run list --workflow=release.yml --limit=1 --json databaseId -q '.[0].databaseId')"
The workflow has five jobs:
ci and ci-macos (parallel): re-run make ci on Linux and macOS at the
tagged commit, gating everything downstream.
build (matrix, needs ci + ci-macos): builds --release --locked for
aarch64-apple-darwin, aarch64-unknown-linux-gnu,
x86_64-unknown-linux-gnu, and the musl legs aarch64-unknown-linux-musl and
x86_64-unknown-linux-musl (statically linked, glibc-version-independent;
used by install.sh). Uploads each mind-<version>-<target>.tar.gz as an
artifact and attests build provenance for it. A --locked failure here means
Cargo.lock is stale; fix it and re-tag.
release (needs build): downloads the artifacts, generates SHA256SUMS,
and runs gh release create with every tarball plus SHA256SUMS; a missing
target's glob would fail the command, so the job fails closed on a partial
matrix.
publish (needs release): publishes to crates.io via trusted publishing
(OIDC, rust-lang/crates-io-auth-action, no stored token), then regenerates
Formula/mind.rb from the tarball checksums via resources/update-formula.sh
and commits it back to main as github-actions[bot].
8. Verify the published release
gh release view "v<version>"
cargo info mind-cli
git pull
grep -n 'version\|sha256' Formula/mind.rb
Optionally smoke-test the install path (resources/install.sh, or
brew upgrade mind from the tap).
9. Put main back on a -dev version
Bump Cargo.toml to the next patch version with a -dev suffix (after
0.22.0, use 0.22.1-dev), sync the lockfile, and add a fresh
## [Unreleased] heading to CHANGELOG.md:
cargo build
git add Cargo.toml Cargo.lock CHANGELOG.md
git commit -m "back to dev"
git push
Without this, a binary built from main reports the released version, so
mind --version in a bug report and evolve --check cannot tell a release from
unreleased work. The exact next number does not matter; step 3 sets the real one.
Notes
- The version lives only in
Cargo.toml; Makefile and the workflow derive the
tag from it. Do not hand-write the tag except via the make release override.
- If the workflow fails after the tag was pushed, delete the tag
(
git push origin :refs/tags/v<version> and git tag -d v<version>), fix the
cause on main, and re-run from step 5. A partially-created GitHub Release may
need to be deleted in the UI or with gh release delete.
- The release is outward-facing and hard to reverse (it publishes binaries and
pushes a formula commit). Confirm steps 1-5 are correct before running
make release.
- Known flake:
ci-macos can fail the timing-based lock test
tui::action::tests::execute_lock_is_exclusive_not_shared under a loaded
runner (it did on the first v0.13.0 tag, run 28724441026; the re-tag passed).
If that single test is the only failure on ci-macos, treat it as a flake:
delete the tag (see above), re-tag, and re-run. Investigate only if it fails
deterministically across re-runs.