OpenClaw macOS Companion (menu bar + gateway broker)
macOS 앱은 OpenClaw의 menu-bar companion입니다. 이 앱은 권한을 소유하고, Gateway를 로컬에서 관리/연결하며(launchd 또는 수동), 에이전트에 macOS 기능을 node로 노출합니다.역할
- menu bar에 네이티브 알림과 상태를 표시합니다.
- TCC prompt(Notifications, Accessibility, Screen Recording, Microphone, Speech Recognition, Automation/AppleScript)를 소유합니다.
- Gateway를 실행하거나 연결합니다(로컬 또는 원격).
- macOS 전용 tool(Canvas, Camera, Screen Recording,
system.run)을 노출합니다. - remote 모드에서는 로컬 node host service를 시작하고(launchd), local 모드에서는 중지합니다.
- 선택적으로 UI 자동화를 위해 PeekabooBridge를 호스팅합니다.
- 요청 시 npm/pnpm을 통해 전역 CLI(
openclaw)를 설치합니다(Gateway runtime에는 bun 비권장).
Local vs remote 모드
- Local (기본값): 앱은 실행 중인 로컬 Gateway가 있으면 여기에 연결하고, 없으면
openclaw gateway install을 통해 launchd 서비스를 활성화합니다. - Remote: 앱은 SSH/Tailscale을 통해 Gateway에 연결하며 로컬 프로세스를 시작하지 않습니다. 앱은 원격 Gateway가 이 Mac에 접근할 수 있도록 로컬 node host service를 시작합니다. 앱은 Gateway를 child process로 spawn하지 않습니다.
Launchd 제어
앱은 사용자별 LaunchAgentai.openclaw.gateway를 관리합니다(--profile/OPENCLAW_PROFILE 사용 시 ai.openclaw.<profile>; 레거시 com.openclaw.*도 여전히 unload 가능).
ai.openclaw.<profile>로 바꾸세요.
LaunchAgent가 설치되어 있지 않다면 앱에서 활성화하거나 openclaw gateway install을 실행하세요.
Node 기능 (mac)
macOS 앱은 자신을 node로 제시합니다. 일반적인 명령:- Canvas:
canvas.present,canvas.navigate,canvas.eval,canvas.snapshot,canvas.a2ui.* - Camera:
camera.snap,camera.clip - Screen:
screen.record - System:
system.run,system.notify
permissions 맵을 보고하여 에이전트가 무엇이 허용되는지 판단할 수 있게 합니다.
Node 서비스 + 앱 IPC:
- 헤드리스 node host service가 실행 중이면(remote 모드), Gateway WS에 node로 연결됩니다.
system.run은 로컬 Unix socket을 통해 macOS 앱(UI/TCC 컨텍스트)에서 실행됩니다. prompt와 출력은 앱 내부에 머뭅니다.
Exec approvals (system.run)
system.run은 macOS 앱의 Exec approvals(Settings → Exec approvals)로 제어됩니다.
보안 + ask + allowlist는 Mac 로컬의 다음 위치에 저장됩니다.
allowlist항목은 해석된 바이너리 경로에 대한 glob pattern입니다.- shell 제어 또는 확장 구문(
&&,||,;,|,`,$,<,>,(,))을 포함하는 raw shell command text는 allowlist miss로 처리되며, 명시적 승인(또는 shell 바이너리 allowlisting)이 필요합니다. - prompt에서 “Always Allow”를 선택하면 해당 명령이 allowlist에 추가됩니다.
system.runenvironment override는 필터링 후(PATH,DYLD_*,LD_*,NODE_OPTIONS,PYTHON*,PERL*,RUBYOPT,SHELLOPTS,PS4제거) 앱 환경과 병합됩니다.- shell wrapper(
bash|sh|zsh ... -c/-lc)의 경우 요청 범위 environment override는 작은 명시적 allowlist(TERM,LANG,LC_*,COLORTERM,NO_COLOR,FORCE_COLOR)로 축소됩니다. - allowlist 모드에서 allow-always 결정을 할 때, 알려진 dispatch wrapper(
env,nice,nohup,stdbuf,timeout)는 wrapper 경로 대신 내부 실행 파일 경로를 저장합니다. 안전하게 unwrapping할 수 없으면 allowlist 항목이 자동 저장되지 않습니다.
Deep link
앱은 로컬 작업을 위해openclaw:// URL scheme를 등록합니다.
openclaw://agent
Gateway agent 요청을 트리거합니다.
message(required)sessionKey(optional)thinking(optional)deliver/to/channel(optional)timeoutSeconds(optional)key(optional unattended mode key)
key가 없으면 앱이 확인 prompt를 표시합니다.key가 없으면 앱은 확인 prompt에 대해 짧은 메시지 제한을 적용하고deliver/to/channel을 무시합니다.- 유효한
key가 있으면 실행은 unattended 방식으로 진행됩니다(개인 자동화용).
Onboarding 흐름 (일반적)
- OpenClaw.app을 설치하고 실행합니다.
- 권한 체크리스트(TCC prompt)를 완료합니다.
- Local 모드가 활성화되어 있고 Gateway가 실행 중인지 확인합니다.
- 터미널 접근이 필요하면 CLI를 설치합니다.
상태 디렉터리 위치 (macOS)
OpenClaw 상태 디렉터리를 iCloud나 다른 클라우드 동기화 폴더에 두지 마세요. 동기화 기반 경로는 지연을 늘리고 세션 및 자격 증명에서 파일 잠금/동기화 경쟁을 일으킬 수 있습니다. 다음처럼 로컬 비동기화 상태 경로를 사용하는 것이 좋습니다.openclaw doctor가 다음 위치 아래의 상태를 감지하면:
~/Library/Mobile Documents/com~apple~CloudDocs/...~/Library/CloudStorage/...
Build & dev workflow (native)
cd apps/macos && swift buildswift run OpenClaw(또는 Xcode)- 앱 패키징:
scripts/package-mac-app.sh
Debug gateway connectivity (macOS CLI)
앱을 실행하지 않고도 macOS 앱이 사용하는 동일한 Gateway WebSocket handshake 및 discovery 로직을 시험하려면 debug CLI를 사용하세요.--url <ws://host:port>: config override--mode <local|remote>: config에서 해석 (기본값: config 또는 local)--probe: 새로운 health probe를 강제--timeout <ms>: 요청 timeout (기본값:15000)--json: diffing용 구조화 출력
--include-local: “local”로 필터링될 gateway도 포함--timeout <ms>: 전체 discovery window (기본값:2000)--json: diffing용 구조화 출력
dns-sd 기반 discovery와 다른지 확인하려면 openclaw gateway discover --json과 비교하세요.
원격 연결 plumbing (SSH tunnel)
macOS 앱이 Remote 모드에서 실행되면, 로컬 UI 구성 요소가 원격 Gateway를 localhost처럼 사용할 수 있도록 SSH tunnel을 엽니다.Control tunnel (Gateway WebSocket port)
- Purpose: health check, status, Web Chat, config 및 기타 control-plane 호출
- Local port: Gateway 포트(기본값
18789), 항상 고정 - Remote port: 원격 호스트의 동일한 Gateway 포트
- Behavior: 임의의 로컬 포트 사용 없음. 앱은 기존의 healthy tunnel을 재사용하거나 필요 시 재시작합니다.
- SSH shape: BatchMode + ExitOnForwardFailure + keepalive 옵션을 포함한
ssh -N -L <local>:127.0.0.1:<remote> - IP reporting: SSH tunnel은 loopback을 사용하므로 gateway는 node IP를
127.0.0.1로 보게 됩니다. 실제 client IP가 표시되길 원하면 Direct (ws/wss) transport를 사용하세요(macOS remote access 참고).