- Move screenshot to standard docs/images location - Update control-ui.md to reference correct image path - Improve screenshot script with better click fallbacks - Remove duplicate screenshot from docs/gateway/images Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
7.2 KiB
| summary | read_when | ||
|---|---|---|---|
| Browser-based control UI for the Gateway (chat, nodes, config) |
|
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./clawdbot)
It speaks directly to the Gateway WebSocket on the same port.
Quick open (local)
If the Gateway is running on the same computer, open:
If the page fails to load, start the Gateway first: clawdbot gateway.
Auth is supplied during the WebSocket handshake via:
connect.params.auth.tokenconnect.params.auth.passwordThe 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.
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
~/.clawdbot/clawdbot.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 - Analytics: token usage stats, cost estimates, and plan quota display (
usage.cost,usage.status)
Analytics
The Analytics tab provides visibility into your token usage and costs:
Plan Quota
Shows your current usage against plan limits (for providers that expose quota data):
- Usage bars: Visual progress bars for each rate limit window (5-hour, weekly, model-specific)
- Reset timers: Time remaining until each limit resets
- Provider support: Currently supports Anthropic API keys with quota access
For Claude Code OAuth tokens (which use the user:inference scope only), plan quota is not available programmatically. The UI displays a link to claude.ai/settings/usage where you can check your usage directly.
Usage Summary
Aggregates token consumption from your session transcripts:
- Summary cards: Total tokens, input/output breakdown, cache read/write, estimated cost
- Daily charts: Bar charts showing token usage and cost over time
- Time periods: Select 7, 14, 30, or 90 day views
- Refresh: Click to reload data from the gateway
Cost estimates are based on published model pricing and may not reflect actual billing (discounts, commitments, etc.).
Chat behavior
chat.sendis non-blocking: it acks immediately with{ runId, status: "started" }and the response streams viachatevents.- Re-sending with the same
idempotencyKeyreturns{ status: "in_flight" }while running, and{ status: "ok" }after completion. chat.injectappends an assistant note to the session transcript and broadcasts achatevent for UI-only updates (no agent run, no channel delivery).- Stop:
- Click Stop (calls
chat.abort) - Type
/stop(orstop|esc|abort|wait|exit|interrupt) to abort out-of-band chat.abortsupports{ sessionKey }(norunId) to abort all active runs for that session
- Click Stop (calls
Tailnet access (recommended)
Integrated Tailscale Serve (preferred)
Keep the Gateway on loopback and let Tailscale Serve proxy it with HTTPS:
clawdbot gateway --tailscale serve
Open:
https://<magicdns>/(or your configuredgateway.controlUi.basePath)
By default, Serve requests can authenticate via Tailscale identity headers
(tailscale-user-login) when gateway.auth.allowTailscale is true. Clawdbot
only accepts these when the request hits loopback with Tailscale’s
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
clawdbot gateway --bind tailnet --token "$(openssl rand -hex 32)"
Then open:
http://<tailscale-ip>:18789/(or your configuredgateway.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,
Clawdbot 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):
{
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 for HTTPS setup guidance.
Building the UI
The Gateway serves static files from dist/control-ui. Build them with:
pnpm ui:build # auto-installs UI deps on first run
Optional absolute base (when you want fixed asset URLs):
CLAWDBOT_CONTROL_UI_BASE_PATH=/clawdbot/ pnpm ui:build
For local development (separate dev server):
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.
- Start the UI dev server:
pnpm ui:dev - Open a URL like:
http://localhost:5173/?gatewayUrl=ws://<gateway-host>:18789
Optional one-time auth (if needed):
http://localhost:5173/?gatewayUrl=wss://<gateway-host>:18789&token=<gateway-token>
Notes:
gatewayUrlis stored in localStorage after load and removed from the URL.tokenis stored in localStorage;passwordis kept in memory only.- Use
wss://when the Gateway is behind TLS (Tailscale Serve, HTTPS proxy, etc.).
Remote access setup details: Remote access.
