Complemento macOS de OpenClaw (barra de menú + broker del Gateway)

La app de macOS es el complemento de barra de menú para OpenClaw. Gestiona permisos, administra/se conecta al Gateway localmente (launchd o manual) y expone las capacidades de macOS al agente como un nodo.

Qué hace

  • Muestra notificaciones nativas y estado en la barra de menú.
  • Gestiona las solicitudes TCC (Notificaciones, Accesibilidad, Grabación de pantalla, Micrófono, Reconocimiento de voz, Automatización/AppleScript).
  • Ejecuta o se conecta al Gateway (local o remoto).
  • Expone herramientas exclusivas de macOS (Canvas, Cámara, Grabación de pantalla, system.run).
  • Inicia el servicio de host de nodo local en modo remoto (launchd), y lo detiene en modo local.
  • Opcionalmente aloja PeekabooBridge para automatización de UI.
  • Instala el CLI global (openclaw) vía npm/pnpm a petición (no se recomienda bun para el runtime del Gateway).

Modo local vs remoto

  • Local (por defecto): la app se conecta a un Gateway local en ejecución si existe; de lo contrario, habilita el servicio launchd vía openclaw gateway install.
  • Remoto: la app se conecta a un Gateway por SSH/Tailscale y nunca inicia un proceso local. La app inicia el servicio de host de nodo local para que el Gateway remoto pueda alcanzar este Mac. La app no genera el Gateway como un proceso hijo.

Control de launchd

La app gestiona un LaunchAgent por usuario etiquetado ai.openclaw.gateway (o ai.openclaw.<profile> cuando se usa --profile/OPENCLAW_PROFILE; legacy com.openclaw.* se sigue descargando).

launchctl kickstart -k gui/$UID/ai.openclaw.gateway
launchctl bootout gui/$UID/ai.openclaw.gateway

Reemplaza la etiqueta con ai.openclaw.<profile> cuando ejecutes un perfil con nombre.

Si el LaunchAgent no está instalado, habilítalo desde la app o ejecuta openclaw gateway install.

Capacidades del nodo (mac)

La app de macOS se presenta como un nodo. Comandos comunes:

  • Canvas: canvas.present, canvas.navigate, canvas.eval, canvas.snapshot, canvas.a2ui.*
  • Cámara: camera.snap, camera.clip
  • Pantalla: screen.record
  • Sistema: system.run, system.notify

El nodo reporta un mapa de permissions para que los agentes puedan decidir qué está permitido.

Servicio de nodo + IPC de la app:

  • Cuando el servicio headless de host de nodo está ejecutándose (modo remoto), se conecta al WS del Gateway como nodo.
  • system.run se ejecuta en la app de macOS (contexto UI/TCC) a través de un socket Unix local; los prompts y la salida permanecen en la app.

Diagrama (SCI):

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

Aprobaciones de ejecución (system.run)

system.run está controlado por Aprobaciones de ejecución en la app de macOS (Ajustes → Exec approvals). La seguridad + ask + allowlist se almacenan localmente en el Mac en:

~/.openclaw/exec-approvals.json

Ejemplo:

{
  "version": 1,
  "defaults": {
    "security": "deny",
    "ask": "on-miss"
  },
  "agents": {
    "main": {
      "security": "allowlist",
      "ask": "on-miss",
      "allowlist": [{ "pattern": "/opt/homebrew/bin/rg" }]
    }
  }
}

