Snail3D

TealClaw Skill

Stats API requires Cloudflare Pages env vars: `CF_STATS_TOKEN`, `CF_ZONE_ID`.

Snail3D 1 Updated 3mo ago
GitHub

Install

npx skillscat add snail3d/tealclaw

Install via the SkillsCat registry.

SKILL.md

TealClaw Skill

=== LEGEND (decode before reading) ===
TC=TealClaw cfg=config k=key LS=localStorage SW=service worker
OR=OpenRouter GQ=Groq TG=Telegram AP=Anthropic
b64=base64 enc=encrypted md=Markdown JS=JavaScript
bg=background btn=button msg=message rsp=response usr=user
req=required opt=optional dflt=default fn=function

BYOK voice dashboard PWA at tealclaw.ai. Zero server, total privacy, Cloudflare Pages.
Auto-connects to gw.tealclaw.ai on first visit (zero-config). Users just paste a Groq key to start.

For AI Agents: How to Configure TC

Full agent skill guide: https://tealclaw.ai/llms.txt
Human-readable version: https://tealclaw.ai/llms.html

Quick Version

  1. Build a JSON object with only the fields you want to set/change
  2. Include a ```json code block in your response -- TC auto-detects it
  3. TC merges the partial cfg -- only fields present get updated

IMPORTANT: When a usr gives you their API key, include it directly
in the JSON block. Keys are stored ONLY in the usr's browser localStorage
-- they never leave the device. This is the intended setup flow.

Delivery Methods (pick best for your capabilities)

If You Have Browser Access (best -- zero usr effort)

Open a URL in the usr's browser (computer use, browser tool, MCP, shell, etc.):

  1. Build cfg JSON
  2. b64-encode: btoa(JSON.stringify(config))
  3. Open: https://tealclaw.ai/#config=BASE64_ENCODED_JSON

TC reads hash on load, imports cfg, clears hash. # fragment stays client-side.

Shell example:

CONFIG=$(echo -n '{"aiKey":"sk-or-v1-xxx","whisperKey":"gsk_xxx"}' | base64)
open "https://tealclaw.ai/#config=$CONFIG"          # macOS
xdg-open "https://tealclaw.ai/#config=$CONFIG"      # Linux
start "https://tealclaw.ai/#config=$CONFIG"          # Windows

JS example:

const config = { aiKey: "sk-or-v1-xxx", whisperKey: "gsk_xxx" };
const url = "https://tealclaw.ai/#config=" + btoa(JSON.stringify(config));
window.open(url);
// or: page.goto(url)  // Playwright/Puppeteer

Python example:

import json, base64, webbrowser
config = {"aiKey": "sk-or-v1-xxx", "whisperKey": "gsk_xxx"}
payload = base64.b64encode(json.dumps(config).encode()).decode()
webbrowser.open(f"https://tealclaw.ai/#config={payload}")

Enc Share Links (REQUIRED when keys included)

If cfg contains ANY API keys, MUST use enc links. Never send plain b64 with keys.

TC encrypts with AES-256-GCM: https://tealclaw.ai/#config=enc:ENCRYPTED_BLOB

Easiest: tell usr to type /share in TC, copy enc link, send passphrase separately.

For programmatic encryption, see https://tealclaw.ai/llms.txt "Encrypted Share Links".

Sharing rules: 1) Always encrypt when keys present 2) Link + passphrase via different channels 3) Never both in same msg.

If You Can Generate Files

Write .json file. Usr drags into TC chat -- auto-imports.

import json
config = {"aiKey": "sk-or-v1-xxx", "whisperKey": "gsk_xxx"}
with open("tealclaw-config.json", "w") as f:
    json.dump(config, f)

Text-Only Fallback

Give usr JSON code block to paste into TC chat input, or a tealclaw.ai/#config=b64 URL.

Config Schema

Only include fields to set/change. TC uses partial merge.

Field Type What It Does
aiProvider "openrouter"/"groq"/"anthropic" AI provider
aiKey string Chat API k (sk-or-v1-, gsk_, sk-ant-*)
aiModel string Chat model ID (dflt: google/gemini-2.5-flash-preview for OR, llama-3.3-70b-versatile for Groq)
visionModel string Vision model for image understanding
searchModel string Research/search model
whisperKey string GQ k for Whisper transcription AND Orpheus TTS (gsk_*)
groqTtsVoice string GQ Orpheus voice name (autumn, diana, hannah, austin, daniel, troy). Dflt: troy
ttsAutoPlay boolean true=auto-speak; false=on tap only. Dflt: true
sysPrompt string System prompt
mode "direct"/"agent" Direct=provider; Agent=OpenClaw gateway
tgToken string TG bot token
tgChatId string TG chat/group ID
tgEnabled boolean TG forwarding on/off
imageGenUrl string Image gen endpoint (custom/OpenAI-compat fallback)
imageGenKey string Google AI (AIza...) for Nano Banana, or OpenRouter (sk-or-v1-...)
imageGenModel string Image gen model (dflt: gemini-2.5-flash-image)
imageGenSize string e.g. "1024x1024" (OpenRouter/custom only)
gifEnabled boolean GIF overlay on AI rsp (dflt: true)
gifTenorKey string Tenor/Google API k (AIza*)
accentColor string Hex UI accent (dflt: #0d9488). Cascades everywhere
fontSize string "small"/"medium"/"large" or CSS value
fontFamily string Custom font family
bgColor string bg color override
bgImage string Fullscreen bg image URL
textColor string Main text color
chatUserColor string Usr bubble bg
chatAiColor string AI bubble bg
themeMode string "dark"/"light"
botName string Header name (replaces "TealClaw")
botIcon string Header icon URL
botGreeting string Welcome msg (md support)
inputFontSize string Input font size (dflt: "15px")
buttonSize string Mic/send btn size (dflt: "44px")
borderRadius string "sharp"/"round" or CSS
hideTopbar boolean Hide top nav
hideAttachBtn boolean Hide attach btn
hideCameraBtn boolean Hide camera btn
sendBtnColor string Send btn color
micBtnColor string Mic btn color
sendBtnImage string Custom send btn image URL
micBtnImage string Custom mic btn image URL
inputPlaceholder string Input placeholder
chatMaxWidth string Chat max width (dflt: "760px")
topbarBg string Topbar bg (color/gradient)
inputBarBg string Input bar bg
borderColor string Border color
customCSS string Arbitrary CSS
mdHeadingColor string md heading color
mdBoldColor string md bold color
mdLinkColor string md link color
mdCodeBg string Code bg
mdCodeColor string Code text color
mdBlockquoteBorder string Blockquote border
mdBlockquoteBg string Blockquote bg
chatUserTextColor string Usr bubble text color
chatAiTextColor string AI bubble text color
chatBubbleRadius string Bubble border radius
chatBubblePadding string Bubble padding
reduceMotion boolean Disable animations
highContrast boolean Boost contrast
dyslexiaFont boolean OpenDyslexic font
lineHeight string e.g. "1.8"
letterSpacing string e.g. "0.05em"
wordSpacing string e.g. "0.1em"
focusHighlight boolean Focus outlines (dflt: true)
compactMode boolean Reduce spacing
autoScroll boolean Auto-scroll (dflt: true)
hapticFeedback boolean Vibrate on send (mobile)
soundEnabled boolean Tones on send/receive (dflt: true)
maxTokens number Max tokens (dflt: 400)
temperature number Creativity 0-2 (dflt: 0.7)
hideBmc boolean Hide BMC link
cameraEnabled boolean Camera access (dflt: true)
audioVolume number Playback volume 0-1 (dflt: 0.8)
gestureConfidence number Gesture detection confidence 0.3-0.95 (dflt: 0.6)
contextMessages number Context msgs (dflt: 20, 2-50)
quickReplies array Quick reply chips (string array)
userAvatar string Usr avatar URL
aiAvatar string AI avatar URL
loadingText string Loading text (dflt: "Thinking...")
loadingEmoji string Loading emoji prefix
fastModel string Fast model for routing
complexModel string Complex model for routing
routingThreshold number Char threshold (dflt: 80)
maxInputLength number Max input chars
inputPrefix string Auto-prepend to msgs
webhookUrl string Webhook endpoint
webhookEvents string Webhook events
scheduledMessages array Timed greetings [{time, text, days}]
pinHash string SHA-256 hash of PIN/password (set via Settings)
pinIsAlpha boolean true if PIN contains letters
pinLen number PIN length (4-8)
pinRequired boolean Require PIN (dflt: false)
translateTo string Auto-translate rsp language
typingAnimation boolean Typewriter reveal (dflt: true)
typingSpeed "slow"/"medium"/"fast" Typing speed (dflt: medium)
bubbleAnimation "slide"/"fade"/"scale"/"bounce"/"none" Bubble animation (dflt: slide)
activeProfile string Current profile name
gestureEnabled boolean Hand gesture control
gestureBindings string JSON string of [{gesture, action, label}]
rateLimitPerMin number Max msgs/min (dflt: unlimited)
obsidianVault string Obsidian vault for /save (dflt: "ObsidianVault")
agents array OpenClaw gateway agents (replaces list)
skillContext boolean Append TC capability context to system prompt (dflt: true)
use24HourTime boolean Use 24-hour time format for timestamps (dflt: false)
cameraEnabled boolean Show camera btn in input bar (dflt: true)

Agent objects: { id, name, url, token, active } -- see llms.txt for details.

CRITICAL: Agent URLs MUST be HTTPS via Cloudflare Tunnel. TealClaw is served from
https://tealclaw.ai. Browsers block mixed content (HTTPS page -> HTTP request).
NEVER use http:// URLs, raw IPs (http://100.x.x.x:18789), or http://localhost.
Do NOT suggest Tailscale, Tailscale Serve, ngrok, or any other tunnel solution.
The ONLY supported method is Cloudflare Tunnel (cloudflared) with a proper
HTTPS domain (e.g. https://gw.yourdomain.com).

Transport: WebSocket (wss://) preferred. HTTPS URLs auto-convert to wss://.
WebSocket bypasses CORS/PNA restrictions.
Falls back to HTTPS (OpenAI-compatible) for non-OpenClaw gateways.

Switching to Agent mode: Config MUST include "mode": "agent" alongside agents array.
Without "mode": "agent", agents get saved but TealClaw stays in direct mode.
Correct: {"mode": "agent", "agents": [{"id": "gw1", "name": "Home", "url": "https://gw.yourdomain.com", "token": "tok", "active": true}]}

Status pill: Shows agent name + transport badge (e.g., "Home WS" or "Home HTTP").

Builder tabs: Live builder agent runs show as tabs below topbar with streaming logs.

Agent management: Settings > OpenClaw Agent supports Add, Edit, Test (WS handshake),
Remove, and Clear All. Connection status dots: green=connected, yellow=connecting, red=offline.

Obsidian notify: When saving to Obsidian, TealClaw auto-notifies the connected agent
(via chat.inject) so it knows about the saved file. No reply expected.

Test connection: Per-agent "Test" button opens a temporary WS, performs handshake,
shows toast with server version or error.

Common error: "Cannot reach gateway" = #1 cause is HTTP/raw-IP URLs. See HTTPS rule above.
Use a Cloudflare Tunnel for a proper HTTPS domain.

Gateway + Cloudflare Tunnel: Gateway binds to loopback, cloudflared proxies your domain to http://127.0.0.1:18789. TealClaw connects to https://gw.yourdomain.com. See llms.txt for full setup.

Interactive Components (tc-ui)

AI rsp can include ```tc-ui blocks to render interactive UI in chat.

