diff --git a/docs/automation/standing-orders.md b/docs/automation/standing-orders.md
index 438b1067604..33c2d7b2d7a 100644
--- a/docs/automation/standing-orders.md
+++ b/docs/automation/standing-orders.md
@@ -7,7 +7,7 @@ read_when:
title: "Standing orders"
---
-Standing orders grant your agent **permanent operating authority** for defined programs. Instead of giving individual task instructions each time, you define programs with clear scope, triggers, and escalation rules — and the agent executes autonomously within those boundaries.
+Standing orders grant your agent **permanent operating authority** for defined programs. Instead of giving individual task instructions each time, you define programs with clear scope, triggers, and escalation rules - and the agent executes autonomously within those boundaries.
This is the difference between telling your assistant "send the weekly report" every Friday vs. granting standing authority: "You own the weekly report. Compile it every Friday, send it, and only escalate if something looks wrong."
@@ -33,15 +33,15 @@ Standing orders are defined in your [agent workspace](/concepts/agent-workspace)
Each program specifies:
-1. **Scope** — what the agent is authorized to do
-2. **Triggers** — when to execute (schedule, event, or condition)
-3. **Approval gates** — what requires human sign-off before acting
-4. **Escalation rules** — when to stop and ask for help
+1. **Scope** - what the agent is authorized to do
+2. **Triggers** - when to execute (schedule, event, or condition)
+3. **Approval gates** - what requires human sign-off before acting
+4. **Escalation rules** - when to stop and ask for help
The agent loads these instructions every session via the workspace bootstrap files (see [Agent Workspace](/concepts/agent-workspace) for the full list of auto-injected files) and executes against them, combined with [cron jobs](/automation/cron-jobs) for time-based enforcement.
-Put standing orders in `AGENTS.md` to guarantee they're loaded every session. The workspace bootstrap automatically injects `AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md`, and `MEMORY.md` — but not arbitrary files in subdirectories.
+Put standing orders in `AGENTS.md` to guarantee they're loaded every session. The workspace bootstrap automatically injects `AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, `BOOTSTRAP.md`, and `MEMORY.md` - but not arbitrary files in subdirectories.
## Anatomy of a standing order
@@ -66,7 +66,7 @@ Put standing orders in `AGENTS.md` to guarantee they're loaded every session. Th
- Do not send reports to external parties
- Do not modify source data
-- Do not skip delivery if metrics look bad — report accurately
+- Do not skip delivery if metrics look bad - report accurately
```
## Standing orders plus cron jobs
@@ -109,7 +109,7 @@ openclaw cron add \
### Weekly cycle
- **Monday:** Review platform metrics and audience engagement
-- **Tuesday–Thursday:** Draft social posts, create blog content
+- **Tuesday-Thursday:** Draft social posts, create blog content
- **Friday:** Compile weekly marketing brief → deliver to owner
### Content rules
@@ -176,9 +176,9 @@ openclaw cron add \
Standing orders work best when combined with strict execution discipline. Every task in a standing order should follow this loop:
-1. **Execute** — Do the actual work (don't just acknowledge the instruction)
-2. **Verify** — Confirm the result is correct (file exists, message delivered, data parsed)
-3. **Report** — Tell the owner what was done and what was verified
+1. **Execute** - Do the actual work (don't just acknowledge the instruction)
+2. **Verify** - Confirm the result is correct (file exists, message delivered, data parsed)
+3. **Report** - Tell the owner what was done and what was verified
```markdown
### Execution rules
@@ -188,7 +188,7 @@ Standing orders work best when combined with strict execution discipline. Every
- "Done" without verification is not acceptable. Prove it.
- If execution fails: retry once with adjusted approach.
- If still fails: report failure with diagnosis. Never silently fail.
-- Never retry indefinitely — 3 attempts max, then escalate.
+- Never retry indefinitely - 3 attempts max, then escalate.
```
This pattern prevents the most common agent failure mode: acknowledging a task without completing it.
@@ -228,18 +228,18 @@ Each program should have:
- Start with narrow authority and expand as trust builds
- Define explicit approval gates for high-risk actions
-- Include "What NOT to do" sections — boundaries matter as much as permissions
+- Include "What NOT to do" sections - boundaries matter as much as permissions
- Combine with cron jobs for reliable time-based execution
- Review agent logs weekly to verify standing orders are being followed
-- Update standing orders as your needs evolve — they're living documents
+- Update standing orders as your needs evolve - they're living documents
### Avoid
- Grant broad authority on day one ("do whatever you think is best")
-- Skip escalation rules — every program needs a "when to stop and ask" clause
-- Assume the agent will remember verbal instructions — put everything in the file
-- Mix concerns in a single program — separate programs for separate domains
-- Forget to enforce with cron jobs — standing orders without triggers become suggestions
+- Skip escalation rules - every program needs a "when to stop and ask" clause
+- Assume the agent will remember verbal instructions - put everything in the file
+- Mix concerns in a single program - separate programs for separate domains
+- Forget to enforce with cron jobs - standing orders without triggers become suggestions
## Related
diff --git a/docs/channels/feishu.md b/docs/channels/feishu.md
index e181e145fc6..0b01918baf1 100644
--- a/docs/channels/feishu.md
+++ b/docs/channels/feishu.md
@@ -6,8 +6,6 @@ read_when:
title: Feishu
---
-# Feishu / Lark
-
Feishu/Lark is an all-in-one collaboration platform where teams chat, share documents, manage calendars, and get work done together.
**Status:** production-ready for bot DMs + group chats. WebSocket is the default mode; webhook mode is optional.
@@ -43,10 +41,10 @@ Requires OpenClaw 2026.4.25 or above. Run `openclaw --version` to check. Upgrade
Configure `dmPolicy` to control who can DM the bot:
-- `"pairing"` — unknown users receive a pairing code; approve via CLI
-- `"allowlist"` — only users listed in `allowFrom` can chat (default: bot owner only)
-- `"open"` — allow public DMs only when `allowFrom` includes `"*"`; with restrictive entries, only matching users can chat
-- `"disabled"` — disable all DMs
+- `"pairing"` - unknown users receive a pairing code; approve via CLI
+- `"allowlist"` - only users listed in `allowFrom` can chat (default: bot owner only)
+- `"open"` - allow public DMs only when `allowFrom` includes `"*"`; with restrictive entries, only matching users can chat
+- `"disabled"` - disable all DMs
**Approve a pairing request:**
@@ -69,8 +67,8 @@ Default: `allowlist`
**Mention requirement** (`channels.feishu.requireMention`):
-- `true` — require @mention (default)
-- `false` — respond without @mention
+- `true` - require @mention (default)
+- `false` - respond without @mention
- Per-group override: `channels.feishu.groups..requireMention`
- Broadcast-only `@all` and `@_all` are not treated as bot mentions. A message that mentions both `@all` and the bot directly still counts as a bot mention.
@@ -261,8 +259,8 @@ per account.
### Message limits
-- `textChunkLimit` — outbound text chunk size (default: `2000` chars)
-- `mediaMaxMb` — media upload/download limit (default: `30` MB)
+- `textChunkLimit` - outbound text chunk size (default: `2000` chars)
+- `mediaMaxMb` - media upload/download limit (default: `30` MB)
### Streaming
@@ -301,7 +299,7 @@ Reduce the number of Feishu/Lark API calls with two optional flags:
### ACP sessions
-Feishu/Lark supports ACP for DMs and group thread messages. Feishu/Lark ACP is text-command driven — there are no native slash-command menus, so use `/acp ...` messages directly in the conversation.
+Feishu/Lark supports ACP for DMs and group thread messages. Feishu/Lark ACP is text-command driven - there are no native slash-command menus, so use `/acp ...` messages directly in the conversation.
#### Persistent ACP binding
@@ -409,19 +407,19 @@ Full configuration: [Gateway configuration](/gateway/configuration)
| `channels.feishu.domain` | API domain (`feishu` or `lark`) | `feishu` |
| `channels.feishu.connectionMode` | Event transport (`websocket` or `webhook`) | `websocket` |
| `channels.feishu.defaultAccount` | Default account for outbound routing | `default` |
-| `channels.feishu.verificationToken` | Required for webhook mode | — |
-| `channels.feishu.encryptKey` | Required for webhook mode | — |
+| `channels.feishu.verificationToken` | Required for webhook mode | - |
+| `channels.feishu.encryptKey` | Required for webhook mode | - |
| `channels.feishu.webhookPath` | Webhook route path | `/feishu/events` |
| `channels.feishu.webhookHost` | Webhook bind host | `127.0.0.1` |
| `channels.feishu.webhookPort` | Webhook bind port | `3000` |
-| `channels.feishu.accounts..appId` | App ID | — |
-| `channels.feishu.accounts..appSecret` | App Secret | — |
+| `channels.feishu.accounts..appId` | App ID | - |
+| `channels.feishu.accounts..appSecret` | App Secret | - |
| `channels.feishu.accounts..domain` | Per-account domain override | `feishu` |
| `channels.feishu.accounts..tts` | Per-account TTS override | `messages.tts` |
| `channels.feishu.dmPolicy` | DM policy | `allowlist` |
| `channels.feishu.allowFrom` | DM allowlist (open_id list) | [BotOwnerId] |
| `channels.feishu.groupPolicy` | Group policy | `allowlist` |
-| `channels.feishu.groupAllowFrom` | Group allowlist | — |
+| `channels.feishu.groupAllowFrom` | Group allowlist | - |
| `channels.feishu.requireMention` | Require @mention in groups | `true` |
| `channels.feishu.groups..requireMention` | Per-group @mention override; explicit IDs also admit the group in allowlist mode | inherited |
| `channels.feishu.groups..enabled` | Enable/disable a specific group | `true` |
@@ -489,8 +487,8 @@ stay in the same session.
## Related
-- [Channels Overview](/channels) — all supported channels
-- [Pairing](/channels/pairing) — DM authentication and pairing flow
-- [Groups](/channels/groups) — group chat behavior and mention gating
-- [Channel Routing](/channels/channel-routing) — session routing for messages
-- [Security](/gateway/security) — access model and hardening
+- [Channels Overview](/channels) - all supported channels
+- [Pairing](/channels/pairing) - DM authentication and pairing flow
+- [Groups](/channels/groups) - group chat behavior and mention gating
+- [Channel Routing](/channels/channel-routing) - session routing for messages
+- [Security](/gateway/security) - access model and hardening
diff --git a/docs/channels/matrix.md b/docs/channels/matrix.md
index e366cd0108a..97f2746eb15 100644
--- a/docs/channels/matrix.md
+++ b/docs/channels/matrix.md
@@ -30,7 +30,7 @@ openclaw plugins install ./path/to/local/matrix-plugin
1. Create a Matrix account on your homeserver.
2. Configure `channels.matrix` with either `homeserver` + `accessToken`, or `homeserver` + `userId` + `password`.
3. Restart the gateway.
-4. Start a DM with the bot, or invite it to a room (see [auto-join](#auto-join) — fresh invites only land when `autoJoin` allows them).
+4. Start a DM with the bot, or invite it to a room (see [auto-join](#auto-join) - fresh invites only land when `autoJoin` allows them).
### Interactive setup
@@ -80,7 +80,7 @@ Password-based (the token is cached after first login):
`channels.matrix.autoJoin` defaults to `off`. With the default, the bot will not appear in new rooms or DMs from fresh invites until you join manually.
-OpenClaw cannot tell at invite time whether an invited room is a DM or a group, so all invites — including DM-style invites — go through `autoJoin` first. `dm.policy` only applies later, after the bot has joined and the room has been classified.
+OpenClaw cannot tell at invite time whether an invited room is a DM or a group, so all invites - including DM-style invites - go through `autoJoin` first. `dm.policy` only applies later, after the bot has joined and the room has been classified.
Set `autoJoin: "allowlist"` plus `autoJoinAllowlist` to restrict which invites the bot accepts, or `autoJoin: "always"` to accept every invite.
@@ -122,7 +122,7 @@ Matrix stores cached credentials under `~/.openclaw/credentials/matrix/`:
- default account: `credentials.json`
- named accounts: `credentials-.json`
-When cached credentials exist there, OpenClaw treats Matrix as configured even if the access token is not in the config file — that covers setup, `openclaw doctor`, and channel-status probes.
+When cached credentials exist there, OpenClaw treats Matrix as configured even if the access token is not in the config file - that covers setup, `openclaw doctor`, and channel-status probes.
### Environment variables
@@ -237,7 +237,7 @@ When an approval prompt is too long for one Matrix event, OpenClaw chunks the vi
### Self-hosted push rules for quiet finalized previews
-`streaming: "quiet"` only notifies recipients once a block or turn is finalized — a per-user push rule has to match the finalized preview marker. See [Matrix push rules for quiet previews](/channels/matrix-push-rules) for the full recipe (recipient token, pusher check, rule install, per-homeserver notes).
+`streaming: "quiet"` only notifies recipients once a block or turn is finalized - a per-user push rule has to match the finalized preview marker. See [Matrix push rules for quiet previews](/channels/matrix-push-rules) for the full recipe (recipient token, pusher check, rule install, per-homeserver notes).
## Bot-to-bot rooms
@@ -270,7 +270,7 @@ Use strict room allowlists and mention requirements when enabling bot-to-bot tra
## Encryption and verification
-In encrypted (E2EE) rooms, outbound image events use `thumbnail_file` so image previews are encrypted alongside the full attachment. Unencrypted rooms still use plain `thumbnail_url`. No configuration is needed — the plugin detects E2EE state automatically.
+In encrypted (E2EE) rooms, outbound image events use `thumbnail_file` so image previews are encrypted alongside the full attachment. Unencrypted rooms still use plain `thumbnail_url`. No configuration is needed - the plugin detects E2EE state automatically.
All `openclaw matrix` commands accept `--verbose` (full diagnostics), `--json` (machine-readable output), and `--account ` (multi-account setups). Output is concise by default with quiet internal SDK logging. The examples below show the canonical form; add the flags as needed.
@@ -331,7 +331,7 @@ openclaw matrix verify status --include-recovery-key --json
### Verify this device with a recovery key
-The recovery key is sensitive — pipe it via stdin instead of passing it on the command line. Set `MATRIX_RECOVERY_KEY` (or `MATRIX__RECOVERY_KEY` for a named account):
+The recovery key is sensitive - pipe it via stdin instead of passing it on the command line. Set `MATRIX_RECOVERY_KEY` (or `MATRIX__RECOVERY_KEY` for a named account):
```bash
printf '%s\n' "$MATRIX_RECOVERY_KEY" | openclaw matrix verify device --recovery-key-stdin
@@ -405,7 +405,7 @@ openclaw matrix verify request --user-id @ops:example.org --device-id ABCDEF
Sends a verification request from this OpenClaw account. `--own-user` requests self-verification (you accept the prompt in another Matrix client of the same user); `--user-id`/`--device-id`/`--room-id` target someone else. `--own-user` cannot be combined with the other targeting flags.
-For lower-level lifecycle handling — typically while shadowing inbound requests from another client — these commands act on a specific request `` (printed by `verify list` and `verify request`):
+For lower-level lifecycle handling - typically while shadowing inbound requests from another client - these commands act on a specific request `` (printed by `verify list` and `verify request`):
| Command | Purpose |
| ------------------------------------------ | ------------------------------------------------------------------- |
@@ -435,7 +435,7 @@ Without `--account `, Matrix CLI commands use the implicit default account.
Matrix posts verification lifecycle notices into the strict DM verification room as `m.notice` messages: request, ready (with "Verify by emoji" guidance), start/completion, and SAS (emoji/decimal) details when available.
- Incoming requests from another Matrix client are tracked and auto-accepted. For self-verification, OpenClaw starts the SAS flow automatically and confirms its own side once emoji verification is available — you still need to compare and confirm "They match" in your Matrix client.
+ Incoming requests from another Matrix client are tracked and auto-accepted. For self-verification, OpenClaw starts the SAS flow automatically and confirms its own side once emoji verification is available - you still need to compare and confirm "They match" in your Matrix client.
Verification system notices are not forwarded to the agent chat pipeline.
@@ -516,7 +516,7 @@ Explicit conversation bindings always win over `sessionScope`, so bound rooms an
- `"inbound"`: reply inside a thread only when the inbound message was already in that thread.
- `"always"`: reply inside a thread rooted at the triggering message; that conversation is routed through a matching thread-scoped session from the first trigger onward.
-`dm.threadReplies` overrides this for DMs only — for example, keep room threads isolated while keeping DMs flat.
+`dm.threadReplies` overrides this for DMs only - for example, keep room threads isolated while keeping DMs flat.
### Thread inheritance and slash commands
@@ -676,7 +676,7 @@ It does not delete old rooms automatically. It picks the healthy DM and updates
Matrix can act as a native approval client. Configure under `channels.matrix.execApprovals` (or `channels.matrix.accounts..execApprovals` for a per-account override):
- `enabled`: deliver approvals through Matrix-native prompts. When unset or `"auto"`, Matrix auto-enables once at least one approver can be resolved. Set `false` to disable explicitly.
-- `approvers`: Matrix user IDs (`@owner:example.org`) allowed to approve exec requests. Optional — falls back to `channels.matrix.dm.allowFrom`.
+- `approvers`: Matrix user IDs (`@owner:example.org`) allowed to approve exec requests. Optional - falls back to `channels.matrix.dm.allowFrom`.
- `target`: where prompts go. `"dm"` (default) sends to approver DMs; `"channel"` sends to the originating Matrix room or DM; `"both"` sends to both.
- `agentFilter` / `sessionFilter`: optional allowlists for which agents/sessions trigger Matrix delivery.
@@ -693,7 +693,7 @@ Both kinds share Matrix reaction shortcuts and message updates. Approvers see re
Fallback slash commands: `/approve allow-once`, `/approve allow-always`, `/approve deny`.
-Only resolved approvers can approve or deny. Channel delivery for exec approvals includes the command text — only enable `channel` or `both` in trusted rooms.
+Only resolved approvers can approve or deny. Channel delivery for exec approvals includes the command text - only enable `channel` or `both` in trusted rooms.
Related: [Exec approvals](/tools/exec-approvals).
@@ -742,7 +742,7 @@ Authorization rules still apply: command senders must satisfy the same DM or roo
- Set `defaultAccount` to pick the named account that implicit routing, probing, and CLI commands prefer.
- If you have multiple accounts and one is literally named `default`, OpenClaw uses it implicitly even when `defaultAccount` is unset.
-- If you have multiple named accounts and no default is selected, CLI commands refuse to guess — set `defaultAccount` or pass `--account `.
+- If you have multiple named accounts and no default is selected, CLI commands refuse to guess - set `defaultAccount` or pass `--account `.
- The top-level `channels.matrix.*` block is only treated as the implicit `default` account when its auth is complete (`homeserver` + `accessToken`, or `homeserver` + `userId` + `password`). Named accounts remain discoverable from `homeserver` + `userId` once cached credentials cover auth.
**Promotion:**
@@ -907,8 +907,8 @@ Allowlist-style fields (`groupAllowFrom`, `dm.allowFrom`, `groups..users`)
## Related
-- [Channels Overview](/channels) — all supported channels
-- [Pairing](/channels/pairing) — DM authentication and pairing flow
-- [Groups](/channels/groups) — group chat behavior and mention gating
-- [Channel Routing](/channels/channel-routing) — session routing for messages
-- [Security](/gateway/security) — access model and hardening
+- [Channels Overview](/channels) - all supported channels
+- [Pairing](/channels/pairing) - DM authentication and pairing flow
+- [Groups](/channels/groups) - group chat behavior and mention gating
+- [Channel Routing](/channels/channel-routing) - session routing for messages
+- [Security](/gateway/security) - access model and hardening
diff --git a/docs/gateway/bonjour.md b/docs/gateway/bonjour.md
index 9f06cd18ca1..773dc5b546e 100644
--- a/docs/gateway/bonjour.md
+++ b/docs/gateway/bonjour.md
@@ -6,8 +6,6 @@ read_when:
title: "Bonjour discovery"
---
-# Bonjour / mDNS discovery
-
OpenClaw can use Bonjour (mDNS / DNS-SD) to discover an active Gateway (WebSocket endpoint).
Multicast `local.` browsing is a **LAN-only convenience**. The bundled `bonjour`
plugin owns LAN advertising. It auto-starts on macOS hosts and is opt-in on
@@ -17,20 +15,20 @@ is still best-effort and does **not** replace SSH or Tailnet-based connectivity.
## Wide-area Bonjour (Unicast DNS-SD) over Tailscale
-If the node and gateway are on different networks, multicast mDNS won’t cross the
-boundary. You can keep the same discovery UX by switching to **unicast DNS‑SD**
-("Wide‑Area Bonjour") over Tailscale.
+If the node and gateway are on different networks, multicast mDNS won't cross the
+boundary. You can keep the same discovery UX by switching to **unicast DNS-SD**
+("Wide-Area Bonjour") over Tailscale.
-High‑level steps:
+High-level steps:
1. Run a DNS server on the gateway host (reachable over Tailnet).
-2. Publish DNS‑SD records for `_openclaw-gw._tcp` under a dedicated zone
+2. Publish DNS-SD records for `_openclaw-gw._tcp` under a dedicated zone
(example: `openclaw.internal.`).
3. Configure Tailscale **split DNS** so your chosen domain resolves via that
DNS server for clients (including iOS).
OpenClaw supports any discovery domain; `openclaw.internal.` is just an example.
-iOS/Android nodes browse both `local.` and your configured wide‑area domain.
+iOS/Android nodes browse both `local.` and your configured wide-area domain.
### Gateway config (recommended)
@@ -49,10 +47,10 @@ openclaw dns setup --apply
This installs CoreDNS and configures it to:
-- listen on port 53 only on the gateway’s Tailscale interfaces
+- listen on port 53 only on the gateway's Tailscale interfaces
- serve your chosen domain (example: `openclaw.internal.`) from `~/.openclaw/dns/.db`
-Validate from a tailnet‑connected machine:
+Validate from a tailnet-connected machine:
```bash
dns-sd -B _openclaw-gw._tcp openclaw.internal.
@@ -63,7 +61,7 @@ dig @ -p 53 _openclaw-gw._tcp.openclaw.internal PTR +short
In the Tailscale admin console:
-- Add a nameserver pointing at the gateway’s tailnet IP (UDP/TCP 53).
+- Add a nameserver pointing at the gateway's tailnet IP (UDP/TCP 53).
- Add split DNS so your discovery domain uses that nameserver.
Once clients accept tailnet DNS, iOS nodes and CLI discovery can browse
@@ -74,7 +72,7 @@ Once clients accept tailnet DNS, iOS nodes and CLI discovery can browse
The Gateway WS port (default `18789`) binds to loopback by default. For LAN/tailnet
access, bind explicitly and keep auth enabled.
-For tailnet‑only setups:
+For tailnet-only setups:
- Set `gateway.bind: "tailnet"` in `~/.openclaw/openclaw.json`.
- Restart the Gateway (or restart the macOS menubar app).
@@ -87,11 +85,11 @@ DNS-SD publishing remains Gateway-owned.
## Service types
-- `_openclaw-gw._tcp` — gateway transport beacon (used by macOS/iOS/Android nodes).
+- `_openclaw-gw._tcp` - gateway transport beacon (used by macOS/iOS/Android nodes).
## TXT keys (non-secret hints)
-The Gateway advertises small non‑secret hints to make UI flows convenient:
+The Gateway advertises small non-secret hints to make UI flows convenient:
- `role=gateway`
- `displayName=`
@@ -115,7 +113,7 @@ Security notes:
## Debugging on macOS
-Useful built‑in tools:
+Useful built-in tools:
- Browse instances:
@@ -129,7 +127,7 @@ Useful built‑in tools:
dns-sd -L "" _openclaw-gw._tcp local.
```
-If browsing works but resolving fails, you’re usually hitting a LAN policy or
+If browsing works but resolving fails, you're usually hitting a LAN policy or
mDNS resolver issue.
## Debugging in Gateway logs
@@ -158,7 +156,7 @@ To capture logs:
- Settings → Gateway → Advanced → **Discovery Debug Logs**
- Settings → Gateway → Advanced → **Discovery Logs** → reproduce → **Copy**
-The log includes browser state transitions and result‑set changes.
+The log includes browser state transitions and result-set changes.
## When to enable Bonjour
@@ -257,8 +255,8 @@ If a node no longer auto-discovers the Gateway after Docker setup:
## Common failure modes
-- **Bonjour doesn’t cross networks**: use Tailnet or SSH.
-- **Multicast blocked**: some Wi‑Fi networks disable mDNS.
+- **Bonjour doesn't cross networks**: use Tailnet or SSH.
+- **Multicast blocked**: some Wi-Fi networks disable mDNS.
- **Advertiser stuck in probing/announcing**: hosts with blocked multicast,
container bridges, WSL, or interface churn can leave the ciao advertiser in a
non-announced state. OpenClaw retries a few times and then disables Bonjour
@@ -273,7 +271,7 @@ If a node no longer auto-discovers the Gateway after Docker setup:
## Escaped instance names (`\032`)
-Bonjour/DNS‑SD often escapes bytes in service instance names as decimal `\DDD`
+Bonjour/DNS-SD often escapes bytes in service instance names as decimal `\DDD`
sequences (e.g. spaces become `\032`).
- This is normal at the protocol level.
diff --git a/docs/tools/browser.md b/docs/tools/browser.md
index 1ee22369008..4421ec627e0 100644
--- a/docs/tools/browser.md
+++ b/docs/tools/browser.md
@@ -42,7 +42,7 @@ openclaw browser --browser-profile openclaw open https://example.com
openclaw browser --browser-profile openclaw snapshot
```
-If you get “Browser disabled”, enable it in config (see below) and restart the
+If you get "Browser disabled", enable it in config (see below) and restart the
Gateway.
If `openclaw browser` is missing entirely, or the agent says the browser tool
@@ -342,10 +342,10 @@ This is the default path for remote gateways.
Notes:
- The node host exposes its local browser control server via a **proxy command**.
-- Profiles come from the node’s own `browser.profiles` config (same as local).
+- Profiles come from the node's own `browser.profiles` config (same as local).
- `nodeHost.browserProxy.allowProfiles` is optional. Leave it empty for the legacy/default behavior: all configured profiles remain reachable through the proxy, including profile create/delete routes.
- If you set `nodeHost.browserProxy.allowProfiles`, OpenClaw treats it as a least-privilege boundary: only allowlisted profiles can be targeted, and persistent profile create/delete routes are blocked on the proxy surface.
-- Disable if you don’t want it:
+- Disable if you don't want it:
- On the node: `nodeHost.browserProxy.enabled=false`
- On the gateway: `gateway.nodes.browser.mode="off"`
@@ -422,14 +422,14 @@ Some hosted browser services expose a **direct WebSocket** endpoint rather than
the standard HTTP-based CDP discovery (`/json/version`). OpenClaw accepts three
CDP URL shapes and picks the right connection strategy automatically:
-- **HTTP(S) discovery** — `http://host[:port]` or `https://host[:port]`.
+- **HTTP(S) discovery** - `http://host[:port]` or `https://host[:port]`.
OpenClaw calls `/json/version` to discover the WebSocket debugger URL, then
connects. No WebSocket fallback.
-- **Direct WebSocket endpoints** — `ws://host[:port]/devtools//` or
+- **Direct WebSocket endpoints** - `ws://host[:port]/devtools//` or
`wss://...` with a `/devtools/browser|page|worker|shared_worker|service_worker/`
path. OpenClaw connects directly via a WebSocket handshake and skips
`/json/version` entirely.
-- **Bare WebSocket roots** — `ws://host[:port]` or `wss://host[:port]` with no
+- **Bare WebSocket roots** - `ws://host[:port]` or `wss://host[:port]` with no
`/devtools/...` path (e.g. [Browserless](https://browserless.io),
[Browserbase](https://www.browserbase.com)). OpenClaw tries HTTP
`/json/version` discovery first (normalising the scheme to `http`/`https`);
@@ -481,7 +481,7 @@ Notes:
Key ideas:
-- Browser control is loopback-only; access flows through the Gateway’s auth or node pairing.
+- Browser control is loopback-only; access flows through the Gateway's auth or node pairing.
- The standalone loopback browser HTTP API uses **shared-secret auth only**:
gateway token bearer auth, `x-openclaw-password`, or HTTP Basic auth with the
configured gateway password.
@@ -512,7 +512,7 @@ Defaults:
- The `openclaw` profile is auto-created if missing.
- The `user` profile is built-in for Chrome MCP existing-session attach.
- Existing-session profiles are opt-in beyond `user`; create them with `--driver existing-session`.
-- Local CDP ports allocate from **18800–18899** by default.
+- Local CDP ports allocate from **18800-18899** by default.
- Deleting a profile moves its local data directory to Trash.
All control endpoints accept `?profile=`; the CLI uses `--browser-profile`.
@@ -598,7 +598,7 @@ What to check if attach does not work:
Agent use:
-- Use `profile="user"` when you need the user’s logged-in browser state.
+- Use `profile="user"` when you need the user's logged-in browser state.
- If you use a custom existing-session profile, pass that explicit profile name.
- Only choose this mode when the user is at the computer to approve the attach
prompt.
@@ -641,10 +641,10 @@ directory.
Compared to the managed `openclaw` profile, existing-session drivers are more constrained:
-- **Screenshots** — page captures and `--ref` element captures work; CSS `--element` selectors do not. `--full-page` cannot combine with `--ref` or `--element`. Playwright is not required for page or ref-based element screenshots.
-- **Actions** — `click`, `type`, `hover`, `scrollIntoView`, `drag`, and `select` require snapshot refs (no CSS selectors). `click-coords` clicks visible viewport coordinates and does not require a snapshot ref. `click` is left-button only. `type` does not support `slowly=true`; use `fill` or `press`. `press` does not support `delayMs`. `type`, `hover`, `scrollIntoView`, `drag`, `select`, `fill`, and `evaluate` do not support per-call timeouts. `select` accepts a single value.
-- **Wait / upload / dialog** — `wait --url` supports exact, substring, and glob patterns; `wait --load networkidle` is not supported. Upload hooks require `ref` or `inputRef`, one file at a time, no CSS `element`. Dialog hooks do not support timeout overrides.
-- **Managed-only features** — batch actions, PDF export, download interception, and `responsebody` still require the managed browser path.
+- **Screenshots** - page captures and `--ref` element captures work; CSS `--element` selectors do not. `--full-page` cannot combine with `--ref` or `--element`. Playwright is not required for page or ref-based element screenshots.
+- **Actions** - `click`, `type`, `hover`, `scrollIntoView`, `drag`, and `select` require snapshot refs (no CSS selectors). `click-coords` clicks visible viewport coordinates and does not require a snapshot ref. `click` is left-button only. `type` does not support `slowly=true`; use `fill` or `press`. `press` does not support `delayMs`. `type`, `hover`, `scrollIntoView`, `drag`, `select`, `fill`, and `evaluate` do not support per-call timeouts. `select` accepts a single value.
+- **Wait / upload / dialog** - `wait --url` supports exact, substring, and glob patterns; `wait --load networkidle` is not supported. Upload hooks require `ref` or `inputRef`, one file at a time, no CSS `element`. Dialog hooks do not support timeout overrides.
+- **Managed-only features** - batch actions, PDF export, download interception, and `responsebody` still require the managed browser path.
@@ -740,7 +740,7 @@ Security guidance:
The agent gets **one tool** for browser automation:
-- `browser` — doctor/status/start/stop/tabs/open/focus/close/snapshot/screenshot/navigate/act
+- `browser` - doctor/status/start/stop/tabs/open/focus/close/snapshot/screenshot/navigate/act
How it maps:
@@ -759,6 +759,6 @@ This keeps the agent deterministic and avoids brittle selectors.
## Related
-- [Tools Overview](/tools) — all available agent tools
-- [Sandboxing](/gateway/sandboxing) — browser control in sandboxed environments
-- [Security](/gateway/security) — browser control risks and hardening
+- [Tools Overview](/tools) - all available agent tools
+- [Sandboxing](/gateway/sandboxing) - browser control in sandboxed environments
+- [Security](/gateway/security) - browser control risks and hardening