OpenClaw Gateway CLI: Run, Query, and Discover Gateways

Learn how to use the openclaw gateway command to run, query, and discover gateways. Essential for developers managing OpenClaw's WebSocket server and its configuration.

Read this when

  • Running the Gateway from the CLI (dev or servers)
  • Debugging Gateway auth, bind modes, and connectivity
  • Discovering gateways via Bonjour (local + wide-area DNS-SD)
  • Integrating an external Gateway process supervisor

The Gateway functions as OpenClaw's WebSocket server, handling channels, nodes, sessions, and hooks. Every subcommand listed here falls under openclaw gateway ....

Run the Gateway

openclaw gateway
openclaw gateway run   # equivalent, explicit form

Startup behavior

  • Startup is refused unless gateway.mode=local appears in ~/.openclaw/openclaw.json. For ad-hoc or development scenarios, pass --allow-unconfigured; this skips the guard without writing or fixing any config.
  • On launch, deterministic legacy-key migrations run automatically for eligible invalid single-file configs, with no prompts, even during non-interactive service execution. Writing happens only after complete validation, plugins included, and the prior config stays in the .bak ring. Excluded are configs using $include, those managed by Nix, and ones created by a newer version. Refer to Legacy config key migrations.
  • When automatic migration fails to produce a valid config, an interactive terminal may offer to execute openclaw doctor --fix and retry startup once after user consent. In non-interactive mode, the command is printed instead. If the repaired config remains invalid, startup halts.
  • openclaw onboard --mode local and openclaw setup both generate gateway.mode=local. If the config file is present but gateway.mode is absent, the situation is treated as damaged or clobbered config, and the Gateway will not guess local for you. Re-run onboarding, set the key manually, or supply --allow-unconfigured.
  • Binding outside loopback without authentication is disallowed.
  • Currently, --bind values lan, tailnet, and custom resolve only over IPv4 paths; IPv6-only bring-your-own-host deployments require an IPv4 sidecar or proxy positioned before the Gateway.
  • SIGUSR1 causes an in-process restart once authorized. commands.restart (enabled by default) controls externally delivered SIGUSR1; setting it to false prevents manual OS-signal restarts. The agent-facing gateway tool is read-only, so agents request restarts via the human-approved openclaw delegation tool.
  • SIGINT/SIGTERM terminate the process but leave custom terminal state untouched. If you wrap the CLI in a TUI or raw-mode input, restore the terminal yourself before exiting.

Options

  • true, " type="number"> WebSocket port (default comes from config/env; typically 18789).

  • true, " type="string"> Bind mode options: loopback (default), lan, tailnet, auto, custom.

  • true, " type="string"> Shared token for connect.params.auth.token. When set, defaults to OPENCLAW_GATEWAY_TOKEN.

  • true, " type="string"> Auth mode choices: none, token, password, trusted-proxy.

  • true, " type="string"> Password for --auth password.

  • true, " type="string"> Load the Gateway password from a file.

  • true, " type="string"> Tailscale exposure options: off, serve, funnel.

  • --allow-unconfigured (boolean), Launch without enforcing gateway.mode=local. For ad-hoc/dev bootstrap only; does not persist or fix config.

  • --dev (boolean), Generate a dev config and workspace when absent (bypasses BOOTSTRAP.md).

  • --ambient-channels (boolean), Lets the Gateway pull channel settings straight from environment variables found in the surrounding context. Absent this, each channel needs its own explicit channels.<id> configuration section.

  • --dev-ambient-channels (boolean), Older name for --ambient-channels, kept for backward compatibility.

  • --reset (boolean), Wipes development configuration, stored credentials, active sessions, and the workspace area. Mandatory that --dev be present.

  • --force (boolean), Terminates whatever listener already occupies the target port prior to launch. Within a non-interactive shell, a confirmed Gateway listener will not be killed by this; instead rely on --dev or a dedicated --profile with an unoccupied port.

  • --verbose (boolean), Emits detailed logging to both stdout and stderr.

  • --cli-backend-logs (boolean), Restricts console output to CLI backend messages only, which also turns on stdout/stderr.

  • true, " type="string" default="auto"> Chooses the WebSocket log format from auto, full, or compact.

  • --compact (boolean), Shorthand for --ws-log compact.

  • --raw-stream (boolean), Writes each raw model stream event as a JSONL entry.

  • true, " type="string"> Filesystem location for the raw stream JSONL output.

The flag --claude-cli-logs has been superseded by --cli-backend-logs.

When --bind custom is in play, gateway.customBindHost must hold an IPv4 address. If that address is anything other than 127.0.0.1 or 0.0.0.0, a matching 127.0.0.1 listener on the same port becomes necessary for clients on the same host; should either listener fail to bind, startup errors out. A wildcard 0.0.0.0 does not introduce an extra mandatory alias. For IPv6-only bring-your-own-host deployments, place an IPv4 sidecar or proxy ahead of the Gateway.

