automation/skills/openclaw-deploy/SKILL.md
Topic skill (no dedicated `ov openclaw` command — the surface is layer composition + image deployment). MUST be invoked before any work involving: OpenClaw gateway configuration, model auth, browser integration, channel setup, or any image composing `openclaw-*` layers (`openclaw`, `openclaw-full`, or a custom image composing `openclaw`/`openclaw-full` + `sway-desktop`).
npx skillsauth add overthinkos/overthink-plugins openclaw-deployInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
OpenClaw is an AI gateway that connects LLM agents to messaging channels (WhatsApp, Telegram, Discord, Slack, Signal, iMessage, IRC, Teams) and exposes them via a WebSocket API, CLI, and web Control UI. It runs as a Node.js process with an embedded agent runtime, model failover, browser automation, and multi-agent routing.
In Overthink, OpenClaw runs as a supervisord service inside containers. The openclaw layer provides the npm package; compose it with the sway-desktop metalayer (full Sway desktop + Chrome browser + VNC) for browser-based workflows like OAuth and web automation. For a desktop+browser image, compose your own from the layers (shown below); for non-browser channels use the headless openclaw / openclaw-full images.
The gateway listens on port 18789 (WebSocket + HTTP). All CLI commands (openclaw *) connect to the gateway WebSocket. The Control UI is served at the gateway root URL. Config is stored in ~/.openclaw/openclaw.json (JSON5 format).
| Action | Command | Description |
|--------|---------|-------------|
| Gateway health | openclaw health | Check gateway connectivity |
| Gateway status | openclaw status --all | Full status with channels |
| Model status | openclaw models status | Show model, auth, and usage |
| Browser status | openclaw browser status | Show browser connection state |
| Browser tabs | openclaw browser tabs | List open Chrome tabs |
| Open URL | openclaw browser open <url> | Open URL in Chrome |
| Page snapshot | openclaw browser snapshot | Accessible page structure (AI refs) |
| Screenshot | openclaw browser screenshot | Capture PNG to media dir |
| Config get/set | openclaw config get/set <key> <val> | Read/write config values |
| Doctor | openclaw doctor --fix | Health checks + auto-fixes |
| Security audit | openclaw security audit | Check security posture |
| Channel login | openclaw channels login --channel <ch> | Connect a messaging channel |
| Agent message | openclaw agent --agent main --message "..." | Send test prompt |
| Setup wizard | openclaw configure | Interactive config wizard |
| Logs | openclaw logs --follow | Tail gateway logs |
For container lifecycle, use ov commands -- see /ov-core:service.
The openclaw layer (layers/openclaw/) depends on nodejs and supervisord. It installs the openclaw npm package globally, exposes port 18789, declares a data volume at ~/.openclaw, and runs as a supervisord service:
[program:openclaw]
command=%(ENV_HOME)s/.npm-global/bin/openclaw gateway --port 18789
The gateway binds to loopback only (no --bind lan). External access is handled by port_relay (socat), which forwards from the container interface to loopback. This avoids CORS origin checks entirely — the gateway only ever sees loopback connections.
Compose your own desktop+browser image — e.g. an openclaw-desktop entry in image.yml combining openclaw-full + sway-desktop on a Fedora base:
image:
openclaw-desktop:
base: fedora
layer: [agent-forwarding, openclaw-full, sway-desktop, dbus, ov]
port: ["18789:18789", "5900:5900", "9222:9222", "9224:9224"]
The resulting image exposes:
| Port | Service | Protocol | |------|---------|----------| | 18789 | Gateway WebSocket + Control UI | HTTP | | 5900 | VNC (wayvnc) | TCP | | 9222 | Chrome DevTools | HTTP |
Tunnel config exposes all ports via Tailscale (ports: all). Platform: linux/amd64 only.
ov alias add openclaw openclaw-desktop
# Now: openclaw --help (runs inside the container)
ov image build openclaw-desktop # Build image
ov config openclaw-desktop # Generate quadlet, daemon-reload
ov start openclaw-desktop # Start via systemd
ov stop openclaw-desktop # Stop
ov status openclaw-desktop # Check systemd status
ov logs openclaw-desktop -f # Follow container logs
The gateway binds to loopback only (no --bind lan). Only one config value is required before the gateway will start:
openclaw config set gateway.mode local
Without gateway.mode=local, the gateway refuses to start.
dangerouslyAllowHostHeaderOriginFallback is NOT needed because port_relay (socat) handles external access — the gateway only sees loopback connections, so no CORS origin checks are triggered.
For Chrome integration, also set:
openclaw config set browser.cdpUrl "http://127.0.0.1:9222"
After setting these, restart the gateway:
supervisorctl restart openclaw
| Mode | Description |
|------|-------------|
| none | No auth (loopback only) |
| token | Bearer token in WebSocket handshake |
| password | Password auth |
| trusted-proxy | Proxy handles auth (e.g., Tailscale identity headers) |
| Mode | Description |
|------|-------------|
| loopback | 127.0.0.1 only (default) |
| lan | All interfaces (0.0.0.0) -- requires auth |
| tailnet | Tailscale interface only |
openclaw health --json # Gateway health
openclaw doctor --fix # Diagnose and fix issues
openclaw status --all --deep # Full status with channels
# HTTP endpoints on gateway port:
# GET /healthz -- liveness
# GET /readyz -- readiness
// In ~/.openclaw/openclaw.json
agents: {
defaults: {
model: {
primary: "openai-codex/gpt-5.4",
fallbacks: ["anthropic/claude-sonnet-4-5"]
}
}
}
Critical: The openclaw models auth login TUI requires a real terminal to complete the post-callback token exchange. Do NOT pipe through tee or redirect stdout — it breaks the TUI event loop. Use ov tmux (see /ov-automation:tmux):
IMG=<image>
# 1. Start OAuth in a tmux session (real terminal)
ov tmux run $IMG -s oauth "openclaw models auth login --provider openai-codex --set-default"
# 2. Read the OAuth URL from tmux output
sleep 5
ov tmux capture $IMG -s oauth | grep -o 'https://auth.openai.com/[^ ]*'
# 3. Open URL in Chrome, click "Continue with Google", then "Continue" on consent
ov eval cdp open $IMG "<oauth-url>"
TAB=$(ov eval cdp list $IMG | grep -i "openai" | head -1 | awk '{print $1}')
ov eval cdp click $IMG $TAB 'button._buttonStyleFix_wvuha_65' --vnc # Continue with Google
sleep 5
ov eval cdp click $IMG $TAB 'button._primary_3rdp0_107' --vnc # Continue (consent)
# 4. Verify completion
sleep 10
ov tmux capture $IMG -s oauth
# Should show: "OpenAI OAuth complete", "Default model set to openai-codex/gpt-5.4"
Prerequisites: Chrome must have an active Google session. The "Continue with Google" button on OpenAI's auth page uses Chrome's Google cookies — sign Chrome into Google (with sync enabled) via the VNC desktop before starting the OAuth flow.
Callback architecture: The OAuth callback hits http://127.0.0.1:1455/auth/callback inside the container. Chrome and openclaw-models share the same network namespace — no port mapping needed for 1455. The BROWSER=browser-open env var (set by the chrome layer) auto-opens URLs via CDP, but may not trigger in all TTY contexts — open the URL manually via ov eval cdp open as a fallback.
Stale port 1455: If a previous attempt left port 1455 occupied: ov shell $IMG -c 'kill -9 $(ss -tlnp sport = :1455 | grep -oP "pid=\K\d+")'
Tokens persist in ~/.openclaw/agents/main/agent/auth-profiles.json in the data volume. Survive ov stop/ov start and image rebuilds. Only destroyed by ov remove --purge.
Model name: openai-codex/gpt-5.4. The --set-default flag sets it as the default model in openclaw.json.
openclaw models status
# Shows: provider, model, auth profiles, token expiry, usage quotas
Two-stage failure handling:
Backoff: 1min -> 5min -> 25min -> 1hr (capped). Auth profiles pin per session and reset on /new or compaction.
models: {
providers: {
"my-local": {
baseUrl: "http://localhost:4000/v1",
api: "openai-completions",
models: [{ id: "my-model", contextWindow: 128000, maxTokens: 32000 }]
}
}
}
In a composed openclaw desktop image (e.g. openclaw-desktop), Chrome already runs as a supervisord service on port 9222. OpenClaw must connect to it rather than launching a new instance:
openclaw config set browser.cdpUrl "http://127.0.0.1:9222"
supervisorctl restart openclaw
Do not use openclaw browser start in this image -- it attempts to launch a separate Chrome instance that fails without Wayland environment variables.
After configuration, verify:
openclaw browser status # Should show running: true, cdpPort: 9222
openclaw browser tabs # Lists open Chrome tabs
openclaw browser open https://example.com # Open URL in new tab
openclaw browser navigate https://other.com # Navigate current tab
openclaw browser snapshot # AI-accessible page structure
openclaw browser snapshot --format aria # Accessibility tree
openclaw browser screenshot # PNG to media dir
openclaw browser screenshot --full-page # Full page capture
openclaw browser click 12 # Click element by AI ref
openclaw browser type 23 "hello" --submit # Type + submit
openclaw browser press Enter # Key press
openclaw browser hover 44 # Hover element
openclaw browser fill --fields '[{"ref":"1","value":"Ada"}]'
openclaw browser wait --text "Done" # Wait for text
openclaw browser wait --url "**/dashboard" # Wait for URL pattern
openclaw browser evaluate --fn '(el) => el.textContent' --ref 7
openclaw browser console --level error # Console messages
openclaw browser cookies # Read cookies
openclaw browser pdf # Save page as PDF
Snapshots provide element references for interaction:
click 12, type 23 "text")--interactive): e-prefixed refs (click e12)--efficient): compact + interactive + depth reductionbrowser: {
profiles: {
openclaw: { cdpPort: 18800 }, // managed (default)
user: { driver: "existing-session", attachOnly: true }, // attach to running Chrome
remote: { cdpUrl: "http://10.0.0.42:9222" }, // remote CDP
cloud: { cdpUrl: "wss://connect.browserbase.com?apiKey=<KEY>" }
}
}
agents: {
defaults: {
workspace: "~/.openclaw/workspace",
maxConcurrent: 4,
compaction: { mode: "safeguard" },
subagents: { maxConcurrent: 8, maxChildrenPerAgent: 5, maxSpawnDepth: 1 },
tools: { profile: "coding" }, // coding|minimal|messaging|full
elevatedDefault: "off" // off|on|ask|full
}
}
Placed in the agent workspace, injected on first session turn:
AGENTS.md -- operating instructions and memorySOUL.md -- persona, boundaries, toneTOOLS.md -- user-maintained tool documentationIDENTITY.md -- agent name and characteristicsagents: {
list: [
{ id: "main", default: true, name: "Main", model: "openai-codex/gpt-5.4" },
{ id: "home", name: "Home Assistant", model: "anthropic/claude-sonnet-4-5" }
],
bindings: [
{ agentId: "home", match: { channel: "telegram", peer: { id: "123" } } }
]
}
WhatsApp, Telegram, Discord, Slack, Signal, Google Chat, Mattermost, iMessage, IRC, Microsoft Teams, BlueBubbles.
| Policy | Description |
|--------|-------------|
| pairing | Unknown senders get approval code (default) |
| allowlist | Only pre-approved senders |
| open | Accept all (requires allowFrom: ["*"]) |
| disabled | Ignore all DMs |
# Connect WhatsApp (QR code linking)
openclaw channels login --channel whatsapp
# Connect Telegram (requires bot token from BotFather)
openclaw config set channels.telegram.botToken "BOT_TOKEN"
openclaw channels login --channel telegram
# Connect Discord (requires bot token)
openclaw config set channels.discord.token "BOT_TOKEN"
# Check channel status
openclaw channels status --probe
| Path | Purpose |
|------|---------|
| ~/.openclaw/openclaw.json | Main config (JSON5) |
| ~/.openclaw/agents/<id>/agent/auth-profiles.json | Model auth tokens |
| ~/.openclaw/agents/<id>/sessions/ | Session data |
| ~/.openclaw/workspace/ | Agent workspace |
| ~/.openclaw/media/browser/ | Browser screenshots |
| ~/.openclaw/logs/ | Audit logs |
| /tmp/openclaw/openclaw-YYYY-MM-DD.log | Gateway runtime log |
Check supervisord: supervisorctl status openclaw. If cycling between STARTING and STOPPED:
# Run manually to see error output
supervisorctl stop openclaw
timeout 15 openclaw gateway --port 18789
Common fixes:
gateway.mode not set -> openclaw config set gateway.mode localallowedOrigins errors, verify the relay is running: supervisorctl status relay-18789If openclaw browser status shows running: false:
openclaw config set browser.cdpUrl "http://127.0.0.1:9222"
supervisorctl restart openclaw
Use --tty for the interactive CLI. The BROWSER=browser-open env var auto-opens OAuth URLs in Chrome. The callback URL (http://127.0.0.1:1455/auth/callback) is container-internal and needs no port mapping.
ov shell <image> --tty -c "openclaw models auth login --provider openai-codex --set-default"
For browser-assisted OAuth (Google sign-in), see /ov-eval:cdp.
After the first container start, configure the gateway:
ov shell <image> -c "openclaw config set gateway.mode local"
ov shell <image> -c "openclaw config set browser.cdpUrl 'http://127.0.0.1:9222'"
ov shell <image> -c "supervisorctl restart openclaw"
/ov-eval:cdp -- ov eval cdp CDP commands (lower-level container-external automation)/ov-core:deploy -- Quadlet, tunnels, volume backing, VNC password/ov-core:service -- ov start/stop/enable/disable/status/logs/update/remove/ov-eval:vnc -- VNC desktop automation and password management/ov-automation:alias -- Host command aliases (ov alias add openclaw)/ov-core:shell -- ov shell --tty for interactive container commandsMUST be invoked when the task involves OpenClaw gateway configuration, model auth, browser integration, channel setup, or openclaw images. Invoke this skill BEFORE reading source code or launching Explore agents.
Workflow position: Post-deployment. Configure the gateway after the container is running. See also /ov-openclaw:openclaw* (image variants).
development
Claude Code multi-agent support in Overthink — sub-agents, dynamic workflows, and agent teams, and how each drives the existing `ov eval` disposable beds to test and verify. MUST be invoked before authoring or invoking an ov sub-agent / dynamic workflow / agent team, wiring agent-lifecycle hooks, or asking "which primitive should drive the R10 beds?".
tools
Mounts a virtiofs share tagged `workspace` at /workspace inside a VM guest via a systemd .mount unit. Use when a kind:vm entity shares a host directory into the guest and you need it auto-mounted (and re-mounted at every boot).
development
MUST be invoked before any work involving: the `kind: android` schema kind, a `target: android` deploy, the `apk:` layer package format (installing Android apps declaratively), AndroidDeployTarget, an in-pod emulator OR a remote/physical adb-endpoint device, or nested `pod → android` deployment. The first-class Android device + app surface that sits above `ov eval adb`/`appium`.
tools
Use when committing, branching, pushing, merging, tagging, creating PRs, or approving/merging PRs with gh — the feat/-branch, R10-gated, never-force-push landing workflow across the main repo + the plugins submodule + image/<distro> submodules. Covers sync-to-upstream, branch/worktree pruning, the fork+PR path for contributors without write access, and cross-repo @github landing order.