Skills clawtime

install
source · Clone the upstream repo
git clone https://github.com/openclaw/skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/bewareofddog/clawtime-setup" ~/.claude/skills/clawdbot-skills-clawtime && rm -rf "$T"
manifest: skills/bewareofddog/clawtime-setup/SKILL.md
source content

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, use 
child_process.execFile()
with argument arrays instead of
child_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

VariableRequiredDescription
PUBLIC_URL
Public HTTPS URL (must match
allowedOrigins
in gateway config)
GATEWAY_TOKEN
OpenClaw gateway auth token
SETUP_TOKEN
For registrationPassphrase for
?setup=<token>
passkey registration URL
TTS_COMMAND
For voicePiper command with
{{TEXT}}
and
{{OUTPUT}}
placeholders
BOT_NAME
NoDisplay name (default: "Beware")
BOT_EMOJI
NoAvatar emoji (default: "🌀")
PORT
NoServer port (default: 3000)

Storing Tokens Securely (recommended)

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.