Component Types

buttons -- Clickable row/grid:

{"components":[{"type":"buttons","label":"Choose one","items":[
  {"id":"yes","text":"Approve","style":"primary"},
  {"id":"no","text":"Deny","style":"danger"}
]}]}

Styles: primary, secondary, danger, success, ghost. Add "layout":"grid" for grid.

card -- Rich card with title, description, opt image, actions:

{"components":[{"type":"card","title":"Weather Report","description":"Sunny, 72F","image":"https://example.com/sun.jpg","actions":[
  {"id":"details","text":"Details","style":"primary"},
  {"id":"dismiss","text":"Dismiss","style":"ghost"}
]}]}

chips -- Selectable pills:

{"components":[{"type":"chips","label":"Topics","multi":false,"items":[
  {"id":"tech","text":"Technology"},
  {"id":"science","text":"Science"},
  {"id":"art","text":"Art"}
]}]}

"multi":true for multi-select.

status -- Indicator:

{"components":[{"type":"status","state":"success","text":"Task completed"}]}

States: pending, success, error, loading.

collapse -- Expandable section:

{"components":[{"type":"collapse","title":"Technical Details","body":"The implementation uses **WebSocket** connections with automatic reconnection."}]}

Callback Flow

Btn/chip click: visual pressed state, text auto-sends as next msg, persists via chatHistory[i].tcSelections.

