Skip to content

Commit bb5010b

Browse files
steipeteitskai-devgwh7078longstoryscottmoejaberr
committed
docs: absorb docs sweep
Co-authored-by: Kai <kai@itskai.dev> Co-authored-by: Weihang <gwh7078@163.com> Co-authored-by: Scott Long <longstoryscott@gmail.com> Co-authored-by: moejaberr <mjaber@uoguelph.ca> Co-authored-by: huihui0822 <109355071+huihui0822@users.noreply.github.com>
1 parent 60e3749 commit bb5010b

15 files changed

Lines changed: 214 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Docs: https://docs.openclaw.ai
66

77
### Changes
88

9+
- Docs: clarify IPv4-only Gateway BYOH binding, trusted-proxy scope clearing, Android pairing approval, macOS Accessibility grants, Zalo profile env vars, password-store SecretRef setup, and Chinese memory navigation. Thanks @itskai-dev, @gwh7078, @longstoryscott, @MoeJaberr, and @yuaiccc.
910
- Docs: consolidate GLM under Z.AI, add the Upstash Box install guide and Gateway exposure runbook, clarify MEDIA directives, Copilot and Voyage setup, config path quoting, real behavior proof, and memory-file write guidance. Thanks @BobDu, @alitariksahin, @Jefsky, @musaabhasan, @OmerZeyveli, @leno23, @WuKongAI-CMU, @luoyanglang, and @majin1102.
1011
- Docs: clarify media provider credentials, Codex/OpenClaw code-mode boundaries, Slack and Telegram ack reactions, Feishu dynamic agents, secrets plaintext boundaries, memory guidance, and Chinese glossary terms. Thanks @nielskaspers, @cosmopolitan033, @drclaw-iq, @alexgduarte, @zccyman, @chengoak, and @cassthebandit.
1112
- Packaging: exclude documentation images and assets from the npm tarball, reducing published package size without affecting runtime docs search or CLI behavior. Thanks @SebTardif.

apps/android/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,12 +253,13 @@ Pre-req checklist:
253253
5) Grant runtime permissions for capabilities you expect to pass (camera/mic/location/notification listener/location, etc.).
254254
6) No interactive system dialogs should be pending before test start.
255255
7) Canvas host is enabled and reachable from the device (do not run gateway with `OPENCLAW_SKIP_CANVAS_HOST=1`; startup logs should include `canvas host mounted at .../__openclaw__/`).
256-
8) Local operator test client pairing is approved. If first run fails with `pairing required`, approve latest pending device pairing request, then rerun:
256+
8) Local operator test client pairing is approved. If first run fails with `pairing required`, preview the latest pending request, approve the printed request ID, then rerun:
257257
9) For A2UI checks, keep the app on **Screen** tab; the node now auto-refreshes canvas capability once on first A2UI reachability failure (TTL-safe retry).
258258

259259
```bash
260260
openclaw devices list
261-
openclaw devices approve --latest
261+
openclaw devices approve --latest # preview only; copy the requestId from output
262+
openclaw devices approve <requestId>
262263
```
263264

264265
Run:
@@ -284,7 +285,7 @@ What it does:
284285
Common failure quick-fixes:
285286

286287
- `pairing required` before tests start:
287-
- approve pending device pairing (`openclaw devices approve --latest`) and rerun.
288+
- list pending requests (`openclaw devices list`), then approve with the exact ID (`openclaw devices approve <requestId>`) and rerun.
288289
- `A2UI host not reachable` / `A2UI_HOST_NOT_CONFIGURED`:
289290
- ensure the Canvas plugin host is running and reachable, keep the app on the **Screen** tab. The app refreshes the Canvas plugin surface URL once before failing; if it still fails, reconnect app and rerun.
290291
- `NODE_BACKGROUND_UNAVAILABLE: canvas unavailable`:

docs/.i18n/zh-Hans-navigation.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,18 @@
137137
"zh-CN/concepts/session",
138138
"zh-CN/concepts/session-pruning",
139139
"zh-CN/concepts/session-tool",
140-
"zh-CN/concepts/memory",
140+
{
141+
"group": "记忆",
142+
"pages": [
143+
"zh-CN/concepts/memory",
144+
"zh-CN/concepts/memory-builtin",
145+
"zh-CN/concepts/memory-qmd",
146+
"zh-CN/concepts/memory-honcho",
147+
"zh-CN/concepts/memory-search",
148+
"zh-CN/concepts/active-memory",
149+
"zh-CN/concepts/dreaming"
150+
]
151+
},
141152
"zh-CN/concepts/compaction"
142153
]
143154
},

