Skip to content

CI Build & Release

Mirage uses the GitHub Actions workflow build-macos.yml to automatically build the renderers and main app for both architectures, and publishes them to different update channels depending on how the workflow was triggered.

The workflow runs in the following cases:

  • A push to the main branch;
  • A push of a tag whose name starts with v (for example v1.2.0);
  • A manual run from the repository’s Actions page (workflow_dispatch).
Architecture Runner
x86_64 macos-15-intel
arm64 macos-15

The two architectures are built independently. Each one completes its own renderers + main app packaging and uses its own separate appcast update feed.

Each runner performs the following in order:

  1. Check out the repository (fetch-depth: 0, used to compute the incrementing build number);
  2. Verify that the MIRAGE_STEAM_WEB_API_KEY secret is a 32-digit hex value;
  3. Install build dependencies via Homebrew;
  4. Build the three renderers and the Mirage main app in order;
  5. Sign the update packages and appcast with the Sparkle Ed25519 private key;
  6. Publish to the corresponding GitHub Release and update feed.
Trigger GitHub Release Update Channel
Push a v* tag Stable Release Stable feed
Push to main Rolling prerelease Release Beta feed
  • By default, the app automatically checks for and downloads the stable version;
  • After enabling “Receive beta updates” in Software Update Settings, Sparkle also checks the beta channel;
  • The two architectures each use a separate appcast; the update packages, appcasts, and release notes are all signed with the Sparkle Ed25519 key.

Releases must run serially: both architectures update the same set of signed update feeds, so the workflow uses a concurrency group to avoid concurrent release conflicts.

The workflow automatically writes the full Git commit and an incrementing build number generated by git rev-list --count for every build, so there is no need to update the version number manually.

Only a commit with a higher build number gets installed, which prevents a newer development build from being downgraded to an older Release.

The next time the app launches after an update, it checks the Mirage screen saver component installed in ~/Library/Screen Savers; only when its build number lags behind the app’s bundled component does it atomically replace it and restart the relevant system screen saver services. See Screen Saver for details.

Before the first run, add these under the repository’s Settings → Secrets and variables → Actions:

Secret Purpose
MIRAGE_STEAM_WEB_API_KEY A 32-digit Steam Web API Key, written into the app’s Info.plist
MIRAGE_SPARKLE_PRIVATE_KEY Mirage’s dedicated Sparkle Ed25519 private key, used only to sign update packages and appcasts

If GitHub CLI is installed locally:

Terminal window
gh secret set MIRAGE_STEAM_WEB_API_KEY < .secrets/steam_web_api_key

The current workflow uses ad-hoc signing and does not include Apple Developer ID signing or notarization. Users installing for the first time may still need to allow Mirage manually in macOS Gatekeeper; the authenticity of subsequent updates, however, is verified by the built-in Ed25519 public key.