macOS Release
OpenClaw macOS release checklist (Sparkle feed, packaging, signing)
This app now ships Sparkle auto-updates. Release builds must be Developer ID–signed, zipped, and published with a signed appcast entry.
Prereqs
- Developer ID Application cert installed (example: ''Developer ID Application: <Developer Name> (<TEAMID>)'').
- Sparkle private key path set in environment as ''SPARKLE_PRIVATE_KEY_FILE'' (path to your Sparkle ed25519 private key; public key baked into Info.plist). If it is missing, check ''~/.profile''.
- Notary credentials (keychain profile or API key) for ''xcrun notarytool'' if you want Gatekeeper-safe DMG/zip distribution.
- We use a Keychain profile named ''openclaw-notary'', created from App Store Connect API key env vars in your shell profile:
- ''APP_STORE_CONNECT_API_KEY_P8'', ''APP_STORE_CONNECT_KEY_ID'', ''APP_STORE_CONNECT_ISSUER_ID''
- ''echo "$APP_STORE_CONNECT_API_KEY_P8" | sed 's/\\n/\n/g' > /tmp/openclaw-notary.p8''
- ''xcrun notarytool store-credentials "openclaw-notary" --key /tmp/openclaw-notary.p8 --key-id "$APP_STORE_CONNECT_KEY_ID" --issuer "$APP_STORE_CONNECT_ISSUER_ID"''
- ''pnpm'' deps installed (''pnpm install --config.node-linker=hoisted'').
- Sparkle tools are fetched automatically via SwiftPM at ''apps/macos/.build/artifacts/sparkle/Sparkle/bin/'' (''sign_update'', ''generate_appcast'', etc.).
Build & package
Notes:
- ''APP_BUILD'' maps to ''CFBundleVersion''/''sparkle:version''; keep it numeric + monotonic (no ''-beta''), or Sparkle compares it as equal.
- Defaults to current architecture (''$(uname -m)''). For release/universal builds, set ''BUILD_ARCHS="arm64 x86_64"'' (or ''BUILD_ARCHS=all'').
- Use ''scripts/package-mac-dist.sh'' for release artifacts (zip + DMG + notarization). Use ''scripts/package-mac-app.sh'' for local/dev packaging.
BUNDLE_ID=bot.molt.mac \
APP_VERSION=2026.1.27-beta.1 \
APP_BUILD="$(git rev-list --count HEAD)" \
BUILD_CONFIG=release \
SIGN_IDENTITY="Developer ID Application: '<Developer Name>' ('<TEAMID>')" \
scripts/package-mac-app.sh
ditto -c -k --sequesterRsrc --keepParent dist/OpenClaw.app dist/OpenClaw-2026.1.27-beta.1.zip
scripts/create-dmg.sh dist/OpenClaw.app dist/OpenClaw-2026.1.27-beta.1.dmg
NOTARIZE=1 NOTARYTOOL_PROFILE=openclaw-notary \
BUNDLE_ID=bot.molt.mac \
APP_VERSION=2026.1.27-beta.1 \
APP_BUILD="$(git rev-list --count HEAD)" \
BUILD_CONFIG=release \
SIGN_IDENTITY="Developer ID Application: '<Developer Name>' ('<TEAMID>')" \
scripts/package-mac-dist.sh
ditto -c -k --keepParent apps/macos/.build/release/OpenClaw.app.dSYM dist/OpenClaw-2026.1.27-beta.1.dSYM.zipAppcast entry
Use release note generator so Sparkle renders formatted HTML notes:
SPARKLE_PRIVATE_KEY_FILE=/path/to/ed25519-private-key scripts/make_appcast.sh dist/OpenClaw-2026.1.27-beta.1.zip https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml
Generates HTML release notes from ''CHANGELOG.md'' (via ''''scripts/changelog-to-html.sh'''') and embeds them in appcast entry.
Commit updated ''appcast.xml'' alongside release assets (zip + dSYM) when publishing.
Publish & verify
- Upload ''OpenClaw-2026.1.27-beta.1.zip'' (and ''OpenClaw-2026.1.27-beta.1.dSYM.zip'') to GitHub release for tag ''v2026.1.27-beta.1''.
- Ensure raw appcast URL matches the baked feed: ''https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml''.
- Sanity checks:
- ''curl -I https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml'' returns 200.
- ''curl -I <enclosure url>'' returns 200 after assets upload.
- On a previous public build, run "Check for Updates…" from About tab and verify Sparkle installs the new build cleanly.
Definition of done: signed app + appcast are published, update flow works from an older installed version, and release assets are attached to GitHub release.