Reveal the configured token

Execute the following on the Gateway machine whenever a client requires the configured shared token:

openclaw gateway auth-token --show

This command resolves gateway.auth.token, OPENCLAW_GATEWAY_TOKEN, and any configured SecretRefs, outputting only the token itself. An interactive terminal is a prerequisite, and redirected or piped output is refused so the credential never quietly lands in command logs. Treat whatever appears on screen as sensitive.

If no persistent token has been set up, run openclaw doctor --generate-gateway-token, restart the Gateway, then execute the command once more. Generic openclaw config get output stays masked, --json included.

Restart the Gateway

openclaw gateway restart
openclaw gateway restart --safe
openclaw gateway restart --safe --skip-deferral
openclaw gateway restart --force
openclaw gateway restart --wait 30s

--safe has the running Gateway check active work ahead of time and plan a single combined restart for when that work finishes. That wait tops out at 5 minutes, after which the restart is forced regardless. --safe cannot be used alongside --force or --wait.

--skip-deferral only bypasses the safe-restart gate that defers for active work. It can push the Gateway into shutdown even when active-work blockers are being reported, though the close-stage pending-reply drain still runs before the process exits. --safe is required here; use it when a deferral is stuck on a runaway task and reply delivery can still be given time to finish.

--wait <duration> changes the drain budget for a standard, non-safe restart. It accepts raw milliseconds or unit suffixes like ms, s, m, h, and d (for instance 30s, 5m, 1h30m); --wait 0 means wait forever. It is incompatible with --force and --safe.

--force bypasses the active-work drain entirely and restarts at once. A plain restart with no flags preserves the usual service-manager restart behavior.

Warning

An inline --password may show up in local process listings. Go with --password-file, an env variable, or a SecretRef-backed gateway.auth.password instead.

Install identity

Service management (install, start, stop, restart, uninstall, Doctor service repair, and self-update service handling) belongs to the install that owns the host service. That is the canonical .openclaw directory under the OS account home, or the .openclaw-<profile> directory a named profile projects there. Named profiles use distinct native service identities.

OPENCLAW_HOME, or an OPENCLAW_STATE_DIR or OPENCLAW_CONFIG_PATH that points elsewhere, is treated as isolated state and skipped. A relocated or copied state tree cannot adopt and rewrite the account's host service.

On macOS and Windows, native service-managed profile names must be lowercase. Runtime-only profiles may still use uppercase, but case-distinct names such as Main and main share paths on normal case-insensitive filesystems and cannot safely own separate native services. On macOS, the lowercase names gateway and node are also unavailable for native service management because their historical LaunchAgent labels collide with the default Gateway and node-host services.

Named profiles must also use the native service identity derived from OPENCLAW_PROFILE. Unset OPENCLAW_LAUNCHD_LABEL, OPENCLAW_SYSTEMD_UNIT, or OPENCLAW_WINDOWS_TASK_NAME before service management; custom identities remain available for the default profile or runtime-only/external-supervisor setups.

On Linux, openclaw gateway install --force refuses a sealed systemd service definition, or one whose write authority cannot be verified, before changing configuration, authentication tokens, or service files. The error keeps its SERVICE_DEFINITION_SEALED or SERVICE_DEFINITION_UNKNOWN prefix and adds a reason tag and next action, without printing private paths, config, environment values, or underlying inspection errors.

For [unsafe-permissions], inspect the named artifact category locally. The service directory is ~/.config/systemd/user; on a fresh install, its nearest existing ancestor may be ~/.config. The service state directory belongs to the selected profile. Check directory metadata, not file contents:

ls -ld ~/.config ~/.config/systemd ~/.config/systemd/user

Missing directories are normal on a fresh install. After confirming the affected path is yours and is not intentionally shared, remove group/other write access with chmod go-w <path> and retry the same command. Mode 0700 is appropriate for private directories. Do not recursively chmod, take ownership of system paths, or use sudo/--force to bypass the check. Foreign-owned files and sealed mounts require the deployment owner; inspection failures require restoring filesystem or native service-manager access first.

Type-wide service.d defaults are inspected as shared read-only inputs and do not require write access. Root-owned selected units and unit-specific drop-ins remain protected.

External supervisors

Set OPENCLAW_SUPERVISOR_MODE=external only when another process manager owns the Gateway lifecycle. In this mode:

  • openclaw gateway restart preserves the existing safe, forced, and bounded-wait behavior while targeting the verified running Gateway instead of launchd, systemd, or Task Scheduler. Exact-lock restart delivery runs inside that Gateway, so a replacement CLI does not migrate shared state before the old process hands off.
  • Native service install, start, stop, and uninstall operations are refused with guidance to use the external supervisor.
  • OpenClaw self-update is refused so the supervisor can stop the Gateway, replace and finalize the runtime, and restart it safely.
  • A fresh-process restart writes a bounded SQLite handoff before clean exit. If persistence fails, the Gateway falls back to an in-process restart instead of exiting without a consumable handoff.

