Skip to content

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.sh
  • scripts/update-versions.js
  • docs/release-notes/
  • docs/release-notes/google-play/
  • metadata/
  • metadata/metadata.json
  • apps/desktop/src-tauri/linux/Mindwtr.metainfo.xml
  • https://github.com/dongdongbh/mindwtr-web/tree/main/docs for public docs changes
  • wiki/ is retired — it holds only a landing page pointing to the docs site; never add content pages
  • .github/workflows/
  • .github/workflows/release-rc.yml for 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.

PlatformRC channelStable behavior
All direct downloadsGitHub prereleaseFinal GitHub release becomes the stable download source.
iOSTestFlightApp Store remains the stable channel.
macOS App Store buildTestFlightMac App Store remains the stable channel.
Android Play buildGoogle Play internal testing and open testing (beta) by default; closed/custom tracks when configuredProduction receives a later stable upload, and the internal test track is refreshed by the stable workflow.
Linux FlatpakFlathub beta branchStable releases publish to both stable and beta branches so beta users are not stranded.
Arch LinuxAUR mindwtr-bin-betaThe stable release refreshes the persistent beta package.
Debian/Fedora LinuxBeta APT/RPM repositoriesStable packages remain in separate stable repository directories.
Windows direct downloadGitHub prerelease installer/portableMicrosoft 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 internal and open testing (beta) by default; manual runs can choose comma-separated Play testing tracks or none.
  • 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-beta is built and validated after the GitHub prerelease assets exist, then its exact PKGBUILD and .SRCINFO are 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:

DayAction
T-7 to T-5Feature freeze. Only bug fixes, release notes, metadata, and release blockers are allowed.
T-5Create 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-4Run channel artifact smoke checks as reviewed builds become available. Fix only blockers.
T-3Confirm 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-1Triage feedback. Cut rc.2 only for blockers. Non-blockers move to the next cycle.
Release dayTag vX.Y.Z, publish stable everywhere, and also update any persistent test channels that exist to the stable version.
T+1 to T+2Watch 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

  1. Make sure main is 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.md and link it from CHANGELOG.md until the next patch version is prepared, for example v0.9.1 after v0.9.0.
  2. Bump the version with:
bash
./scripts/bump-version.sh 0.x.y

This 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:

bash
ANDROID_REMOTE_MAX_VERSION_CODE=85 ./scripts/bump-version.sh 0.x.y

The 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.

  1. Run the release hard gates before tagging:
    • Type/test gate:
      • bun run test
      • bun run typecheck
      • bun 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
    • 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
  2. Prepare or update release notes and metadata:
    • docs/release-notes/<version>.md
    • docs/release-notes/google-play/<version>.txt
    • metadata/*/release_notes.txt
    • metadata/*/changelogs/<androidVersionCode>.txt
    • metadata/metadata.json
    • apps/desktop/src-tauri/linux/Mindwtr.metainfo.xml
  3. 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 .wiki checkout.
  4. Review the resulting version and metadata changes carefully.
  5. Commit the release prep:
bash
git add -A
git commit -m "chore(release): v0.x.y"
  1. Tag the release:
bash
git tag v0.x.y
  1. Push main and the tag:
bash
git push origin main --tags
  1. 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.json contains the full RC version for an RC tag
  • Android versionCode was 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 Management and App Store primary category Productivity
  • 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.md or docs/release-notes/vX.Y.Z-rc.N.md and include the full RC version in the first heading; reserve docs/release-notes/X.Y.Z.md for the final stable release
  • for stable releases, make the first line exactly # Mindwtr X.Y.Z or # Mindwtr vX.Y.Z; release.yml rejects other headings
  • keep Google Play snippets in docs/release-notes/google-play/ aligned when needed
  • update metadata/*/release_notes.txt for App Store release notes
  • add the new Android changelog file under metadata/*/changelogs/<versionCode>.txt
  • keep Microsoft Store release notes in metadata/metadata.json aligned 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

Mindwtr is free, open source, and local-first.
Getting Things Done and GTD are registered trademarks of the David Allen Company. Mindwtr is not affiliated with, endorsed by, or sponsored by the David Allen Company.