Skip to content
Back to skills

Clawtime Setup

DSecurity

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, configure the tunnel, register a passkey, set up TTS, start/stop the server, or diagnose errors. Triggered by requests like "install clawtime", "set up clawtime", "start clawtime", "clawtime isn't working"...

  • 14 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 7, 2026
securitypythongoshellbashnodegitsecurity

Works with

  • cli

Security analysis

D42/100
  • criticalAccesses system keychains or credential stores
  • criticalModifies startup scripts or system services for persistence
  • criticalSends environment variables or credentials to an external URL
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 5 files and shows the line behind each finding

Scanned September 7, 2026

npx -y skills add modbender/skill-library-mcp --skill clawtime-setup --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Clawtime Setup?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Clawtime Setup
[![Security: D — Skills Directory](https://www.skillsdirectory.com/api/skills/modbender-clawtime-setup/badge)](https://www.skillsdirectory.com/skills/modbender-clawtime-setup)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: clawtime
description: >
  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, configure the tunnel, register a passkey, set up TTS, start/stop the server, or
  diagnose errors. Triggered by requests like "install clawtime", "set up clawtime",
  "start clawtime", "clawtime isn't working", "register passkey", "device auth issue".
metadata:
  openclaw:
    requires:
      bins:
        - node
        - git
        - cloudflared
        - npm
      optionalBins:
        - python3
        - ffmpeg
        - piper
    env:
      - PUBLIC_URL
      - GATEWAY_TOKEN
      - SETUP_TOKEN
    files:
      - scripts/install.sh
      - references/device-auth.md
      - references/troubleshooting.md
      - references/launchd.md
    permissions:
      - network (Cloudflare tunnel, git clone, npm install)
      - keychain (store/retrieve GATEWAY_TOKEN and SETUP_TOKEN)
      - filesystem (~/Projects/clawtime, ~/.clawtime, ~/.cloudflared, ~/Library/LaunchAgents)
---

# 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

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

### 2. Set up Cloudflare Tunnel

```bash
# Login to Cloudflare
cloudflared tunnel login

# Create named tunnel
cloudflared tunnel create clawtime

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

**~/.cloudflared/config.yml:**
```yaml
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:

```bash
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):
```bash
cd ~/Projects/clawtime
PUBLIC_URL=https://portal.yourdomain.com \
SETUP_TOKEN=<your-setup-token> \
GATEWAY_TOKEN=<gateway-token> \
node server.js
```

With Piper TTS:
```bash
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

```bash
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) |

### Storing Tokens Securely (recommended)

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

```bash
# 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:

```bash
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

```bash
# 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

```bash
# 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

```bash
# 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.

Files in this skill

  • SKILL.md7.7 KB
  • references/device-auth.md3.3 KB
  • references/launchd.md4.4 KB
  • references/troubleshooting.md3.3 KB
  • scripts/install.sh10.9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…