docs/channels/zalouser.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,24 @@ Accounts map to `zalouser` profiles in OpenClaw state. Example:
166166
}
167167
```
168168

169+
## Environment variables
170+
171+
The Zalo Personal plugin can also read profile selection from environment variables:
172+
173+
- `ZALOUSER_PROFILE`: profile name to use when no `profile` is set in channel or account config.
174+
- `ZCA_PROFILE`: legacy fallback profile name, used only when `ZALOUSER_PROFILE` is not set.
175+
176+
Profile names select the saved Zalo login credentials in OpenClaw state. Resolution order is:
177+
178+
1. Explicit `profile` in config.
179+
2. `ZALOUSER_PROFILE`.
180+
3. `ZCA_PROFILE`.
181+
4. The account id for non-default accounts, or `default` for the default account.
182+
183+
For multi-account setups, prefer setting `profile` on each account in config so
184+
one environment variable does not make multiple accounts share the same login
185+
session.
186+
169187
## Typing, reactions, and delivery acknowledgements
170188

171189
- OpenClaw sends a typing event before dispatching a reply (best-effort).

docs/cli/gateway.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ openclaw gateway run
4242
- `openclaw onboard --mode local` and `openclaw setup` are expected to write `gateway.mode=local`. If the file exists but `gateway.mode` is missing, treat that as a broken or clobbered config and repair it instead of assuming local mode implicitly.
4343
- If the file exists and `gateway.mode` is missing, the Gateway treats that as suspicious config damage and refuses to "guess local" for you.
4444
- Binding beyond loopback without auth is blocked (safety guardrail).
45+
- `lan`, `tailnet`, and `custom` currently resolve over IPv4-only BYOH paths.
46+
- IPv6-only BYOH is not natively supported on this path today. Use an IPv4 sidecar or proxy if the host itself is IPv6-only.
4547
- `SIGUSR1` triggers an in-process restart when authorized (`commands.restart` is enabled by default; set `commands.restart: false` to block manual restart, while gateway tool/config apply/update remain allowed).
4648
- `SIGINT`/`SIGTERM` handlers stop the gateway process, but they don't restore any custom terminal state. If you wrap the CLI with a TUI or raw-mode input, restore the terminal before exit.
4749

@@ -54,7 +56,7 @@ openclaw gateway run
5456
WebSocket port (default comes from config/env; usually `18789`).
5557
</ParamField>
5658
<ParamField path="--bind <loopback|lan|tailnet|auto|custom>" type="string">
57-
Listener bind mode.
59+
Listener bind mode. `lan`, `tailnet`, and `custom` currently resolve over IPv4-only paths.
5860
</ParamField>
5961
<ParamField path="--auth <token|password>" type="string">
6062
Auth mode override.
@@ -74,6 +76,9 @@ openclaw gateway run
7476
<ParamField path="--tailscale-reset-on-exit" type="boolean">
7577
Reset Tailscale serve/funnel config on shutdown.
7678
</ParamField>
79+
<ParamField path="--bind custom + gateway.customBindHost" type="string">
80+
Expects an IPv4 address today. For IPv6-only BYOH, place an IPv4 sidecar or proxy in front of the Gateway and point OpenClaw at that IPv4 endpoint.
81+
</ParamField>
7782
<ParamField path="--allow-unconfigured" type="boolean">
7883
Allow gateway start without `gateway.mode=local` in config. Bypasses the startup guard for ad-hoc/dev bootstrap only; does not write or repair the config file.
7984
</ParamField>

docs/gateway/protocol.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,14 @@ rather than the pre-handshake defaults.
757757
- `gateway.controlUi.dangerouslyDisableDeviceAuth=true` (break-glass, severe security downgrade).
758758
- direct-loopback `gateway-client` backend RPCs authenticated with the shared
759759
gateway token/password.
760+
- Omitting device identity has scope consequences. When a Control UI connection
761+
lacks device identity, `shouldClearUnboundScopesForMissingDeviceIdentity`
762+
clears self-declared scopes to an empty set for token, password, and
763+
trusted-proxy auth. The connection is allowed on explicit trust paths, but
764+
scope-gated methods fail. The exception is local Control UI token/password
765+
sessions with `allowInsecureAuth`, which preserve scopes. For other cases,
766+
set `gateway.controlUi.dangerouslyDisableDeviceAuth=true` only as a
767+
break-glass scope-preservation path.
760768
- All connections must sign the server-provided `connect.challenge` nonce.
761769

762770
### Device auth migration diagnostics

docs/gateway/secrets.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,94 @@ the config fields that accept SecretRefs.
339339
}
340340
```
341341
</Accordion>
342+
<Accordion title="password-store (`pass`)">
343+
Use a small resolver wrapper when you want SecretRef ids to map directly to
344+
`pass` entries. Save this as an executable in an absolute path that passes
345+
your exec-provider path checks, for example
346+
`/usr/local/bin/openclaw-pass-resolver`. The `#!/usr/bin/env node` shebang
347+
resolves `node` from the resolver process `PATH`, so include `PATH` in
348+
`passEnv`. If `pass` is not on that `PATH`, set `PASS_BIN` in the parent
349+
environment and include it in `passEnv` too:
350+
351+
```js
352+
#!/usr/bin/env node
353+
const { spawnSync } = require("node:child_process");
354+
355+
let stdin = "";
356+
process.stdin.setEncoding("utf8");
357+
process.stdin.on("data", (chunk) => {
358+
stdin += chunk;
359+
});
360+
process.stdin.on("error", (err) => {
361+
process.stderr.write(`${err.message}\n`);
362+
process.exit(1);
363+
});
364+
process.stdin.on("end", () => {
365+
let request;
366+
try {
367+
request = JSON.parse(stdin || "{}");
368+
} catch (err) {
369+
process.stderr.write(`Failed to parse request: ${err.message}\n`);
370+
process.exit(1);
371+
}
372+
373+
const passBin = process.env.PASS_BIN || "pass";
374+
const values = {};
375+
const errors = {};
376+
377+
for (const id of request.ids ?? []) {
378+
const result = spawnSync(passBin, ["show", id], { encoding: "utf8" });
379+
if (result.status === 0) {
380+
values[id] = result.stdout.split(/\r?\n/, 1)[0] ?? "";
381+
} else {
382+
errors[id] = { message: (result.stderr || `pass exited ${result.status}`).trim() };
383+
}
384+
}
385+
386+
process.stdout.write(JSON.stringify({ protocolVersion: 1, values, errors }));
387+
});
388+
```
389+
390+
Then configure the exec provider and point `apiKey` at the `pass` entry path:
391+
392+
```json5
393+
{
394+
secrets: {
395+
providers: {
396+
pass_store: {
397+
source: "exec",
398+
command: "/usr/local/bin/openclaw-pass-resolver",
399+
passEnv: ["PATH", "HOME", "GNUPGHOME", "GPG_TTY", "PASSWORD_STORE_DIR", "PASS_BIN"],
400+
jsonOnly: true,
401+
},
402+
},
403+
},
404+
models: {
405+
providers: {
406+
openai: {
407+
baseUrl: "https://api.openai.com/v1",
408+
models: [{ id: "gpt-5", name: "gpt-5" }],
409+
apiKey: {
410+
source: "exec",
411+
provider: "pass_store",
412+
id: "openclaw/providers/openai/apiKey",
413+
},
414+
},
415+
},
416+
},
417+
}
418+
```
419+
420+
Keep the secret on the first line of the `pass` entry, or customize the
421+
wrapper if you want to return the full `pass show` output instead. After
422+
updating config, verify both the static audit and the exec resolver path:
423+
424+
```bash
425+
openclaw secrets audit --check
426+
openclaw secrets audit --allow-exec
427+
```
428+
429+
</Accordion>
342430
<Accordion title="sops">
343431
```json5
344432
{

docs/gateway/trusted-proxy-auth.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,19 @@ Implications:
5959
- Your reverse proxy auth policy and `allowUsers` become the effective access control.
6060
- Keep gateway ingress locked to trusted proxy IPs only (`gateway.trustedProxies` + firewall).
6161

62+
**Scope clearing without device identity:** Because the browser over plain HTTP
63+
cannot create the device identity that OpenClaw uses to bind operator scopes,
64+
trusted-proxy WebSocket connections that lack device identity have their
65+
self-declared scopes cleared to an empty set. The connection is allowed, but
66+
scope-gated methods (`operator.read`, `operator.write`, etc.) fail with
67+
`missing scope`.
68+
69+
To preserve operator scopes on trusted-proxy WebSocket connections without
70+
device identity, set `gateway.controlUi.dangerouslyDisableDeviceAuth: true`.
71+
This is a break-glass flag (`openclaw security audit` reports it as critical).
72+
Use it only when the reverse proxy is the sole path to the Gateway and device
73+
identity cannot be established.
74+
6275
## Configuration
6376

6477
```json5
@@ -311,6 +324,11 @@ Loopback trusted-proxy identity headers still fail closed: same-host callers are
311324

