OpenClaw macOS 컴패니언 (메뉴바 + gateway broker)
macOS 앱은 OpenClaw를 위한 메뉴바 컴패니언입니다. 권한을 소유하고, 로컬에서 Gateway를 관리/연결하며 (launchd 또는 수동), macOS 기능을 node로 agent에 노출합니다.
기능
- 메뉴바에 네이티브 알림 및 상태 표시.
- TCC 프롬프트 소유 (알림, 접근성, 화면 녹화, 마이크, 음성 인식, 자동화/AppleScript).
- Gateway 실행 또는 연결 (로컬 또는 원격).
- macOS 전용 도구 노출 (Canvas, Camera, Screen Recording, system.run).
- 원격 모드에서 로컬 node host 서비스 시작 (launchd), 로컬 모드에서 중지.
- 선택적으로 UI 자동화를 위한 PeekabooBridge 호스팅.
- 요청 시 npm/pnpm을 통해 전역 CLI(openclaw) 설치 (Gateway 런타임에는 bun 권장하지 않음).
로컬 vs 원격 모드
- 로컬 (기본값): 앱이 실행 중인 로컬 Gateway에 연결; 없으면 openclaw gateway install을 통해 launchd 서비스를 활성화합니다.
- 원격: 앱이 SSH/Tailscale을 통해 Gateway에 연결하며 로컬 프로세스를 시작하지 않습니다. 앱은 원격 Gateway가 이 Mac에 도달할 수 있도록 로컬 node host 서비스를 시작합니다. 앱은 Gateway를 자식 프로세스로 생성하지 않습니다.
Launchd 제어
앱은 bot.molt.gateway로 레이블된 사용자별 LaunchAgent를 관리합니다 (--profile/OPENCLAW_PROFILE 사용 시 bot.molt.<profile>; 레거시 com.openclaw.*는 여전히 언로드됨).
launchctl kickstart -k gui/$UID/bot.molt.gateway
launchctl bootout gui/$UID/bot.molt.gateway
명명된 프로필 실행 시 레이블을 bot.molt.<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
Node는 agent가 허용되는 것을 결정할 수 있도록 permissions 맵을 보고합니다.
Node 서비스 + 앱 IPC:
- 헤드리스 node host 서비스가 실행 중일 때 (원격 모드), Gateway WS에 node로 연결합니다.
- system.run은 로컬 Unix 소켓을 통해 macOS 앱(UI/TCC 컨텍스트)에서 실행됩니다; 프롬프트 + 출력은 앱 내에 유지됩니다.
다이어그램 (SCI):
Gateway -> Node Service (WS)
| IPC (UDS + token + HMAC + TTL)
v
Mac App (UI + TCC + system.run)
Exec 승인 (system.run)
system.run은 macOS 앱(설정 → Exec 승인)의 Exec 승인으로 제어됩니다. 보안 + ask + allowlist는 Mac에 로컬로 저장됩니다:
~/.openclaw/exec-approvals.json
예시:
{
"version": 1,
"defaults": {
"security": "deny",
"ask": "on-miss"
},
"agents": {
"main": {
"security": "allowlist",
"ask": "on-miss",
"allowlist": [
{ "pattern": "/opt/homebrew/bin/rg" }
]
}
}
}
참고사항:
- allowlist 항목은 해결된 바이너리 경로에 대한 glob 패턴입니다.
- 프롬프트에서 "항상 허용"을 선택하면 해당 명령이 allowlist에 추가됩니다.
- system.run 환경 재정의는 필터링(PATH, DYLD_*, LD_*, NODE_OPTIONS, PYTHON*, PERL*, RUBYOPT 삭제)된 후 앱의 환경과 병합됩니다.
딥 링크
앱은 로컬 작업을 위해 openclaw:// URL 스킴을 등록합니다.
openclaw://agent
Gateway agent 요청을 트리거합니다.
open 'openclaw://agent?message=Hello%20from%20deep%20link'
쿼리 매개변수:
- message (필수)
- sessionKey (선택사항)
- thinking (선택사항)
- deliver / to / channel (선택사항)
- timeoutSeconds (선택사항)
- key (선택사항 무인 모드 키)
안전:
- key 없이는 앱이 확인을 요청합니다.
- 유효한 key가 있으면, 실행이 무인 모드입니다 (개인 자동화 용도).
온보딩 흐름 (일반적)
- OpenClaw.app을 설치하고 실행합니다.
- 권한 체크리스트 완료 (TCC 프롬프트).
- 로컬 모드가 활성화되어 있고 Gateway가 실행 중인지 확인합니다.
- 터미널 접근을 원하면 CLI를 설치합니다.
빌드 & 개발 워크플로우 (네이티브)
- cd apps/macos && swift build
- swift run OpenClaw (또는 Xcode)
- 앱 패키징: scripts/package-mac-app.sh
Gateway 연결 디버그 (macOS CLI)
디버그 CLI를 사용하여 앱을 실행하지 않고 macOS 앱이 사용하는 동일한 Gateway WebSocket 핸드셰이크 및 검색 로직을 실행하세요.
cd apps/macos
swift run openclaw-mac connect --json
swift run openclaw-mac discover --timeout 3000 --json
연결 옵션:
- --url <ws://host:port>: 구성 재정의
- --mode <local|remote>: 구성에서 해결 (기본값: 구성 또는 로컬)
- --probe: 새 헬스 프로브 강제
- --timeout <ms>: 요청 타임아웃 (기본값: 15000)
- --json: 비교를 위한 구조화된 출력
검색 옵션:
- --include-local: "로컬"로 필터링될 gateway 포함
- --timeout <ms>: 전체 검색 창 (기본값: 2000)
- --json: 비교를 위한 구조화된 출력
팁: openclaw gateway discover --json과 비교하여 macOS 앱의 검색 파이프라인 (NWBrowser + tailnet DNS‑SD 대체)이 Node CLI의 dns-sd 기반 검색과 다른지 확인하세요.
원격 연결 플러밍 (SSH 터널)
macOS 앱이 원격 모드로 실행될 때, 로컬 UI 구성 요소가 마치 localhost에 있는 것처럼 원격 Gateway와 통신할 수 있도록 SSH 터널을 엽니다.
제어 터널 (Gateway WebSocket 포트)
- 목적: 헬스 체크, 상태, Web Chat, 구성 및 기타 control-plane 호출.
- 로컬 포트: Gateway 포트 (기본값 18789), 항상 안정적.
- 원격 포트: 원격 호스트의 동일한 Gateway 포트.
- 동작: 무작위 로컬 포트 없음; 앱은 기존의 건강한 터널을 재사용하거나 필요한 경우 재시작합니다.
- SSH 형태: ssh -N -L <local>:127.0.0.1:<remote> BatchMode + ExitOnForwardFailure + keepalive 옵션 포함.
- IP 보고: SSH 터널은 loopback을 사용하므로 gateway는 node IP를 127.0.0.1로 봅니다. 실제 클라이언트 IP가 나타나도록 하려면 직접 (ws/wss) 전송을 사용하세요 (macOS 원격 접근 참조).
설정 단계는 macOS 원격 접근을 참조하세요. 프로토콜 세부사항은 Gateway 프로토콜을 참조하세요.