OpenClaw macOS IPC Architecture: Unix Socket, Gateway, and PeekabooBridge

Explains how the macOS app and node host service communicate via Unix sockets, covering Gateway transport, PeekabooBridge, and TCC permissions. Essential for developers integrating system.run or computer.act on macOS.

Read this when

  • Editing IPC contracts or menu bar app IPC

OpenClaw macOS IPC architecture

For exec approvals and system.run, the macOS app and the node host service communicate over a local Unix socket. A debug CLI named apps/macos/Sources/OpenClawMacCLI (an openclaw-mac tool) handles discovery and connectivity checks, while agent actions continue to travel through the Gateway WebSocket and node.invoke. When the node backs the computer.act path, embedded Peekaboo automation executes in-process; standalone Peekaboo clients rely on PeekabooBridge instead.

Goals

  • Only one GUI app instance exists, and it handles all TCC-related tasks: notifications, screen recording, mic, speech, and AppleScript.
  • Automation surface stays minimal: Gateway plus node commands, in-process computer.act, and PeekabooBridge for standalone UI automation clients.
  • Permissions remain predictable because the app always uses the same signed bundle ID and is launched by launchd, so TCC grants persist.

How it works

Gateway + node transport

  • The app runs the Gateway in local mode and attaches to it as a node.
  • Agent actions execute through node.invoke, such as system.run, system.notify, and canvas.present.
  • Node commands cover canvas.present, canvas.hide, canvas.navigate, camera.list, camera.snap, camera.clip, camera.ptz.status, camera.ptz.control, screen.snapshot, screen.record, computer.act, system.run, and system.notify.
  • A permissions map is reported by the node, letting agents see whether screen, camera, microphone, speech, automation, or accessibility access is present.

Node service + app IPC

  • A headless node host service establishes a connection to the Gateway WebSocket.
  • Over a local Unix socket (ExecApprovalsSocket.swift), system.run requests get forwarded to the macOS app.
  • The app runs the exec in UI context, shows prompts when necessary, and sends back the output.

Diagram (SCI):

Agent -> Gateway -> Node Service (WS)
                      |  IPC (UDS + token + HMAC + TTL)
                      v
                  Mac App (UI + TCC + system.run)

PeekabooBridge (UI automation)

  • The built-in agent computer tool bypasses this socket entirely. A paired macOS node handles computer.act in the app process using embedded Peekaboo services.
  • UI automation relies on a separate UNIX socket (~/Library/Application Support/OpenClaw/<socket>) and the PeekabooBridge JSON protocol.
  • Host preference order on the client side: Peekaboo.app, then Claude.app, then OpenClaw.app, then local execution.
  • Security: bridge hosts must match the exact signed Peekaboo client bundle identifier and Peekaboo's canonical current and legacy release signer set; a DEBUG-only same-UID escape hatch is gated by PEEKABOO_ALLOW_UNSIGNED_SOCKET_CLIENTS=1 (Peekaboo convention).
  • See PeekabooBridge usage for more.

Operational flows

  • Restart and rebuild: scripts/restart-mac.sh terminates running instances, rebuilds with Swift, repackages, and relaunches. It detects an available signing identity automatically and uses --no-sign as a fallback when none exists; pass --sign to demand signing (fails without a key) or --no-sign to force the unsigned route. An explicit SIGN_IDENTITY survives packaging; otherwise scripts/codesign-mac-app.sh detects the certificate on its own.
  • Single instance: the app inspects NSWorkspace.runningApplications for a duplicate bundle ID and quits if more than one instance is running (isDuplicateInstance() in MenuBar.swift).

Hardening notes

  • Require a TeamID match for all privileged surfaces as the preferred approach.
  • PeekabooBridge: PEEKABOO_ALLOW_UNSIGNED_SOCKET_CLIENTS=1 (DEBUG-only) can permit same-UID callers during local development.
  • All communication stays local-only; no network sockets are opened.
  • TCC prompts come only from the GUI app bundle; keep the signed bundle ID consistent across rebuilds.
  • Exec approvals socket hardening: file mode 0600, a shared token in the exec_approvals_config row of state/openclaw.sqlite, peer-UID verification (getpeereid), HMAC-SHA256 challenge/response, and a short TTL on requests.
568 words · updated Aug 25, 2026