# MacBook Pro Node - OpenClaw Gateway Integration ## Documentation - [OpenClaw Architecture](docs/OPENCLAW_ARCHITECTURE.md) - [OpenClaw Health Monitoring](docs/OPENCLAW_HEALTH_MONITORING.md) ## Overview This repository documents the OpenClaw gateway integration for the satware AG MacBook Pro, configured as a remote tool node controlled by the agent-zero Docker container running on the Manjaro PC. ## System Information | Property | Value | |----------|-------| | **Hostname** | satware-AG-MacBook-Pro.local | | **OS** | macOS 26.3.1 (Tahoe) | | **Kernel** | Darwin 25.3.0 (x86_64) | | **User** | MWsatwareAG | | **Local IP** | 10.11.206.26 (en0) | | **Tailscale IP** | 100.64.0.12 | | **OpenClaw Version** | core v2026.3.8 | ## Node Configuration ### Node ID ``` 77b912f45a10c92e2970574186426b16f898488c9cd201335235be27d076cdf0 ``` ### Connection Architecture ```text ┌─────────────────────┐ Tailscale ┌─────────────────────┐ │ MacBook Pro │ 100.64.0.x │ Manjaro PC │ │ (Tool Node) │◄──────────────────►│ (Gateway Host) │ │ │ │ │ │ OpenClaw Node │ WebSocket │ OpenClaw Gateway │ │ (remote mode) │◄──────────────────►│ (100.64.0.39) │ │ v2026.3.8 │ Port 18789 │ Port 18789 │ │ │ │ │ │ SSH Client │ SSH Tunnel │ SSH Server │ │ │──────────────────►│ Port 2222 │ └─────────────────────┘ └─────────────────────┘ ``` ### MacBook OpenClaw Config (`~/.openclaw/openclaw.json`) ```json { "meta": { "lastTouchedVersion": "2026.3.8" }, "gateway": { "mode": "remote", "remote": { "url": "ws://100.64.0.39:18789", "token": "skt3_W8A5AVp...", "sshTarget": "root@100.64.0.39:2222", "sshIdentity": "/Users/MWsatwareAG/.ssh/id_ed25519" } } } ``` ### Security Policy (`~/.openclaw/exec-approvals.json`) ```json { "version": 1, "defaults": { "security": "full" }, "agents": {}, "nodes": { "77b912f45a10c92e2970574186426b16f898488c9cd201335235be27d076cdf0": { "displayName": "satware AG MacBook Pro", "security": "full", "allowlist": [ "system.run", "system.run.prepare", "system.which", "browser.proxy" ] } } } ``` ## Node Capabilities | Capability | Commands | Status | |------------|----------|--------| | **system** | `system.run`, `system.run.prepare`, `system.which` | ✅ Working | | **browser** | `browser.proxy` | ⚠️ Requires browser session | | **peekaboo**| `see`, `image`, `app.list`, `clipboard.get/set` | ✅ Active (Vision ready) | | **imsg** | `chats`, `history`, `send` | ✅ Active (Full Disk Access) | | **apple-notes** | `memo` integrations | ✅ Ready | | **apple-reminders** | `remindctl` integrations | ✅ Ready | | **camera** | `camera.list`, `camera.snap`, `camera.clip` | ❌ Not supported on darwin | | **screen** | `screen.record` | ❌ Not in allowlist for darwin | | **canvas** | `canvas.snapshot`, `canvas.present`, etc. | ❌ Not supported on darwin | > **Note**: Vision features in `peekaboo` require **Screen Recording** permissions granted to the Node.js binary (`/usr/local/Cellar/node/25.8.0/bin/node`). UI automation (clicks/typing) requires **Accessibility** permissions granted to the same binary. ## Tested Commands ### peekaboo Advanced UI automation and system introspection. | Command | Status | Notes | |---------|--------|-------| | `peekaboo image` | ✅ | Screenshot capture (Vision) | | `peekaboo app list` | ✅ | Lists running applications | | `peekaboo clipboard` | ✅ | Read/write system clipboard | | `peekaboo dock list` | ✅ | Lists items in macOS Dock | | `peekaboo permissions` | ✅ | Diagnostic for TCC permissions | ### imsg CLI-based iMessage/SMS integration. | Command | Status | Notes | |---------|--------|-------| | `imsg chats` | ✅ | Lists recent conversations | | `imsg history` | ✅ | Retrieves message history | | `imsg send` | ✅ | Sends messages via Messages.app | ### system.run Execute shell commands on the MacBook node. ```bash # Basic invocation pattern docker exec agent-zero openclaw nodes invoke \ --node "77b912f45a10c92e2970574186426b16f898488c9cd201335235be27d076cdf0" \ --command "system.run" \ --params '{"command":["",""]}' ``` #### Working Commands | Command | Result | Notes | |---------|--------|-------| | `hostname` | ✅ | Returns `satware-AG-MacBook-Pro.local` | | `uname -a` | ✅ | Darwin 25.3.0 x86_64 | | `sw_vers` | ✅ | macOS 26.3 (Build 25D125) | | `ls -la /Users/MWsatwareAG` | ✅ | Full filesystem access | | `/sbin/ifconfig en0` | ✅ | Network interface info | | `/usr/bin/curl -s https://httpbin.org/ip` | ✅ | External network access | | `node --version` | ✅ | Node.js v25.8.0 at `/usr/local/bin/node` | | `python3 --version` | ✅ | Python3 at `/usr/bin/python3` | | `git --version` | ✅ | Git at `/usr/local/bin/git` | | `peekaboo --version` | ✅ | v3.0.0-beta3 (Universal) | | `imsg --version` | ✅ | v0.5.0 (Universal, locally built) | #### Known Issues | Issue | Cause | Solution | |-------|-------|----------| | `spawn ENOENT` errors | Command not in PATH | Use full path (e.g., `/sbin/ifconfig`) | | Tailscale CLI timeout | GUI app requires interaction | Use alternative network commands | | `browser.proxy` Not Found | No browser session running | Start browser first | ### system.which Find binary locations on the node. ```bash docker exec agent-zero openclaw nodes invoke \ --node "77b912f45a10c92e2970574186426b16f898488c9cd201335235be27d076cdf0" \ --command "system.which" \ --params '{"bins":["node","python3","git"]}' ``` Returns: ```json {"bins":{"node":"/usr/local/bin/node","python3":"/usr/bin/python3","git":"/usr/local/bin/git"}} ``` ## Quick Reference Commands ### Check Node Status ```bash docker exec agent-zero openclaw nodes status ``` ### Describe Node Capabilities ```bash docker exec agent-zero openclaw nodes describe --node "77b912f45a10c92e2970574186426b16f898488c9cd201335235be27d076cdf0" ``` ### Run Shell Command ```bash docker exec agent-zero openclaw nodes run --node "77b912f45a10c92e2970574186426b16f898488c9cd201335235be27d076cdf0" --raw "uname -a" ``` ## Gateway Configuration The OpenClaw gateway runs inside the `agent-zero` Docker container on the Manjaro PC. ### Gateway Access URLs | URL | Description | |-----|-------------| | `http://127.0.0.1:18789/` | Localhost access (Control UI) | | `http://localhost:18789/` | Localhost access (Control UI) | | `http://100.64.0.39:18789/` | Tailscale LAN access | | `ws://100.64.0.39:18789` | WebSocket endpoint for nodes | ### Gateway Configuration (`/home/ja/internal/luca/openclaw-data/openclaw.json`) Key gateway settings: ```json { "gateway": { "port": 18789, "mode": "local", "bind": "lan", "controlUi": { "allowedOrigins": [ "http://localhost:18789", "http://127.0.0.1:18789", "https://localhost:18789", "http://100.64.0.39:18789" ], "allowInsecureAuth": true } } } ``` ### Exec Approvals Configuration (`/home/ja/internal/luca/openclaw-data/exec-approvals.json`) Node-specific security policy: ```json { "version": 1, "defaults": { "security": "full" }, "nodes": { "77b912f45a10c92e2970574186426b16f898488c9cd201335235be27d076cdf0": { "displayName": "satware AG MacBook Pro", "security": "full", "allowlist": ["system.run", "system.run.prepare", "system.which", "browser.proxy"] } } } ``` ## Network Configuration ### Gateway (Manjaro PC) - **Tailscale IP**: 100.64.0.39 - **WebSocket Port**: 18789 - **SSH Port**: 2222 ### MacBook Pro - **Tailscale IP**: 100.64.0.12 - **Local IP**: 10.11.206.26 - **External IP**: 77.24.181.185 (via curl httpbin.org/ip) ## Security Considerations 1. **exec-approvals.json**: Currently set to `"security": "full"` for testing - Consider `"allowlist"` mode for production - Define specific allowed commands in allowlist 2. **SSH Access**: MacBook has SSH key-based access to gateway container - Key: `~/.ssh/id_ed25519` - Target: `root@100.64.0.39:2222` 3. **WebSocket Connection**: Unencrypted (ws:// not wss://) - Traffic stays within Tailscale mesh network - Consider TLS termination for external access ## Files | File | Location | Purpose | |------|----------|---------| | `openclaw.json` | `~/.openclaw/openclaw.json` | Node configuration | | `exec-approvals.json` | `~/.openclaw/exec-approvals.json` | Security policy | | `paired.json` | Gateway: `openclaw-data/devices/paired.json` | Paired devices registry | | `authorized_keys` | Gateway: `ssh-keys/authorized_keys` | SSH access keys | ## Developer CLI Tools The MacBook has the following version control CLI tools installed via Homebrew (Intel x86, `/usr/local/bin/`). | Tool | Version | Auth | Host | |------|---------|------|------| | `tea` | 0.12.0 | `ja` | `https://git.satware.ai` | | `gh` | 2.87.3 | `jane-alesi` | `github.com` | | `glab` | 1.87.0 | `ja` | `gitlab.satware.com` | | `git` | 2.50.1 | n/a | (Apple Git-155, system) | ### Auth Configuration Paths | Tool | Config File | |------|------------| | `tea` | `~/.config/tea/config.yml` | | `gh` | `~/.config/gh/hosts.yml` | | `glab` | `~/.config/glab-cli/config.yml` | ### Verify Auth (SSH-safe) ```bash export PATH="/usr/local/bin:/usr/bin:/bin:$PATH" # tea - Gitea (git.satware.ai) tea logins list # gh - GitHub gh auth status # glab - GitLab (gitlab.satware.com) glab auth status # git fetch from this repo (bypasses macOS keychain) cd ~/infrastructure/mw-macbook-pro git -c credential.helper="" fetch origin ``` ### Re-run Setup If tokens expire or tools need to be reconfigured: ```bash # tea tea logins add --name git-satware --url https://git.satware.ai --token # gh echo "" | gh auth login --with-token # glab glab auth login --hostname gitlab.satware.com --token ``` > **Note**: The macOS keychain error `fatal: failed to store: -25308` during non-interactive SSH sessions is cosmetic - use `git -c credential.helper=""` to suppress it. Credentials are stored in the config files above. --- ## Related Documentation - OpenClaw Docs: https://docs.openclaw.ai/cli/nodes - Gateway Setup: `/home/ja/internal/luca/docker-compose.yml` - Tailscale: https://tailscale.com ## Verification Status **Last Verified**: 2026-03-11 23:15 CET | Component | Status | |-----------|--------| | **Node Connection** | ✅ Paired & Connected | | **Gateway Health** | ✅ OK (158ms via Tailscale) | | **system.run** | ✅ Working | | **Vision (Peekaboo)**| ✅ Active | | **iMessage (imsg)** | ✅ Active | | **Capabilities** | `browser`, `system`, `peekaboo`, `imsg`, `apple-notes` | ### MacBook launchd Services | Service | Status | Purpose | |---------|--------|---------| | `ai.openclaw.node` | Running | Primary Node service (v2026.3.8) | | `ai.openclaw.gateway` | Unloaded | Disabled (remote node role) | | `com.satware.openclaw-tunnel` | Running | SSH tunnel to gateway | ### Management Commands (on MacBook) ```bash # Check service status launchctl list | grep openclaw # Restart SSH tunnel launchctl unload ~/Library/LaunchAgents/com.satware.openclaw-tunnel.plist launchctl load ~/Library/LaunchAgents/com.satware.openclaw-tunnel.plist ``` ### Verify from Gateway ```bash # Check node status docker exec agent-zero openclaw nodes status # Test command execution docker exec agent-zero openclaw nodes invoke \ --node "77b912f45a10c92e2970574186426b16f898488c9cd201335235be27d076cdf0" \ --command "system.run" \ --params '{"command":["hostname"]}' ``` --- ## SSH system health check (2026-03-04 05:12 CET) Target checked: `MWsatwareAG@100.64.0.12` ### Snapshot | Area | Result | Notes | |------|--------|-------| | Reachability | ✅ OK | SSH login successful | | OS | ✅ OK | macOS 26.3, Darwin 25.3.0 | | Uptime/Load | ✅ OK | Uptime ~12h; load avg ~3.0 on 16 logical CPUs | | CPU | ⚠️ Watch | Short-term spikes from `openclaw-gateway`, `RustDesk`, Weather widget | | Memory | ✅ OK | 16 GB total (`hw.memsize: 17179869184`) | | Disk | ✅ OK | APFS main container ~18% used; high free capacity | | Recent errors | ✅ None critical in sample | No critical/fatal lines surfaced in 2h sample | | Listening ports | ⚠️ Review | `22`, `5900`, `3283`, Tailscale/RustDesk-related listeners | ### Key commands used ```bash ssh -o BatchMode=yes -o ConnectTimeout=10 MWsatwareAG@100.64.0.12 'sw_vers; uname -a; uptime; sysctl vm.loadavg' ssh -o BatchMode=yes -o ConnectTimeout=10 MWsatwareAG@100.64.0.12 'sysctl hw.memsize; df -h; diskutil apfs list | head -n 80' ssh -o BatchMode=yes -o ConnectTimeout=10 MWsatwareAG@100.64.0.12 'ps -Ao pid,pcpu,pmem,comm | sort -k2 -nr | head -n 10' ssh -o BatchMode=yes -o ConnectTimeout=10 MWsatwareAG@100.64.0.12 'netstat -anv -p tcp | grep LISTEN | head -n 20' ``` ## Next steps 1. Run a 5-10 minute process sample to confirm whether high CPU from `openclaw-gateway` is transient. 2. Validate which externally reachable services are required (`22`, `5900`, `3283`, RustDesk/Tailscale). 3. If hardening is required, disable unneeded listeners and re-test remote workflows. 4. Add an automated daily health snapshot job and keep results in this repository. --- *Last updated: 2026-03-11*