RELEASING.md in the repository — edit it there.Releasing
This project has one source of truth for releases: a git tag. Everything else — the version baked into every binary, the "What's New" dialog in the UI, the published GitHub Release, and the attached artifacts — is derived from that tag and from CHANGELOG.md. There is no second place to bump a version by hand.
How versioning works
The running version is computed at build time by build.rs, which probes git:
| Build situation | Reported version |
|---|---|
Clean checkout sitting exactly on a vX.Y.Z tag | X.Y.Z |
| Any commit ahead of a tag, or a dirty working tree | development |
| No tags at all (fresh clone) | development |
That value is exposed to every target through src/version.rs (crate::version::VERSION) and surfaced by:
- the CLI —
slicer-engine --versionandslicer-engine info, - the WebSocket server — the
Connected { version }handshake, - the WASM bundle —
appVersion()/appInfo(), read by the Angular UI, - the Tauri desktop app — via the same WASM bundle.
Because the version is honest by construction, local development builds always read development instead of a stale, misleading number. Only a tagged, clean release ever reports a real semver.
The
versionfield inCargo.tomlis the next target version the maintainers are working towards. It is not what users see — that always comes from the git tag.
The changelog
CHANGELOG.md follows Keep a Changelog and is embedded into every build via include_str!. The UI reads it back out in Settings → What's New, and shows the same list in a one-time dialog — scrolled to the newly installed version — the first time a user runs an upgraded release (development builds are never nagged). On iPadOS, where dialogs are drawn by the OS and cannot hold that much content, the prompt links to the settings section instead.
We maintain it with a hybrid workflow: a script drafts the notes from git history, then a human (or the release skill) curates them into enthusiastic, contributor-aware notes before tagging.
Cutting a release — the easy way
Run the release skill (say "cut a release" to the agent). It automates this whole section: it gathers the commits and contributors since the last tag, curates the CHANGELOG.md section in the project's voice — leading with the biggest features and giving first-time contributors a real spotlight — then tags and pushes once you approve. The manual steps below are what that skill performs, and remain available if you prefer to do it by hand.
Cutting a release — step by step
Draft the notes from git history.
bashscripts/gen-changelog-draft.sh # since the last v* tag scripts/gen-changelog-draft.sh v0.2.0 # or since an explicit tag scripts/release-contributors.sh # contributors + first-timersThe first script prints a categorised
## [Unreleased]block (Added / Changed / Fixed / Documentation / Other). The second lists everyone who landed a change since the last tag and flags first-time contributors so they can be acknowledged. Both write nothing — copy the output as a starting point.Curate
CHANGELOG.mdby hand. Fold the draft into the existing## [Unreleased]section: drop noise, merge related entries, and write for humans. Then promote it to a dated release heading and open a freshUnreleasedsection above it:markdown## [Unreleased] ## [0.2.0] - 2026-09-01 ### Added - ...Commit the changelog.
bashgit add CHANGELOG.md git commit -m "docs: changelog for 0.2.0"Tag and push. The tag must be
vX.Y.Z(optionally with a-rc.1-style suffix for pre-releases, which are published as GitHub pre-releases).bashgit tag v0.2.0 git push origin main --tags
That is the entire manual process. Pushing the tag triggers .github/workflows/release.yml, which:
- Extracts the
## [0.2.0]section fromCHANGELOG.md(viascripts/extract-changelog.sh) and creates the GitHub Release with those exact notes. - Builds the CLI/server binary for Linux, macOS (x86-64 + arm64), and Windows, and attaches each as a
.tar.gz/.zip. - Builds the Tauri desktop app for each platform and attaches the installers/bundles.
Every build in that workflow has SLICER_VERSION pinned to the tag, so the artifacts report the correct version even on a shallow checkout.
Verifying a release locally
# What version will this checkout report?
cargo run -- info
# What are the embedded notes?
cargo run -- changelog # full changelog
cargo run -- changelog --version 0.2.0 # one section
cargo run -- changelog --json # machine-readableOn a clean checkout of the tag, cargo run -- info should print 0.2.0 with channel release; anywhere else it prints development.
Pre-releases
Tag with a suffix — v0.2.0-rc.1 — and the workflow marks the GitHub Release as a pre-release. Add a matching ## [0.2.0-rc.1] section to CHANGELOG.md (or the notes fall back to auto-generated).
Canary builds
Stable releases are tag-driven and deliberate (above). For quick access to the bleeding edge, .github/workflows/canary.yml fires on every push to main (i.e. every merge) and refreshes a single rolling canary GitHub pre-release with fresh Windows and macOS desktop bundles.
- Not a real release. The version is a throwaway pre-release string (
X.Y.Z-canary.<run>+<sha>), so builds still report as unofficial and the UI never nags a "What's New" dialog for them. - No changelog needed. The notes are just the commit range since the last
v*tag — noCHANGELOG.mdcuration is involved. - Always the tip of
main. The rollingcanarytag and its assets are overwritten on each push, so the Releases tab always offers the latest build.
To publish a stable, versioned release, follow the tag-driven flow above.
macOS bundles & code signing
Both desktop workflows build a universal macOS binary (universal-apple-darwin), so a single .dmg runs on Intel and Apple Silicon.
By default the app is only ad-hoc signed (APPLE_SIGNING_IDENTITY=-). That is enough to launch it, but because it is not notarized, macOS attaches a quarantine flag to the downloaded bundle and Gatekeeper reports the app as "damaged and can't be opened". Clearing the flag once fixes it:
xattr -cr "/Applications/Cold Crabby Desktop.app"The canary and release notes already spell this out for users.
Shipping notarized builds
To give users a clean double-click experience (no xattr dance), add these repo secrets — both workflows detect them automatically and switch from ad-hoc signing to real Developer ID signing + notarization:
| Secret | What it is |
|---|---|
APPLE_SIGNING_IDENTITY | e.g. Developer ID Application: Your Name (TEAMID) |
APPLE_CERTIFICATE | base64 of the exported .p12 |
APPLE_CERTIFICATE_PASSWORD | password for that .p12 |
APPLE_ID | your Apple ID email |
APPLE_PASSWORD | an app-specific password for notarization |
APPLE_TEAM_ID | your 10-character Apple Team ID |
This requires a paid Apple Developer account. Until those are set, the ad-hoc + xattr path above is the supported way to run the desktop app.
See also
releaseskill — automates this process locally.- CHANGELOG.md — the notes themselves.
build.rs— version derivation from git.src/version.rs— the version/changelog API..github/workflows/release.yml— the pipeline.