SkillHub

clawtime-setup

v1.2.0

Install, configure, start, and troubleshoot ClawTime — a private self-hosted webchat UI for OpenClaw with passkey (Face ID) auth, Piper TTS voice, and 3D avatar. Requires Cloudflare tunnel for HTTPS (passkeys need a real domain). Use when the user wants to install ClawTime on a new machine, configur...

Sourced from ClawHub, Authored by bewareofddog

Installation

Please help me install the skill `clawtime-setup` from SkillHub official store. npx skills add bewareofddog/clawtime-setup

ClawTime — Local Installation with Cloudflare Tunnel

ClawTime is a private webchat UI connecting to the OpenClaw gateway via WebSocket. Features: passkey (Face ID/Touch ID) auth, Piper TTS voice, 3D avatar.

Why Cloudflare is required: WebAuthn (passkeys) need HTTPS on a real domain. http://localhost only works on the same machine — not from a phone on your network.

Architecture

iPhone/Browser → https://portal.yourdomain.com → Cloudflare Tunnel → localhost:3000 (ClawTime) → ws://127.0.0.1:18789 (OpenClaw Gateway)

Prerequisites

  • Node.js v22+
  • cloudflared CLI: brew install cloudflared
  • A domain with DNS on Cloudflare (free tier works)
  • OpenClaw running: openclaw status
  • (Optional) Piper TTS + ffmpeg for voice

Installation Steps

1. Clone & install

cd ~/Projects
git clone https://github.com/youngkent/clawtime.git
cd clawtime
npm install --legacy-peer-deps

2. Set up Cloudflare Tunnel

# Login to Cloudflare
cloudflared tunnel login

# Create named tunnel
cloudflared tunnel create clawtime

# Configure routing
# Edit ~/.cloudflared/config.yml:

~/.cloudflared/config.yml:

tunnel: clawtime
credentials-file: /Users/YOUR_USER/.cloudflared/<tunnel-id>.json

ingress:
  - hostname: portal.yourdomain.com
    service: http://localhost:3000
  - service: http_status:404

Then in Cloudflare DNS dashboard: add a CNAME record: - Name: portal → Target: <tunnel-id>.cfargotunnel.com (Proxied ✅)

3. Configure OpenClaw gateway

The gateway must whitelist ClawTime's origin:

openclaw config patch '{"gateway":{"controlUi":{"allowedOrigins":["https://portal.yourdomain.com"]}}}'
openclaw gateway restart

⚠️ PUBLIC_URL must match this origin exactly — it's used as the WebSocket origin header for device auth.

4. Start ClawTime server

Minimum (no TTS):

cd ~/Projects/clawtime
PUBLIC_URL=https://portal.yourdomain.com 
SETUP_TOKEN=<your-setup-token> 
GATEWAY_TOKEN=<gateway-token> 
node server.js

With Piper TTS:

cd ~/Projects/clawtime
PUBLIC_URL=https://portal.yourdomain.com 
SETUP_TOKEN=<your-setup-token> 
GATEWAY_TOKEN=<gateway-token> 
BOT_NAME="Beware" 
BOT_EMOJI="🌀" 
TTS_COMMAND='python3 -m piper --data-dir ~/Documents/resources/piper-voices -m en_US-kusal-medium -f /tmp/clawtime-tts-tmp.wav -- {{TEXT}} && ffmpeg -y -loglevel error -i /tmp/clawtime-tts-tmp.wav {{OUTPUT}}' 
node server.js

⚠️ TTS Security Note: The {{TEXT}} placeholder is substituted into a shell command. ClawTime's server must sanitize text before substitution to prevent command injection. The server should strip or escape shell metacharacters (; | & $ ( ) { } < >) from user input before passing it to the TTS command. If you're modifying the TTS pipeline, usechild_process.execFile()with argument arrays instead ofchild_process.exec()` with string interpolation.

5. Start Cloudflare tunnel

cloudflared tunnel run clawtime

6. Register passkey (first time only)

  1. Open https://portal.yourdomain.com/?setup=<your-setup-token> in Safari
  2. Follow the passkey (Face ID / Touch ID) prompt
  3. ❌ Do NOT use private/incognito mode — Safari blocks passkeys there
  4. ❌ Do NOT use Chrome on iOS — use Safari

After registration, access ClawTime at https://portal.yourdomain.com.


Environment Variables

Variable Required Description
PUBLIC_URL Public HTTPS URL (must match allowedOrigins in gateway config)
GATEWAY_TOKEN OpenClaw gateway auth token
SETUP_TOKEN For registration Passphrase for ?setup=<token> passkey registration URL
TTS_COMMAND For voice Piper command with {{TEXT}} and {{OUTPUT}} placeholders
BOT_NAME No Display name (default: "Beware")
BOT_EMOJI No Avatar emoji (default: "🌀")
PORT No Server port (default: 3000)

Instead of passing tokens as plaintext env vars or in plist files, store them in macOS Keychain:

# Store tokens in Keychain
security add-generic-password -s "clawtime-gateway-token" -a "$(whoami)" -w "YOUR_GATEWAY_TOKEN"
security add-generic-password -s "clawtime-setup-token" -a "$(whoami)" -w "YOUR_SETUP_TOKEN"

Then retrieve them at launch time:

GATEWAY_TOKEN=$(security find-generic-password -s "clawtime-gateway-token" -a "$(whoami)" -w) 
SETUP_TOKEN=$(security find-generic-password -s "clawtime-setup-token" -a "$(whoami)" -w) 
PUBLIC_URL=https://portal.yourdomain.com 
node server.js

This avoids storing secrets in plaintext on disk.


Device Authentication (Critical)

ClawTime authenticates with the OpenClaw gateway using Ed25519 keypair auth. This is where most installs break — see details in references/device-auth.md.

Quick summary: - Keypair auto-generated in ~/.clawtime/device-key.json on first run - Device ID = SHA-256 of raw 32-byte Ed25519 pubkey (NOT the full SPKI-encoded key) - Signature payload format: v2|deviceId|clientId|clientMode|role|scopes|signedAtMs|token|nonce - If device auth fails → delete ~/.clawtime/device-key.json and restart


Auto-Start on Boot (macOS launchd)

See references/launchd.md for plist templates for both the server and tunnel.


Managing Services

# Stop server
pkill -f "node server.js"

# Stop tunnel
pkill -f "cloudflared"

# View logs (if backgrounded)
tail -f /tmp/clawtime.log
tail -f /tmp/cloudflared.log

# Restart after code/config changes
pkill -9 -f "node server.js"; sleep 2; # then re-run start command

Getting the Gateway Token

# From macOS Keychain
security find-generic-password -s "openclaw-gateway-token" -a "$(whoami)" -w

# From config file
cat ~/.openclaw/openclaw.json | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('gateway',{}).get('token',''))"

Passkey Operations

# Reset passkeys (re-register from scratch)
echo '[]' > ~/.clawtime/credentials.json
# Restart server, then visit /?setup=<token>

# Reset device key (new keypair on next restart)
rm ~/.clawtime/device-key.json

Troubleshooting

See references/troubleshooting.md for all common errors and fixes. See references/device-auth.md for deep-dive on gateway auth issues.