Initial commit: OpenClaw Skill Collection

6 custom skills (assign-task, dispatch-webhook, daily-briefing,
task-capture, qmd-brain, tts-voice) with technical documentation.
Compatible with Claude Code, OpenClaw, Codex CLI, and OpenCode.
This commit is contained in:
2026-03-13 10:58:30 +08:00
commit 4c966a3ad2
884 changed files with 140761 additions and 0 deletions

View File

@@ -0,0 +1,221 @@
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.openclaw.ai/llms.txt
> Use this file to discover all available pages before exploring further.
# Control UI
# Control UI (browser)
The Control UI is a small **Vite + Lit** single-page app served by the Gateway:
* default: `http://<host>:18789/`
* optional prefix: set `gateway.controlUi.basePath` (e.g. `/openclaw`)
It speaks **directly to the Gateway WebSocket** on the same port.
## Quick open (local)
If the Gateway is running on the same computer, open:
* [http://127.0.0.1:18789/](http://127.0.0.1:18789/) (or [http://localhost:18789/](http://localhost:18789/))
If the page fails to load, start the Gateway first: `openclaw gateway`.
Auth is supplied during the WebSocket handshake via:
* `connect.params.auth.token`
* `connect.params.auth.password`
The dashboard settings panel lets you store a token; passwords are not persisted.
The onboarding wizard generates a gateway token by default, so paste it here on first connect.
## Device pairing (first connection)
When you connect to the Control UI from a new browser or device, the Gateway
requires a **one-time pairing approval** — even if you're on the same Tailnet
with `gateway.auth.allowTailscale: true`. This is a security measure to prevent
unauthorized access.
**What you'll see:** "disconnected (1008): pairing required"
**To approve the device:**
```bash theme={null}
# List pending requests
openclaw devices list
# Approve by request ID
openclaw devices approve <requestId>
```
Once approved, the device is remembered and won't require re-approval unless
you revoke it with `openclaw devices revoke --device <id> --role <role>`. See
[Devices CLI](/cli/devices) for token rotation and revocation.
**Notes:**
* Local connections (`127.0.0.1`) are auto-approved.
* Remote connections (LAN, Tailnet, etc.) require explicit approval.
* Each browser profile generates a unique device ID, so switching browsers or
clearing browser data will require re-pairing.
## What it can do (today)
* Chat with the model via Gateway WS (`chat.history`, `chat.send`, `chat.abort`, `chat.inject`)
* Stream tool calls + live tool output cards in Chat (agent events)
* Channels: WhatsApp/Telegram/Discord/Slack + plugin channels (Mattermost, etc.) status + QR login + per-channel config (`channels.status`, `web.login.*`, `config.patch`)
* Instances: presence list + refresh (`system-presence`)
* Sessions: list + per-session thinking/verbose overrides (`sessions.list`, `sessions.patch`)
* Cron jobs: list/add/run/enable/disable + run history (`cron.*`)
* Skills: status, enable/disable, install, API key updates (`skills.*`)
* Nodes: list + caps (`node.list`)
* Exec approvals: edit gateway or node allowlists + ask policy for `exec host=gateway/node` (`exec.approvals.*`)
* Config: view/edit `~/.openclaw/openclaw.json` (`config.get`, `config.set`)
* Config: apply + restart with validation (`config.apply`) and wake the last active session
* Config writes include a base-hash guard to prevent clobbering concurrent edits
* Config schema + form rendering (`config.schema`, including plugin + channel schemas); Raw JSON editor remains available
* Debug: status/health/models snapshots + event log + manual RPC calls (`status`, `health`, `models.list`)
* Logs: live tail of gateway file logs with filter/export (`logs.tail`)
* Update: run a package/git update + restart (`update.run`) with a restart report
Cron jobs panel notes:
* For isolated jobs, delivery defaults to announce summary. You can switch to none if you want internal-only runs.
* Channel/target fields appear when announce is selected.
## Chat behavior
* `chat.send` is **non-blocking**: it acks immediately with `{ runId, status: "started" }` and the response streams via `chat` events.
* Re-sending with the same `idempotencyKey` returns `{ status: "in_flight" }` while running, and `{ status: "ok" }` after completion.
* `chat.inject` appends an assistant note to the session transcript and broadcasts a `chat` event for UI-only updates (no agent run, no channel delivery).
* Stop:
* Click **Stop** (calls `chat.abort`)
* Type `/stop` (or `stop|esc|abort|wait|exit|interrupt`) to abort out-of-band
* `chat.abort` supports `{ sessionKey }` (no `runId`) to abort all active runs for that session
## Tailnet access (recommended)
### Integrated Tailscale Serve (preferred)
Keep the Gateway on loopback and let Tailscale Serve proxy it with HTTPS:
```bash theme={null}
openclaw gateway --tailscale serve
```
Open:
* `https://<magicdns>/` (or your configured `gateway.controlUi.basePath`)
By default, Serve requests can authenticate via Tailscale identity headers
(`tailscale-user-login`) when `gateway.auth.allowTailscale` is `true`. OpenClaw
verifies the identity by resolving the `x-forwarded-for` address with
`tailscale whois` and matching it to the header, and only accepts these when the
request hits loopback with Tailscales `x-forwarded-*` headers. Set
`gateway.auth.allowTailscale: false` (or force `gateway.auth.mode: "password"`)
if you want to require a token/password even for Serve traffic.
### Bind to tailnet + token
```bash theme={null}
openclaw gateway --bind tailnet --token "$(openssl rand -hex 32)"
```
Then open:
* `http://<tailscale-ip>:18789/` (or your configured `gateway.controlUi.basePath`)
Paste the token into the UI settings (sent as `connect.params.auth.token`).
## Insecure HTTP
If you open the dashboard over plain HTTP (`http://<lan-ip>` or `http://<tailscale-ip>`),
the browser runs in a **non-secure context** and blocks WebCrypto. By default,
OpenClaw **blocks** Control UI connections without device identity.
**Recommended fix:** use HTTPS (Tailscale Serve) or open the UI locally:
* `https://<magicdns>/` (Serve)
* `http://127.0.0.1:18789/` (on the gateway host)
**Downgrade example (token-only over HTTP):**
```json5 theme={null}
{
gateway: {
controlUi: { allowInsecureAuth: true },
bind: "tailnet",
auth: { mode: "token", token: "replace-me" },
},
}
```
This disables device identity + pairing for the Control UI (even on HTTPS). Use
only if you trust the network.
See [Tailscale](/gateway/tailscale) for HTTPS setup guidance.
## Building the UI
The Gateway serves static files from `dist/control-ui`. Build them with:
```bash theme={null}
pnpm ui:build # auto-installs UI deps on first run
```
Optional absolute base (when you want fixed asset URLs):
```bash theme={null}
OPENCLAW_CONTROL_UI_BASE_PATH=/openclaw/ pnpm ui:build
```
For local development (separate dev server):
```bash theme={null}
pnpm ui:dev # auto-installs UI deps on first run
```
Then point the UI at your Gateway WS URL (e.g. `ws://127.0.0.1:18789`).
## Debugging/testing: dev server + remote Gateway
The Control UI is static files; the WebSocket target is configurable and can be
different from the HTTP origin. This is handy when you want the Vite dev server
locally but the Gateway runs elsewhere.
1. Start the UI dev server: `pnpm ui:dev`
2. Open a URL like:
```text theme={null}
http://localhost:5173/?gatewayUrl=ws://<gateway-host>:18789
```
Optional one-time auth (if needed):
```text theme={null}
http://localhost:5173/?gatewayUrl=wss://<gateway-host>:18789&token=<gateway-token>
```
Notes:
* `gatewayUrl` is stored in localStorage after load and removed from the URL.
* `token` is stored in localStorage; `password` is kept in memory only.
* When `gatewayUrl` is set, the UI does not fall back to config or environment credentials.
Provide `token` (or `password`) explicitly. Missing explicit credentials is an error.
* Use `wss://` when the Gateway is behind TLS (Tailscale Serve, HTTPS proxy, etc.).
* `gatewayUrl` is only accepted in a top-level window (not embedded) to prevent clickjacking.
* For cross-origin dev setups (e.g. `pnpm ui:dev` to a remote Gateway), add the UI
origin to `gateway.controlUi.allowedOrigins`.
Example:
```json5 theme={null}
{
gateway: {
controlUi: {
allowedOrigins: ["http://localhost:5173"],
},
},
}
```
Remote access setup details: [Remote access](/gateway/remote).

View File

@@ -0,0 +1,45 @@
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.openclaw.ai/llms.txt
> Use this file to discover all available pages before exploring further.
# Dashboard
# Dashboard (Control UI)
The Gateway dashboard is the browser Control UI served at `/` by default
(override with `gateway.controlUi.basePath`).
Quick open (local Gateway):
* [http://127.0.0.1:18789/](http://127.0.0.1:18789/) (or [http://localhost:18789/](http://localhost:18789/))
Key references:
* [Control UI](/web/control-ui) for usage and UI capabilities.
* [Tailscale](/gateway/tailscale) for Serve/Funnel automation.
* [Web surfaces](/web) for bind modes and security notes.
Authentication is enforced at the WebSocket handshake via `connect.params.auth`
(token or password). See `gateway.auth` in [Gateway configuration](/gateway/configuration).
Security note: the Control UI is an **admin surface** (chat, config, exec approvals).
Do not expose it publicly. The UI stores the token in `localStorage` after first load.
Prefer localhost, Tailscale Serve, or an SSH tunnel.
## Fast path (recommended)
* After onboarding, the CLI auto-opens the dashboard and prints a clean (non-tokenized) link.
* Re-open anytime: `openclaw dashboard` (copies link, opens browser if possible, shows SSH hint if headless).
* If the UI prompts for auth, paste the token from `gateway.auth.token` (or `OPENCLAW_GATEWAY_TOKEN`) into Control UI settings.
## Token basics (local vs remote)
* **Localhost**: open `http://127.0.0.1:18789/`.
* **Token source**: `gateway.auth.token` (or `OPENCLAW_GATEWAY_TOKEN`); the UI stores a copy in localStorage after you connect.
* **Not localhost**: use Tailscale Serve (tokenless if `gateway.auth.allowTailscale: true`), tailnet bind with a token, or an SSH tunnel. See [Web surfaces](/web).
## If you see “unauthorized” / 1008
* Ensure the gateway is reachable (local: `openclaw status`; remote: SSH tunnel `ssh -N -L 18789:127.0.0.1:18789 user@host` then open `http://127.0.0.1:18789/`).
* Retrieve the token from the gateway host: `openclaw config get gateway.auth.token` (or generate one: `openclaw doctor --generate-gateway-token`).
* In the dashboard settings, paste the token into the auth field, then connect.

View File

@@ -0,0 +1,114 @@
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.openclaw.ai/llms.txt
> Use this file to discover all available pages before exploring further.
# Web
# Web (Gateway)
The Gateway serves a small **browser Control UI** (Vite + Lit) from the same port as the Gateway WebSocket:
* default: `http://<host>:18789/`
* optional prefix: set `gateway.controlUi.basePath` (e.g. `/openclaw`)
Capabilities live in [Control UI](/web/control-ui).
This page focuses on bind modes, security, and web-facing surfaces.
## Webhooks
When `hooks.enabled=true`, the Gateway also exposes a small webhook endpoint on the same HTTP server.
See [Gateway configuration](/gateway/configuration) → `hooks` for auth + payloads.
## Config (default-on)
The Control UI is **enabled by default** when assets are present (`dist/control-ui`).
You can control it via config:
```json5 theme={null}
{
gateway: {
controlUi: { enabled: true, basePath: "/openclaw" }, // basePath optional
},
}
```
## Tailscale access
### Integrated Serve (recommended)
Keep the Gateway on loopback and let Tailscale Serve proxy it:
```json5 theme={null}
{
gateway: {
bind: "loopback",
tailscale: { mode: "serve" },
},
}
```
Then start the gateway:
```bash theme={null}
openclaw gateway
```
Open:
* `https://<magicdns>/` (or your configured `gateway.controlUi.basePath`)
### Tailnet bind + token
```json5 theme={null}
{
gateway: {
bind: "tailnet",
controlUi: { enabled: true },
auth: { mode: "token", token: "your-token" },
},
}
```
Then start the gateway (token required for non-loopback binds):
```bash theme={null}
openclaw gateway
```
Open:
* `http://<tailscale-ip>:18789/` (or your configured `gateway.controlUi.basePath`)
### Public internet (Funnel)
```json5 theme={null}
{
gateway: {
bind: "loopback",
tailscale: { mode: "funnel" },
auth: { mode: "password" }, // or OPENCLAW_GATEWAY_PASSWORD
},
}
```
## Security notes
* Gateway auth is required by default (token/password or Tailscale identity headers).
* Non-loopback binds still **require** a shared token/password (`gateway.auth` or env).
* The wizard generates a gateway token by default (even on loopback).
* The UI sends `connect.params.auth.token` or `connect.params.auth.password`.
* The Control UI sends anti-clickjacking headers and only accepts same-origin browser
websocket connections unless `gateway.controlUi.allowedOrigins` is set.
* With Serve, Tailscale identity headers can satisfy auth when
`gateway.auth.allowTailscale` is `true` (no token/password required). Set
`gateway.auth.allowTailscale: false` to require explicit credentials. See
[Tailscale](/gateway/tailscale) and [Security](/gateway/security).
* `gateway.tailscale.mode: "funnel"` requires `gateway.auth.mode: "password"` (shared password).
## Building the UI
The Gateway serves static files from `dist/control-ui`. Build them with:
```bash theme={null}
pnpm ui:build # auto-installs UI deps on first run
```

View File

@@ -0,0 +1,48 @@
> ## Documentation Index
> Fetch the complete documentation index at: https://docs.openclaw.ai/llms.txt
> Use this file to discover all available pages before exploring further.
# WebChat
# WebChat (Gateway WebSocket UI)
Status: the macOS/iOS SwiftUI chat UI talks directly to the Gateway WebSocket.
## What it is
* A native chat UI for the gateway (no embedded browser and no local static server).
* Uses the same sessions and routing rules as other channels.
* Deterministic routing: replies always go back to WebChat.
## Quick start
1. Start the gateway.
2. Open the WebChat UI (macOS/iOS app) or the Control UI chat tab.
3. Ensure gateway auth is configured (required by default, even on loopback).
## How it works (behavior)
* The UI connects to the Gateway WebSocket and uses `chat.history`, `chat.send`, and `chat.inject`.
* `chat.inject` appends an assistant note directly to the transcript and broadcasts it to the UI (no agent run).
* History is always fetched from the gateway (no local file watching).
* If the gateway is unreachable, WebChat is read-only.
## Remote use
* Remote mode tunnels the gateway WebSocket over SSH/Tailscale.
* You do not need to run a separate WebChat server.
## Configuration reference (WebChat)
Full configuration: [Configuration](/gateway/configuration)
Channel options:
* No dedicated `webchat.*` block. WebChat uses the gateway endpoint + auth settings below.
Related global options:
* `gateway.port`, `gateway.bind`: WebSocket host/port.
* `gateway.auth.mode`, `gateway.auth.token`, `gateway.auth.password`: WebSocket auth.
* `gateway.remote.url`, `gateway.remote.token`, `gateway.remote.password`: remote gateway target.
* `session.*`: session storage and main key defaults.