Notas:

  • Las entradas de allowlist son patrones glob para rutas de binarios resueltas.
  • El texto de comando shell que contiene sintaxis de control o expansión (&&, ||, ;, |, `, $, <, >, (, )) se trata como un miss en la allowlist y requiere aprobación explícita (o añadir el binario del shell a la allowlist).
  • Elegir “Always Allow” en el prompt añade ese comando a la allowlist.
  • Las sobrecargas de entorno de system.run se filtran (descarta PATH, DYLD_*, LD_*, NODE_OPTIONS, PYTHON*, PERL*, RUBYOPT, SHELLOPTS, PS4) y luego se fusionan con el entorno de la app.
  • Para wrappers de shell (bash|sh|zsh ... -c/-lc), las sobrecargas de entorno del ámbito de la solicitud se reducen a una pequeña allowlist explícita (TERM, LANG, LC_*, COLORTERM, NO_COLOR, FORCE_COLOR).
  • Para decisiones de allow-always en modo allowlist, los wrappers de despacho conocidos (env, nice, nohup, stdbuf, timeout) persisten las rutas del ejecutable interno en lugar de las rutas del wrapper. Si el unwrapping no es seguro, no se persiste ninguna entrada de allowlist automáticamente.

La app registra el esquema URL openclaw:// para acciones locales.

openclaw://agent

Dispara una solicitud agent del Gateway.

open 'openclaw://agent?message=Hello%20from%20deep%20link'

Parámetros de consulta:

  • message (obligatorio)
  • sessionKey (opcional)
  • thinking (opcional)
  • deliver / to / channel (opcional)
  • timeoutSeconds (opcional)
  • key (clave opcional de modo desatendido)

Seguridad:

  • Sin key, la app solicita confirmación.
  • Sin key, la app aplica un límite corto de mensaje para el prompt de confirmación e ignora deliver / to / channel.
  • Con una key válida, la ejecución es desatendida (pensada para automatizaciones personales).

Flujo de onboarding (típico)

  1. Instala y abre OpenClaw.app.
  2. Completa la lista de permisos (prompts TCC).
  3. Asegúrate de que el modo Local esté activo y el Gateway esté ejecutándose.
  4. Instala el CLI si quieres acceso por terminal.

Ubicación del directorio de estado (macOS)

Evita colocar tu directorio de estado de OpenClaw en iCloud u otras carpetas sincronizadas en la nube. Las rutas respaldadas por sincronización pueden añadir latencia y ocasionalmente causar carreras de bloqueo/sincronización de archivos para sesiones y credenciales.

Prefiere una ruta de estado local no sincronizada como:

OPENCLAW_STATE_DIR=~/.openclaw

Si openclaw doctor detecta el estado bajo:

  • ~/Library/Mobile Documents/com~apple~CloudDocs/...
  • ~/Library/CloudStorage/...

advertirá y recomendará mover de vuelta a una ruta local.

Flujo de compilación y desarrollo (nativo)

  • cd apps/macos && swift build
  • swift run OpenClaw (o Xcode)
  • Empaquetar app: scripts/package-mac-app.sh

Depurar conectividad del Gateway (CLI de macOS)

Usa el CLI de depuración para ejercitar el mismo handshake WebSocket del Gateway y la lógica de descubrimiento que usa la app de macOS, sin iniciar la app.

cd apps/macos
swift run openclaw-mac connect --json
swift run openclaw-mac discover --timeout 3000 --json

Opciones de conexión:

  • --url <ws://host:port>: sobrescribir configuración
  • --mode <local|remote>: resolver desde configuración (por defecto: config o local)
  • --probe: forzar un sondeo de salud fresco
  • --timeout <ms>: timeout de solicitud (por defecto: 15000)
  • --json: salida estructurada para comparación

Opciones de descubrimiento:

  • --include-local: incluir Gateways que se filtrarían como “local”
  • --timeout <ms>: ventana de descubrimiento total (por defecto: 2000)
  • --json: salida estructurada para comparación

Consejo: compara contra openclaw gateway discover --json para ver si el pipeline de descubrimiento de la app macOS (NWBrowser + fallback DNS-SD de tailnet) difiere del descubrimiento basado en dns-sd del CLI de Node.

Plomería de conexión remota (túneles SSH)

Cuando la app de macOS se ejecuta en modo Remoto, abre un túnel SSH para que los componentes de UI locales puedan comunicarse con un Gateway remoto como si estuviera en localhost.

Túnel de control (puerto WebSocket del Gateway)

  • Propósito: verificaciones de salud, estado, Web Chat, configuración y otras llamadas del plano de control.
  • Puerto local: el puerto del Gateway (por defecto 18789), siempre estable.
  • Puerto remoto: el mismo puerto del Gateway en el host remoto.
  • Comportamiento: sin puerto local aleatorio; la app reutiliza un túnel saludable existente o lo reinicia si es necesario.
  • Forma SSH: ssh -N -L <local>:127.0.0.1:<remote> con BatchMode + ExitOnForwardFailure + opciones de keepalive.
  • Reporte de IP: el túnel SSH usa loopback, así que el Gateway verá la IP del nodo como 127.0.0.1. Usa transporte Direct (ws/wss) si quieres que la IP real del cliente aparezca (ver acceso remoto macOS).

Para pasos de configuración, consulta acceso remoto macOS. Para detalles del protocolo, consulta protocolo del Gateway.

Documentación relacionada