An external supervisor can also claim durable ownership of shared-state writes:

OPENCLAW_SUPERVISOR_MODE=external \
  openclaw database ownership claim --manager gateway-supervisor --json

Before claiming, stop and verify every older Gateway, CLI, Doctor, updater, and native app process that can write the shared state database. Pre-contract processes do not understand the ownership row and cannot be retroactively fenced. Claim only after every remaining writer uses ownership-aware code and carries OPENCLAW_SUPERVISOR_MODE=external.

The claim is idempotent for the same stable manager identifier and refuses a different manager. There is no automatic claim or unclaim path. Once claimed, unmarked writable shared-state opens fail before permissions, schema migration, additive repair, compaction, or other mutation. Read-only access remains available. This is protection against accidental unmarked same-user writers, not an authentication or lease protocol.

For upgrades and rollbacks, have the supervisor create a consolidated WAL-consistent copied snapshot with no SQLite sidecars, then run the target release's own openclaw database preflight <copied-state.sqlite> --json before activation. Numeric schema versions alone do not prove that a same-version additive shape is compatible. See Database schemas.

OPENCLAW_SERVICE_REPAIR_POLICY=external remains a separate Doctor repair policy. It does not declare runtime ownership; supervisors that need both behaviors should set both variables.

External supervisors can negotiate and consume restart handoffs through the hidden machine contract:

openclaw gateway restart-handoff capabilities --json
openclaw gateway restart-handoff consume --expected-pid <pid> --json

Protocol version 1 supports the consume operation. Consumption validates the expected PID and bounded handoff fields inside one immediate SQLite transaction. An accepted handoff is deleted before success is returned, so concurrent or replayed consumers cannot both accept it. A PID mismatch is retained for the matching owner; missing, expired, and invalid rows do not authorize a restart.

Valid machine requests return JSON with exit code 0, including non-restart results. Invalid arguments return reason: "invalid-expected-pid" with exit code 2; state-store failures return reason: "store-unavailable" with exit code 1. Supervisors should probe capabilities on the exact runtime or launcher they will use rather than infer support from an OpenClaw version string or read the private SQLite schema directly.

Gateway profiling

  • OPENCLAW_GATEWAY_STARTUP_TRACE=1 captures startup phase timing, with eventLoopMax delay and plugin lookup-table durations broken out per phase (installed-index, manifest registry, startup planning, owner-map work).
  • OPENCLAW_GATEWAY_RESTART_TRACE=1 emits restart-scoped restart trace: lines covering signal handling, active-work drain, shutdown phases, next start, ready timing, and memory metrics.
  • OPENCLAW_DIAGNOSTICS=timeline combined with OPENCLAW_DIAGNOSTICS_TIMELINE_PATH=<path> produces a best-effort JSONL startup diagnostics timeline aimed at external QA harnesses (equivalent to config diagnostics.flags: ["timeline"]; the path remains env-only). Adding OPENCLAW_DIAGNOSTICS_EVENT_LOOP=1 pulls in event-loop samples.
  • pnpm build followed by pnpm test:startup:gateway -- --runs 5 --warmup 1 measures Gateway startup against the built CLI entry: first process output, /healthz, /readyz, startup trace timings, event-loop delay, and plugin lookup-table timing.
  • pnpm build then pnpm test:restart:gateway -- --case skipChannels --runs 1 --restarts 5 gauges in-process restart on macOS or Linux (Windows unsupported; restart needs SIGUSR1). It relies on SIGUSR1, turns on both traces in the child process, and logs next /healthz, next /readyz, downtime, ready timing, CPU, RSS, and restart trace metrics.
  • /healthz checks liveness; /readyz indicates usable readiness. Treat trace lines and benchmark output as owner-attribution signal, not a definitive performance verdict from a single span or sample.

Query a running Gateway

All query commands rely on WebSocket RPC.

Output modes

  • Default: human-readable (colored in TTY).
  • --json: machine-readable JSON (no styling/spinner).
  • --no-color (or NO_COLOR=1): disable ANSI while keeping human layout.

Shared options

  • --url <url>: Gateway WebSocket URL.
  • --token <token>: Gateway token.
  • --password <password>: Gateway password.
  • --timeout <ms>: timeout/budget (default varies per command; see each command below).
  • --expect-final: wait for a "final" response (agent calls).

Note

When --url is set, the CLI won't fall back to config or environment credentials. Pass --token or --password explicitly. Missing explicit credentials is an error.

