macOS Developer Setup for OpenClaw App

This guide covers compiling and launching the OpenClaw macOS app from source, including prerequisites, build steps, and signing options. It is intended for developers setting up a macOS development environment.

Read this when

  • Setting up the macOS development environment

macOS developer setup

Compile and launch the OpenClaw macOS app directly from source code.

Prerequisites

  • Xcode 26.2 or newer (Swift 6.2 toolchain), running on the most recent macOS that Software Update offers.
  • Node.js 24.15+ with pnpm for the gateway, CLI, and packaging scripts. Node 22.22.3+ is also supported.

1. Install dependencies

pnpm install

2. Build and package the app

./scripts/package-mac-app.sh

The output lands in dist/OpenClaw.app. If no Apple Developer ID certificate is present, the script switches to ad-hoc signing automatically.

To produce a dev or proof build that skips the local MLX voice helper, set OPENCLAW_SKIP_MLX_TTS=1. That step omits the openclaw-mlx-tts binary and its sizeable mlx-swift Metal shader stack, which certain beta Xcode toolchains fail to compile. The resulting app lacks on-device MLX voice and will be rejected for release builds, since those must include the helper.

Consult apps/macos/README.md for details on dev run modes, signing flags, and Team ID troubleshooting. A quick dev loop from the repo root is scripts/restart-mac.sh; append --no-sign for ad-hoc signing, keeping in mind TCC permissions do not persist with --no-sign.

Note

Apps signed ad-hoc can trigger security warnings. If the app exits right away with "Abort trap 6", check Troubleshooting.

3. Install the CLI and Gateway

The packaged app carries the canonical scripts/install-cli.sh installer inside it. On a new profile, pick This Mac during onboarding, and the app sets up the matching user-space CLI and runtime before the Gateway wizard starts.

For manual development recovery, install the matching CLI on your own:

The npm command below targets npm 12 or npm 11.16+. On npm 11.15 and earlier, leave out --allow-scripts=openclaw.

npm install -g openclaw@<version> --allow-scripts=openclaw

pnpm add -g --allow-build=openclaw openclaw@<version> and bun add -g --trust openclaw@<version> are viable alternatives. Bun's --trust lets the OpenClaw lifecycle scripts run for that install. Node stays the recommended runtime for the Gateway itself.

Troubleshooting

Build fails: toolchain or SDK mismatch

Building the macOS app requires the latest macOS SDK along with the Swift 6.2 toolchain (Xcode 26.2+).

xcodebuild -version
xcrun swift --version

When versions do not line up, refresh macOS/Xcode and rebuild.

Build fails: MLX voice helper Metal shaders

With a beta-only Xcode toolchain (such as Xcode 27 paired with the macOS 27 SDK), only the openclaw-mlx-tts helper might fail while the main app compiles without issue. The mlx-swift Metal compilation errors show up non-deterministically (a different .metal file each attempt, followed by Could not read serialized diagnostics file and a nonzero metal exit), because the beta metal compiler and its separately downloaded Metal Toolchain remain unstable. That is an upstream toolchain problem, not an OpenClaw one.

When on-device MLX voice is not needed, skip the helper:

OPENCLAW_SKIP_MLX_TTS=1 ./scripts/package-mac-app.sh

Otherwise, grab the Metal Toolchain (xcodebuild -downloadComponent MetalToolchain) and build from a stable Xcode release.

App crashes on permission grant

If the app crashes while you try to grant Speech Recognition or Microphone access, a corrupted TCC cache or signature mismatch is likely the cause.

  1. Clear TCC permissions for the debug bundle id:

    tccutil reset All ai.openclaw.mac.debug
    
  2. If that does not work, switch BUNDLE_ID in scripts/package-mac-app.sh temporarily to give macOS a clean slate.

Gateway "Starting..." indefinitely

Check whether a zombie process is occupying the port:

openclaw gateway status
openclaw gateway stop

# If you're not using a LaunchAgent (dev mode / manual runs), find the listener:
lsof -nP -iTCP:18789 -sTCP:LISTEN

If a manual run holds the port, stop it with Ctrl+C, or kill the PID found above as a last resort.

611 words · updated Aug 25, 2026