Skip to content

Shipping macOS Updates with Sparkle and OpenClaw

I’ve spent too many hours manually shipping binaries only to realize I missed a signing certificate or broke the update path for existing users. It is one of those tasks that feels like it should be simple but has enough moving parts to make you want to walk away from your desk. I want to show you how I handle the macOS release process for OpenClaw so your users get those “New Version Available” popups without the headache.

Before we start, make sure you have these four items ready:

  • Developer ID Application certificate: This must be installed in your keychain (e.g., Developer ID Application: <Developer Name> (<TEAMID>)).
  • Sparkle private key: Set the path to your ed25519 private key in your environment as SPARKLE_PRIVATE_KEY_FILE.
  • Notary credentials: A keychain profile named openclaw-notary for xcrun notarytool.
  • pnpm: Install dependencies using pnpm install --config.node-linker=hoisted.

I use a few specific scripts to handle the heavy lifting of signing and notarizing. Here is the path to get a release out the door in about 5 minutes.

If you haven’t done this yet, you need to store your Apple ID credentials so the scripts can talk to Apple’s notarization service.

Terminal window
# Create a keychain profile once:
xcrun notarytool store-credentials "openclaw-notary" \
--apple-id "<apple-id>" --team-id "<team-id>" --password "<app-specific-password>"

I recommend using scripts/package-mac-dist.sh for actual releases because it handles both the zip and DMG, plus notarization.

Terminal window
NOTARIZE=1 NOTARYTOOL_PROFILE=openclaw-notary \
BUNDLE_ID=ai.openclaw.mac \
APP_VERSION=2026.3.7 \
BUILD_CONFIG=release \
SIGN_IDENTITY="Developer ID Application: <Developer Name> (<TEAMID>)" \
scripts/package-mac-dist.sh

Sparkle needs an appcast.xml file to know an update exists. I use a script that pulls release notes directly from the changelog.

Terminal window
SPARKLE_PRIVATE_KEY_FILE=/path/to/ed25519-private-key scripts/make_appcast.sh dist/OpenClaw-2026.3.7.zip https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml

Upload your OpenClaw-2026.3.7.zip and the updated appcast.xml to your release tag. I always run two quick checks:

  1. Check that the appcast URL returns a 200 status via curl -I.
  2. Open an older version of the app and click “Check for Updates” to ensure the flow works.

If Sparkle isn’t seeing your new update, check your APP_BUILD value. Sparkle requires this to be numeric and monotonic (increasing).

  • The Problem: If you omit APP_BUILD, the script tries to derive it from your APP_VERSION. If you use a non-numeric string, Sparkle might treat it as equal to the old version.
  • The Fix: Explicitly set APP_BUILD to a higher number when you run the build script if the auto-derivation isn’t catching the change.

If the scripts complain about missing binaries like sign_update, ensure you have run the build at least once. These tools are fetched via SwiftPM and live at apps/macos/.build/artifacts/sparkle/Sparkle/bin/.

If you run into other issues, check out the AI Setup Assistant.

OpenClaw

OpenClaw Expert

Still stuck?

If this page didn't answer your case, ask OpenClaw Expert for step-by-step guidance.