gateway health

openclaw gateway health --url ws://127.0.0.1:18789
openclaw gateway health --port 18789

/healthz acts as a liveness probe: it returns as soon as the server can answer HTTP. /readyz is stricter and stays red while startup plugin sidecars, channels, or configured hooks are still settling. Local or authenticated detailed /readyz responses include an eventLoop diagnostic block (delay, utilization, CPU-core ratio, degraded flag).

  • true, " type="number"> Target a local loopback Gateway on this port. Overrides OPENCLAW_GATEWAY_URL and OPENCLAW_GATEWAY_PORT for this call.

gateway usage-cost

Fetch usage-cost summaries from session logs.

openclaw gateway usage-cost
openclaw gateway usage-cost --days 7
openclaw gateway usage-cost --agent work --json
openclaw gateway usage-cost --all-agents
openclaw gateway usage-cost --json
  • true, " type="number" default="30"> Number of days to include.

  • true, " type="string"> Scope the summary to one configured agent id.

  • --all-agents (boolean), Aggregate across all configured agents. Cannot combine with --agent.

gateway stability

Fetch the recent diagnostic stability recorder from a running Gateway.

openclaw gateway stability
openclaw gateway stability --type payload.large
openclaw gateway stability --bundle latest
openclaw gateway stability --bundle latest --export
openclaw gateway stability --json
  • true, " type="number" default="25"> Maximum recent events to include (max 1000).

  • true (true), " type="string"> Filter by diagnostic event type, e.g. payload.large or diagnostic.memory.pressure.

  • true, " type="number"> Include only events after a diagnostic sequence number.

  • --bundle [path] (string), Read a persisted stability bundle instead of calling the running Gateway. --bundle latest (or bare --bundle) picks the newest bundle under the state directory; you can also pass a bundle JSON path directly.

  • --export (boolean), Write a shareable support diagnostics zip instead of printing stability details.

  • true, " type="string"> Destination for --export output.

Privacy and bundle behavior

  • Operational metadata is what records retain: event names, counts, byte sizes, memory readings, queue/session state, approval ids, channel/plugin names, and redacted session summaries. Excluded are chat text, webhook bodies, tool outputs, raw request/response bodies, tokens, cookies, secret values, hostnames, and raw session ids. Turning on diagnostics.enabled: false completely disables the recorder.
  • The same diagnostic snapshot gets written to ~/.openclaw/logs/stability/openclaw-stability-*.json when the recorder has events, covering fatal Gateway exits, shutdown timeouts, and restart startup failures. Use openclaw gateway stability --bundle latest to inspect the newest bundle; --limit, --type, and --since-seq also apply to bundle output.

gateway diagnostics export

Generate a local diagnostics zip meant for bug reports. For privacy details and bundle contents, refer to Diagnostics Export.

openclaw gateway diagnostics export
openclaw gateway diagnostics export --output openclaw-diagnostics.zip
openclaw gateway diagnostics export --json
  • true, " type="string"> Where to write the zip. Falls back to a support export under the state directory.

  • true, " type="number" default="5000"> Maximum sanitized log lines to include.

  • true, " type="number" default="1000000"> Maximum log bytes to inspect.

  • true, " type="string"> Gateway WebSocket URL for the health snapshot.

  • true, " type="string"> Gateway token for the health snapshot.

  • true, " type="string"> Gateway password for the health snapshot.

  • true, " type="number" default="3000"> Status/health snapshot timeout.

  • --no-stability-bundle (boolean), Skip persisted stability bundle lookup.

  • --json (boolean), Print the written path, size, and manifest as JSON.

The export bundles: manifest.json (file inventory), summary.md (Markdown summary), diagnostics.json (top-level config/logs/discovery/stability/status/health summary), config/sanitized.json, status/gateway-status.json, health/gateway-health.json, logs/openclaw-sanitized.jsonl, and stability/latest.json when a bundle exists.

Sharing is the intended use. It carries operational details that aid debugging: safe log fields, subsystem names, status codes, durations, configured modes, ports, plugin/provider ids, non-secret feature settings, and redacted operational log messages. Chat text, webhook bodies, tool outputs, credentials, cookies, account/message identifiers, prompt/instruction text, hostnames, and secret values are omitted or redacted. If a log message resembles user/chat/tool payload text (e.g. "user said", "chat text", "tool output", "webhook body"), the export records only that a message was omitted plus its byte count.

gateway status

Displays the Gateway service (launchd/systemd/schtasks) along with an optional connectivity/auth probe.

