docs: add docs:list helper and front matter
This commit is contained in:
@@ -1,18 +1,23 @@
|
||||
# Clawdis relay as a child process of the macOS app
|
||||
---
|
||||
summary: "Running the gateway as a child process of the macOS app and why"
|
||||
read_when:
|
||||
- Integrating the mac app with the gateway lifecycle
|
||||
---
|
||||
# Clawdis gateway as a child process of the macOS app
|
||||
|
||||
Date: 2025-12-06 · Status: draft · Owner: steipete
|
||||
|
||||
## Goal
|
||||
Run the Node-based Clawdis/clawdis relay as a direct child of the LSUIElement app (instead of a launchd agent) while keeping all TCC-sensitive work inside the Swift app/XPC and wiring the existing “Clawdis Active” toggle to start/stop the child.
|
||||
Run the Node-based Clawdis/clawdis gateway as a direct child of the LSUIElement app (instead of a launchd agent) while keeping all TCC-sensitive work inside the Swift app/XPC and wiring the existing “Clawdis Active” toggle to start/stop the child.
|
||||
|
||||
## When to prefer the child-process mode
|
||||
- You want relay lifetime strictly coupled to the menu-bar app (dies when the app quits) and controlled by the “Clawdis Active” toggle without touching launchd.
|
||||
- You want gateway lifetime strictly coupled to the menu-bar app (dies when the app quits) and controlled by the “Clawdis Active” toggle without touching launchd.
|
||||
- You’re okay giving up login persistence/auto-restart that launchd provides, or you’ll add your own backoff loop.
|
||||
- You want simpler log capture and supervision inside the app (no external plist or user-visible LaunchAgent).
|
||||
|
||||
## Tradeoffs vs. launchd
|
||||
- **Pros:** tighter coupling to UI state; simpler surface (no plist install/bootout); easier to stream stdout/stderr; fewer moving parts for beta users.
|
||||
- **Cons:** no built-in KeepAlive/login auto-start; app crash kills relay; you must build your own restart/backoff; Activity Monitor will show both processes under the app; still need correct TCC handling (see below).
|
||||
- **Cons:** no built-in KeepAlive/login auto-start; app crash kills gateway; you must build your own restart/backoff; Activity Monitor will show both processes under the app; still need correct TCC handling (see below).
|
||||
- **TCC:** behaviorally, child processes often inherit the parent app’s “responsible process” for TCC, but this is *not a contract*. Continue to route all protected actions through the Swift app/XPC so prompts stay tied to the signed app bundle.
|
||||
|
||||
## TCC guardrails (must keep)
|
||||
@@ -29,10 +34,10 @@ Run the Node-based Clawdis/clawdis relay as a direct child of the LSUIElement ap
|
||||
- Add a small `RelayProcessManager` (Swift) that owns:
|
||||
- `execution: Execution?` from `Swift Subprocess` to track the child.
|
||||
- `start(config)` called when “Clawdis Active” flips ON:
|
||||
- binary: host Node running the bundled relay under `Clawdis.app/Contents/Resources/Relay/`
|
||||
- binary: host Node running the bundled gateway under `Clawdis.app/Contents/Resources/Gateway/`
|
||||
- args: current clawdis entrypoint and flags
|
||||
- cwd/env: point to `~/.clawdis` as today; inject the expanded PATH so Homebrew Node resolves under launchd
|
||||
- output: stream stdout/stderr to `/tmp/clawdis-relay.log` (cap buffer via Subprocess OutputLimits)
|
||||
- output: stream stdout/stderr to `/tmp/clawdis-gateway.log` (cap buffer via Subprocess OutputLimits)
|
||||
- restart: optional linear/backoff restart if exit was non-zero and Active is still true
|
||||
- `stop()` called when Active flips OFF or app terminates: cancel the execution and `waitUntilExit`.
|
||||
- Wire SwiftUI toggle:
|
||||
@@ -41,19 +46,19 @@ Run the Node-based Clawdis/clawdis relay as a direct child of the LSUIElement ap
|
||||
- Keep the existing `LaunchdManager` around so we can switch back if needed; the toggle can choose between launchd or child mode with a flag if we want both.
|
||||
|
||||
## Packaging and signing
|
||||
- Bundle the relay payload (dist + production node_modules) under `Contents/Resources/Relay/`; rely on host Node ≥22 instead of embedding a runtime.
|
||||
- Bundle the gateway payload (dist + production node_modules) under `Contents/Resources/Gateway/`; rely on host Node ≥22 instead of embedding a runtime.
|
||||
- Codesign native addons and dylibs inside the bundle; no nested runtime binary to sign now.
|
||||
- Host runtime should not call TCC APIs directly; keep privileged work inside the app/XPC.
|
||||
|
||||
## Logging and observability
|
||||
- Stream child stdout/stderr to `/tmp/clawdis-relay.log`; surface the last N lines in the Debug tab.
|
||||
- Stream child stdout/stderr to `/tmp/clawdis-gateway.log`; surface the last N lines in the Debug tab.
|
||||
- Emit a user notification (via existing NotificationManager) on crash/exit while Active is true.
|
||||
- Add a lightweight heartbeat from Node → app (e.g., ping over stdout) so the app can show status in the menu.
|
||||
|
||||
## Failure/edge cases
|
||||
- App crash/quit kills the relay. Decide if that is acceptable for the deployment tier; otherwise, stick with launchd for production and keep child-process for dev/experiments.
|
||||
- If the relay exits repeatedly, back off (e.g., 1s/2s/5s/10s) and give up after N attempts with a menu warning.
|
||||
- Respect the existing pause semantics: when paused, the XPC should return `ok=false, "clawdis paused"`; the relay should avoid calling privileged routes while paused.
|
||||
- App crash/quit kills the gateway. Decide if that is acceptable for the deployment tier; otherwise, stick with launchd for production and keep child-process for dev/experiments.
|
||||
- If the gateway exits repeatedly, back off (e.g., 1s/2s/5s/10s) and give up after N attempts with a menu warning.
|
||||
- Respect the existing pause semantics: when paused, the XPC should return `ok=false, "clawdis paused"`; the gateway should avoid calling privileged routes while paused.
|
||||
|
||||
## Open questions / follow-ups
|
||||
- Do we need dual-mode (launchd for prod, child for dev)? If yes, gate via a setting or build flag.
|
||||
@@ -62,5 +67,5 @@ Run the Node-based Clawdis/clawdis relay as a direct child of the LSUIElement ap
|
||||
|
||||
## Decision snapshot (current recommendation)
|
||||
- Keep all TCC surfaces in the Swift app/XPC.
|
||||
- Implement `RelayProcessManager` with Swift Subprocess to start/stop the relay on the “Clawdis Active” toggle.
|
||||
- Implement `RelayProcessManager` with Swift Subprocess to start/stop the gateway on the “Clawdis Active” toggle.
|
||||
- Maintain the launchd path as a fallback for uptime/login persistence until child-mode proves stable.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
summary: "How the macOS app reports gateway/Baileys health states"
|
||||
read_when:
|
||||
- Debugging mac app health indicators
|
||||
---
|
||||
# Health Checks on macOS
|
||||
|
||||
How to see whether the WhatsApp Web/Baileys bridge is healthy from the menu bar app.
|
||||
@@ -19,4 +24,4 @@ How to see whether the WhatsApp Web/Baileys bridge is healthy from the menu bar
|
||||
- Cache the last good snapshot and the last error separately to avoid flicker; show the timestamp of each.
|
||||
|
||||
## When in doubt
|
||||
- You can still use the CLI flow in `docs/health.md` (status, heartbeat dry-run, relay heartbeat) and tail `/tmp/clawdis/clawdis.log` for `web-heartbeat` / `web-reconnect`.
|
||||
- You can still use the CLI flow in `docs/health.md` (status, heartbeat dry-run, gateway heartbeat) and tail `/tmp/clawdis/clawdis.log` for `web-heartbeat` / `web-reconnect`.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
summary: "Menu bar icon states and animations for Clawdis on macOS"
|
||||
read_when:
|
||||
- Changing menu bar icon behavior
|
||||
---
|
||||
# Menu Bar Icon States
|
||||
|
||||
Author: steipete · Updated: 2025-12-06 · Scope: macOS app (`apps/macos`)
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
summary: "Enabling verbose macOS unified logging for Clawdis with privacy flags"
|
||||
read_when:
|
||||
- Capturing macOS logs or investigating private data logging
|
||||
---
|
||||
# Logging private data on macOS
|
||||
|
||||
Unified logging redacts most payloads unless a subsystem opts into `privacy -off`. Per Peter's write-up on macOS [logging privacy shenanigans](https://steipete.me/posts/2025/logging-privacy-shenanigans) (2025) this is controlled by a plist in `/Library/Preferences/Logging/Subsystems/` keyed by the subsystem name. Only new log entries pick up the flag, so enable it before reproducing an issue.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
summary: "Menu bar status logic and what is surfaced to users"
|
||||
read_when:
|
||||
- Tweaking mac menu UI or status logic
|
||||
---
|
||||
# Menu Bar Status Logic
|
||||
|
||||
## What is shown
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
---
|
||||
summary: "macOS app flow for controlling a remote Clawdis gateway over SSH"
|
||||
read_when:
|
||||
- Setting up or debugging remote mac control
|
||||
---
|
||||
# Remote Clawdis (macOS ⇄ remote host)
|
||||
|
||||
Updated: 2025-12-08
|
||||
|
||||
This flow lets the macOS app act as a full remote control for a Clawdis relay running on another host (e.g. a Mac Studio). All features—health checks, permissions bootstrapping via the helper CLI, Voice Wake forwarding, and Web Chat—reuse the same remote SSH configuration from *Settings → General*.
|
||||
This flow lets the macOS app act as a full remote control for a Clawdis gateway running on another host (e.g. a Mac Studio). All features—health checks, permissions bootstrapping via the helper CLI, Voice Wake forwarding, and Web Chat—reuse the same remote SSH configuration from *Settings → General*.
|
||||
|
||||
## Modes
|
||||
- **Local (this Mac)**: Everything runs on the laptop. No SSH involved.
|
||||
@@ -23,8 +28,8 @@ This flow lets the macOS app act as a full remote control for a Clawdis relay ru
|
||||
4) Health checks and Web Chat will now run through this SSH tunnel automatically.
|
||||
|
||||
## Web Chat over SSH
|
||||
- The relay hosts a loopback-only HTTP server (default 18788, see `webchat.port`).
|
||||
- The mac app forwards `127.0.0.1:<port>` over SSH (`ssh -L <ephemeral>:127.0.0.1:<port>`), then loads `/webchat/?session=<key>` in-app. Sends go in-process on the relay (no CLI spawn/PATH issues).
|
||||
- The gateway hosts a loopback-only HTTP server (default 18788, see `webchat.port`).
|
||||
- The mac app forwards `127.0.0.1:<port>` over SSH (`ssh -L <ephemeral>:127.0.0.1:<port>`), then loads `/webchat/?session=<key>` in-app. Sends go in-process on the gateway (no CLI spawn/PATH issues).
|
||||
- Keep the feature enabled in *Settings → Config → Web chat*. Disable it to hide the menu entry entirely.
|
||||
|
||||
## Permissions
|
||||
@@ -38,14 +43,14 @@ This flow lets the macOS app act as a full remote control for a Clawdis relay ru
|
||||
## Troubleshooting
|
||||
- **exit 127 / not found**: `clawdis` isn’t on PATH for non-login shells. Add it to `/etc/paths`, your shell rc, or symlink into `/usr/local/bin`/`/opt/homebrew/bin`.
|
||||
- **Health probe failed**: check SSH reachability, PATH, and that Baileys is logged in (`clawdis status --json`).
|
||||
- **Web Chat stuck**: confirm the relay is running on the remote host and `webchat.enabled` is true; ensure the forwarded port matches *Settings → Config*. Since RPC is in-process, PATH is no longer a factor.
|
||||
- **Web Chat stuck**: confirm the gateway is running on the remote host and `webchat.enabled` is true; ensure the forwarded port matches *Settings → Config*. Since RPC is in-process, PATH is no longer a factor.
|
||||
- **Voice Wake**: trigger phrases are forwarded automatically in remote mode; no separate forwarder is needed.
|
||||
|
||||
## Notification sounds
|
||||
Pick sounds per notification from scripts with the helper CLI, e.g.:
|
||||
|
||||
```bash
|
||||
clawdis-mac notify --title "Ping" --body "Remote relay ready" --sound Glass
|
||||
clawdis-mac notify --title "Ping" --body "Remote gateway ready" --sound Glass
|
||||
```
|
||||
|
||||
There is no global “default sound” toggle in the app anymore; callers choose a sound (or none) per request.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
summary: "Signing steps for macOS debug builds generated by packaging scripts"
|
||||
read_when:
|
||||
- Building or signing mac debug builds
|
||||
---
|
||||
# mac signing (debug builds)
|
||||
|
||||
This app is usually built from `scripts/package-mac-app.sh`, which now:
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
summary: "Voice overlay lifecycle when wake-word and push-to-talk overlap"
|
||||
read_when:
|
||||
- Adjusting voice overlay behavior
|
||||
---
|
||||
## Voice Overlay Lifecycle (macOS)
|
||||
|
||||
Audience: macOS app contributors. Goal: keep the voice overlay predictable when wake-word and push-to-talk overlap.
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
---
|
||||
summary: "Voice wake and push-to-talk modes plus routing details in the mac app"
|
||||
read_when:
|
||||
- Working on voice wake or PTT pathways
|
||||
---
|
||||
# Voice Wake & Push-to-Talk
|
||||
|
||||
Updated: 2025-12-08 · Owners: mac app
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
---
|
||||
summary: "How the mac app embeds the gateway WebChat and how to debug it"
|
||||
read_when:
|
||||
- Debugging mac WebChat view or loopback port
|
||||
---
|
||||
# Web Chat (macOS app)
|
||||
|
||||
The macOS menu bar app opens the relay’s loopback web chat server in a WKWebView. It reuses the **primary Clawd session** (`main` by default, configurable via `inbound.reply.session.mainKey`). The server is started by the Node relay (default port 18788, see `webchat.port`).
|
||||
The macOS menu bar app opens the gateway’s loopback web chat server in a WKWebView. It reuses the **primary Clawd session** (`main` by default, configurable via `inbound.reply.session.mainKey`). The server is started by the Node gateway (default port 18788, see `webchat.port`).
|
||||
|
||||
## Launch & debugging
|
||||
- Manual: Lobster menu → “Open Chat”.
|
||||
@@ -9,12 +14,12 @@ The macOS menu bar app opens the relay’s loopback web chat server in a WKWebVi
|
||||
- WK logs: navigation lifecycle, readyState, js location, and JS errors/unhandled rejections are mirrored to OSLog for easier diagnosis.
|
||||
|
||||
## How it’s wired
|
||||
- Assets: `apps/macos/Sources/Clawdis/Resources/WebChat/` contains the `pi-web-ui` dist plus a local import map pointing at bundled vendor modules and a tiny `pi-ai` stub. Everything is served from the relay at `/webchat/*`.
|
||||
- Bridge: none. The web UI calls `/webchat/rpc` directly; Swift no longer proxies messages. RPC is handled in-process inside the relay (no CLI spawn/PATH dependency).
|
||||
- Assets: `apps/macos/Sources/Clawdis/Resources/WebChat/` contains the `pi-web-ui` dist plus a local import map pointing at bundled vendor modules and a tiny `pi-ai` stub. Everything is served from the gateway at `/webchat/*`.
|
||||
- Bridge: none. The web UI calls `/webchat/rpc` directly; Swift no longer proxies messages. RPC is handled in-process inside the gateway (no CLI spawn/PATH dependency).
|
||||
- Session: always primary; multiple transports (WhatsApp/Telegram/Desktop) share the same session key so context is unified.
|
||||
|
||||
## Security / surface area
|
||||
- Loopback server only; remote mode uses SSH port-forwarding from the relay host to the Mac. CSP is set to `default-src 'self' 'unsafe-inline' data: blob:`.
|
||||
- Loopback server only; remote mode uses SSH port-forwarding from the gateway host to the Mac. CSP is set to `default-src 'self' 'unsafe-inline' data: blob:`.
|
||||
- Web Inspector is opt-in via right-click; otherwise WKWebView stays in the app sandbox.
|
||||
|
||||
## Known limitations
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
---
|
||||
summary: "macOS XPC architecture for Clawdis app, CLI helper, and gateway bridge"
|
||||
read_when:
|
||||
- Editing XPC contracts or menu bar app IPC
|
||||
---
|
||||
# Clawdis macOS XPC architecture (Dec 2025)
|
||||
|
||||
## Goals
|
||||
- Single GUI app instance that owns all TCC-facing work (notifications, screen recording, mic, speech, AppleScript).
|
||||
- A small surface for automation: the `clawdis-mac` CLI and the Node relay talk to the app via a local XPC channel.
|
||||
- A small surface for automation: the `clawdis-mac` CLI and the Node gateway talk to the app via a local XPC channel.
|
||||
- Predictable permissions: always the same signed bundle ID, launched by launchd, so TCC grants stick.
|
||||
- Limit who can connect: only signed clients from our team (with a same-UID fallback for development).
|
||||
|
||||
@@ -10,7 +15,7 @@
|
||||
- The app registers a Mach service named `com.steipete.clawdis.xpc` via a user LaunchAgent at `~/Library/LaunchAgents/com.steipete.clawdis.plist`.
|
||||
- The launch agent runs `dist/Clawdis.app/Contents/MacOS/Clawdis` with `RunAtLoad=true`, `KeepAlive=false`, and a `MachServices` entry for the XPC name.
|
||||
- The app hosts the XPC listener (`NSXPCListener(machServiceName:)`) and exports `ClawdisXPCService`.
|
||||
- The CLI (`clawdis-mac`) connects with `NSXPCConnection(machServiceName:)`; the Node relay shells out to the CLI.
|
||||
- The CLI (`clawdis-mac`) connects with `NSXPCConnection(machServiceName:)`; the Node gateway shells out to the CLI.
|
||||
- Security: on incoming connections we read the audit token (or PID) and allow only:
|
||||
- Code-signed clients with team ID `Y5PE65HELJ`; or
|
||||
- Same-UID processes (fallback to avoid blocking local dev).
|
||||
|
||||
Reference in New Issue
Block a user