Remote web chat tunnel and onboarding polish
This commit is contained in:
@@ -1,29 +1,51 @@
|
||||
# Remote Clawd mode (Dec 2025)
|
||||
# Remote Clawdis (macOS ⇄ remote host)
|
||||
|
||||
## What it is
|
||||
- Run the Clawdis relay on another machine (Linux/macOS) reachable over SSH while the macOS app keeps TCC, notifications, and UI.
|
||||
- You can toggle Local vs Remote in **Settings → General → Clawdis runs**; remote adds fields for SSH target, identity file, and project root.
|
||||
- We recommend running a Tailscale node on both sides so the target is reachable even off-LAN.
|
||||
Updated: 2025-12-08
|
||||
|
||||
## Requirements
|
||||
- SSH access with public-key auth (`BatchMode=yes`); set `user@host[:port]` and an identity file.
|
||||
- The remote host must have a working `clawdis` install in the project root you specify.
|
||||
- `clawdis-mac` is still used for permissioned actions; the CLI path is auto-discovered on the remote via `command -v` + common prefixes.
|
||||
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*.
|
||||
|
||||
## How it works
|
||||
- The app builds commands through the new runner:
|
||||
- `clawdis status/health/agent/relay` are wrapped in `ssh … /bin/sh -c '<cd project && clawdis …>'` with CLI path lookup.
|
||||
- `clawdis rpc` is tunneled over a long-lived SSH process so web chat and the app’s Agent tab stay responsive.
|
||||
- Local TCC flows remain unchanged; if the remote agent needs local permissions, it should SSH back here and invoke `clawdis-mac …` (same CLI surface).
|
||||
## Modes
|
||||
- **Local (this Mac)**: Everything runs on the laptop. No SSH involved.
|
||||
- **Remote over SSH**: Clawdis commands are executed on the remote host. The mac app opens an SSH connection with `-o BatchMode` plus your chosen identity/key.
|
||||
|
||||
## Setup steps
|
||||
1) Open **Settings → General → Clawdis runs** and pick **Remote over SSH**.
|
||||
2) Fill **SSH target**, **Identity file**, and **Project root** (where `clawdis` lives on the remote).
|
||||
3) Click **Test remote**; it runs `clawdis status --json` remotely and caches the resolved CLI path.
|
||||
4) Run onboarding’s WhatsApp login step on the machine where the relay will run (remote if remote mode is enabled).
|
||||
## Prereqs on the remote host
|
||||
1) Install Node + pnpm and build/install the Clawdis CLI (`pnpm install && pnpm build && pnpm link --global`).
|
||||
2) Ensure `clawdis` is on PATH for non-interactive shells. If you prefer, symlink `clawdis-mac` too so TCC-capable actions can run remotely when needed.
|
||||
3) Open SSH with key auth. We recommend **Tailscale** IPs for stable reachability off-LAN.
|
||||
|
||||
## Notes
|
||||
- Connection strings accept `user@host:port`; leading `ssh ` is stripped if pasted from a shell snippet.
|
||||
- Project root defaults to the path you enter; if blank, no `cd` is issued before the relay command.
|
||||
- The remote log path remains `/tmp/clawdis/clawdis.log`; view it via SSH if you need details.
|
||||
- If you switch back to Local, existing remote state is left untouched; re-run Test remote when switching again.
|
||||
## macOS app setup
|
||||
1) Open *Settings → General*.
|
||||
2) Under **Clawdis runs**, pick **Remote over SSH** and set:
|
||||
- **SSH target**: `user@host` (optional `:port`).
|
||||
- **Identity file** (advanced): path to your key.
|
||||
- **Project root** (advanced): remote checkout path used for commands.
|
||||
3) Hit **Test remote**. Success indicates the remote `clawdis status --json` runs correctly. Failures usually mean PATH/CLI issues; exit 127 means the CLI isn’t found remotely.
|
||||
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 (`clawdis webchat --port <port>`; default 18788).
|
||||
- The mac app forwards `127.0.0.1:<port>` over SSH (`ssh -L <ephemeral>:127.0.0.1:<port>`), loads `/webchat/info`, and serves the Web Chat UI in-app.
|
||||
- Keep the feature enabled in *Settings → Config → Web chat*. Disable it to hide the menu entry entirely.
|
||||
|
||||
## Permissions
|
||||
- The remote host needs the same TCC approvals as local (Automation, Accessibility, Screen Recording, Microphone, Speech Recognition, Notifications). Run onboarding on that machine to grant them once.
|
||||
- When remote commands need local TCC (e.g., screenshots on the remote Mac), ensure `clawdis-mac` is installed there so the helper can request/hold those permissions.
|
||||
|
||||
## WhatsApp login flow (remote)
|
||||
- Run `clawdis login --verbose` **on the remote host**. Scan the QR with WhatsApp on your phone.
|
||||
- Re-run login on that host if auth expires. Health check will surface link problems.
|
||||
|
||||
## 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 remote webchat server is running (`clawdis webchat --json`) and the port matches *Settings → Config*.
|
||||
- **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
|
||||
```
|
||||
|
||||
There is no global “default sound” toggle in the app anymore; callers choose a sound (or none) per request.
|
||||
|
||||
@@ -1,56 +1,33 @@
|
||||
# Web Chat architecture (local + remote)
|
||||
# Web Chat (loopback + SSH tunnel)
|
||||
|
||||
Date: 2025-12-08 · Status: draft plan
|
||||
Updated: 2025-12-08
|
||||
|
||||
## Goal
|
||||
- Serve the Clawdis Web Chat UI from the Node relay (loopback-only HTTP), while the macOS app keeps the same UX by embedding it in a WKWebView.
|
||||
- Keep remote mode working: when Clawdis runs on a remote host via SSH, the mac app should still show the web chat backed by that remote relay (via an SSH tunnel).
|
||||
## What shipped
|
||||
- A lightweight HTTP server now lives inside the Node relay (`clawdis webchat --port 18788`).
|
||||
- It binds to **127.0.0.1** only and serves:
|
||||
- `GET /webchat/info?session=<key>` → `{port, token, sessionId, initialMessages, basePath}` plus history from the relay’s session store.
|
||||
- `GET /webchat/*` → static Web Chat assets.
|
||||
- `POST /webchat/rpc` → runs `clawdis agent --json` and returns `{ ok, payloads?, error? }`.
|
||||
- The macOS app embeds this UI in a WKWebView. In **remote mode** it first opens an SSH tunnel (`ssh -L <local>:127.0.0.1:<port>`) to the remote host, then loads `/webchat/info` through that tunnel.
|
||||
- Initial messages are preloaded from the relay’s session store, so remote sessions appear immediately.
|
||||
- Sending now goes over the HTTP `/webchat/rpc` endpoint (no more AgentRPC fallback).
|
||||
- Feature flag + port live in *Settings → Config → Web chat*. When disabled, the “Open Chat” menu entry is hidden.
|
||||
|
||||
## Proposed architecture
|
||||
1) **Server location**
|
||||
- A tiny HTTP server lives in the Node relay process.
|
||||
- Bind to 127.0.0.1 on a chosen port (fixed or random with discovery endpoint).
|
||||
- Serve static assets for `/webchat/` and a JSON RPC endpoint for sending messages.
|
||||
## Security
|
||||
- Loopback only; remote access requires SSH port-forwarding.
|
||||
- Optional bearer token support is wired; tokens are returned by `/webchat/info` and accepted by `/webchat/rpc`.
|
||||
|
||||
2) **Endpoints**
|
||||
- `GET /webchat/*`: serves bundled web assets (current WebChat build, moved from mac bundle into the Node package, e.g., `src/webchat/dist`).
|
||||
- `GET /webchat/info`: returns `{ baseUrl, token? }` for the mac app to embed (token optional; see security below).
|
||||
- `POST /webchat/rpc`: accepts `{ text, session, thinking?, deliver?, to? }` and replies with `{ ok, payloads?, error? }`. Internally calls the same agent pipeline that `clawdis rpc` uses today (in-process, no subprocess).
|
||||
- (Optional) `GET /webchat/history?session=<key>`: returns pre-serialized message history so the mac app doesn’t scrape JSONL. Can be folded into `/webchat/info` as an `initialMessages` field.
|
||||
## Failure handling
|
||||
- Bootstrap errors show in-app (“Web chat failed to connect …”) instead of hanging.
|
||||
- The mac app logs tunnel and endpoint details to the `com.steipete.clawdis/WebChat` subsystem.
|
||||
|
||||
3) **Sessions & history**
|
||||
- Use the relay’s own session store (default `~/.clawdis/sessions/sessions.json` on the relay host). No SSH file reads from the mac app anymore.
|
||||
- When the page loads, it receives `initialMessages` from the server (either embedded in `info` or via a history endpoint).
|
||||
- Remote mode automatically shows the remote session because the remote relay owns that store.
|
||||
## Dev notes
|
||||
- Static assets stay in `apps/macos/Sources/Clawdis/Resources/WebChat`; the server reads them directly.
|
||||
- Server code: `src/webchat/server.ts`.
|
||||
- CLI entrypoint: `clawdis webchat --json [--port N]`.
|
||||
- Mac glue: `WebChatWindow.swift` (bootstrap + tunnel) and `WebChatTunnel` (SSH -L).
|
||||
|
||||
4) **Mac app embedding**
|
||||
- On WebChatWindow init, the mac app calls `/webchat/info`:
|
||||
- Local mode: directly over loopback (127.0.0.1:port chosen by relay).
|
||||
- Remote mode: establish/reuse an SSH tunnel forwarding the relay’s webchat port to a local ephemeral port, then call `/webchat/info` through the tunnel and load the returned `baseUrl`.
|
||||
- WKWebView loads `baseUrl` (e.g., `http://127.0.0.1:<forward>/webchat/`).
|
||||
- Web page sends messages to `/webchat/rpc` (same origin as the static assets), so no extra mac plumbing.
|
||||
|
||||
5) **Security**
|
||||
- Bind to loopback only. For extra hardening, issue a random short-lived token in `/webchat/info` and require it as a header/query on `/webchat/rpc` and history.
|
||||
- Remote mode relies on SSH port forwarding; no WAN exposure.
|
||||
|
||||
6) **Failure handling**
|
||||
- If `/webchat/info` fails, show an in-app error (“Web chat server unreachable”).
|
||||
- Log the chosen port/URL and tunnel target in mac logs for debugging.
|
||||
- History fetch failures fall back to an empty transcript but keep sending enabled.
|
||||
|
||||
7) **Migration steps**
|
||||
- Move WebChat bundle into the Node project (e.g., `src/webchat/dist`) and serve statically.
|
||||
- Add the loopback HTTP server and `/webchat` routes to the relay startup.
|
||||
- Expose `/webchat/info` (port + token + optional initialMessages).
|
||||
- Mac app: replace local asset load with the fetched `baseUrl`; use SSH tunnel in remote mode.
|
||||
- Remove mac-side JSONL scraping and `AgentRPC` usage for web chat; keep other agent uses intact.
|
||||
- Tests: webchat loads + sends in local and remote modes; tunnel discovery works; history returns non-empty when sessions exist.
|
||||
|
||||
8) **Current behavior (for reference, to be replaced)**
|
||||
- Mac app reads remote session files over SSH (`clawdis sessions --json`, then `cat` the `.jsonl`) and injects history; sends via `clawdis rpc` subprocess. This document tracks the plan to move both pieces into the relay server instead.
|
||||
|
||||
## Open questions
|
||||
- Fixed port vs random per run? (Random + info endpoint is safer.)
|
||||
- Token enforcement default on/off? (Recommended on when remote tunneling isn’t used.)
|
||||
- Should `/webchat/rpc` also expose typing/streaming? (Nice-to-have; not required for parity.)
|
||||
## TODO / nice-to-haves
|
||||
- Enforce token by default once mobile/remote auth flows are in place.
|
||||
- Stream responses instead of one-shot payloads.
|
||||
- Expose a readiness endpoint for health checks.
|
||||
|
||||
Reference in New Issue
Block a user