mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:10:44 +00:00
docs: typography hygiene across 5 pages
Replaced 75 typography characters (curly quotes, apostrophes, em/en dashes, non-breaking hyphens) with ASCII equivalents per docs/CLAUDE.md heading and content hygiene rules. - docs/plugins/skill-workshop.md: 15 chars - docs/gateway/pairing.md: 15 chars - docs/gateway/configuration.md: 15 chars - docs/concepts/oauth.md: 15 chars - docs/channels/bluebubbles.md: 15 chars
This commit is contained in:
@@ -381,7 +381,7 @@ BlueBubbles supports advanced message actions when enabled in config:
|
||||
- **reply**: Reply to a specific message (`messageId`, `text`, `to`).
|
||||
- **sendWithEffect**: Send with iMessage effect (`text`, `to`, `effectId`).
|
||||
- **renameGroup**: Rename a group chat (`chatGuid`, `displayName`).
|
||||
- **setGroupIcon**: Set a group chat's icon/photo (`chatGuid`, `media`) — flaky on macOS 26 Tahoe (API may return success but the icon does not sync).
|
||||
- **setGroupIcon**: Set a group chat's icon/photo (`chatGuid`, `media`) - flaky on macOS 26 Tahoe (API may return success but the icon does not sync).
|
||||
- **addParticipant**: Add someone to a group (`chatGuid`, `address`).
|
||||
- **removeParticipant**: Remove someone from a group (`chatGuid`, `address`).
|
||||
- **leaveGroup**: Leave a group chat (`chatGuid`).
|
||||
@@ -412,12 +412,12 @@ See [Configuration](/gateway/configuration) for template variables.
|
||||
|
||||
## Coalescing split-send DMs (command + URL in one composition)
|
||||
|
||||
When a user types a command and a URL together in iMessage — e.g. `Dump https://example.com/article` — Apple splits the send into **two separate webhook deliveries**:
|
||||
When a user types a command and a URL together in iMessage - e.g. `Dump https://example.com/article` - Apple splits the send into **two separate webhook deliveries**:
|
||||
|
||||
1. A text message (`"Dump"`).
|
||||
2. A URL-preview balloon (`"https://..."`) with OG-preview images as attachments.
|
||||
|
||||
The two webhooks arrive at OpenClaw ~0.8-2.0 s apart on most setups. Without coalescing, the agent receives the command alone on turn 1, replies (often "send me the URL"), and only sees the URL on turn 2 — at which point the command context is already lost.
|
||||
The two webhooks arrive at OpenClaw ~0.8-2.0 s apart on most setups. Without coalescing, the agent receives the command alone on turn 1, replies (often "send me the URL"), and only sees the URL on turn 2 - at which point the command context is already lost.
|
||||
|
||||
`channels.bluebubbles.coalesceSameSenderDms` opts a DM into merging consecutive same-sender webhooks into a single agent turn. Group chats continue to key per-message so multi-user turn structure is preserved.
|
||||
|
||||
@@ -446,7 +446,7 @@ The two webhooks arrive at OpenClaw ~0.8-2.0 s apart on most setups. Without coa
|
||||
}
|
||||
```
|
||||
|
||||
With the flag on and no explicit `messages.inbound.byChannel.bluebubbles`, the debounce window widens to **2500 ms** (the default for non-coalescing is 500 ms). The wider window is required — Apple's split-send cadence of 0.8-2.0 s does not fit in the tighter default.
|
||||
With the flag on and no explicit `messages.inbound.byChannel.bluebubbles`, the debounce window widens to **2500 ms** (the default for non-coalescing is 500 ms). The wider window is required - Apple's split-send cadence of 0.8-2.0 s does not fit in the tighter default.
|
||||
|
||||
To tune the window yourself:
|
||||
|
||||
@@ -467,7 +467,7 @@ The two webhooks arrive at OpenClaw ~0.8-2.0 s apart on most setups. Without coa
|
||||
</Tab>
|
||||
<Tab title="Trade-offs">
|
||||
- **Added latency for DM control commands.** With the flag on, DM control-command messages (like `Dump`, `Save`, etc.) now wait up to the debounce window before dispatching, in case a payload webhook is coming. Group-chat commands keep instant dispatch.
|
||||
- **Merged output is bounded** — merged text caps at 4000 chars with an explicit `…[truncated]` marker; attachments cap at 20; source entries cap at 10 (first-plus-latest retained beyond that). Every source `messageId` still reaches inbound-dedupe so a later MessagePoller replay of any individual event is recognized as a duplicate.
|
||||
- **Merged output is bounded** - merged text caps at 4000 chars with an explicit `…[truncated]` marker; attachments cap at 20; source entries cap at 10 (first-plus-latest retained beyond that). Every source `messageId` still reaches inbound-dedupe so a later MessagePoller replay of any individual event is recognized as a duplicate.
|
||||
- **Opt-in, per-channel.** Other channels (Telegram, WhatsApp, Slack, …) are unaffected.
|
||||
|
||||
</Tab>
|
||||
@@ -494,7 +494,7 @@ If the flag is on and split-sends still arrive as two turns, check each layer:
|
||||
grep coalesceSameSenderDms ~/.openclaw/openclaw.json
|
||||
```
|
||||
|
||||
Then `openclaw gateway restart` — the flag is read at debouncer-registry creation.
|
||||
Then `openclaw gateway restart` - the flag is read at debouncer-registry creation.
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Debounce window wide enough for your setup">
|
||||
@@ -508,13 +508,13 @@ If the flag is on and split-sends still arrive as two turns, check each layer:
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="Session JSONL timestamps ≠ webhook arrival">
|
||||
Session event timestamps (`~/.openclaw/agents/<id>/sessions/*.jsonl`) reflect when the gateway hands a message to the agent, **not** when the webhook arrived. A queued-second message tagged `[Queued messages while agent was busy]` means the first turn was still running when the second webhook arrived — the coalesce bucket had already flushed. Tune the window against the BB server log, not the session log.
|
||||
Session event timestamps (`~/.openclaw/agents/<id>/sessions/*.jsonl`) reflect when the gateway hands a message to the agent, **not** when the webhook arrived. A queued-second message tagged `[Queued messages while agent was busy]` means the first turn was still running when the second webhook arrived - the coalesce bucket had already flushed. Tune the window against the BB server log, not the session log.
|
||||
</Accordion>
|
||||
<Accordion title="Memory pressure slowing reply dispatch">
|
||||
On smaller machines (8 GB), agent turns can take long enough that the coalesce bucket flushes before the reply completes, and the URL lands as a queued second turn. Check `memory_pressure` and `ps -o rss -p $(pgrep openclaw-gateway)`; if the gateway is over ~500 MB RSS and the compressor is active, close other heavy processes or bump to a larger host.
|
||||
</Accordion>
|
||||
<Accordion title="Reply-quote sends are a different path">
|
||||
If the user tapped `Dump` as a **reply** to an existing URL-balloon (iMessage shows a "1 Reply" badge on the Dump bubble), the URL lives in `replyToBody`, not in a second webhook. Coalescing does not apply — that's a skill/prompt concern, not a debouncer concern.
|
||||
If the user tapped `Dump` as a **reply** to an existing URL-balloon (iMessage shows a "1 Reply" badge on the Dump bubble), the URL lives in `replyToBody`, not in a second webhook. Coalescing does not apply - that's a skill/prompt concern, not a debouncer concern.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
@@ -617,15 +617,15 @@ When the same handle has both an iMessage and an SMS chat on the Mac (for exampl
|
||||
- Edit/unsend require macOS 13+ and a compatible BlueBubbles server version. On macOS 26 (Tahoe), edit is currently broken due to private API changes.
|
||||
- Group icon updates can be flaky on macOS 26 (Tahoe): the API may return success but the new icon does not sync.
|
||||
- OpenClaw auto-hides known-broken actions based on the BlueBubbles server's macOS version. If edit still appears on macOS 26 (Tahoe), disable it manually with `channels.bluebubbles.actions.edit=false`.
|
||||
- `coalesceSameSenderDms` enabled but split-sends (e.g. `Dump` + URL) still arrive as two turns: see the [split-send coalescing troubleshooting](#split-send-coalescing-troubleshooting) checklist — common causes are too-tight debounce window, session-log timestamps misread as webhook arrival, or a reply-quote send (which uses `replyToBody`, not a second webhook).
|
||||
- `coalesceSameSenderDms` enabled but split-sends (e.g. `Dump` + URL) still arrive as two turns: see the [split-send coalescing troubleshooting](#split-send-coalescing-troubleshooting) checklist - common causes are too-tight debounce window, session-log timestamps misread as webhook arrival, or a reply-quote send (which uses `replyToBody`, not a second webhook).
|
||||
- For status/health info: `openclaw status --all` or `openclaw status --deep`.
|
||||
|
||||
For general channel workflow reference, see [Channels](/channels) and the [Plugins](/tools/plugin) guide.
|
||||
|
||||
## Related
|
||||
|
||||
- [Channel Routing](/channels/channel-routing) — session routing for messages
|
||||
- [Channels Overview](/channels) — all supported channels
|
||||
- [Groups](/channels/groups) — group chat behavior and mention gating
|
||||
- [Pairing](/channels/pairing) — DM authentication and pairing flow
|
||||
- [Security](/gateway/security) — access model and hardening
|
||||
- [Channel Routing](/channels/channel-routing) - session routing for messages
|
||||
- [Channels Overview](/channels) - all supported channels
|
||||
- [Groups](/channels/groups) - group chat behavior and mention gating
|
||||
- [Pairing](/channels/pairing) - DM authentication and pairing flow
|
||||
- [Security](/gateway/security) - access model and hardening
|
||||
|
||||
@@ -8,7 +8,7 @@ read_when:
|
||||
title: "OAuth"
|
||||
---
|
||||
|
||||
OpenClaw supports “subscription auth” via OAuth for providers that offer it
|
||||
OpenClaw supports "subscription auth" via OAuth for providers that offer it
|
||||
(notably **OpenAI Codex (ChatGPT OAuth)**). For Anthropic, the practical split
|
||||
is now:
|
||||
|
||||
@@ -25,7 +25,7 @@ For Anthropic in production, API key auth is the safer recommended path.
|
||||
- where tokens are **stored** (and why)
|
||||
- how to handle **multiple accounts** (profiles + per-session overrides)
|
||||
|
||||
OpenClaw also supports **provider plugins** that ship their own OAuth or API‑key
|
||||
OpenClaw also supports **provider plugins** that ship their own OAuth or API-key
|
||||
flows. Run them via:
|
||||
|
||||
```bash
|
||||
@@ -38,7 +38,7 @@ OAuth providers commonly mint a **new refresh token** during login/refresh flows
|
||||
|
||||
Practical symptom:
|
||||
|
||||
- you log in via OpenClaw _and_ via Claude Code / Codex CLI → one of them randomly gets “logged out” later
|
||||
- you log in via OpenClaw _and_ via Claude Code / Codex CLI → one of them randomly gets "logged out" later
|
||||
|
||||
To reduce that, OpenClaw treats `auth-profiles.json` as a **token sink**:
|
||||
|
||||
@@ -105,7 +105,7 @@ Claude login on the host, onboarding/configure can reuse it directly.
|
||||
|
||||
## OAuth exchange (how login works)
|
||||
|
||||
OpenClaw’s interactive login flows are implemented in `@mariozechner/pi-ai` and wired into the wizards/commands.
|
||||
OpenClaw's interactive login flows are implemented in `@mariozechner/pi-ai` and wired into the wizards/commands.
|
||||
|
||||
### Anthropic setup-token
|
||||
|
||||
@@ -125,7 +125,7 @@ Flow shape (PKCE):
|
||||
1. generate PKCE verifier/challenge + random `state`
|
||||
2. open `https://auth.openai.com/oauth/authorize?...`
|
||||
3. try to capture callback on `http://127.0.0.1:1455/auth/callback`
|
||||
4. if callback can’t bind (or you’re remote/headless), paste the redirect URL/code
|
||||
4. if callback can't bind (or you're remote/headless), paste the redirect URL/code
|
||||
5. exchange at `https://auth.openai.com/oauth/token`
|
||||
6. extract `accountId` from the access token and store `{ access, refresh, expires, accountId }`
|
||||
|
||||
@@ -156,7 +156,7 @@ Two patterns:
|
||||
|
||||
### 1) Preferred: separate agents
|
||||
|
||||
If you want “personal” and “work” to never interact, use isolated agents (separate sessions + credentials + workspace):
|
||||
If you want "personal" and "work" to never interact, use isolated agents (separate sessions + credentials + workspace):
|
||||
|
||||
```bash
|
||||
openclaw agents add work
|
||||
@@ -189,6 +189,6 @@ Related docs:
|
||||
|
||||
## Related
|
||||
|
||||
- [Authentication](/gateway/authentication) — model provider auth overview
|
||||
- [Secrets](/gateway/secrets) — credential storage and SecretRef
|
||||
- [Configuration Reference](/gateway/configuration-reference#auth-storage) — auth config keys
|
||||
- [Authentication](/gateway/authentication) - model provider auth overview
|
||||
- [Secrets](/gateway/secrets) - credential storage and SecretRef
|
||||
- [Configuration Reference](/gateway/configuration-reference#auth-storage) - auth config keys
|
||||
|
||||
@@ -103,16 +103,16 @@ candidate contains redacted secret placeholders such as `***`.
|
||||
<Accordion title="Set up a channel (WhatsApp, Telegram, Discord, etc.)">
|
||||
Each channel has its own config section under `channels.<provider>`. See the dedicated channel page for setup steps:
|
||||
|
||||
- [WhatsApp](/channels/whatsapp) — `channels.whatsapp`
|
||||
- [Telegram](/channels/telegram) — `channels.telegram`
|
||||
- [Discord](/channels/discord) — `channels.discord`
|
||||
- [Feishu](/channels/feishu) — `channels.feishu`
|
||||
- [Google Chat](/channels/googlechat) — `channels.googlechat`
|
||||
- [Microsoft Teams](/channels/msteams) — `channels.msteams`
|
||||
- [Slack](/channels/slack) — `channels.slack`
|
||||
- [Signal](/channels/signal) — `channels.signal`
|
||||
- [iMessage](/channels/imessage) — `channels.imessage`
|
||||
- [Mattermost](/channels/mattermost) — `channels.mattermost`
|
||||
- [WhatsApp](/channels/whatsapp) - `channels.whatsapp`
|
||||
- [Telegram](/channels/telegram) - `channels.telegram`
|
||||
- [Discord](/channels/discord) - `channels.discord`
|
||||
- [Feishu](/channels/feishu) - `channels.feishu`
|
||||
- [Google Chat](/channels/googlechat) - `channels.googlechat`
|
||||
- [Microsoft Teams](/channels/msteams) - `channels.msteams`
|
||||
- [Slack](/channels/slack) - `channels.slack`
|
||||
- [Signal](/channels/signal) - `channels.signal`
|
||||
- [iMessage](/channels/imessage) - `channels.imessage`
|
||||
- [Mattermost](/channels/mattermost) - `channels.mattermost`
|
||||
|
||||
All channels share the same DM policy pattern:
|
||||
|
||||
@@ -329,7 +329,7 @@ candidate contains redacted secret placeholders such as `***`.
|
||||
}
|
||||
```
|
||||
|
||||
Build the image first — from a source checkout run `scripts/sandbox-setup.sh`, or from an npm install see the inline `docker build` command in [Sandboxing § Images and setup](/gateway/sandboxing#images-and-setup).
|
||||
Build the image first - from a source checkout run `scripts/sandbox-setup.sh`, or from an npm install see the inline `docker build` command in [Sandboxing § Images and setup](/gateway/sandboxing#images-and-setup).
|
||||
|
||||
See [Sandboxing](/gateway/sandboxing) for the full guide and [full reference](/gateway/config-agents#agentsdefaultssandbox) for all options.
|
||||
|
||||
@@ -531,7 +531,7 @@ candidate contains redacted secret placeholders such as `***`.
|
||||
|
||||
## Config hot reload
|
||||
|
||||
The Gateway watches `~/.openclaw/openclaw.json` and applies changes automatically — no manual restart needed for most settings.
|
||||
The Gateway watches `~/.openclaw/openclaw.json` and applies changes automatically - no manual restart needed for most settings.
|
||||
|
||||
Direct file edits are treated as untrusted until they validate. The watcher waits
|
||||
for editor temp-write/rename churn to settle, reads the final file, and rejects
|
||||
@@ -550,7 +550,7 @@ for the checklist.
|
||||
| Mode | Behavior |
|
||||
| ---------------------- | --------------------------------------------------------------------------------------- |
|
||||
| **`hybrid`** (default) | Hot-applies safe changes instantly. Automatically restarts for critical ones. |
|
||||
| **`hot`** | Hot-applies safe changes only. Logs a warning when a restart is needed — you handle it. |
|
||||
| **`hot`** | Hot-applies safe changes only. Logs a warning when a restart is needed - you handle it. |
|
||||
| **`restart`** | Restarts the Gateway on any config change, safe or not. |
|
||||
| **`off`** | Disables file watching. Changes take effect on the next manual restart. |
|
||||
|
||||
@@ -568,7 +568,7 @@ Most fields hot-apply without downtime. In `hybrid` mode, restart-required chang
|
||||
|
||||
| Category | Fields | Restart needed? |
|
||||
| ------------------- | ----------------------------------------------------------------- | --------------- |
|
||||
| Channels | `channels.*`, `web` (WhatsApp) — all built-in and plugin channels | No |
|
||||
| Channels | `channels.*`, `web` (WhatsApp) - all built-in and plugin channels | No |
|
||||
| Agent & models | `agent`, `agents`, `models`, `routing` | No |
|
||||
| Automation | `hooks`, `cron`, `agent.heartbeat` | No |
|
||||
| Sessions & messages | `session`, `messages` | No |
|
||||
@@ -578,7 +578,7 @@ Most fields hot-apply without downtime. In `hybrid` mode, restart-required chang
|
||||
| Infrastructure | `discovery`, `canvasHost`, `plugins` | **Yes** |
|
||||
|
||||
<Note>
|
||||
`gateway.reload` and `gateway.remote` are exceptions — changing them does **not** trigger a restart.
|
||||
`gateway.reload` and `gateway.remote` are exceptions - changing them does **not** trigger a restart.
|
||||
</Note>
|
||||
|
||||
### Reload planning
|
||||
|
||||
@@ -27,8 +27,8 @@ Only clients that explicitly call `node.pair.*` use this flow.
|
||||
1. A node connects to the Gateway WS and requests pairing.
|
||||
2. The Gateway stores a **pending request** and emits `node.pair.requested`.
|
||||
3. You approve or reject the request (CLI or UI).
|
||||
4. On approval, the Gateway issues a **new token** (tokens are rotated on re‑pair).
|
||||
5. The node reconnects using the token and is now “paired”.
|
||||
4. On approval, the Gateway issues a **new token** (tokens are rotated on re-pair).
|
||||
5. The node reconnects using the token and is now "paired".
|
||||
|
||||
Pending requests expire automatically after **5 minutes**.
|
||||
|
||||
@@ -49,17 +49,17 @@ openclaw nodes rename --node <id|name|ip> --name "Living Room iPad"
|
||||
|
||||
Events:
|
||||
|
||||
- `node.pair.requested` — emitted when a new pending request is created.
|
||||
- `node.pair.resolved` — emitted when a request is approved/rejected/expired.
|
||||
- `node.pair.requested` - emitted when a new pending request is created.
|
||||
- `node.pair.resolved` - emitted when a request is approved/rejected/expired.
|
||||
|
||||
Methods:
|
||||
|
||||
- `node.pair.request` — create or reuse a pending request.
|
||||
- `node.pair.list` — list pending + paired nodes (`operator.pairing`).
|
||||
- `node.pair.approve` — approve a pending request (issues token).
|
||||
- `node.pair.reject` — reject a pending request.
|
||||
- `node.pair.remove` — remove a stale paired node entry.
|
||||
- `node.pair.verify` — verify `{ nodeId, token }`.
|
||||
- `node.pair.request` - create or reuse a pending request.
|
||||
- `node.pair.list` - list pending + paired nodes (`operator.pairing`).
|
||||
- `node.pair.approve` - approve a pending request (issues token).
|
||||
- `node.pair.reject` - reject a pending request.
|
||||
- `node.pair.remove` - remove a stale paired node entry.
|
||||
- `node.pair.verify` - verify `{ nodeId, token }`.
|
||||
|
||||
Notes:
|
||||
|
||||
@@ -120,7 +120,7 @@ The macOS app can optionally attempt a **silent approval** when:
|
||||
- the request is marked `silent`, and
|
||||
- the app can verify an SSH connection to the gateway host using the same user.
|
||||
|
||||
If silent approval fails, it falls back to the normal “Approve/Reject” prompt.
|
||||
If silent approval fails, it falls back to the normal "Approve/Reject" prompt.
|
||||
|
||||
## Trusted-CIDR device auto-approval
|
||||
|
||||
@@ -159,7 +159,7 @@ to trusted non-browser local reconnects that already proved possession of local
|
||||
or shared credentials, including same-host native app reconnects after OS
|
||||
version metadata changes. Browser/Control UI clients and remote clients still
|
||||
use the explicit re-approval flow. Scope upgrades (read to write/admin) and
|
||||
public key changes are **not** eligible for metadata-upgrade auto-approval —
|
||||
public key changes are **not** eligible for metadata-upgrade auto-approval -
|
||||
they stay as explicit re-approval requests.
|
||||
|
||||
## QR pairing helpers
|
||||
@@ -199,7 +199,7 @@ Security notes:
|
||||
|
||||
- The transport is **stateless**; it does not store membership.
|
||||
- If the Gateway is offline or pairing is disabled, nodes cannot pair.
|
||||
- If the Gateway is in remote mode, pairing still happens against the remote Gateway’s store.
|
||||
- If the Gateway is in remote mode, pairing still happens against the remote Gateway's store.
|
||||
|
||||
## Related
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ Skill Workshop is useful when the agent learns a procedure such as:
|
||||
|
||||
It is not intended for:
|
||||
|
||||
- facts like “the user likes blue”
|
||||
- facts like "the user likes blue"
|
||||
- broad autobiographical memory
|
||||
- raw transcript archiving
|
||||
- secrets, credentials, or hidden prompt text
|
||||
@@ -217,7 +217,7 @@ The reviewer has no tools:
|
||||
- `toolsAllow: []`
|
||||
- `disableMessageTool: true`
|
||||
|
||||
The reviewer returns either `{ "action": "none" }` or one proposal. The `action` field is `create`, `append`, or `replace` — prefer `append`/`replace` when a relevant skill already exists; use `create` only when no existing skill fits.
|
||||
The reviewer returns either `{ "action": "none" }` or one proposal. The `action` field is `create`, `append`, or `replace` - prefer `append`/`replace` when a relevant skill already exists; use `create` only when no existing skill fits.
|
||||
|
||||
Example `create`:
|
||||
|
||||
@@ -579,12 +579,12 @@ warning/debug message and skips that review pass.
|
||||
|
||||
Use Skill Workshop when the user says:
|
||||
|
||||
- “next time, do X”
|
||||
- “from now on, prefer Y”
|
||||
- “make sure to verify Z”
|
||||
- “save this as a workflow”
|
||||
- “this took a while; remember the process”
|
||||
- “update the local skill for this”
|
||||
- "next time, do X"
|
||||
- "from now on, prefer Y"
|
||||
- "make sure to verify Z"
|
||||
- "save this as a workflow"
|
||||
- "this took a while; remember the process"
|
||||
- "update the local skill for this"
|
||||
|
||||
Good skill text:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user