Release Process
This page documents the normal Mindwtr release flow at a practical level. It is intended for maintainers working from the repository.
Source Files
Release automation and version metadata are centered in:
scripts/bump-version.shscripts/update-versions.jsdocs/release-notes/docs/release-notes/google-play/metadata/metadata/metadata.jsonapps/desktop/src-tauri/linux/Mindwtr.metainfo.xmlhttps://github.com/dongdongbh/mindwtr-web/tree/main/docsfor public docs changeswiki/is retired — it holds only a landing page pointing to the docs site; never add content pages.github/workflows/.github/workflows/release-rc.ymlfor release-candidate automation
RC Train for Bi-Weekly Releases
Use a release-candidate train for normal bi-weekly minor releases. This is not a general beta program. An RC is the build intended to become stable unless testers find a blocker.
Use SemVer prerelease names:
- first candidate:
v1.1.0-rc.1 - follow-up blocker fix:
v1.1.0-rc.2 - final stable release:
v1.1.0
Do not replace artifacts for an RC that reached testers. Fix that case with the next RC number. If a run fails before GitHub publishes the prerelease, cancel it, fix main, delete and recreate the same RC tag on the corrected commit, then push the tag again.
Run ./scripts/bump-version.sh vX.Y.Z-rc.N for an RC. The script keeps app and package version files on the stable base version (X.Y.Z) while writing the full RC version to apps/mobile/release-version.json for env-free FOSS builds. The RC workflow checks both values before platform builds start.
When to Use the RC Train
Use the full RC train for:
- scheduled bi-weekly minor releases
- releases with cross-platform changes
- releases that touch sync, storage, capture, packaging, entitlements, updater metadata, or store metadata
- releases where multiple distribution artifacts changed
The maintainer may skip the RC train for trivial patch releases, such as a narrow one-line fix, documentation-only correction, or metadata-only update that does not affect installed app behavior. Skipping the train should be explicit in the release notes or release checklist.
RC Channel Matrix
Publish RC builds only to channels that can support testers without creating high maintenance overhead.
| Platform | RC channel | Stable behavior |
|---|---|---|
| All direct downloads | GitHub prerelease | Final GitHub release becomes the stable download source. |
| iOS | TestFlight | App Store remains the stable channel. |
| macOS App Store build | TestFlight | Mac App Store remains the stable channel. |
| Android Play build | Google Play internal testing and open testing (beta) by default; closed/custom tracks when configured | Production receives a later stable upload, and the internal test track is refreshed by the stable workflow. |
| Linux Flatpak | Flathub beta branch | Stable releases publish to both stable and beta branches so beta users are not stranded. |
| Arch Linux | AUR mindwtr-bin-beta | The stable release refreshes the persistent beta package. |
| Debian/Fedora Linux | Beta APT/RPM repositories | Stable packages remain in separate stable repository directories. |
| Windows direct download | GitHub prerelease installer/portable | Microsoft Store remains stable-only unless package flights are later automated. |
Keep these stable-only unless there is a clear need and automation is already in place:
- F-Droid
- IzzyOnDroid
- Microsoft Store package flights
- winget
- Homebrew stable cask
- Chocolatey
- Scoop stable bucket
- stable APT/RPM repos
Microsoft Store package flights remain a possible future addition.
Current RC Automation
The RC workflow is .github/workflows/release-rc.yml.
A new vX.Y.Z-rc.N tag push starts the workflow and verifies the tag, stable base versions, committed FOSS release version, and tag commit before platform builds start. A failed run with no published GitHub prerelease recovers by deleting and recreating the same tag on the corrected commit. If a GitHub release already exists for the tag, the workflow validates only; publish changes under the next RC number. Use workflow_dispatch only for controlled channel retries or non-default channel selection.
The workflow reuses the stable channel build jobs where practical, then creates a GitHub prerelease from the exact Linux, macOS, Windows, Android, and Android FOSS artifacts.
It also publishes tester builds to the store-backed channels that are already wired:
- Android AAB to Google Play
internaland open testing (beta) by default; manual runs can choose comma-separated Play testing tracks ornone. - iOS App Store build to TestFlight with App Store review submission disabled.
- macOS App Store build to TestFlight with App Store review submission disabled.
- Flathub beta branch update PRs through the shared Flathub workflow; manual runs can disable this when channel setup is not ready.
- AUR
mindwtr-bin-betais built and validated after the GitHub prerelease assets exist, then its exactPKGBUILDand.SRCINFOare saved as a review artifact. The RC workflow does not push to AUR. - Beta APT/RPM repository updates after the GitHub prerelease exists; manual runs can disable them.
The stable release.yml remains the stable-release workflow. It is guarded so prerelease tags do not publish stable-only channels such as production Google Play, Microsoft Store, Snap stable, Linux APT/RPM repos, Flathub stable, AUR stable, Scoop, winget, Homebrew, or Chocolatey.
Flathub beta requires the beta branch and permissions in flathub/tech.dongdongbh.mindwtr. AUR publication is a separate manual workflow protected by the aur-publish GitHub Environment. Review the saved proposal, approve the Environment deployment, and publish only when AUR accepts pushes. Upstream AUR maintenance delays that channel without making the Mindwtr release fail.
Because a Play testing upload consumes an Android versionCode, every RC that uploads to Play needs a fresh versionCode. The RC workflow resolves that code once before Android builds start, then the Play build and Android FOSS build consume the same preflight output and run in parallel. The workflow uploads one AAB and assigns the same versionCode to every configured testing track. The current final stable flow should also use a fresh production upload with a higher versionCode, or a future stable-promotion workflow should promote the already-tested Play build. Do not tag a final stable release with an Android versionCode that has already been uploaded to Play unless the stable workflow has been taught to promote that existing build.
Timeline
The review-latency channels need a head start. Use this default schedule:
| Day | Action |
|---|---|
| T-7 to T-5 | Feature freeze. Only bug fixes, release notes, metadata, and release blockers are allowed. |
| T-5 | Create the release branch, run ./scripts/bump-version.sh vX.Y.Z-rc.1, generate RC-specific release notes such as docs/release-notes/X.Y.Z-rc.1.md, and tag vX.Y.Z-rc.1 so release-rc.yml uploads the enabled tester channels. |
| T-4 | Run channel artifact smoke checks as reviewed builds become available. Fix only blockers. |
| T-3 | Confirm the GitHub prerelease from release-rc.yml, verify the Flathub beta PR and saved mindwtr-bin-beta proposal when those workflow inputs were enabled, and announce the RC to testers. |
| T-2 to T-1 | Triage feedback. Cut rc.2 only for blockers. Non-blockers move to the next cycle. |
| Release day | Tag vX.Y.Z, publish stable everywhere, and also update any persistent test channels that exist to the stable version. |
| T+1 to T+2 | Watch crashes, GitHub issues, Discord, store feedback, and downstream package reports. Patch with the next patch tag, such as v1.1.1 after v1.1.0, if needed. |
Blocker Bar for rc.2
Cut another RC only for one of these blockers:
- launch crash
- data loss or data corruption
- sync corruption or repeatable sync failure
- install, update, signing, entitlement, or packaging failure
- broken capture, task creation, task editing, or task completion
- broken migration from the previous stable release
- severe platform-specific regression on a supported channel
Everything else waits for the next scheduled release or a later patch. This keeps the bi-weekly train from turning into an open-ended beta loop.
Required RC Smoke Gates
Every distribution channel is a different runtime. The RC is not ready until the artifact from each RC channel has been smoke-launched in a channel-faithful environment as far as CI or local testing allows.
Minimum smoke checks:
- launch the exact artifact that users receive
- create, edit, complete, and delete a task
- verify capture or quick-add opens and saves
- verify the app can read existing data from the previous stable release
- verify sync settings open without crashing
- verify updater, store, or sandbox-specific startup behavior where applicable
- verify logs do not show fatal startup errors
For channels with prior failure history, keep channel-specific gates:
- FOSS APK and Play APK/AAB are separate dependency sets
- Flatpak must launch inside the Flatpak runtime
- AUR packages must build in a clean Arch container before publishing
- MSIX/Microsoft Store packages must not hard-fail on tray, shortcut, or sandbox-limited capabilities
- App Store and TestFlight builds must preserve required entitlements
Tester Announcement
The RC announcement should be short and actionable:
- version and channel links
- top user-visible changes
- known risks or areas needing testing
- exact feedback path: GitHub issue, Discord channel, or email
- reminder that this is a release candidate, not a feature preview
Stable Release Flow
- Make sure
mainis in the intended release state and commit any pre-release work first.- If the previous version is already released, put follow-up fixes under
docs/release-notes/unreleased.mdand link it fromCHANGELOG.mduntil the next patch version is prepared, for examplev0.9.1afterv0.9.0.
- If the previous version is already released, put follow-up fixes under
- Bump the version with:
./scripts/bump-version.sh 0.x.yThis updates workspace package versions and bumps the Android versionCode.
If Google Play already has a higher versionCode from RC or tester uploads, pass that maximum into the bump script before tagging:
ANDROID_REMOTE_MAX_VERSION_CODE=85 ./scripts/bump-version.sh 0.x.yThe script writes a tracked apps/mobile/app.json value above the Play max, so the release tag, GitHub APK, and downstream reproducible-build recipes all see the same Android metadata. Stable release CI still rejects CI-only versionCode overrides; fix the source metadata before tagging instead of relying on an untracked workflow mutation.
- Run the release hard gates before tagging:
- Type/test gate:
bun run testbun run typecheckbun run native:test
- FOSS/static gate:
- inspect
git diff vPREV..HEAD -- apps/mobile/package.json - inspect F-Droid/FOSS config files (
apps/mobile/plugins/android-manifest-fixes.js,apps/mobile/scripts/,.github/workflows/release-android-foss.yml,config/izzyonandroid.yml) - run
python3 scripts/ci/repair-package-lock.py --check apps/desktop/package-lock.json
- inspect
- CloudKit schema gate:
- inspect synced schema files against the previous tag
- if a new CloudKit-backed field or record type was added, update/deploy the production schema before release
- Type/test gate:
- Prepare or update release notes and metadata:
docs/release-notes/<version>.mddocs/release-notes/google-play/<version>.txtmetadata/*/release_notes.txtmetadata/*/changelogs/<androidVersionCode>.txtmetadata/metadata.jsonapps/desktop/src-tauri/linux/Mindwtr.metainfo.xml
- Update public docs in the Mindwtr web docs source when release/docs process details changed. The GitHub Wiki is retired; do not add or update
wiki/content pages, and do not run git in a separate.wikicheckout. - Review the resulting version and metadata changes carefully.
- Commit the release prep:
git add -A
git commit -m "chore(release): v0.x.y"- Tag the release:
git tag v0.x.y- Push
mainand the tag:
git push origin main --tags- Let GitHub Actions publish the platform artifacts and any downstream packaging jobs.
Before Tagging
At minimum, verify:
- release notes exist and match the actual changes
- package versions are aligned across the monorepo
apps/mobile/release-version.jsoncontains the full RC version for an RC tag- Android
versionCodewas incremented - desktop package lock passes
repair-package-lock.py --check - FOSS config still strips blocked permissions and keeps only intentional ones
- CloudKit-backed schema did not change, or the production schema was updated first
- store/release metadata changes are intentional and scoped per platform
- mobile store categories in the consoles are still correct: Google Play
Productivity > Task Managementand App Store primary categoryProductivity - Google Play locale bodies fit the 500-character API limit
For larger releases, also verify:
- desktop updater metadata
- mobile store metadata / Fastlane inputs
- docs-site changes for user-visible features in the Mindwtr web docs source
- cross-backend sync smoke with a small seed dataset: add, update, delete, and attachment transfer should converge across Cloud, WebDAV/file sync, and any platform-native backend available to the release tester; a second sync should report no new conflicts
Release Notes
Versioned release notes live in docs/release-notes/.
Guidelines:
- keep the top summary user-facing
- include the important fixes/features first
- list notable commits when helpful
- for RCs, use
docs/release-notes/X.Y.Z-rc.N.mdordocs/release-notes/vX.Y.Z-rc.N.mdand include the full RC version in the first heading; reservedocs/release-notes/X.Y.Z.mdfor the final stable release - for stable releases, make the first line exactly
# Mindwtr X.Y.Zor# Mindwtr vX.Y.Z;release.ymlrejects other headings - keep Google Play snippets in
docs/release-notes/google-play/aligned when needed - update
metadata/*/release_notes.txtfor App Store release notes - add the new Android changelog file under
metadata/*/changelogs/<versionCode>.txt - keep Microsoft Store release notes in
metadata/metadata.jsonaligned with the same release - add or refresh the top AppStream entry in
apps/desktop/src-tauri/linux/Mindwtr.metainfo.xml
Post-Release Checks
After the tag is pushed:
- verify GitHub release creation
- verify expected desktop/mobile artifacts are attached
- verify store-specific workflows succeeded when applicable
- spot-check the updater/download surfaces against the new version
- verify stable was also published to persistent test channels that exist, so testers remain on the newest build
Rollback Mindset
If a bad release is detected:
- stop follow-up tagging until the failure mode is understood
- prefer a fast forward fix release over rewriting published history
- keep release notes explicit about the corrective patch