| name | macos-release-notarize |
| description | Build, sign, notarize, staple, and verify Runner macOS release artifacts. Use when asked to produce a distributable macOS Runner build, debug Gatekeeper/notarization/signing failures, package the bundled Swift sidecar and mlx.metallib, or document/update the release process. |
macOS Release Notarize
Workflow
Use pnpm release:macos from the repository root for repeatable macOS releases. It builds Runner, strips local symbols from the app and sidecar binaries, signs both with Developer ID, runs a hardening audit, submits a temporary app zip to Apple notarization, staples the ticket to Runner.app, validates signing/stapling, packages the app into a signed DMG, notarizes and staples the DMG, and emits the final DMG under dist/release/macos/.
Never print or commit Apple credentials. Prefer a notarytool keychain profile:
xcrun notarytool store-credentials runner-notary \
--apple-id "$APPLE_ID" \
--team-id "$APPLE_TEAM_ID" \
--password "$APP_SPECIFIC_PASSWORD"
Then run:
pnpm release:macos -- --notary-profile runner-notary
If no keychain profile is available, the script also accepts the standard env-based auth forms:
- Apple ID:
APPLE_ID, APPLE_PASSWORD, APPLE_TEAM_ID
- App Store Connect API key:
APPLE_API_KEY_PATH, APPLE_API_KEY_ID, APPLE_API_ISSUER
Checks
Before calling the script, confirm a Developer ID Application identity exists:
security find-identity -v -p codesigning
The default identity is Developer ID Application: Ivan Potapov (HNTDGD2AB7). Override it when needed:
RUNNER_MACOS_SIGNING_IDENTITY="Developer ID Application: Name (TEAMID)" \
pnpm release:macos -- --notary-profile runner-notary
Expected successful validations:
codesign --verify --deep --strict --verbose=4 src-tauri/target/release/bundle/macos/Runner.app
xcrun stapler validate -v src-tauri/target/release/bundle/macos/Runner.app
spctl -a -vv src-tauri/target/release/bundle/macos/Runner.app
spctl rejection means the artifact is not accepted by Gatekeeper. Do not call it notarized unless notarytool returned Accepted and stapler validation passed.
The script also fails the release if the .app contains source maps, source files, debug symbol bundles, static/object files, model/tokenizer artifacts, prompt/key-like files, debug entitlements, disabled CSP, opener:default, obvious secret/token patterns, or local development model paths such as runner-speech-models. For emergency diagnosis only, pass --skip-audit or set RUNNER_RELEASE_AUDIT=0.
Runner-Specific Notes
The app must include both Contents/Resources/runner-tts-sidecar and Contents/Resources/mlx.metallib. The sidecar must have its own embedded NSMicrophoneUsageDescription and be signed with Developer ID before the outer app is signed.
The checked-in tauri.conf.json may use ad-hoc signing for local builds. The release script passes a temporary Tauri config overlay so repository config does not need to store a machine-specific Developer ID identity.
The script strips local/debug symbols by default to reduce easy static inspection of release binaries. For debugging-only builds, pass --no-strip or set RUNNER_RELEASE_STRIP=0.
Do not ship secrets, private prompts, license keys, or proprietary model weights that must remain confidential. Any prompt needed by the local on-device runtime should be treated as public release behavior, because it is bundled into the client and can be extracted from a distributed app.