Gateway on macOS: Bundled Gateway Setup and Recovery
Learn how the OpenClaw macOS app uses a separate CLI and launchd service for the Gateway, including automatic setup and manual recovery steps for users who need to install it themselves.
Read this when
- Packaging OpenClaw.app
- Debugging the macOS gateway launchd service
- Installing the gateway CLI for macOS
OpenClaw.app ships without Node or the Gateway runtime bundled. Instead, the macOS application expects a separate openclaw CLI installation, never launches the Gateway as a subprocess, and relies on a launchd service scoped to the current user to maintain the Gateway (or connects to one already listening locally).
Automatic setup
When onboarding on a new Mac, pick This Mac. Before the Gateway wizard appears, the app executes its signed installer script that comes bundled: this installs a Node runtime in user space along with the matching openclaw CLI into ~/.openclaw, then sets up and activates the per-user launchd service. No Terminal, Homebrew, or admin rights are required for this route.
Only the installer script is bundled with the app, not the Node or Gateway payloads; downloading the runtime and the corresponding OpenClaw package demands an internet connection.
Manual recovery
For those installing by hand, Node 26 is the recommended choice, though other supported versions work as well: Node 22.22.3+, Node 24.15+, or Node 25.9+. Install openclaw globally:
The following command targets npm 12 or npm 11.16+. Anyone on npm 11.15 or older should leave out --allow-scripts=openclaw.
npm install -g openclaw@<version> --allow-scripts=openclaw
If automatic setup fails, try Retry setup. When that does not help, install the CLI manually using the command above and then pick Check again during onboarding.
Launchd (Gateway as LaunchAgent)
Label: ai.openclaw.gateway applies to the default profile, while ai.openclaw.<profile> is used for a profile with a name.
Plist location (per-user): ~/Library/LaunchAgents/ai.openclaw.gateway.plist (or ai.openclaw.<profile>.plist).
For the default profile in Local mode, the macOS app handles LaunchAgent installation and updates. The CLI can also perform the install directly: openclaw gateway install (named profiles are chosen through the OPENCLAW_PROFILE environment variable).
How it behaves:
- Enabling or disabling the LaunchAgent is controlled by "OpenClaw Active".
- Closing the app does not halt the Gateway, launchd keeps it running.
- When a Gateway is already listening on the configured port, the app connects to that instance rather than spinning up another.
For lifecycle checks and recovery, turn to the CLI:
openclaw gateway status --deep
openclaw gateway restart
Launchd takes care of login-time auto-start, restarting after crashes, and a single predictable log destination, so the Gateway's lifetime is not coupled to the app process.
Attach-only development
To run the development app when another process already controls the local Gateway, do so without installing or altering its LaunchAgent:
scripts/restart-mac.sh --attach-only
Starting the app directly via --attach-only or --no-launchd produces the same result. The override persists in ~/.openclaw/disable-launchagent; deleting that file brings back the app-managed launchd behavior.
Logging notes:
- launchd stdout:
~/Library/Logs/openclaw/gateway.log(named profiles usegateway-<profile>.log) - launchd stderr: suppressed
- When the host keeps looping with repeated
EADDRINUSEor quick restarts, look for duplicateai.openclaw.gateway/ai.openclaw.nodeLaunchAgents and the launchd-marker workaround described in Gateway troubleshooting.
Version compatibility
The macOS app compares the Gateway version against its own. During onboarding, managed setup runs automatically whenever an existing CLI is absent or does not match. Retry setup repeats the installation, while Check again is for after you have repaired an external CLI.
State directory on macOS
Store OpenClaw state on a local disk that is not synced. Steer clear of iCloud Drive and other cloud-synced locations; latency from sync and file locks can interfere with sessions, credentials, and Gateway state.
Only set OPENCLAW_STATE_DIR to a local path when an override is genuinely needed. openclaw doctor flags common cloud-synced state paths and suggests returning to local storage. Consult environment variables and Doctor for details.
Debug app connectivity
From a source checkout, the macOS debug CLI exercises the same Gateway WebSocket handshake and discovery logic that the app relies on:
cd apps/macos
swift run openclaw-mac connect --json
swift run openclaw-mac discover --timeout 3000 --json
connect takes --url, --token, --timeout, --probe, and --json (plus client-identity overrides; run --help to see the complete list). discover accepts --timeout, --json, and --include-local. When you need to tell apart CLI discovery from app-side connection problems, compare discovery output with openclaw gateway discover --json.
Smoke check
openclaw --version
OPENCLAW_SKIP_CHANNELS=1 \
OPENCLAW_SKIP_CANVAS_HOST=1 \
openclaw gateway --port 18999 --bind loopback
Next:
openclaw gateway call health --port 18999 --timeout 3000