DEV Community

Agent Island
Agent Island

Posted on • Originally published at agent-island.dev

A macOS updater has two jobs: discover and verify

A desktop updater has two separate jobs: find the new release and reject an untrusted package. Treating those as one step makes failures hard to diagnose.

I help run Agent Island, a local status companion for Claude Code and Codex. The macOS build exposed this distinction clearly while we worked on its update path.

Discovery is only a version lookup

The current app checks GitHub Releases shortly after launch and then every six hours when automatic checks are enabled. The response provides a tag and a public release page. A numeric dotted comparison decides whether the tag is newer than the installed version.

That mechanism can answer one question: does a newer public release exist?

It cannot prove that a downloaded application is authentic. A network filter can also block the GitHub API while the installed app continues to run normally.

Verification belongs to the installer

The macOS build also includes Sparkle. A release appcast declares the version, package URL, and EdDSA signature. Sparkle verifies that signature against a public key embedded in the installed app before it accepts the update.

The private signing key stays in the maintainer keychain and the release workflow secret. A changed download URL cannot produce a valid package without that key.

This gives the update path two explicit boundaries:

  1. GitHub release discovery decides which version is current.
  2. Sparkle signature verification decides whether an update package is trusted.

A failure in the first boundary should report a version-check problem. A failure in the second should report a signature or installation problem.

Old installs need an honest migration path

An updater framework can exist while its feed is empty or its discovery path is incomplete. In that state, telling users to wait for a prompt is wrong. They need a manual comparison against the latest public release, followed by a direct download or package-manager upgrade.

From Agent Island v1.7.1, the app adds the GitHub-backed version nudge. Builds older than that may need one manual update before they enter the current path.

First launch is a different trust decision

Agent Island does not currently use a paid Apple Developer account. The macOS package is ad-hoc signed rather than notarized, so the first launch requires Finder's right-click and Open flow.

That Gatekeeper decision is separate from Sparkle's update signature. The first controls whether macOS permits the downloaded app to run. The second protects later update packages.

Disabling Gatekeeper globally would collapse a useful system boundary. A per-app first launch keeps the check narrow.

What to record when an update fails

A useful report needs only a few facts:

  • installed version;
  • macOS version;
  • direct DMG or Homebrew install;
  • result of Check now;
  • whether discovery failed or installation failed;
  • exact visible error text.

It does not need Claude Code transcripts, provider tokens, OAuth data, or private project paths.

The full implementation note and current release boundary are documented in the original article: Verifiable macOS Updates.

The source is MIT licensed, so the release and updater code can be inspected directly.

Top comments (0)