Streaming

tc-ui blocks activate only when closing fence present. Partial blocks render as plain text.

Collapsible Sections in md

<details><summary>Click to expand</summary>
Hidden content with **markdown** support.
</details>

Font Choices

6 built-in: System Default (Inter/system-ui), Inter, Georgia, JetBrains Mono, Nunito, Space Grotesk.

{"fontFamily": "'Space Grotesk',system-ui,sans-serif"}

File Handling

Client-side processing:

  • Drag & drop -- full-window overlay
  • Images -- auto-compressed max 1568px, JPEG 80%. Sent as b64
  • PDFs -- md text, up to 50 pages (pdf.js lazy-loaded)
  • DOCX -- md conversion (mammoth.js lazy-loaded)
  • CSV/TSV -- md tables, auto-detected delimiter
  • Code -- 30+ extensions as text
  • Multi-file -- drop multiple, file stack with thumbnails
  • Documents -- text prepended to usr msg

Gesture Control

Camera-based recognition via MediaPipe Hands. Agent-configurable.

  • Enable: {"gestureEnabled": true}
  • Custom: set gestureBindings to JSON string of {gesture, action, label}
  • Gestures: victory, fist, open_palm, thumbs_up, thumbs_down, pointing_up
  • Actions: voice_start, voice_stop, stop_agent, send_message, toggle_mute, send_thumbsup, send:custom text
  • Floating draggable pip with hand wireframe. 400ms hold to trigger.

