The macOS app is the menu‑bar companion for CoderClaw. It owns permissions, manages/attaches to the Gateway locally (launchd or manual), and exposes macOS capabilities to the agent as a node.
system.run).coderclaw) via npm/pnpm on request (bun not recommended for the Gateway runtime).coderclaw gateway install.The app manages a per‑user LaunchAgent labeled bot.molt.gateway
(or bot.molt.<profile> when using --profile/CODERCLAW_PROFILE; legacy com.coderclaw.* still unloads).
launchctl kickstart -k gui/$UID/bot.molt.gateway
launchctl bootout gui/$UID/bot.molt.gateway
Replace the label with bot.molt.<profile> when running a named profile.
If the LaunchAgent isn’t installed, enable it from the app or run
coderclaw gateway install.
The macOS app presents itself as a node. Common commands:
canvas.present, canvas.navigate, canvas.eval, canvas.snapshot, canvas.a2ui.*camera.snap, camera.clipscreen.recordsystem.run, system.notifyThe node reports a permissions map so agents can decide what’s allowed.
Node service + app IPC:
system.run executes in the macOS app (UI/TCC context) over a local Unix socket; prompts + output stay in-app.Diagram (SCI):
Gateway -> Node Service (WS)
| IPC (UDS + token + HMAC + TTL)
v
Mac App (UI + TCC + system.run)
system.run is controlled by Exec approvals in the macOS app (Settings → Exec approvals).
Security + ask + allowlist are stored locally on the Mac in:
~/.coderclaw/exec-approvals.json
Example:
{
"version": 1,
"defaults": {
"security": "deny",
"ask": "on-miss"
},
"agents": {
"main": {
"security": "allowlist",
"ask": "on-miss",
"allowlist": [{ "pattern": "/opt/homebrew/bin/rg" }]
}
}
}
Notes:
allowlist entries are glob patterns for resolved binary paths.system.run environment overrides are filtered (drops PATH, DYLD_*, LD_*, NODE_OPTIONS, PYTHON*, PERL*, RUBYOPT) and then merged with the app’s environment.The app registers the coderclaw:// URL scheme for local actions.
coderclaw://agentTriggers a Gateway agent request.
open 'coderclaw://agent?message=Hello%20from%20deep%20link'
Query parameters:
message (required)sessionKey (optional)thinking (optional)deliver / to / channel (optional)timeoutSeconds (optional)key (optional unattended mode key)Safety:
key, the app prompts for confirmation.key, the app enforces a short message limit for the confirmation prompt and ignores deliver / to / channel.key, the run is unattended (intended for personal automations).cd apps/macos && swift buildswift run CoderClaw (or Xcode)scripts/package-mac-app.shUse the debug CLI to exercise the same Gateway WebSocket handshake and discovery logic that the macOS app uses, without launching the app.
cd apps/macos
swift run coderclaw-mac connect --json
swift run coderclaw-mac discover --timeout 3000 --json
Connect options:
--url <ws://host:port>: override config--mode <local|remote>: resolve from config (default: config or local)--probe: force a fresh health probe--timeout <ms>: request timeout (default: 15000)--json: structured output for diffingDiscovery options:
--include-local: include gateways that would be filtered as “local”--timeout <ms>: overall discovery window (default: 2000)--json: structured output for diffingTip: compare against coderclaw gateway discover --json to see whether the
macOS app’s discovery pipeline (NWBrowser + tailnet DNS‑SD fallback) differs from
the Node CLI’s dns-sd based discovery.
When the macOS app runs in Remote mode, it opens an SSH tunnel so local UI components can talk to a remote Gateway as if it were on localhost.
18789), always stable.ssh -N -L <local>:127.0.0.1:<remote> with BatchMode +
ExitOnForwardFailure + keepalive options.127.0.0.1. Use Direct (ws/wss) transport if you want the real client
IP to appear (see macOS remote access).For setup steps, see macOS remote access. For protocol details, see Gateway protocol.