openclaw gateway status
openclaw gateway status --json
openclaw gateway status --require-rpc
openclaw gateway status --port 19001
  • true, " type="string"> Probe this explicit WebSocket URL instead of the service-derived target. Cannot combine with --port.

  • true, " type="number"> Select a local Gateway port using the invoking CLI config for auth and TLS. Accepts gateway --port 19001 status and gateway status --port 19001; an explicit status port wins. Native service details remain visible as diagnostics but do not select the probe target.

  • true, " type="string"> Token auth for the probe.

  • true, " type="string"> Password auth for the probe.

  • true, " type="number" default="10000"> Probe timeout.

  • --no-probe (boolean), Skip the connectivity probe (service-only view).

  • --deep (boolean), Scan system-level services too.

  • --require-rpc (boolean), Upgrade the connectivity probe to a read probe and exit non-zero if it fails. Cannot combine with --no-probe.

Status semantics

  • Remains usable for troubleshooting even when the local CLI configuration is absent or broken.
  • The default output demonstrates service state, WebSocket connectivity, and the auth capability visible during handshake, not read/write/admin operations.
  • Probes avoid mutating first-time device auth: they use a cached device token if one is present, but never generate a new CLI device identity or read-only pairing record just to check status.
  • Resolves configured auth SecretRefs for probe auth when feasible. If a required SecretRef cannot be resolved, --json reports rpc.authWarning when probe connectivity or auth fails; pass --token/--password explicitly or correct the secret source. Unresolved-auth warnings are suppressed once the probe succeeds.
  • JSON output includes gateway.version when the running Gateway reports it; --require-rpc can fall back to the status.runtimeVersion RPC payload if the handshake probe cannot provide version metadata.
  • Use --require-rpc in scripts or automation when a listening service is insufficient and you also need read-scope RPC to be healthy.
  • --deep scans for extra launchd/systemd/schtasks installs; when multiple gateway-like services are detected, human output prints cleanup hints (usually run one gateway per machine) and reports a recent supervisor restart handoff when applicable.
  • --deep also runs config validation in plugin-aware mode (pluginValidation: "full") and surfaces plugin manifest warnings (e.g. missing channel config metadata). Default gateway status keeps the fast read-only path that skips plugin validation.
  • On Linux, status reports the effective service currently loaded by systemd, including loaded drop-ins. If the unit or a drop-in changed on disk, Systemd reload: pending means you must run systemctl --user daemon-reload (or sudo systemctl daemon-reload for a system service) before those changes take effect.
  • Human output includes the resolved file log path plus CLI-vs-service config paths/validity to help diagnose profile or state-dir drift.
  • Human output includes Gateway heap: with configured service heap controls and a separate install-time recommendation based on memory visible to the CLI. JSON output exposes the same report as service.gatewayHeap. Neither is a measurement of the running Gateway's V8 heap ceiling; use runtime memory diagnostics for that.

Linux systemd auth-drift checks

  • Service auth drift checks read both Environment= and EnvironmentFile= from the unit (including %h, quoted paths, multiple files, and optional - files).
  • Resolves gateway.auth.token SecretRefs using merged runtime env (service command env first, then process env fallback).
  • Token-drift checks skip config token resolution when token auth is not effectively active (gateway.auth.mode explicitly password/none/trusted-proxy, or mode unset where password can win and no token candidate can win).

gateway probe

The "debug everything" command. It always probes:

  • your configured remote gateway (if set), and
  • localhost (loopback), even if remote is configured.

Passing --url adds that explicit target ahead of both. Human output labels targets URL (explicit), Remote (configured) / Remote (configured, inactive), and Local loopback.

Note

If multiple probe targets are reachable, all are printed. An SSH tunnel, TLS/proxy URL, and configured remote URL can point at the same gateway even with different transport ports; multiple_gateways is reserved for distinct or identity-ambiguous reachable gateways. Running multiple gateways is supported for isolated profiles (e.g. a rescue bot), but most installs run a single gateway.

openclaw gateway probe
openclaw gateway probe --json
openclaw gateway probe --port 18789
  • true, " type="number"> Use this port for the local loopback probe target and SSH tunnel remote port. Without --url, this selects only the local loopback target instead of configured gateway environment URL, environment port, or remote targets.

Interpretation

  • Reachable: yes means at least one target accepted a WebSocket connect.
  • Capability: read-only|write-capable|admin-capable|pairing-pending|connect-only reports what the probe could prove about auth, separate from reachability.
  • Read probe: ok means read-scope detail RPC calls (health/status/system-presence/config.get) also succeeded.
  • Read probe: limited - missing scope: operator.read means connect succeeded but read-scope RPC is limited. Reported as degraded reachability, not full failure.
  • Read probe: failed after Connect: ok means the WebSocket connected but follow-up read diagnostics timed out or failed, also degraded, not unreachable.
  • Like gateway status, probe reuses existing cached device auth but does not create first-time device identity or pairing state.
  • Exit code is non-zero only when no probed target is reachable.

JSON output

Top level:

  • ok: a minimum of one target must be reachable.
  • degraded: at least one target accepted a connection but never finished the full detail RPC diagnostics.
  • capability: the highest capability observed across reachable targets (read_only, write_capable, admin_capable, pairing_pending, connected_no_operator_scope, or unknown).
  • primaryTargetId: the preferred target to designate as the active winner, prioritized as explicit URL, SSH tunnel, configured remote, then local loopback.
  • warnings[]: best-effort warning entries that include code, message, and optionally targetIds.
  • network: local loopback or tailnet URL suggestions derived from the current configuration and host networking.
  • discovery.timeoutMs / discovery.count: the discovery budget and result count actually applied during this probe pass.

For each target (targets[].connect): ok (reachability plus degraded classification), rpcOk (full detail RPC success), scopeLimited (detail RPC failed due to missing operator scope).

For each target (targets[].auth): role and scopes are reported in hello-ok when they exist, along with the exposed capability classification.

Common warning codes

  • ssh_tunnel_failed: SSH tunnel setup failed, so the command reverted to direct probes.
  • multiple_gateways: multiple distinct gateway identities were reachable, or OpenClaw could not confirm that reachable targets correspond to the same gateway. This does not apply when an SSH tunnel, proxy URL, or configured remote URL points to the same gateway.
  • auth_secretref_unresolved: a configured auth SecretRef could not be resolved for a target that failed.
  • probe_scope_limited: WebSocket connection succeeded, but the read probe was constrained by a missing operator.read.
  • local_tls_runtime_unavailable: local Gateway TLS is enabled, yet OpenClaw could not retrieve the local certificate fingerprint.

Remote over SSH (Mac app parity)

The macOS app's "Remote over SSH" mode relies on a local port-forward, making a loopback-only remote gateway accessible at ws://127.0.0.1:<port>.

CLI equivalent:

openclaw gateway probe --ssh user@gateway-host
  • true, " type="string"> user@host or user@host:port (port defaults to 22).

OpenClaw only launches an SSH client located in OS-managed system directories. On native Windows, enable the OpenSSH Client optional feature; it is installed at %SystemRoot%\System32\OpenSSH.

  • true, " type="string"> Identity file.

  • --ssh-auto (boolean), Select the first discovered gateway host as the SSH target from the resolved discovery endpoint (local. plus the configured wide-area domain, if present). TXT-only hints are disregarded.

Config defaults (optional): gateway.remote.sshTarget, gateway.remote.sshIdentity.

gateway call <method>

Low-level RPC utility.

openclaw gateway call status
openclaw gateway call health --port 18999
openclaw gateway call logs.tail --params '{"limit": 200}'
  • true, " type="string" default="{}"> JSON object string for parameters.

  • true, " type="string"> Gateway WebSocket URL.

  • true, " type="number"> Target a local loopback Gateway on this port. For this call, it overrides OPENCLAW_GATEWAY_URL and OPENCLAW_GATEWAY_PORT. It cannot be used with --url.

  • true, " type="string"> Gateway token.

  • true, " type="string"> Gateway password.

  • true, " type="number" default="10000"> Timeout budget.

  • --expect-final (boolean), Primarily for agent-style RPCs that stream intermediate events before delivering a final payload.

  • --json (boolean), Output in machine-readable JSON.

openclaw.setup.detect applies a 40-second default so the Gateway can wrap up its bounded AI-access scan. An explicit --timeout still takes priority.

Note

--params has to be valid JSON, and each method checks its own parameter shape (extra or misnamed fields get rejected). For a local Gateway on a custom port, use --port; explicit --url targets still demand explicit credentials.

gateway suspend

Get an idle Gateway ready for a cooperative host freeze or snapshot. Without --wait, active work exits with a nonzero code and blocker details. With --wait, the CLI keeps retrying up to the bounded deadline, using a single stable request ID.

openclaw gateway suspend
openclaw gateway suspend --request-id snapshot-2026-08-11 --wait 30
openclaw gateway suspend --port 18999 --json

The ready output shows the suspension ID, lease expiry, and the corresponding resume command. Standard RPC options like --url, --token, --password, --timeout, --json, and --port are all supported.

gateway resume <suspensionId>

End a prepared suspension after a thaw or when the host operation gets abandoned.

openclaw gateway resume <suspensionId>
openclaw gateway resume <suspensionId> --port 18999 --json

An expired or already resumed lease counts as a successful no-op. A different active suspension ID is turned down.

Manage the Gateway service

openclaw gateway install
openclaw gateway start
openclaw gateway stop
openclaw gateway restart
openclaw gateway uninstall

Install with a wrapper

Use --wrapper when the managed service has to launch through another executable, such as a secrets manager shim or a run-as helper. The wrapper gets the standard Gateway args and must eventually exec openclaw or Node with those args.

cat > ~/.local/bin/openclaw-doppler <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
exec doppler run --project my-project --config production -- openclaw "$@"
EOF
chmod +x ~/.local/bin/openclaw-doppler

openclaw gateway install --wrapper ~/.local/bin/openclaw-doppler --force
openclaw gateway restart

The environment can also set the wrapper. gateway install checks that the path points to an executable file, writes the wrapper into the service ProgramArguments, and stores OPENCLAW_WRAPPER in the service environment so later forced reinstalls, updates, and doctor repairs can use it.

OPENCLAW_WRAPPER="$HOME/.local/bin/openclaw-doppler" openclaw gateway install --force
openclaw doctor

To remove a persisted wrapper, clear OPENCLAW_WRAPPER while reinstalling:

OPENCLAW_WRAPPER= openclaw gateway install --force
openclaw gateway restart

Command options

  • gateway status: --url, --port, --token, --password, --timeout, --no-probe, --require-rpc, --deep, --json
  • gateway install: --port, --runtime <node|bun> (default: node), --token, --wrapper <path>, --force, --json
  • gateway restart: --safe, --skip-deferral, --force, --wait <duration>, --preserve-definition, --json
  • gateway uninstall|start: --json
  • gateway stop: --disable, --force, --json

Service runtime

  • As the managed Gateway runtime, Node stands as the primary choice, the default option, and the one we recommend.
  • With WAL-reset-safe node:sqlite, Bun 1.4+ can be selected explicitly through gateway install --runtime bun, though it requires opting in.

Lifecycle behavior

  • Running gateway start twice has no side effects: if the managed service is already up, it simply reports the active process and does nothing else. A service that is loaded but stopped gets started, just as before.
  • When no managed service exists on the system, gateway start outputs installation guidance and returns a nonzero exit code. gateway restart may first restore a LaunchAgent that is installed yet unloaded, or a verified unmanaged Gateway; if neither a managed service nor a recovery path can handle the request, the same guidance is printed and the exit code is nonzero. Attempting to stop a service that is not present still succeeds as a no-op.
  • Should gateway start or gateway restart have to fix an outdated service definition, the operation is blocked if the shell invoking it resolves a state directory, config path, or port that differs from what the installed service uses. Align or clear the conflicting environment overrides, or deliberately retarget the service with openclaw gateway install --force.
  • On Linux, gateway start and gateway restart also decline ineffective repairs when a user-owned systemd drop-in overrides the command or working directory. Check the effective unit with systemctl --user cat <unit>.service, then modify or delete that drop-in. gateway install --force only rewrites the managed base unit and warns if the override is still present; Environment= drop-ins continue to work.
  • gateway restart --preserve-definition only restarts a native service that can be inspected, skips automatic definition repair, and verifies health at the port of the installed launcher. It will not bring back an unmanaged listener and cannot be used alongside --safe or external supervision. On macOS it can bootstrap an unloaded readable plist without touching the plist, environment, wrapper, or permissions; a denied native activation fails without any file repair. On Windows it also keeps existing Startup entries. The older daemon restart command accepts the same option. Older CLIs reject the option before any restart or repair begins.
  • During writable Linux service installs or refreshes, leave the unit and state directories in place and avoid concurrent manual edits. OpenClaw serializes its own writers and stops on detected changes, but it cannot coordinate arbitrary filesystem modifications. If a parent directory is moved or replaced mid-publication, a temporary file may be left inside the moved directory; check it before retrying.
  • To restart a managed service, call gateway restart. Do not substitute a restart by chaining gateway stop and gateway start.
  • In a non-interactive shell, gateway stop demands --force. Interactive terminals keep the existing behavior without a prompt. For automation and tests, choose gateway run --dev or an isolated --profile with an available port.
  • On macOS, gateway stop defaults to launchctl bootout, which unloads the LaunchAgent from the current boot session without recording a disable, so KeepAlive auto-recovery remains active for future crashes and gateway start re-enables cleanly without a manual launchctl enable. To persistently suppress KeepAlive and RunAtLoad so the gateway does not respawn until the next explicit gateway start, pass --disable; use this when a manual stop should survive reboots.
  • Gateway lifecycle mutations append best-effort key-value audit records to <state-dir>/logs/gateway-restart.log, covering CLI start, stop, and restart operations, safe restart requests, supervisor restarts, and detached handoffs.
  • Lifecycle commands accept --json for scripting.

Managed Gateway heap sizing

  • For a managed Node Gateway without an existing heap setting, gateway install inserts --max-old-space-size into Node's launch arguments, ahead of the entry script. It explicitly clears NODE_OPTIONS in the service environment so ambient service-manager preload/debug flags cannot leak into the Gateway. Plain spawned Node processes do not inherit the new automatic budget through NODE_OPTIONS; Node's fork and Worker inheritance rules are unchanged.
  • Capacity is the smaller of valid physical RAM and a valid constraint reported by Node, never fluctuating free RAM. With no usable capacity reading, Node keeps its native default. The installer targets 50% of capacity, with a nominal 2048 MiB floor and a cap of the greater of 8192 MiB or 25% of capacity. A final 75% capacity cap reserves native-memory headroom and can put small-host budgets below the nominal floor.
  • Examples: 32 GiB capacity selects 8 GiB old space; 64 GiB selects 16 GiB; 128 GiB selects 32 GiB. Old space is only part of V8's total heap, and neither is a limit on total process memory (RSS). Raising the ceiling does not preallocate that memory.
  • Existing managed service heap controls are preserved across forced reinstalls and doctor repairs, including absolute old-space, percentage old-space, and total-heap flags. Only heap flags survive managed NODE_OPTIONS sanitization; arbitrary preload/debug flags do not. Put intentional preload/debug settings in an operator-owned systemd Environment= drop-in, or set them inside an installed wrapper before it launches Node. Do not edit the generated service environment for those settings. Existing stored numbers are preserved even when they resemble an older automatic default or exceed the new recommendation.
  • When an operator-owned service override controls NODE_OPTIONS (including an empty value or reset), regeneration does not add a new automatic heap argument. Operator values and drop-in files stay separate from the managed base. Existing managed argv controls remain: Node's argv wins over NODE_OPTIONS for the same option, and percentage old-space sizing takes precedence over absolute old-space sizing. Inspect both surfaces before changing a cap.
  • Ambient installer NODE_OPTIONS and the installer's own Node arguments are not saved as Gateway heap settings. The budget is chosen at installation and takes effect when the service process starts; it is not recalculated while the Gateway runs. Upgrading OpenClaw alone does not resize a running Gateway, and foreground launches do not replace themselves to apply this policy.
  • The installer's memory constraints can differ from the future service's constraints. Node/libuv reporting is platform-dependent and does not guarantee detection of every ancestor cgroup limit; inspect the actual service or container limits before increasing a budget.
  • This policy applies to managed Node Gateway launches, not foreground gateway run, custom supervisors, Docker runtime commands, Bun, or node-host services. Those retain their own runtime configuration. See memory troubleshooting for explicit native Node settings.

Auth and SecretRefs at install time

  • When token auth requires a token and gateway.auth.token is SecretRef-managed, gateway install validates that the SecretRef is resolvable but does not persist the resolved token into service environment metadata.
  • If token auth requires a token and the configured token SecretRef is unresolved, install fails closed instead of persisting fallback plaintext.
  • For password auth on gateway run, prefer OPENCLAW_GATEWAY_PASSWORD, --password-file, or a SecretRef-backed gateway.auth.password over inline --password.
  • In inferred auth mode, shell-only OPENCLAW_GATEWAY_PASSWORD does not relax install token requirements; use durable config (gateway.auth.password or config env) when installing a managed service.
  • If both gateway.auth.token and gateway.auth.password are configured and gateway.auth.mode is unset, install is blocked until mode is set explicitly.

Discover gateways (Bonjour)

gateway discover scans for Gateway beacons (_openclaw-gw._tcp).

  • Multicast DNS-SD: local.
  • Unicast DNS-SD (wide-area Bonjour): pick a domain (for instance, openclaw.internal.) and configure split DNS along with a DNS server; refer to Bonjour.

Beacons are advertised only by gateways that have Bonjour discovery turned on (the default setting).

Every beacon carries TXT hints: role (indicates gateway role), transport (transport type, such as gateway), gatewayPort (WebSocket port, typically 18789), tailnetDns (MagicDNS hostname, if present), and gatewayTls / gatewayTlsSha256 (TLS status plus cert fingerprint). In full discovery mode (discovery.mdns.mode: "full"; the default is "minimal", which excludes them, so clients fall back to port 22 for SSH targets), only sshPort and cliPath get published.

gateway discover

openclaw gateway discover
  • true, " type="number" default="2000"> Timeout applied per command (browse or resolve).

  • --json (boolean), Emits machine-readable output (also turns off styling and the spinner).

Examples:

openclaw gateway discover --timeout 4000
openclaw gateway discover --json | jq '.beacons[].wsUrl'

Note

  • When a wide-area domain is active, scans cover local. in addition to that domain.
  • In JSON output, wsUrl comes from the resolved service endpoint, not from TXT-only hints like lanHost or tailnetDns.
  • On both local. mDNS and wide-area DNS-SD, discovery.mdns.mode governs whether sshPort/cliPath are published (see above).
5,977 words · updated Sep 1, 2026