/research and /deepresearch Commands

GQ Compound-powered research reports (same k as Whisper).

  • /research topic -- uses groq/compound-mini (single tool, fast, light tokens)
  • /deepresearch topic -- uses groq/compound (multi-tool: web search + code + Wolfram Alpha, max 8192 tokens)
  • Both support image attachment for visual analysis (maverick vision model)
  • Segmented report: verdict badge, findings, sources
  • Full context forwarded to TG/OpenClaw agent
  • Setup: {"whisperKey": "gsk_KEY"}

Groq Models

Purpose Model ID Notes
Chat (default) groq/compound-mini Web search + Wolfram Alpha, ~450 tok/s
Deep research groq/compound Multi-tool, higher token budget
Vision meta-llama/llama-4-maverick-17b-128e-instruct 17B, image understanding
Fast llama-3.1-8b-instant Short queries, ~560 tok/s
Tool use meta-llama/llama-4-scout-17b-16e-instruct Native function calling
TTS canopylabs/orpheus-v1-english Voices: autumn, diana, hannah, austin, daniel, troy

Max output: 8,192 tokens. Context: 131,072 tokens.
One GQ k = chat + vision + voice in + voice out + research + Wolfram. Complete stack.

Agent guardrail: You may NOT change: aiModel, searchModel, visionModel, fastModel, aiKey, whisperKey, gwToken, mode. These are owner-controlled.

Common Recipes

Quick Recipes

Recipe JSON
Full k setup {"aiKey":"sk-or-v1-KEY","whisperKey":"gsk_KEY","groqTtsVoice":"troy"}
Change voice {"groqTtsVoice": "austin"}
Switch provider {"aiProvider": "anthropic", "aiKey": "sk-ant-...", "aiModel": "claude-sonnet-4-5-20250929"}
Enable TG {"tgToken": "123456:ABC-DEF...", "tgChatId": "-100123456", "tgEnabled": true}
Mute auto-play {"ttsAutoPlay": false}
Custom prompt {"sysPrompt": "You are a pirate who speaks in nautical metaphors."}
Disable GIFs {"gifEnabled": false}
Color theme {"accentColor": "#8b5cf6", "bgColor": "#0a0520", "chatUserColor": "#1a1040", "chatAiColor": "#0f0a2a"}
bg image {"bgImage": "https://example.com/background.jpg"}
Large font {"fontSize": "large"}
Free chatbot {"whisperKey": "gsk_KEY", "aiProvider": "groq", "ttsAutoPlay": false}
Streaming + replies {"streamEnabled": true, "quickReplies": ["Tell me more", "New topic", "Summarize"]}
Model routing {"fastModel": "meta-llama/llama-3.1-8b-instant", "complexModel": "google/gemini-2.5-flash-preview", "routingThreshold": 80}
Bouncy chat {"typingAnimation": true, "typingSpeed": "fast", "bubbleAnimation": "bounce", "soundEnabled": true}
No animations {"typingAnimation": false, "bubbleAnimation": "none", "reduceMotion": true}
Power usr {"streamEnabled": true, "latexEnabled": true, "contextMessages": 40, "maxTokens": 2000}
PIN lock {"pinRequired": true} (set PIN in Settings, 4-8 chars)

