Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
OpenClaw macOS app (dev + signing)
Quick dev run
# from repo root
scripts/restart-mac.sh
Options:
scripts/restart-mac.sh --no-sign # fastest dev; ad-hoc signing (TCC permissions do not stick)
scripts/restart-mac.sh --sign # force code signing (requires cert)
scripts/restart-mac.sh --background-only # keep services running without automatic windows
--background-only suppresses first-run onboarding, update and CLI prompts, and
the --chat/--dashboard auto-open helpers. Pairing, control-channel, and Mac
node services still start. It also keeps GUI-owned onboarding and saved Gateway
profile Keychain state cold, so a signer or ACL transition cannot raise a
SecurityAgent prompt during unattended work. The primary Gateway route still
comes from the normal environment/config endpoint. Combine it with
--attach-only when an external process owns the local Gateway.
App profiles
Launch a fully isolated app instance with the same profile name used by the CLI:
OPENCLAW_PROFILE=work /Applications/OpenClaw.app/Contents/MacOS/OpenClaw
Profile names use 1–64 lowercase letters, numbers, underscores, or hyphens and
must start with a letter or number. default selects the normal app; gateway,
mac, and node are reserved LaunchAgent identities.
scripts/restart-mac.sh intentionally rejects named profiles because its
packaging cleanup is host-global. Build/package normally, then launch the named
profile directly with the command above.
A named profile keeps state in ~/.openclaw-<name>, uses its own app defaults,
Keychain services, duplicate-instance lock, and the CLI-managed Gateway service
ai.openclaw.<name>. Unless config or environment selects a port, each profile
derives a stable port in the profile 20000...59999 range. The app does not
install or modify the host-global Mac node
service or OpenClaw login item while a profile is active. The runtime child node
still runs in process as usual. App relocation, Sparkle updates, and post-update
service repair are disabled in profile mode; update the installed app through
the normal default-profile workflow.
Packaging flows
Development bundle (signed but not notarized):
scripts/package-mac-app.sh
This creates dist/OpenClaw.app and signs it via scripts/codesign-mac-app.sh.
It is not a distribution artifact. For a notarized app ZIP and DMG, use:
scripts/package-mac-dist.sh
For an unattended Peekaboo elevation host, use the closed Foundation signing
profile and source-addressed ZIP workflow. package is an internal release
operator command: it requires the OpenClaw Foundation signing identity and
notarization credentials, and its archive is not a general-download artifact.
scripts/mac-elevation-host.sh package
cd dist/elevation-host
shasum -a 256 -c "OpenClaw-<full-source-sha>-stable.zip.sha256"
shasum -a 256 -c "OpenClaw-<full-source-sha>-stable-installer.sh.sha256"
./OpenClaw-<full-source-sha>-stable-installer.sh install \
--archive "OpenClaw-<full-source-sha>-stable.zip"
./OpenClaw-<full-source-sha>-stable-installer.sh status
The elevation package is ZIP-only, notarized and stapled, contains exactly
OpenClaw.app, omits Apple Events entitlements, records an immutable receipt,
and verifies a freshly extracted copy. The same source-addressed artifact set
includes an executable installer copied from that exact Git commit plus separate
archive and installer checksum files, so a target Mac does not need a source
checkout. Transfer the complete set and verify both checksums before running the
installer. Installation owns the separate
ai.openclaw.mac.elevation-host launchd job with RunAtLoad and KeepAlive.
It refuses to replace or race the ordinary ai.openclaw.mac Launch at login
job. recover restores the recorded prior bundle after a failed cutover;
uninstall removes only the elevation job and preserves the app, state,
Keychain, TCC, and recovery receipt. Installation exits successfully once the
launchd-owned process is Bridge-ready; missing TCC remains a degraded status
result until the required grants are present.
Signing behavior
Auto-selects identity (first match):
- Developer ID Application
- Apple Distribution
- Apple Development
- first available identity
If none found:
- errors by default
- set
ALLOW_ADHOC_SIGNING=1orSIGN_IDENTITY="-"to ad-hoc sign
Team ID audit (Sparkle mismatch guard)
After signing, we read the app bundle Team ID and compare every Mach-O inside the app. If any embedded binary has a different Team ID, signing fails.
Skip the audit:
SKIP_TEAM_ID_CHECK=1 scripts/package-mac-app.sh
Library validation workaround (dev only)
If Sparkle Team ID mismatch blocks loading (common with Apple Development certs), opt in:
DISABLE_LIBRARY_VALIDATION=1 scripts/package-mac-app.sh
This adds com.apple.security.cs.disable-library-validation to app entitlements.
Use for local dev only; keep off for release builds.
Useful env flags
SIGN_IDENTITY="Apple Development: Your Name (TEAMID)"ALLOW_ADHOC_SIGNING=1(ad-hoc, TCC permissions do not persist)CODESIGN_TIMESTAMP=off(offline debug)DISABLE_LIBRARY_VALIDATION=1(dev-only Sparkle workaround)SKIP_TEAM_ID_CHECK=1(bypass audit)