Slim CLAUDE.md from 65K to 21K by splitting app-specific docs
Move OpenClaw, Palmr, MinIO, JSX publishing, MCP configs, and migration candidates into dedicated docs/ files. Keep only DevOps-essential content inline (deployment rules, DNS, router, credentials, troubleshooting). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
217
docs/openclaw.md
Normal file
217
docs/openclaw.md
Normal file
@@ -0,0 +1,217 @@
|
||||
# OpenClaw (AI Assistant Gateway)
|
||||
|
||||
Self-hosted AI assistant gateway running on the NUC via Docker Compose. Connects to messaging platforms (WhatsApp, Telegram, Discord, etc.) and routes messages through Claude.
|
||||
|
||||
## Access
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Control UI (HTTPS)** | `https://alezmad-nuc.tail58f5ad.ts.net:8443` |
|
||||
| **Gateway WS** | `ws://192.168.1.3:18789` |
|
||||
| **Gateway Token** | `3547c3f2b7b4a33eb077cf804bcca446057f81ba1578b2045dbb3aa4e04346ee` |
|
||||
| **Model** | `anthropic/claude-sonnet-4-5-20250929` |
|
||||
| **Repo on NUC** | `~/openclaw/` |
|
||||
| **Config** | `~/.openclaw/openclaw.json` |
|
||||
| **Version** | `2026.2.10` |
|
||||
|
||||
**HTTPS Required:** The Control UI requires a secure context (HTTPS or localhost). Access via Tailscale Serve on port 8443.
|
||||
|
||||
## Tailscale Serve (HTTPS access)
|
||||
|
||||
The gateway is exposed via Tailscale Serve (not Funnel - tailnet only, not public):
|
||||
|
||||
```bash
|
||||
# Start HTTPS proxy (requires sudo, must run from NUC terminal)
|
||||
ssh nuc
|
||||
sudo tailscale serve --bg --https=8443 http://localhost:18789
|
||||
# Password: 7vXHpSTD
|
||||
```
|
||||
|
||||
**The `--bg` flag makes it persistent.** Without it, Ctrl+C stops the proxy.
|
||||
|
||||
## Docker Compose Management
|
||||
|
||||
```bash
|
||||
# Start gateway
|
||||
ssh nuc "cd ~/openclaw && docker compose up -d openclaw-gateway"
|
||||
|
||||
# Restart gateway
|
||||
ssh nuc "cd ~/openclaw && docker compose restart openclaw-gateway"
|
||||
|
||||
# View logs
|
||||
ssh nuc "docker logs openclaw-openclaw-gateway-1 2>&1 | tail -30"
|
||||
|
||||
# Run CLI commands (use docker exec for commands that need gateway connection)
|
||||
ssh nuc "docker exec openclaw-openclaw-gateway-1 node dist/index.js <command> --token 3547c3f2b7b4a33eb077cf804bcca446057f81ba1578b2045dbb3aa4e04346ee --url ws://127.0.0.1:18789"
|
||||
|
||||
# Run CLI commands that don't need gateway (use docker compose run)
|
||||
ssh nuc "cd ~/openclaw && script -qc 'docker compose run --rm openclaw-cli <command>' /dev/null"
|
||||
```
|
||||
|
||||
## Device Pairing
|
||||
|
||||
When the Control UI shows "pairing required", approve the pending device:
|
||||
|
||||
```bash
|
||||
# List pending devices
|
||||
ssh nuc "docker exec openclaw-openclaw-gateway-1 node dist/index.js devices list --token 3547c3f2b7b4a33eb077cf804bcca446057f81ba1578b2045dbb3aa4e04346ee --url ws://127.0.0.1:18789"
|
||||
|
||||
# Approve a device (use requestId from the list)
|
||||
ssh nuc "docker exec openclaw-openclaw-gateway-1 node dist/index.js devices approve <requestId> --token 3547c3f2b7b4a33eb077cf804bcca446057f81ba1578b2045dbb3aa4e04346ee --url ws://127.0.0.1:18789"
|
||||
```
|
||||
|
||||
**Dashboard URL with embedded token (auto-authenticates):**
|
||||
```
|
||||
https://alezmad-nuc.tail58f5ad.ts.net:8443/#token=3547c3f2b7b4a33eb077cf804bcca446057f81ba1578b2045dbb3aa4e04346ee
|
||||
```
|
||||
|
||||
## Channel Plugins
|
||||
|
||||
Channels are plugins that must be enabled before use. 35 available, 4 loaded by default.
|
||||
|
||||
```bash
|
||||
# List all plugins
|
||||
ssh nuc "script -qc 'cd ~/openclaw && docker compose run --rm openclaw-cli plugins list' /dev/null"
|
||||
|
||||
# Enable a channel plugin
|
||||
ssh nuc "script -qc 'cd ~/openclaw && docker compose run --rm openclaw-cli plugins enable <plugin-id>' /dev/null"
|
||||
|
||||
# Then restart gateway
|
||||
ssh nuc "cd ~/openclaw && docker compose restart openclaw-gateway"
|
||||
```
|
||||
|
||||
**Currently enabled channels:** WhatsApp (linked and active)
|
||||
|
||||
**Available channel plugins:**
|
||||
| Plugin ID | Channel |
|
||||
|-----------|---------|
|
||||
| `whatsapp` | WhatsApp |
|
||||
| `telegram` | Telegram |
|
||||
| `discord` | Discord |
|
||||
| `slack` | Slack |
|
||||
| `signal` | Signal |
|
||||
| `matrix` | Matrix |
|
||||
| `msteams` | Microsoft Teams |
|
||||
| `googlechat` | Google Chat |
|
||||
| `imessage` | iMessage |
|
||||
| `irc` | IRC |
|
||||
|
||||
## Setting Up Channels That Require QR Codes (WhatsApp, etc.)
|
||||
|
||||
**The CLI needs a TTY for QR display.** Cannot run directly via `ssh nuc "command"`. Use `script` to fake a TTY and capture output:
|
||||
|
||||
```bash
|
||||
# Step 1: Enable the plugin
|
||||
ssh nuc "script -qc 'cd ~/openclaw && docker compose run --rm openclaw-cli plugins enable whatsapp' /dev/null"
|
||||
|
||||
# Step 2: Restart gateway
|
||||
ssh nuc "cd ~/openclaw && docker compose restart openclaw-gateway"
|
||||
|
||||
# Step 3: Run login with TTY capture (captures QR to file)
|
||||
ssh nuc "script -q /tmp/openclaw-qr.txt -c 'cd ~/openclaw && docker compose run --rm openclaw-cli channels login'"
|
||||
|
||||
# Step 4: If QR needs to be viewed remotely, copy and render as image
|
||||
scp nuc:/tmp/openclaw-qr.txt /tmp/
|
||||
# Then use Python + Pillow to convert Unicode block chars to PNG
|
||||
```
|
||||
|
||||
**QR to PNG conversion (run locally on Mac):**
|
||||
```python
|
||||
from PIL import Image
|
||||
import re
|
||||
|
||||
with open("/tmp/openclaw-qr.txt", "rb") as f:
|
||||
content = f.read().decode("utf-8", errors="replace")
|
||||
|
||||
lines = content.split("\n")
|
||||
qr_lines = []
|
||||
for l in lines:
|
||||
clean = re.sub(r"\x1b\[[0-9;]*[a-zA-Z]", "", l).replace(chr(0), "")
|
||||
if any(c in clean for c in ["\u2584", "\u2588", "\u2580"]):
|
||||
qr_lines.append(clean)
|
||||
|
||||
scale = 10
|
||||
width = max(len(l) for l in qr_lines)
|
||||
height = len(qr_lines) * 2
|
||||
img = Image.new("RGB", (width * scale, height * scale), "white")
|
||||
|
||||
for row_idx, line in enumerate(qr_lines):
|
||||
for col_idx, ch in enumerate(line):
|
||||
top_black = ch in ["\u2588", "\u2580"]
|
||||
bot_black = ch in ["\u2588", "\u2584"]
|
||||
for dy in range(scale):
|
||||
for dx in range(scale):
|
||||
if top_black:
|
||||
img.putpixel((col_idx*scale+dx, row_idx*2*scale+dy), (0,0,0))
|
||||
if bot_black:
|
||||
img.putpixel((col_idx*scale+dx, (row_idx*2+1)*scale+dy), (0,0,0))
|
||||
|
||||
img.save("/tmp/qr.png")
|
||||
```
|
||||
|
||||
## Anthropic Authentication
|
||||
|
||||
Uses a Claude Code OAuth token (valid 1 year). Set in both config and docker-compose env:
|
||||
|
||||
**Config (`~/.openclaw/openclaw.json`):**
|
||||
```json
|
||||
{
|
||||
"env": {
|
||||
"ANTHROPIC_API_KEY": "sk-ant-oat01-..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Docker env (`~/openclaw/.env`):**
|
||||
```
|
||||
ANTHROPIC_API_KEY=sk-ant-oat01-...
|
||||
```
|
||||
|
||||
**To regenerate token (run on Mac where `claude` CLI is installed):**
|
||||
```bash
|
||||
claude setup-token
|
||||
# Copy the output token and update both config + .env on NUC
|
||||
```
|
||||
|
||||
## Config Schema (current)
|
||||
|
||||
```json
|
||||
{
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"model": {
|
||||
"primary": "anthropic/claude-sonnet-4-5-20250929"
|
||||
}
|
||||
}
|
||||
},
|
||||
"gateway": {
|
||||
"port": 18789,
|
||||
"mode": "local",
|
||||
"bind": "lan",
|
||||
"auth": {
|
||||
"mode": "token"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Config gotchas:**
|
||||
- `agent.model` is **legacy** — use `agents.defaults.model.primary` instead
|
||||
- Run `docker exec openclaw-openclaw-gateway-1 node dist/index.js doctor --fix` to migrate legacy keys
|
||||
- The `gateway.pairing` key does NOT exist — device pairing is managed via the `devices` CLI, not config
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
1. **"control ui requires HTTPS or localhost"**: Access via `https://alezmad-nuc.tail58f5ad.ts.net:8443` (Tailscale Serve), NOT `http://192.168.1.3:18789`
|
||||
|
||||
2. **"pairing required"**: Approve the device via `devices approve` command (see Device Pairing section above)
|
||||
|
||||
3. **"unauthorized: gateway token missing"**: Use the dashboard URL with `#token=...` hash to auto-authenticate
|
||||
|
||||
4. **CLI commands fail with "gateway closed"**: Use `docker exec` into the running gateway container instead of `docker compose run` (the CLI container can't reach the gateway on its internal Docker IP)
|
||||
|
||||
5. **Config "invalid" after edit**: Run `doctor --fix` inside the gateway container to clean up
|
||||
|
||||
6. **Channel "unsupported"**: Enable the plugin first with `plugins enable <id>`, then restart gateway
|
||||
|
||||
7. **CLAUDE_AI_SESSION_KEY warnings**: Harmless — these are for Claude web session auth which isn't used when using API key
|
||||
Reference in New Issue
Block a user