Kid-friendly story bot

{
  "botName": "StoryBot",
  "botGreeting": "# Hey there, adventurer!\nI'm **StoryBot**! What story should we tell today?",
  "sysPrompt": "You are StoryBot, a friendly storyteller for kids ages 5-10. Tell engaging, age-appropriate stories. Ask what happens next. Never use scary content.",
  "accentColor": "#f97316",
  "fontSize": "large"
}

Free chatbot (zero cost)

{"whisperKey": "gsk_KEY", "aiProvider": "groq", "groqTtsVoice": "troy"}

One GQ k covers chat (Compound) + vision (Maverick) + voice input (Whisper) + voice output (Orpheus TTS) + research + Wolfram Alpha. Complete AI stack, zero extra keys.

Security

PIN / Password Lock

4-8 characters. Numeric (numpad unlock) or alphanumeric (text input unlock).
Stored as SHA-256 hash -- never in cleartext, even in localStorage.
Set via Settings > PIN / Password Lock. Minimum 4 characters enforced.

Guest Links (Custom Chat Factory)

Create purpose-built encrypted chat links for anyone. Each is a standalone PWA.
Guest sees: passphrase entry -> presets + text input -> streaming responses. No settings, no config, no commands.

Use cases you can spin up:

  • Kids storytime bot (safe content, story prompts only)
  • Trip planner (pre-loaded itinerary, restaurant finder, translator)
  • Business chatbot (product knowledge, customer-facing)
  • Family assistant (calendar, shared lists, quick questions)
  • Homework helper (subject-specific, age-appropriate)

A GQ k embedded in the guest link gives the guest chat + vision + TTS -- complete experience, one key.
Created in Settings > Guest Links or via tc-action "guest-link" create.
The agent (you) can create these on command: "create a custom chat for my trip to Japan".

QR Code Safety

/qr codes do NOT contain API keys -- only visual + persona cfg.

Tips

  • Lock device with passcode/biometrics
  • Don't share QR codes publicly
  • API keys stay in browser LS, never sent to tealclaw.ai
  • Use /profile to separate personal/shared cfgs

Chat Commands

Command What It Does
/help Show all commands
/research query Research report (Compound Mini). Voice: "research query"
/deepresearch query Deep multi-tool research (Compound). Voice: "deepresearch query"
/imagine prompt Generate image (Nano Banana). Attach image for edit/remix. Voice: "imagine prompt"
/export / all / md Export convo(s)
/profile save/load/list/delete name Manage cfg profiles
/qr Share cfg QR code
/keys Current cfg status
/clear / all Clear convo(s)
/telegram / on / off TG setup/toggle
/voice Voice settings
/template Browse 12 style templates
/save / idea text / setup Obsidian save
/session create/info/end Session management

Agent Action Protocol (tc-action)