312325
Trusted-proxy auth is an **identity-bearing** HTTP mode, so callers may optionally declare operator scopes with `x-openclaw-scopes`.
313326

327+
Note: `x-openclaw-scopes` applies to HTTP endpoints only. WebSocket scopes are
328+
determined by the Gateway protocol handshake and device identity binding. For
329+
WebSocket scope behavior with trusted-proxy, see
330+
[Control UI pairing behavior](#control-ui-pairing-behavior).
331+
314332
Examples:
315333

316334
- `x-openclaw-scopes: operator.read`
@@ -407,6 +425,20 @@ The audit checks for:
407425
- You are not relying on wildcard origins unless you intentionally want allow-all behavior.
408426
- If you intentionally use Host-header fallback mode, `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true` is set deliberately.
409427

428+
</Accordion>
429+
<Accordion title="Connection succeeds but methods report missing scope">
430+
The WebSocket connects, but `chat.history` or `sessions.list` fails with
431+
`missing scope: operator.read`.
432+
433+
This is expected for trusted-proxy WebSocket connections without device
434+
identity. Connections lacking device identity have their scopes cleared. The
435+
browser cannot generate device identity over plain HTTP.
436+
437+
Fix:
438+
439+
- Set `gateway.controlUi.dangerouslyDisableDeviceAuth: true` to preserve operator scopes on trusted-proxy WebSocket connections, or
440+
- Use device identity pairing so scopes are bound to the device token.
441+
410442
</Accordion>
411443
<Accordion title="WebSocket still failing">
412444
Make sure your proxy:

docs/platforms/mac/peekaboo.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ export PEEKABOO_BRIDGE_SOCKET=/path/to/bridge.sock
6969

7070
- The bridge validates **caller code signatures**; an allowlist of TeamIDs is
7171
enforced (Peekaboo host TeamID + OpenClaw app TeamID).
72+
- Prefer the signed bridge/app identity over a generic `node` runtime for
73+
Accessibility. Granting Accessibility to `node` lets any package launched by
74+
that Node executable inherit GUI automation access; see
75+
[macOS permissions](/platforms/mac/permissions#accessibility-grants-for-node-and-cli-runtimes).
7276
- Requests time out after ~10 seconds.
7377
- If required permissions are missing, the bridge returns a clear error message
7478
rather than launching System Settings.

docs/platforms/mac/permissions.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
summary: "macOS permission persistence (TCC) and signing requirements"
33
read_when:
44
- Debugging missing or stuck macOS permission prompts
5+
- Deciding whether to grant Accessibility to node or a CLI runtime
56
- Packaging or signing the macOS app
67
- Changing bundle IDs or app install paths
78
title: "macOS permissions"
@@ -22,6 +23,25 @@ macOS treats the app as new and may drop or hide prompts.
2223
Ad-hoc signatures generate a new identity every build. macOS will forget previous
2324
grants, and prompts can disappear entirely until the stale entries are cleared.
2425

26+
## Accessibility grants for Node and CLI runtimes
27+
28+
Prefer granting Accessibility to OpenClaw.app, Peekaboo.app, or another signed
29+
helper with its own bundle identifier instead of a generic `node` binary.
30+
31+
macOS TCC grants Accessibility to the code identity of the process it sees. If a
32+
Homebrew, nvm, pnpm, or npm workflow causes a shared `node` executable to
33+
receive Accessibility, any JavaScript package launched through that same
34+
executable may inherit GUI automation privileges.
35+
36+
Treat a `node` entry in System Settings as broad permission for that Node
37+
runtime, not as permission for one npm package. Avoid granting Accessibility to
38+
`node` unless you trust every script and package launched through that exact
39+
Node install.
40+
41+
If you accidentally granted Accessibility to `node`, remove that entry from
42+
System Settings -> Privacy & Security -> Accessibility. Then grant the signed
43+
app or helper that should own UI automation.
44+
2545
## Recovery checklist when prompts disappear
2646

2747
1. Quit the app.

0 commit comments

Comments
 (0)