{
  "title": "then target the dev instance:",
  "content": "openclaw --dev status\nopenclaw --dev health\nbash theme={null}\nopenclaw --profile main gateway install\nopenclaw --profile rescue gateway install\nbash theme={null}\nOPENCLAW_CONFIG_PATH=~/.openclaw/a.json OPENCLAW_STATE_DIR=~/.openclaw-a openclaw gateway --port 19001\nOPENCLAW_CONFIG_PATH=~/.openclaw/b.json OPENCLAW_STATE_DIR=~/.openclaw-b openclaw gateway --port 19002\nbash theme={null}\nopenclaw gateway status\nopenclaw gateway install\nopenclaw gateway stop\nopenclaw gateway restart\nopenclaw logs --follow\n\n[Unit]\nDescription=OpenClaw Gateway (profile: <profile>, v<version>)\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nExecStart=/usr/local/bin/openclaw gateway --port 18789\nRestart=always\nRestartSec=5\nEnvironment=OPENCLAW_GATEWAY_TOKEN=\nWorkingDirectory=/home/youruser\n\n[Install]\nWantedBy=default.target\n\nsudo loginctl enable-linger youruser\n\nsystemctl --user enable --now openclaw-gateway[-<profile>].service\n\nsudo systemctl daemon-reload\nsudo systemctl enable --now openclaw-gateway[-<profile>].service\n```\n\nWindows installs should use **WSL2** and follow the Linux systemd section above.\n\n## Operational checks\n\n* Liveness: open WS and send `req:connect` → expect `res` with `payload.type=\"hello-ok\"` (with snapshot).\n* Readiness: call `health` → expect `ok: true` and a linked channel in `linkChannel` (when applicable).\n* Debug: subscribe to `tick` and `presence` events; ensure `status` shows linked/auth age; presence entries show Gateway host and connected clients.\n\n* Assume one Gateway per host by default; if you run multiple profiles, isolate ports/state and target the right instance.\n* No fallback to direct Baileys connections; if the Gateway is down, sends fail fast.\n* Non-connect first frames or malformed JSON are rejected and the socket is closed.\n* Graceful shutdown: emit `shutdown` event before closing; clients must handle close + reconnect.\n\n* `openclaw gateway health|status` — request health/status over the Gateway WS.\n* `openclaw message send --target <num> --message \"hi\" [--media ...]` — send via Gateway (idempotent for WhatsApp).\n* `openclaw agent --message \"hi\" --to <num>` — run an agent turn (waits for final by default).\n* `openclaw gateway call <method> --params '{\"k\":\"v\"}'` — raw method invoker for debugging.\n* `openclaw gateway stop|restart` — stop/restart the supervised gateway service (launchd/systemd).\n* Gateway helper subcommands assume a running gateway on `--url`; they no longer auto-spawn one.\n\n## Migration guidance\n\n* Retire uses of `openclaw gateway` and the legacy TCP control port.\n* Update clients to speak the WS protocol with mandatory connect and structured presence.",
  "code_samples": [
    {
      "code": "Defaults (can be overridden via env/flags/config):\n\n* `OPENCLAW_STATE_DIR=~/.openclaw-dev`\n* `OPENCLAW_CONFIG_PATH=~/.openclaw-dev/openclaw.json`\n* `OPENCLAW_GATEWAY_PORT=19001` (Gateway WS + HTTP)\n* browser control service port = `19003` (derived: `gateway.port+2`, loopback only)\n* `canvasHost.port=19005` (derived: `gateway.port+4`)\n* `agents.defaults.workspace` default becomes `~/.openclaw/workspace-dev` when you run `setup`/`onboard` under `--dev`.\n\nDerived ports (rules of thumb):\n\n* Base port = `gateway.port` (or `OPENCLAW_GATEWAY_PORT` / `--port`)\n* browser control service port = base + 2 (loopback only)\n* `canvasHost.port = base + 4` (or `OPENCLAW_CANVAS_HOST_PORT` / config override)\n* Browser profile CDP ports auto-allocate from `browser.controlPort + 9 .. + 108` (persisted per profile).\n\nChecklist per instance:\n\n* unique `gateway.port`\n* unique `OPENCLAW_CONFIG_PATH`\n* unique `OPENCLAW_STATE_DIR`\n* unique `agents.defaults.workspace`\n* separate WhatsApp numbers (if using WA)\n\nService install per profile:",
      "language": "unknown"
    },
    {
      "code": "Example:",
      "language": "unknown"
    },
    {
      "code": "## Protocol (operator view)\n\n* Full docs: [Gateway protocol](/gateway/protocol) and [Bridge protocol (legacy)](/gateway/bridge-protocol).\n* Mandatory first frame from client: `req {type:\"req\", id, method:\"connect\", params:{minProtocol,maxProtocol,client:{id,displayName?,version,platform,deviceFamily?,modelIdentifier?,mode,instanceId?}, caps, auth?, locale?, userAgent? } }`.\n* Gateway replies `res {type:\"res\", id, ok:true, payload:hello-ok }` (or `ok:false` with an error, then closes).\n* After handshake:\n  * Requests: `{type:\"req\", id, method, params}` → `{type:\"res\", id, ok, payload|error}`\n  * Events: `{type:\"event\", event, payload, seq?, stateVersion?}`\n* Structured presence entries: `{host, ip, version, platform?, deviceFamily?, modelIdentifier?, mode, lastInputSeconds?, ts, reason?, tags?[], instanceId? }` (for WS clients, `instanceId` comes from `connect.client.instanceId`).\n* `agent` responses are two-stage: first `res` ack `{runId,status:\"accepted\"}`, then a final `res` `{runId,status:\"ok\"|\"error\",summary}` after the run finishes; streamed output arrives as `event:\"agent\"`.\n\n## Methods (initial set)\n\n* `health` — full health snapshot (same shape as `openclaw health --json`).\n* `status` — short summary.\n* `system-presence` — current presence list.\n* `system-event` — post a presence/system note (structured).\n* `send` — send a message via the active channel(s).\n* `agent` — run an agent turn (streams events back on same connection).\n* `node.list` — list paired + currently-connected nodes (includes `caps`, `deviceFamily`, `modelIdentifier`, `paired`, `connected`, and advertised `commands`).\n* `node.describe` — describe a node (capabilities + supported `node.invoke` commands; works for paired nodes and for currently-connected unpaired nodes).\n* `node.invoke` — invoke a command on a node (e.g. `canvas.*`, `camera.*`).\n* `node.pair.*` — pairing lifecycle (`request`, `list`, `approve`, `reject`, `verify`).\n\nSee also: [Presence](/concepts/presence) for how presence is produced/deduped and why a stable `client.instanceId` matters.\n\n## Events\n\n* `agent` — streamed tool/output events from the agent run (seq-tagged).\n* `presence` — presence updates (deltas with stateVersion) pushed to all connected clients.\n* `tick` — periodic keepalive/no-op to confirm liveness.\n* `shutdown` — Gateway is exiting; payload includes `reason` and optional `restartExpectedMs`. Clients should reconnect.\n\n## WebChat integration\n\n* WebChat is a native SwiftUI UI that talks directly to the Gateway WebSocket for history, sends, abort, and events.\n* Remote use goes through the same SSH/Tailscale tunnel; if a gateway token is configured, the client includes it during `connect`.\n* macOS app connects via a single WS (shared connection); it hydrates presence from the initial snapshot and listens for `presence` events to update the UI.\n\n## Typing and validation\n\n* Server validates every inbound frame with AJV against JSON Schema emitted from the protocol definitions.\n* Clients (TS/Swift) consume generated types (TS directly; Swift via the repo’s generator).\n* Protocol definitions are the source of truth; regenerate schema/models with:\n  * `pnpm protocol:gen`\n  * `pnpm protocol:gen:swift`\n\n## Connection snapshot\n\n* `hello-ok` includes a `snapshot` with `presence`, `health`, `stateVersion`, and `uptimeMs` plus `policy {maxPayload,maxBufferedBytes,tickIntervalMs}` so clients can render immediately without extra requests.\n* `health`/`system-presence` remain available for manual refresh, but are not required at connect time.\n\n## Error codes (res.error shape)\n\n* Errors use `{ code, message, details?, retryable?, retryAfterMs? }`.\n* Standard codes:\n  * `NOT_LINKED` — WhatsApp not authenticated.\n  * `AGENT_TIMEOUT` — agent did not respond within the configured deadline.\n  * `INVALID_REQUEST` — schema/param validation failed.\n  * `UNAVAILABLE` — Gateway is shutting down or a dependency is unavailable.\n\n## Keepalive behavior\n\n* `tick` events (or WS ping/pong) are emitted periodically so clients know the Gateway is alive even when no traffic occurs.\n* Send/agent acknowledgements remain separate responses; do not overload ticks for sends.\n\n## Replay / gaps\n\n* Events are not replayed. Clients detect seq gaps and should refresh (`health` + `system-presence`) before continuing. WebChat and macOS clients now auto-refresh on gap.\n\n## Supervision (macOS example)\n\n* Use launchd to keep the service alive:\n  * Program: path to `openclaw`\n  * Arguments: `gateway`\n  * KeepAlive: true\n  * StandardOut/Err: file paths or `syslog`\n* On failure, launchd restarts; fatal misconfig should keep exiting so the operator notices.\n* LaunchAgents are per-user and require a logged-in session; for headless setups use a custom LaunchDaemon (not shipped).\n  * `openclaw gateway install` writes `~/Library/LaunchAgents/bot.molt.gateway.plist`\n    (or `bot.molt.<profile>.plist`; legacy `com.openclaw.*` is cleaned up).\n  * `openclaw doctor` audits the LaunchAgent config and can update it to current defaults.\n\n## Gateway service management (CLI)\n\nUse the Gateway CLI for install/start/stop/restart/status:",
      "language": "unknown"
    },
    {
      "code": "Notes:\n\n* `gateway status` probes the Gateway RPC by default using the service’s resolved port/config (override with `--url`).\n* `gateway status --deep` adds system-level scans (LaunchDaemons/system units).\n* `gateway status --no-probe` skips the RPC probe (useful when networking is down).\n* `gateway status --json` is stable for scripts.\n* `gateway status` reports **supervisor runtime** (launchd/systemd running) separately from **RPC reachability** (WS connect + status RPC).\n* `gateway status` prints config path + probe target to avoid “localhost vs LAN bind” confusion and profile mismatches.\n* `gateway status` includes the last gateway error line when the service looks running but the port is closed.\n* `logs` tails the Gateway file log via RPC (no manual `tail`/`grep` needed).\n* If other gateway-like services are detected, the CLI warns unless they are OpenClaw profile services.\n  We still recommend **one gateway per machine** for most setups; use isolated profiles/ports for redundancy or a rescue bot. See [Multiple gateways](/gateway/multiple-gateways).\n  * Cleanup: `openclaw gateway uninstall` (current service) and `openclaw doctor` (legacy migrations).\n* `gateway install` is a no-op when already installed; use `openclaw gateway install --force` to reinstall (profile/env/path changes).\n\nBundled mac app:\n\n* OpenClaw\\.app can bundle a Node-based gateway relay and install a per-user LaunchAgent labeled\n  `bot.molt.gateway` (or `bot.molt.<profile>`; legacy `com.openclaw.*` labels still unload cleanly).\n* To stop it cleanly, use `openclaw gateway stop` (or `launchctl bootout gui/$UID/bot.molt.gateway`).\n* To restart, use `openclaw gateway restart` (or `launchctl kickstart -k gui/$UID/bot.molt.gateway`).\n  * `launchctl` only works if the LaunchAgent is installed; otherwise use `openclaw gateway install` first.\n  * Replace the label with `bot.molt.<profile>` when running a named profile.\n\n## Supervision (systemd user unit)\n\nOpenClaw installs a **systemd user service** by default on Linux/WSL2. We\nrecommend user services for single-user machines (simpler env, per-user config).\nUse a **system service** for multi-user or always-on servers (no lingering\nrequired, shared supervision).\n\n`openclaw gateway install` writes the user unit. `openclaw doctor` audits the\nunit and can update it to match the current recommended defaults.\n\nCreate `~/.config/systemd/user/openclaw-gateway[-<profile>].service`:",
      "language": "unknown"
    },
    {
      "code": "Enable lingering (required so the user service survives logout/idle):",
      "language": "unknown"
    },
    {
      "code": "Onboarding runs this on Linux/WSL2 (may prompt for sudo; writes `/var/lib/systemd/linger`).\nThen enable the service:",
      "language": "unknown"
    },
    {
      "code": "**Alternative (system service)** - for always-on or multi-user servers, you can\ninstall a systemd **system** unit instead of a user unit (no lingering needed).\nCreate `/etc/systemd/system/openclaw-gateway[-<profile>].service` (copy the unit above,\nswitch `WantedBy=multi-user.target`, set `User=` + `WorkingDirectory=`), then:",
      "language": "unknown"
    }
  ],
  "headings": [
    {
      "level": "h2",
      "text": "Protocol (operator view)",
      "id": "protocol-(operator-view)"
    },
    {
      "level": "h2",
      "text": "Methods (initial set)",
      "id": "methods-(initial-set)"
    },
    {
      "level": "h2",
      "text": "Events",
      "id": "events"
    },
    {
      "level": "h2",
      "text": "WebChat integration",
      "id": "webchat-integration"
    },
    {
      "level": "h2",
      "text": "Typing and validation",
      "id": "typing-and-validation"
    },
    {
      "level": "h2",
      "text": "Connection snapshot",
      "id": "connection-snapshot"
    },
    {
      "level": "h2",
      "text": "Error codes (res.error shape)",
      "id": "error-codes-(res.error-shape)"
    },
    {
      "level": "h2",
      "text": "Keepalive behavior",
      "id": "keepalive-behavior"
    },
    {
      "level": "h2",
      "text": "Replay / gaps",
      "id": "replay-/-gaps"
    },
    {
      "level": "h2",
      "text": "Supervision (macOS example)",
      "id": "supervision-(macos-example)"
    },
    {
      "level": "h2",
      "text": "Gateway service management (CLI)",
      "id": "gateway-service-management-(cli)"
    },
    {
      "level": "h2",
      "text": "Supervision (systemd user unit)",
      "id": "supervision-(systemd-user-unit)"
    },
    {
      "level": "h2",
      "text": "Windows (WSL2)",
      "id": "windows-(wsl2)"
    },
    {
      "level": "h2",
      "text": "Operational checks",
      "id": "operational-checks"
    },
    {
      "level": "h2",
      "text": "Safety guarantees",
      "id": "safety-guarantees"
    },
    {
      "level": "h2",
      "text": "CLI helpers",
      "id": "cli-helpers"
    },
    {
      "level": "h2",
      "text": "Migration guidance",
      "id": "migration-guidance"
    }
  ],
  "url": "llms-txt#then-target-the-dev-instance:",
  "links": []
}