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.
Triggers
Section titled “Triggers”The workflow runs in the following cases:
- A push to the
mainbranch; - A push of a tag whose name starts with
v(for examplev1.2.0); - A manual run from the repository’s Actions page (
workflow_dispatch).
Build Matrix
Section titled “Build Matrix”| 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.
Build Steps
Section titled “Build Steps”Each runner performs the following in order:
- Check out the repository (
fetch-depth: 0, used to compute the incrementing build number); - Verify that the
MIRAGE_STEAM_WEB_API_KEYsecret is a 32-digit hex value; - Install build dependencies via Homebrew;
- Build the three renderers and the Mirage main app in order;
- Sign the update packages and appcast with the Sparkle Ed25519 private key;
- Publish to the corresponding GitHub Release and update feed.
Release Channels
Section titled “Release Channels”| 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.
Version and Build Numbers
Section titled “Version and Build Numbers”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.
Screen Saver Component Sync
Section titled “Screen Saver Component Sync”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.
Required Secrets
Section titled “Required Secrets”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:
gh secret set MIRAGE_STEAM_WEB_API_KEY < .secrets/steam_web_api_keyState of Signing and Notarization
Section titled “State of Signing and Notarization”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.
