Skip to content

Add automatic release checks and safe in-app updates for the macOS app #232

Open

Description

@MatthewFeroz

Problem

Users currently need to track GitHub releases and manually replace the macOS app to receive newer launcher and bundled QEMU/runtime fixes. Updating packages inside Omarchy does not update the host app, and the guest runtime package version does not identify the installed Mac app version. This makes it easy to miss host-side performance and compatibility fixes.

Could Try Omarchy add automatic release checks and a supported in-app update flow for the macOS app?

Proposed user experience

  • Show the installed app version and provide Check for Updates… in the start menu and native application menu.
  • Offer an opt-in automatic check for stable releases, displaying the available version and release notes, with Install, Later, and Skip choices.
  • Allow background downloads as a preference. Defer app replacement and relaunch until the VM has shut down cleanly; never force-stop a running VM to apply an update.
  • Preserve existing VM disks, paired boot files, selected storage location, and preferences. Explain that a host app update does not migrate the guest to the newest factory image.
  • Handle offline checks and download failures without blocking VM startup; keep manual download available.

Suggested implementation

Consider Sparkle 2 rather than implementing app replacement directly:

  1. Pin the dependency in macos/Package.swift and integrate an updater controller with the launcher/start menu. Include and sign the framework and its helpers through the existing macos/build-app.sh packaging flow.
  2. Configure a maintainer-controlled HTTPS appcast and public Ed25519 update key in macos/Info.plist. Keep private signing material in the release environment, outside the repository. Continue Developer ID signing and notarization.
  3. Extend the release workflow to sign the completed update archive and generate/publish the appcast only after the artifact is available. GitHub Releases can host the downloadable artifact; the appcast can live at a stable project-controlled URL.
  4. Ensure CFBundleVersion increases for every shipped build, align the display version with the release, and encode supported macOS versions in the feed. Stable checks should exclude prereleases by default.
  5. Integrate installation deferral with VMApplicationController and the QEMU process lifecycle. Verify that no VM or recovery process is using the app's bundled runtime before replacement. A shutdown timeout or cancellation should leave the update pending.
  6. Document that the first updater-enabled app must be installed manually and that existing guest migration/pinned-package policies remain separate.

The current package manifest has no Sparkle dependency, and the current Info.plist has no update feed/key configuration. This proposal is for host app updates; #29 and #134 concern guest migration/package updates.

Acceptance checks

  • Newer compatible stable releases are offered; current/older/incompatible versions are not.
  • Manual checks work when automatic checks are disabled; failed checks do not block launch.
  • A corrupted or invalidly signed download is rejected without replacing the working app.
  • A running VM is never interrupted by an automatic install; installation waits for confirmed clean shutdown.
  • Updating and relaunching retains the same existing VM, boot files, data, preferences, and custom storage location.
  • Exercise the complete flow between two signed/notarized macOS builds, including cancellation, interrupted downloads, and running from a read-only DMG.

Opening this as a design issue first, per CONTRIBUTING.md's guidance for large behavioral changes. No implementation or macOS integration testing is claimed here.

Activity

  1. vcanuel commented on Oct 24, 2026

    @vcanuel
    Contributor

    Hi @themartiano! I'd love to take on the Sparkle stage of this issue. Downloading the DMG from GitHub for every release is a bit painful, and #234 already laid the groundwork.

    My plan is three small PRs:

    1. Bundle and sign Sparkle 2, but leave it inactive (no feed yet).
    2. Have the release scripts sign the update and publish appcast.xml as a release asset.
    3. Wire it into Check for Updates…, keeping the existing preference. Installation waits until the VM is shut down cleanly, and VM storage is never touched.

    Two things are up to you:

    • Signing key: an Ed25519 key kept by whoever signs releases. Only the public key goes in the app.
    • Appcast URL: I'd suggest releases/latest/download/appcast.xml. It needs no extra hosting, and it only goes live once a release is published.

    Sound good? If so, I'll start with PR 1 since it changes no behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions