diff --git a/docs/.i18n/glossary.zh-CN.json b/docs/.i18n/glossary.zh-CN.json
index 5252dadb3ff..c946bf68e15 100644
--- a/docs/.i18n/glossary.zh-CN.json
+++ b/docs/.i18n/glossary.zh-CN.json
@@ -131,6 +131,14 @@
"source": "Gateway RPC reference",
"target": "Gateway RPC 参考"
},
+ {
+ "source": "Building a Gateway client",
+ "target": "构建 Gateway 客户端"
+ },
+ {
+ "source": "Embedding OpenClaw",
+ "target": "嵌入 OpenClaw"
+ },
{
"source": "Secure file operations",
"target": "安全文件操作"
diff --git a/docs/docs.json b/docs/docs.json
index 43d1203c906..1c93a25ffff 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -1686,6 +1686,8 @@
"group": "Protocols and APIs",
"pages": [
"gateway/protocol",
+ "gateway/clients",
+ "gateway/embedding",
"gateway/bridge-protocol",
"gateway/openai-http-api",
"gateway/openresponses-http-api",
diff --git a/docs/docs_map.md b/docs/docs_map.md
index 350e3efe62c..041dbde9f73 100644
--- a/docs/docs_map.md
+++ b/docs/docs_map.md
@@ -3247,6 +3247,20 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- H2: Troubleshooting
- H2: Related
+## gateway/clients.md
+
+- Route: /gateway/clients
+- Headings:
+ - H2: Install the packages
+ - H2: Choose scopes and pair the device
+ - H2: Advertise client capabilities
+ - H2: Recover state after reconnect
+ - H2: Use history metadata and stable anchors
+ - H2: Subscribe instead of polling usage
+ - H2: Backfill exec approvals
+ - H2: Track protocol versions
+ - H2: Related
+
## gateway/cloud-workers.md
- Route: /gateway/cloud-workers
@@ -3496,6 +3510,19 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- H2: Detailed behavior and rationale
- H2: Related
+## gateway/embedding.md
+
+- Route: /gateway/embedding
+- Headings:
+ - H2: Start the child with an embedding preset
+ - H3: Electron shell snapshot warning
+ - H2: Handle invalid config by exit code
+ - H2: Wait for protocol readiness
+ - H2: Interpret restart and shutdown
+ - H2: Use RPC instead of state files
+ - H2: Install; do not flatten
+ - H2: Related
+
## gateway/external-apps.md
- Route: /gateway/external-apps
@@ -3793,6 +3820,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- Route: /gateway/protocol
- Headings:
+ - H2: npm packages
- H2: Transport and framing
- H2: Handshake
- H3: Worker role and closed protocol
diff --git a/docs/gateway/clients.md b/docs/gateway/clients.md
new file mode 100644
index 00000000000..7542ee001f6
--- /dev/null
+++ b/docs/gateway/clients.md
@@ -0,0 +1,197 @@
+---
+summary: "Build a third-party operator or WebChat client for the Gateway WebSocket protocol"
+read_when:
+ - Building an operator, dashboard, or WebChat client outside the OpenClaw repository
+ - Implementing Gateway reconnect, history, approvals, or device pairing
+ - Updating a third-party client for a new Gateway wire version
+title: "Building a Gateway client"
+---
+
+Use the published Gateway packages to build operator dashboards, WebChat clients,
+and other third-party applications. This guide covers the client lifecycle around
+the wire contract: authentication, capabilities, reconnect recovery, history,
+subscriptions, and version upgrades.
+
+For frame shapes, the handshake, errors, and the complete method surface, read the
+[Gateway protocol specification](https://docs.openclaw.ai/gateway/protocol).
+
+## Install the packages
+
+```bash
+npm install @openclaw/gateway-client @openclaw/gateway-protocol
+```
+
+
+These packages ship with OpenClaw release trains. During the initial rollout, npm
+may return `E404` until the first package-bearing OpenClaw release is published;
+install them only after the registry pages below resolve.
+
+
+- [`@openclaw/gateway-protocol`](https://www.npmjs.com/package/@openclaw/gateway-protocol)
+ provides schemas, runtime validators, TypeScript types, client identity and
+ capability registries, structured error readers, and protocol version constants.
+ Its npm tarball also includes the generated
+ [`protocol.schema.json`](https://unpkg.com/@openclaw/gateway-protocol/protocol.schema.json)
+ machine-readable contract.
+- [`@openclaw/gateway-client`](https://www.npmjs.com/package/@openclaw/gateway-client)
+ is the reference connection implementation. Import the package root for the Node
+ client and `@openclaw/gateway-client/browser` for the browser-safe protocol,
+ device-auth, and reconnect helpers.
+
+The Node entry owns its WebSocket transport. A browser host supplies a WebSocket
+adapter plus persistent storage and signing callbacks for the device identity and
+device token.
+
+## Choose scopes and pair the device
+
+A full interactive chat client that also renders approval prompts should request
+`role: "operator"` with these scopes:
+
+| Scope | Use it for |
+| -------------------- | ----------------------------------------------------------------------------------------- |
+| `operator.read` | `chat.history`, `sessions.list`, `sessions.subscribe`, model status, and read-only events |
+| `operator.write` | `chat.send` and ordinary session mutations |
+| `operator.approvals` | Listing, displaying, and resolving exec or plugin approvals |
+
+Add `operator.questions` only if the client handles interactive questions,
+`operator.pairing` only if it manages paired devices or nodes, and
+`operator.admin` only for administrative operations such as `config.patch`.
+The [operator scopes reference](https://docs.openclaw.ai/gateway/operator-scopes)
+defines the complete method and approval-time rules.
+
+Do not create a per-client bearer token by hand-editing `openclaw.json`. Configure
+the Gateway's shared bootstrap authentication with `openclaw configure --section
+gateway` or the `openclaw onboard --gateway-auth ...` options, then let device
+pairing mint the client token:
+
+1. Persist an Ed25519 device identity in the client.
+2. Wait for `connect.challenge`, sign the challenge-bound device payload, and send
+ `connect` with the requested operator role, scopes, and the shared Gateway token
+ or password for bootstrap authentication.
+3. If the Gateway returns structured `PAIRING_REQUIRED` details, show the request
+ ID and pause or retry according to `error.details.recommendedNextStep`.
+4. On the Gateway host, review the request with `openclaw devices list`, then
+ approve that exact current request with `openclaw devices approve `.
+5. Reconnect and persist `hello-ok.auth.deviceToken` with the negotiated role and
+ scopes. Use that device token for later connections.
+
+Scope or role upgrades create a new pending pairing request. Token rotation cannot
+expand the approved pairing contract. See the
+[Devices CLI](https://docs.openclaw.ai/cli/devices) for approval, rotation, and
+revocation commands.
+
+## Advertise client capabilities
+
+`connect.params.caps` describes optional behavior the client can consume. It does
+not grant authorization. Import names from `GATEWAY_CLIENT_CAPS` instead of
+duplicating string literals:
+
+```ts
+import { GATEWAY_CLIENT_CAPS } from "@openclaw/gateway-protocol/client-info";
+
+const caps = [GATEWAY_CLIENT_CAPS.TOOL_EVENTS];
+```
+
+The current registry contains `approvals`, `exec-approvals`, `inline-widgets`,
+`run-tool-bindings`, `session-scoped-events`, `plugin-approvals`,
+`task-suggestions`, `terminal-offset-seq`, `tool-events`, and `ui-commands`.
+Advertise only capabilities the client actually implements.
+
+
+`tool-events` gates live tool-execution streaming. The Gateway registers only
+connections that advertise this capability as recipients for a run's structured
+tool events. Without it, the connection receives no live tool events and the
+handshake does not report an error.
+
+
+Capability-gated agent tools are a separate use of the same declaration. If an
+agent tool requires a client capability, the Gateway omits that tool unless the
+originating client advertised every required capability.
+
+## Recover state after reconnect
+
+Treat every successful reconnect as a new projection over durable history and
+current in-memory run state:
+
+1. Re-establish `sessions.subscribe` and the selected session's
+ `sessions.messages.subscribe` subscription.
+2. Call `chat.history` for the selected `sessionKey` and replace local persisted
+ rows with the returned `messages` projection.
+3. If `inFlightRun` is present, adopt its `runId`, buffered `text`, and optional
+ `plan`. Adopt the run even when `text` is empty.
+4. Read `sessionInfo.hasActiveRun` and `sessionInfo.activeRunIds`. Prefer exact
+ membership in `activeRunIds` when deciding whether a retained run still owns
+ the streaming UI. A true `hasActiveRun` with no listed ID can represent another
+ active runtime projection.
+5. Reconcile subsequent `agent` events by `payload.runId` and `payload.seq`.
+ Maintain the highest accepted sequence independently for each run, ignore an
+ already-seen or lower sequence, and treat a forward gap as a reason to reload
+ authoritative history.
+
+The outer event frame also has an optional `seq`, which orders events on the
+current WebSocket connection. It resets with a new connection. The `seq` inside
+an `agent` event payload is assigned per run and orders that run's lifecycle,
+assistant, plan, tool, and other stream events.
+
+## Use history metadata and stable anchors
+
+Rows returned by `chat.history` can carry an `__openclaw` metadata envelope:
+
+- `id` is the transcript entry identity. Use it for anchored history requests,
+ but not as a unique display-row key.
+- `seq` is the positive transcript-record sequence. One stored record can project
+ into more than one display row, so keep siblings with the same `id` and sequence
+ together.
+- `kind` identifies synthetic rows. A compaction boundary uses
+ `kind: "compaction"` and may include `tokensBefore` and `tokensAfter` when a
+ matching checkpoint recorded those metrics.
+
+Page backward with the response's `hasMore` and `nextOffset` values. Numeric
+offsets describe the current transcript projection, so do not persist them as
+long-lived bookmarks across reset or compaction. Persist `__openclaw.id` instead.
+To restore around a known row, call `chat.history` with `messageId` and the
+`sessionId` that returned it. The Gateway can resolve that anchor from reset
+archive history; anchored responses intentionally omit numeric paging metadata.
+
+## Subscribe instead of polling usage
+
+Load the initial catalog with `sessions.list`, then call `sessions.subscribe` once
+per connection. Merge `sessions.changed` events by `sessionKey`. Session change
+payloads can carry live `inputTokens`, `outputTokens`, `totalTokens`,
+`totalTokensFresh`, `contextTokens`, `estimatedCostUsd`, response-usage settings,
+and active-run state.
+
+Some change notifications are only invalidation signals. If an event omits the
+row fields your view needs, refresh `sessions.list`. Do not poll `usage.cost` or
+`sessions.usage` to keep a live session list current; reserve those methods for
+on-demand aggregate or detailed reports.
+
+## Backfill exec approvals
+
+A client with `operator.approvals` should install its event listener as soon as
+`hello-ok` completes, then call `exec.approval.list` to backfill requests that
+predate the connection. Reconcile the list and live
+`exec.approval.requested` / `exec.approval.resolved` events by approval ID so a
+transition racing the list request is neither lost nor resurrected.
+
+## Track protocol versions
+
+The current wire version is `4`. General operator and WebChat clients must
+negotiate the exact current version with `minProtocol: 4` and `maxProtocol: 4`.
+Only authenticated node clients and lightweight probes have the N-1 acceptance
+window, currently protocol `3` through `4`.
+
+Protocol changes are additive first. `protocol.schema.json` includes `since`
+release-vintage metadata and required scope metadata for core methods, but a wire
+version bump is still an explicit breaking event for third-party clients. Pin the
+package versions you test, upgrade the client and Gateway together when the wire
+version changes, and review the
+[OpenClaw changelog](https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md)
+before each upgrade.
+
+## Related
+
+- [Gateway protocol](https://docs.openclaw.ai/gateway/protocol)
+- [Embedding OpenClaw](https://docs.openclaw.ai/gateway/embedding)
+- [Gateway RPC reference](https://docs.openclaw.ai/reference/rpc)
+- [Gateway integrations for external apps](https://docs.openclaw.ai/gateway/external-apps)
diff --git a/docs/gateway/embedding.md b/docs/gateway/embedding.md
new file mode 100644
index 00000000000..e430824966e
--- /dev/null
+++ b/docs/gateway/embedding.md
@@ -0,0 +1,161 @@
+---
+summary: "Supervise the OpenClaw Gateway as a child process from Electron or another host app"
+read_when:
+ - Embedding OpenClaw in a desktop or server application
+ - Supervising the Gateway as a child process
+ - Handling Gateway readiness, restart, shutdown, or invalid config without scraping logs
+title: "Embedding OpenClaw"
+---
+
+An embedding host should supervise the installed `openclaw` executable, use the
+Gateway WebSocket protocol as its control plane, and treat the child process as a
+replaceable runtime. This keeps process ownership, readiness, failure recovery,
+and upgrades explicit without depending on OpenClaw's private state layout.
+
+For client authentication and reconnect state, read
+[Building a Gateway client](https://docs.openclaw.ai/gateway/clients).
+
+## Start the child with an embedding preset
+
+Use a real `node_modules` installation and spawn the package executable. A useful
+baseline for a host that owns discovery, restart, and channel lifecycle is:
+
+```ts
+import { spawn } from "node:child_process";
+import { dirname, resolve } from "node:path";
+import { fileURLToPath } from "node:url";
+
+// Supply an absolute path to a real Node runtime managed by the host application.
+declare const hostNodeExecutable: string;
+
+const packageEntry = fileURLToPath(import.meta.resolve("openclaw"));
+const openclawEntry = resolve(dirname(packageEntry), "..", "openclaw.mjs");
+const gateway = spawn(hostNodeExecutable, [openclawEntry, "gateway", "--allow-unconfigured"], {
+ env: {
+ ...process.env,
+ OPENCLAW_DISABLE_BONJOUR: "1",
+ OPENCLAW_EXEC_SHELL_SNAPSHOT: "0",
+ OPENCLAW_NO_RESPAWN: "1",
+ OPENCLAW_SKIP_CHANNELS: "1",
+ },
+ stdio: ["ignore", "inherit", "inherit"],
+});
+```
+
+Resolve OpenClaw through the installed package as shown; do not assume that a
+project-local `openclaw` binary is on the host process's `PATH`. The example
+inherits output so the child cannot block on full stdout or stderr pipes. If the
+host captures those streams instead, attach consumers immediately after spawning.
+
+| Setting | Embedding effect |
+| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `OPENCLAW_DISABLE_BONJOUR=1` | Disables Gateway-owned LAN multicast advertising when the host owns discovery. |
+| `OPENCLAW_NO_RESPAWN=1` | In an unmanaged embedding child, prevents OpenClaw from handing an update restart to a detached child. Routine restarts remain in process, so the host keeps ownership of the tracked PID. |
+| `OPENCLAW_EXEC_SHELL_SNAPSHOT=0` | Disables login-shell snapshot capture for host exec commands. |
+| `OPENCLAW_SKIP_CHANNELS=1` | Skips channel startup and reload. Set it only when the embedding app wants a control-plane or WebChat-only Gateway. |
+
+`--allow-unconfigured` bypasses only the `gateway.mode=local` startup guard. It
+does not write configuration or repair an invalid file. Omit it when the embedding
+app provisions a normal local configuration through onboarding, the config CLI,
+or Gateway RPC.
+
+### Electron shell snapshot warning
+
+Shell snapshot capture runs `process.execPath -e