coderClaw

Control UI (browser)

The Control UI is a small Vite + Lit single-page app served by the Gateway:

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: coderclaw gateway.

Auth is supplied during the WebSocket handshake via:

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:

# List pending requests
coderclaw devices list

# Approve by request ID
coderclaw devices approve <requestId>

Once approved, the device is remembered and won’t require re-approval unless you revoke it with coderclaw devices revoke --device <id> --role <role>. See Devices CLI for token rotation and revocation.

Notes:

What it can do (today)

Cron jobs panel notes:

Chat behavior

Integrated Tailscale Serve (preferred)

Keep the Gateway on loopback and let Tailscale Serve proxy it with HTTPS:

coderclaw gateway --tailscale serve

Open:

By default, Serve requests can authenticate via Tailscale identity headers (tailscale-user-login) when gateway.auth.allowTailscale is true. CoderClaw 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 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

coderclaw gateway --bind tailnet --token "$(openssl rand -hex 32)"

Then open:

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, CoderClaw blocks Control UI connections without device identity.

Recommended fix: use HTTPS (Tailscale Serve) or open the UI locally:

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):

CODERCLAW_CONTROL_UI_BASE_PATH=/coderclaw/ 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.

  1. Start the UI dev server: pnpm ui:dev
  2. 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:

Example:

{
  gateway: {
    controlUi: {
      allowedOrigins: ["http://localhost:5173"],
    },
  },
}

Remote access setup details: Remote access.