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.
What You’ll Need
Section titled “What You’ll Need”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-notaryforxcrun notarytool. - pnpm: Install dependencies using
pnpm install --config.node-linker=hoisted.
Quick Start
Section titled “Quick Start”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.
1. Set up Notary credentials
Section titled “1. Set up Notary credentials”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.
# Create a keychain profile once:xcrun notarytool store-credentials "openclaw-notary" \ --apple-id "<apple-id>" --team-id "<team-id>" --password "<app-specific-password>"2. Build and Package
Section titled “2. Build and Package”I recommend using scripts/package-mac-dist.sh for actual releases because it handles both the zip and DMG, plus notarization.
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.sh3. Generate the Appcast
Section titled “3. Generate the Appcast”Sparkle needs an appcast.xml file to know an update exists. I use a script that pulls release notes directly from the changelog.
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.xml4. Publish and Verify
Section titled “4. Publish and Verify”Upload your OpenClaw-2026.3.7.zip and the updated appcast.xml to your release tag. I always run two quick checks:
- Check that the appcast URL returns a 200 status via
curl -I. - Open an older version of the app and click “Check for Updates” to ensure the flow works.
Troubleshooting
Section titled “Troubleshooting”Versioning conflicts
Section titled “Versioning conflicts”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 yourAPP_VERSION. If you use a non-numeric string, Sparkle might treat it as equal to the old version. - The Fix: Explicitly set
APP_BUILDto a higher number when you run the build script if the auto-derivation isn’t catching the change.
Missing Sparkle Tools
Section titled “Missing Sparkle Tools”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.
What’s Next
Section titled “What’s Next”OpenClaw Expert
Still stuck?
If this page didn't answer your case, ask OpenClaw Expert for step-by-step guidance.