Files
openclaw/docs/gateway/index.md
Peter Steinberger 5b56a1f664 feat(gateway): land remaining durable-approvals stack and repair main gates (#104837)
* feat(gateway): propagate approvals to ancestor sessions with replay

Squash-rebased #103921 segment onto the native-clients tip on current main.
Session-scoped approval events publish sanitized pending/terminal
transitions to opted-in session audiences, with authoritative pending
replay on stream subscribe and durable-expiry reconciliation through the
owning manager. SessionApprovalEvent/Replay wire types export from the
approvals owner module; Swift models regenerated.

(cherry picked from commit 2d1dcf9747044710111d0c730fc46ba6013a165c)
(cherry picked from commit ccf88efd56b513d07599ffcee997bf0cddaf9adc)
(cherry picked from commit 8eb33f59f00ec9ee4625259b76bd7ae60d2cd480)
(cherry picked from commit c297cbc93c8401e9c79c20f242245a194f5dd236)
(cherry picked from commit 93d68f28601ff37d863da4db009504993a22533a)
(cherry picked from commit d285ccd8b2f212bb57e814107e7709c896e96b7d)
(cherry picked from commit 5c536982231402b1b58d1683794ea9948b32d077)
(cherry picked from commit 1646e5b6dc4dd20de54e10f110a5909be18d7d50)
(cherry picked from commit 35cf1b705b247fb282f4d56ffe74bd2fb238221f)
(cherry picked from commit 4f8ef3699d)
(cherry picked from commit 74fbdcc99d5fff062d67760a51dba4ee9e84479b)
(cherry picked from commit 222b285502681d2be14b1819798e9ee5555f431e)
(cherry picked from commit b9e744951f676b600e7c5322bfd04b0e99797c07)
(cherry picked from commit 9e904efde5)
(cherry picked from commit 678f2384fa)
(cherry picked from commit 72842e5cf6)
(cherry picked from commit be74c25e80e84a1f065053766f23efb84822e811)
(cherry picked from commit 93ba8c4b09)
(cherry picked from commit 8f23761372)

* feat(gateway): fail-closed plugin and tool approval gates

Squash-rebased #103932 segment onto the ancestor-propagation tip on
current main. Plugin node.invoke approvals claim a one-shot allow-once
decision before handing execution authority to the policy, so observation
or retry cannot replay a consumed approval; sibling tool gates bind
approval ids to their originating reviewer identity.

(cherry picked from commit 122df0d75281f572c012b6484ed5daf085d1d577)
(cherry picked from commit f23d8ac240a8dcf2a42c4daaae962263975a0ae8)
(cherry picked from commit 8632fb6436a224dac7a9a9ef0216884530de2c24)
(cherry picked from commit d9fe2dd5c53665e5732f5f3da5ed1907a686ade8)
(cherry picked from commit bb139f2c8aa36ddad70413e1ef79ff491a6f2ecd)
(cherry picked from commit 9b3e056b68ea515c7d4baef269289b6670570480)
(cherry picked from commit b11e66b59a7af1f3b08712de06864aed64d349e4)
(cherry picked from commit a12916ee592d03dfa35e86a2aaede4476a5d4e5d)
(cherry picked from commit d699de840fc8346892b9ae244fe3c3e8c4413032)
(cherry picked from commit 9b7e5a9608)
(cherry picked from commit 4b507593f1b2f10b4496984c84a2803b853e5c5e)
(cherry picked from commit 56408a186733c4eeb5aa76bd5907cde7b0cd3d5b)
(cherry picked from commit a4051d6d8353d39d6fa0b5d69c36e06c3cd3e796)
(cherry picked from commit 76829805a7)
(cherry picked from commit a8b493f934)
(cherry picked from commit aceb990597)
(cherry picked from commit a29b0e75482470c53a9fb4fe3f204e14cf71868f)
(cherry picked from commit 2e3be08653)
(cherry picked from commit c9ae3d7202)

* fix: main-gate repairs for the durable-approvals stack

- android: capture createdAtMs on the pending exec-approval write at
  registration; canonical readback after a refresh that already replaced
  the visible rows was dropping the approval instead of surfacing the
  still-pending reconciliation message (#104913 merged without this)
- android: generous CI timeout ceilings in GatewayExecApprovalRuntimeTest
- agents: hermetic model-discovery test via the plugins/provider-runtime
  boundary (lazy plugin-runtime resolution hangs vitest workers since #104770)
- cli: usage-cost settle-budget test asserts the budget bound on every call
  instead of pinning the poll count (fast hosts fit a second poll in 50ms)
- protocol coverage: allowlist session.approval for ios/android (native
  review rides exec.approval push/nudge delivery)
- docs map, native i18n inventory, plugin-sdk api baseline regenerated
2026-07-12 10:51:38 +01:00

364 lines
14 KiB
Markdown

---
summary: "Runbook for the Gateway service, lifecycle, and operations"
read_when:
- Running or debugging the gateway process
title: "Gateway runbook"
---
Use this page for day-1 startup and day-2 operations of the Gateway service.
<CardGroup cols={2}>
<Card title="Deep troubleshooting" icon="siren" href="/gateway/troubleshooting">
Symptom-first diagnostics with exact command ladders and log signatures.
</Card>
<Card title="Configuration" icon="sliders" href="/gateway/configuration">
Task-oriented setup guide + full configuration reference.
</Card>
<Card title="Secrets management" icon="key-round" href="/gateway/secrets">
SecretRef contract, runtime snapshot behavior, and migrate/reload operations.
</Card>
<Card title="Secrets plan contract" icon="shield-check" href="/gateway/secrets-plan-contract">
Exact `secrets apply` target/path rules and ref-only auth-profile behavior.
</Card>
</CardGroup>
## 5-minute local startup
<Steps>
<Step title="Start the Gateway">
```bash
openclaw gateway --port 18789
# debug/trace mirrored to stdio
openclaw gateway --port 18789 --verbose
# force-kill listener on selected port, then start
openclaw gateway --force
```
</Step>
<Step title="Verify service health">
```bash
openclaw gateway status
openclaw status
openclaw logs --follow
```
Healthy baseline: `Runtime: running`, `Connectivity probe: ok`, and a `Capability` line that matches what you expect. Use `openclaw gateway status --require-rpc` for read-scope RPC proof, not just reachability.
</Step>
<Step title="Validate channel readiness">
```bash
openclaw channels status --probe
```
With a reachable gateway this runs live per-account channel probes and optional audits. If the gateway is unreachable, the CLI falls back to config-only channel summaries.
</Step>
</Steps>
<Note>
Gateway config reload watches the active config file path (resolved from profile/state defaults, or `OPENCLAW_CONFIG_PATH` when set). Default mode is `gateway.reload.mode="hybrid"`. After the first successful load, the running process serves the active in-memory config snapshot; a successful reload swaps that snapshot atomically.
</Note>
## Runtime model
- One always-on process for routing, control plane, and channel connections.
- Single multiplexed port for:
- WebSocket control/RPC
- HTTP APIs (`/v1/models`, `/v1/embeddings`, `/v1/chat/completions`, `/v1/responses`, `/tools/invoke`)
- Plugin HTTP routes, such as optional `/api/v1/admin/rpc`
- Control UI and hooks
- Default bind mode: `loopback`. Inside a detected container environment the effective default is `auto` (resolves to `0.0.0.0` for port-forwarding), unless Tailscale serve/funnel is active, which always forces `loopback`.
- Auth is required by default. Shared-secret setups use `gateway.auth.token` / `gateway.auth.password` (or `OPENCLAW_GATEWAY_TOKEN` / `OPENCLAW_GATEWAY_PASSWORD`), and non-loopback reverse-proxy setups can use `gateway.auth.mode: "trusted-proxy"`.
## OpenAI-compatible endpoints
OpenClaw's highest-leverage compatibility surface:
- `GET /v1/models`
- `GET /v1/models/{id}`
- `POST /v1/embeddings`
- `POST /v1/chat/completions`
- `POST /v1/responses`
Why this set matters:
- Most Open WebUI, LobeChat, and LibreChat integrations probe `/v1/models` first.
- Many RAG and memory pipelines expect `/v1/embeddings`.
- Agent-native clients increasingly prefer `/v1/responses`.
`/v1/models` is agent-first: it returns `openclaw`, `openclaw/default`, and `openclaw/<agentId>` for every configured agent. `openclaw/default` is the stable alias that always maps to the configured default agent. Send `x-openclaw-model` when you want a backend provider/model override; otherwise the selected agent's normal model and embedding setup stays in control.
All of these run on the main Gateway port and use the same trusted operator auth boundary as the rest of the Gateway HTTP API.
Admin HTTP RPC (`POST /api/v1/admin/rpc`) is a separate, default-off plugin route for host tooling that cannot use WebSocket RPC. See [Admin HTTP RPC](/plugins/admin-http-rpc).
### Port and bind precedence
| Setting | Resolution order |
| ------------ | -------------------------------------------------------------------- |
| Gateway port | `--port``OPENCLAW_GATEWAY_PORT``gateway.port``18789` |
| Bind mode | CLI/override → `gateway.bind``loopback` (or `auto` in containers) |
Installed gateway services record the resolved `--port` in supervisor metadata. After changing `gateway.port`, run `openclaw doctor --fix` or `openclaw gateway install --force` so launchd/systemd/schtasks starts the process on the new port.
Gateway startup uses the same effective port and bind when it seeds local Control UI origins for non-loopback binds. For example, `--bind lan --port 3000` seeds `http://localhost:3000` and `http://127.0.0.1:3000` before runtime validation runs. Add any remote browser origins, such as HTTPS proxy URLs, to `gateway.controlUi.allowedOrigins` explicitly.
### Hot reload modes
| `gateway.reload.mode` | Behavior |
| --------------------- | ------------------------------------------ |
| `off` | No config reload |
| `hot` | Apply only hot-safe changes |
| `restart` | Restart on reload-required changes |
| `hybrid` (default) | Hot-apply when safe, restart when required |
## Operator command set
```bash
openclaw gateway status
openclaw gateway status --deep # adds a system-level service scan
openclaw gateway status --json
openclaw gateway install
openclaw gateway restart
openclaw gateway stop
openclaw secrets reload
openclaw logs --follow
openclaw doctor
```
`gateway status --deep` is for extra service discovery (LaunchDaemons/systemd system units/schtasks), not a deeper RPC health probe.
## Multiple gateways (same host)
Most installs should run one gateway per machine. A single gateway can host multiple agents and channels. You only need multiple gateways when you intentionally want isolation or a rescue bot.
Useful checks:
```bash
openclaw gateway status --deep
openclaw gateway probe
```
What to expect:
- `gateway status --deep` can report `Other gateway-like services detected (best effort)` and print cleanup hints when stale launchd/systemd/schtasks installs are still around.
- `gateway probe` can warn about `multiple reachable gateway identities` when distinct gateways answer, or when OpenClaw cannot prove reachable targets are the same gateway. An SSH tunnel, proxy URL, or configured remote URL to the same gateway is one gateway with multiple transports, even when transport ports differ.
- If that is intentional, isolate ports, config/state, and workspace roots per gateway.
Checklist per instance:
- Unique `gateway.port`
- Unique `OPENCLAW_CONFIG_PATH`
- Unique `OPENCLAW_STATE_DIR`
- Unique `agents.defaults.workspace`
Example:
```bash
OPENCLAW_CONFIG_PATH=~/.openclaw/a.json OPENCLAW_STATE_DIR=~/.openclaw-a openclaw gateway --port 19001
OPENCLAW_CONFIG_PATH=~/.openclaw/b.json OPENCLAW_STATE_DIR=~/.openclaw-b openclaw gateway --port 19002
```
Detailed setup: [/gateway/multiple-gateways](/gateway/multiple-gateways).
## Remote access
Preferred: Tailscale/VPN.
Fallback: SSH tunnel.
```bash
ssh -N -L 18789:127.0.0.1:18789 user@gateway-host
```
Then connect clients locally to `ws://127.0.0.1:18789`.
<Warning>
SSH tunnels do not bypass gateway auth. For shared-secret auth, clients still
must send `token`/`password` even over the tunnel. For identity-bearing modes,
the request still has to satisfy that auth path.
</Warning>
See: [Remote Gateway](/gateway/remote), [Authentication](/gateway/authentication), [Tailscale](/gateway/tailscale).
## Supervision and service lifecycle
Use supervised runs for production-like reliability.
<Tabs>
<Tab title="macOS (launchd)">
```bash
openclaw gateway install
openclaw gateway status
openclaw gateway restart
openclaw gateway stop
```
Use `openclaw gateway restart` for restarts. Do not chain `openclaw gateway stop` and `openclaw gateway start` as a restart substitute.
On macOS, `gateway stop` uses `launchctl bootout` by default. This removes the LaunchAgent from the current boot session without persisting a disable, so KeepAlive auto-recovery still works after unexpected crashes and `gateway start` re-enables cleanly. To persistently suppress auto-respawn across reboots, pass `--disable`: `openclaw gateway stop --disable`.
LaunchAgent labels are `ai.openclaw.gateway` (default) or `ai.openclaw.<profile>` (named profile). `openclaw doctor` audits and repairs service config drift.
</Tab>
<Tab title="Linux (systemd user)">
```bash
openclaw gateway install
systemctl --user enable --now openclaw-gateway[-<profile>].service
openclaw gateway status
```
For persistence after logout, enable lingering:
```bash
sudo loginctl enable-linger $(whoami)
```
On a headless server without a desktop session, also make sure `XDG_RUNTIME_DIR` is set (`export XDG_RUNTIME_DIR=/run/user/$(id -u)`) before retrying `systemctl --user` commands.
Manual user-unit example when you need a custom install path:
```ini
[Unit]
Description=OpenClaw Gateway
After=network-online.target
Wants=network-online.target
StartLimitBurst=5
StartLimitIntervalSec=60
[Service]
ExecStart=/usr/local/bin/openclaw gateway --port 18789
Restart=always
RestartSec=5
RestartPreventExitStatus=78
TimeoutStopSec=30
TimeoutStartSec=30
SuccessExitStatus=0 143
OOMPolicy=continue
KillMode=control-group
[Install]
WantedBy=default.target
```
</Tab>
<Tab title="Windows (native)">
```powershell
openclaw gateway install
openclaw gateway status --json
openclaw gateway restart
openclaw gateway stop
```
Native Windows managed startup uses a Scheduled Task named `OpenClaw Gateway`
(or `OpenClaw Gateway (<profile>)` for named profiles). If Scheduled Task
creation is denied, OpenClaw falls back to a per-user Startup-folder launcher
that points at `gateway.cmd` inside the state directory.
</Tab>
<Tab title="Linux (system service)">
Use a system unit for multi-user/always-on hosts.
```bash
sudo systemctl daemon-reload
sudo systemctl enable --now openclaw-gateway[-<profile>].service
```
Use the same service body as the user unit, but install it under
`/etc/systemd/system/openclaw-gateway[-<profile>].service` and adjust
`ExecStart=` if your `openclaw` binary lives elsewhere.
Do not also let `openclaw doctor --fix` install a user-level gateway service for the same profile/port. Doctor refuses that automatic install when it finds a system-level OpenClaw gateway service; use `OPENCLAW_SERVICE_REPAIR_POLICY=external` when the system unit owns the lifecycle.
</Tab>
</Tabs>
Invalid configuration errors exit with code `78`. Linux systemd units use `RestartPreventExitStatus=78` to stop relaunching until the config is fixed. launchd and Windows Task Scheduler do not have an equivalent per-exit-code stop rule, so the Gateway also persists rapid unclean boot history and suppresses channel/provider account auto-start after repeated startup failures. In that safe mode the control plane still starts for inspection and repair, config hot reloads and `secrets.reload` refuse automatic channel restarts, and an explicit operator `channels.start` request can override the suppression.
## Dev profile quick path
```bash
openclaw --dev setup
openclaw --dev gateway --allow-unconfigured
openclaw --dev status
```
Defaults include isolated state/config and base gateway port `19001`.
## Protocol quick reference (operator view)
- First client frame must be `connect`.
- Gateway returns a `hello-ok` frame with a `snapshot` (`presence`, `health`, `stateVersion`, `uptimeMs`) plus `policy` limits (`maxPayload`, `maxBufferedBytes`, `tickIntervalMs`).
- `hello-ok.features.methods` / `events` are a conservative discovery list, not
a generated dump of every callable helper route.
- Requests: `req(method, params)``res(ok/payload|error)`.
- Common events include `connect.challenge`, `agent`, `chat`,
`session.message`, `session.operation`, `session.tool`, opt-in
`session.approval`, `sessions.changed`, `presence`, `tick`, `health`,
`heartbeat`, pairing/approval lifecycle events, and `shutdown`.
Agent runs are two-stage:
1. Immediate accepted ack (`status:"accepted"`)
2. Final completion response (`status:"ok"|"error"`), with streamed `agent` events in between.
See full protocol docs: [Gateway Protocol](/gateway/protocol).
## Operational checks
### Liveness
- Open WS and send `connect`.
- Expect `hello-ok` response with snapshot.
### Readiness
```bash
openclaw gateway status
openclaw channels status --probe
openclaw health
```
### Gap recovery
Events are not replayed. On sequence gaps, refresh state (`health`, `system-presence`) before continuing.
## Common failure signatures
| Signature | Likely issue |
| -------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| `refusing to bind gateway ... without auth` | Non-loopback bind without a valid gateway auth path |
| `another gateway instance is already listening` / `EADDRINUSE` | Port conflict |
| `Gateway start blocked: set gateway.mode=local` | Config set to remote mode, or `gateway.mode` is missing from a damaged config |
| `unauthorized` during connect | Auth mismatch between client and gateway |
For full diagnosis ladders, use [Gateway Troubleshooting](/gateway/troubleshooting).
## Safety guarantees
- Gateway protocol clients fail fast when Gateway is unavailable (no implicit direct-channel fallback).
- Invalid/non-connect first frames are rejected and closed.
- Graceful shutdown emits `shutdown` event before socket close.
## Related
- [Configuration](/gateway/configuration)
- [Gateway troubleshooting](/gateway/troubleshooting)
- [Background process](/gateway/background-process)
- [Health](/gateway/health)
- [Doctor](/gateway/doctor)
- [Authentication](/gateway/authentication)
- [Remote access](/gateway/remote)
- [Secrets management](/gateway/secrets)