Agents control TC via ```tc-action blocks in rsp. Parsed, executed, stripped from display. Badge shows count.

Format

```tc-action
{"type": "config", "data": {"tealColor": "#8b5cf6", "botName": "Reef"}}
```

Action Types

Type Fields Effect
config data: {...} Update any cfg field live
command command: "/save ..." Trigger slash command
save name, folder, content, tags Save to Obsidian
research query: "topic" Trigger research pipeline
toast message, style (ok/err) Show notification
style vars: {"--teal": "#f00"} Update CSS vars
navigate target (settings/new-chat) Navigate UI
bubble html or text Inject system bubble
video url, title, live, muted Embed video stream (HLS/MP4/WebM). Auto-PiP on scroll.
video-grid feeds[], title, cols Camera grid (1-4 cols). Each feed: {url, label, live}
gallery images[], title Photo collage with lightbox. Each: {url, caption}
surveillance command, camera, cooldown, label Camera face/motion detection. start/stop/snap. Alerts agent.
guest-link action, name, instructions, presets, rateLimit, maxChars, expires Create/list/revoke limited guest links. Actions: create, list, revoke.
prompt question, options[] Interactive buttons in chat. Usr taps choice, returned to agent.
request-config (none) Returns all current settings (keys as presence booleans).

Multiple blocks per rsp OK -- execute sequentially.

Video Streaming Example

```tc-action
{"type":"video","url":"https://cam.example/feed.m3u8","title":"Office Cam","live":true}
```

Embeds a live video player in chat. When user scrolls away, video auto-enters a draggable floating PiP mini-player. Controls: mute, PiP, close, back-to-video.

Camera Grid Example

```tc-action
{"type":"video-grid","title":"Security Cameras","cols":2,"feeds":[
  {"url":"https://cam1.example/feed.m3u8","label":"Front Door","live":true},
  {"url":"https://cam2.example/feed.m3u8","label":"Backyard","live":true}
]}
```

Responsive grid with live badges, expand/fullscreen per cell, layout toggle.

Photo Gallery Example

```tc-action
{"type":"gallery","title":"Vacation Photos","images":[
  {"url":"https://example.com/photo1.jpg","caption":"Beach sunset"},
  {"url":"https://example.com/photo2.jpg","caption":"Mountain view"},
  {"url":"https://example.com/photo3.jpg"}
]}
```

Beautiful responsive grid (auto-layout 1-5+), click opens fullscreen lightbox with arrow + keyboard nav.

Surveillance Example

```tc-action
{"type":"surveillance","command":"start","camera":"user","cooldown":30,"label":"Office Cam"}
```

Starts device camera with face/motion detection. Alerts with snapshots sent to connected OpenClaw agent. Commands: start (begin monitoring), stop (end), snap (capture current frame). Uses Chrome FaceDetector API or motion-diff fallback. cooldown = seconds between alert notifications.

Guest Link Example

```tc-action
{"type":"guest-link","action":"create","name":"Sarah","instructions":"Can manage calendar and ask questions","presets":["Add to calendar","Check schedule","Message Eric"],"rateLimit":10,"maxChars":280,"expires":"30d"}
```

Creates an encrypted guest link. Returns link URL + passphrase in a chat bubble. Guest sees stripped-down PWA with only presets + text input. action: "list" shows all links, action: "revoke" disables by name/id.

Interactive Prompt Example

```tc-action
{"type":"prompt","question":"Which theme would you like?","options":["Dark mode","Light mode","Purple","Keep current"]}
```

Shows tappable buttons in chat. User taps a choice, it's returned to the agent. Use for confirmations, preference selection, or branching workflows.

Request Config Example

```tc-action
{"type":"request-config"}
```

Returns all current settings to the agent (API keys shown as presence booleans, e.g. aiKeySet: true). No user approval needed. Use before suggesting config changes.

Share Config Flow

User clicks "Share Settings with Agent" in Settings > Agent Tools. This sends the current config (sanitized) to the active agent as a chat message, along with a link to the skill docs. The agent reads the config, then replies with tc-action config blocks to modify settings. Full round-trip.

Smart Paste

Bare k auto-detection:

  • sk-or-v1-* --> OR AI k
  • gsk_* --> GQ Whisper k
  • AIza* --> Tenor/Google API k

Architecture

  • Single HTML file -- no build step
  • SW for offline PWA
  • All API keys in browser LS
  • Auto-provisions gateway token from gw.tealclaw.ai on first visit (zero-config)
  • Stateless HMAC tokens (tc1.*) -- no database, no accounts
  • Skill guide: /llms.txt (raw), /llms.html (copy btn)
  • Stats: /stats.html (Cloudflare Analytics via Pages Function)

Development

Open index.html in browser. SW testing: npx serve .

Deployment

Cloudflare Pages auto-deploys on git push. functions/ auto-detected.

Creator & Community

TC by Snail.

Stats API requires Cloudflare Pages env vars: CF_STATS_TOKEN, CF_ZONE_ID.