Compare commits

..

7 Commits

Author SHA1 Message Date
Alex Knight
7848b5296e feat(plugins): add bundled plugin policy 2026-04-24 18:55:02 +10:00
Alex Knight
6b62abff43 fix(plugin-sdk): avoid stealing fresh file locks 2026-04-24 12:54:47 +10:00
Alex Knight
366c180915 fix(plugin-sdk): align persistence queue hardening 2026-04-24 12:44:37 +10:00
Alex Knight
0825b75477 fix(plugin-sdk): harden persistent keyed store edge cases 2026-04-24 12:44:08 +10:00
Alex Knight
4de31692ac fix(plugin-sdk): harden persistent keyed store concurrency 2026-04-24 12:43:39 +10:00
Alex Knight
100b41afd6 feat(plugin-sdk): export persistent keyed store 2026-04-24 12:43:09 +10:00
Alex Knight
9b09445510 feat(plugin-sdk): add persistent keyed store 2026-04-24 12:42:28 +10:00
162 changed files with 5493 additions and 6429 deletions

View File

@@ -14,10 +14,6 @@ on:
description: Optional comma-separated Telegram scenario ids
required: false
type: string
discord_scenario:
description: Optional comma-separated Discord scenario ids
required: false
type: string
permissions:
contents: read
@@ -350,95 +346,3 @@ jobs:
path: ${{ steps.run_lane.outputs.output_dir }}
retention-days: 14
if-no-files-found: warn
run_live_discord:
name: Run Discord live QA lane with Convex leases
needs: [authorize_actor, validate_selected_ref]
runs-on: blacksmith-32vcpu-ubuntu-2404
timeout-minutes: 60
environment: qa-live-shared
steps:
- name: Checkout selected ref
uses: actions/checkout@v6
with:
ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
fetch-depth: 1
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
node-version: ${{ env.NODE_VERSION }}
pnpm-version: ${{ env.PNPM_VERSION }}
install-bun: "true"
- name: Validate required QA credential env
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
shell: bash
run: |
set -euo pipefail
require_var() {
local key="$1"
if [[ -z "${!key:-}" ]]; then
echo "Missing required ${key}." >&2
exit 1
fi
}
require_var OPENAI_API_KEY
require_var OPENCLAW_QA_CONVEX_SITE_URL
require_var OPENCLAW_QA_CONVEX_SECRET_CI
- name: Build private QA runtime
run: pnpm build
- name: Run Discord live lane
id: run_lane
shell: bash
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
OPENCLAW_QA_DISCORD_CAPTURE_CONTENT: "1"
INPUT_SCENARIO: ${{ github.event_name == 'workflow_dispatch' && inputs.discord_scenario || '' }}
run: |
set -euo pipefail
output_dir=".artifacts/qa-e2e/discord-live-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
scenario_args=()
if [[ -n "${INPUT_SCENARIO// }" ]]; then
IFS=',' read -r -a raw_scenarios <<<"${INPUT_SCENARIO}"
for raw in "${raw_scenarios[@]}"; do
scenario="$(printf '%s' "${raw}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
if [[ -n "${scenario}" ]]; then
scenario_args+=(--scenario "${scenario}")
fi
done
fi
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
pnpm openclaw qa discord \
--repo-root . \
--output-dir "${output_dir}" \
--provider-mode live-frontier \
--model openai/gpt-5.4 \
--alt-model openai/gpt-5.4 \
--fast \
--credential-source convex \
--credential-role ci \
"${scenario_args[@]}"
- name: Upload Discord QA artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: qa-live-discord-${{ github.run_id }}-${{ github.run_attempt }}
path: ${{ steps.run_lane.outputs.output_dir }}
retention-days: 14
if-no-files-found: warn

View File

@@ -2325,66 +2325,6 @@ public struct TalkConfigResult: Codable, Sendable {
}
}
public struct TalkRealtimeSessionParams: Codable, Sendable {
public let sessionkey: String?
public let provider: String?
public let model: String?
public let voice: String?
public let instructions: String?
public init(
sessionkey: String?,
provider: String?,
model: String?,
voice: String?,
instructions: String?)
{
self.sessionkey = sessionkey
self.provider = provider
self.model = model
self.voice = voice
self.instructions = instructions
}
private enum CodingKeys: String, CodingKey {
case sessionkey = "sessionKey"
case provider
case model
case voice
case instructions
}
}
public struct TalkRealtimeSessionResult: Codable, Sendable {
public let provider: String
public let clientsecret: String
public let model: String?
public let voice: String?
public let expiresat: Double?
public init(
provider: String,
clientsecret: String,
model: String?,
voice: String?,
expiresat: Double?)
{
self.provider = provider
self.clientsecret = clientsecret
self.model = model
self.voice = voice
self.expiresat = expiresat
}
private enum CodingKeys: String, CodingKey {
case provider
case clientsecret = "clientSecret"
case model
case voice
case expiresat = "expiresAt"
}
}
public struct TalkSpeakParams: Codable, Sendable {
public let text: String
public let voiceid: String?

View File

@@ -2325,66 +2325,6 @@ public struct TalkConfigResult: Codable, Sendable {
}
}
public struct TalkRealtimeSessionParams: Codable, Sendable {
public let sessionkey: String?
public let provider: String?
public let model: String?
public let voice: String?
public let instructions: String?
public init(
sessionkey: String?,
provider: String?,
model: String?,
voice: String?,
instructions: String?)
{
self.sessionkey = sessionkey
self.provider = provider
self.model = model
self.voice = voice
self.instructions = instructions
}
private enum CodingKeys: String, CodingKey {
case sessionkey = "sessionKey"
case provider
case model
case voice
case instructions
}
}
public struct TalkRealtimeSessionResult: Codable, Sendable {
public let provider: String
public let clientsecret: String
public let model: String?
public let voice: String?
public let expiresat: Double?
public init(
provider: String,
clientsecret: String,
model: String?,
voice: String?,
expiresat: Double?)
{
self.provider = provider
self.clientsecret = clientsecret
self.model = model
self.voice = voice
self.expiresat = expiresat
}
private enum CodingKeys: String, CodingKey {
case provider
case clientsecret = "clientSecret"
case model
case voice
case expiresat = "expiresAt"
}
}
public struct TalkSpeakParams: Codable, Sendable {
public let text: String
public let voiceid: String?

View File

@@ -1,4 +1,4 @@
d3b5638e205a94e40d07aa1830c8d57135df18ff9388fb7d72ee84c791ac293f config-baseline.json
bf00f7910d8f0d8e12592e8a1c6bd0397f8e62fef2c11eb0cbd3b3a3e2a78ffe config-baseline.core.json
0f509ffa75fca5e65afa13f7da09f5f8bd6d084e7f17d67e624c843dde842ba7 config-baseline.json
1bd5eee830a832d036e01b1ccc8a637e12703940e70b8ac320cc86e85fc4d25f config-baseline.core.json
22d7cd6d8279146b2d79c9531a55b80b52a2c99c81338c508104729154fdd02d config-baseline.channel.json
a91304e3566ecc8906f199b88a2e38eaee86130aad799bf4d62921e2f0ddc1b5 config-baseline.plugin.json
de2abdf469e828f30e37a5c60f147d6e3f5c9f116e2b1bb3289c21992d5138ba config-baseline.plugin.json

View File

@@ -1,2 +1,2 @@
96905c33f4498446f612ae17dee6affdf84ef0e2e5a0f25bf7191c315f5b826f plugin-sdk-api-baseline.json
d8eb6331562fde29531eaac18409bb7fabcc70623bf25395f8e5710a49765f0f plugin-sdk-api-baseline.jsonl
1b545ffc4f0704382a16765a6cc26eb8da6df3d7ffdd9f489f0ca31399fe9833 plugin-sdk-api-baseline.json
c192f0a2a827c4f756c22ba15eec90728e1edc4bd4a7d96cd097438242c3885a plugin-sdk-api-baseline.jsonl

View File

@@ -207,7 +207,7 @@ Runs `BOOT.md` from the active workspace when the gateway starts.
Plugins can register hooks through the Plugin SDK for deeper integration: intercepting tool calls, modifying prompts, controlling message flow, and more. The Plugin SDK exposes 28 hooks covering model resolution, agent lifecycle, message flow, tool execution, subagent coordination, and gateway lifecycle.
For the complete plugin hook reference including `before_tool_call`, `before_agent_reply`, `before_install`, and all other plugin hooks, see [Plugin Architecture](/plugins/architecture-internals#provider-runtime-hooks).
For the complete plugin hook reference including `before_tool_call`, `before_agent_reply`, `before_install`, and all other plugin hooks, see [Plugin Architecture](/plugins/architecture#provider-runtime-hooks).
## Configuration
@@ -315,5 +315,5 @@ Check for missing binaries (PATH), environment variables, config values, or OS c
- [CLI Reference: hooks](/cli/hooks)
- [Webhooks](/automation/cron-jobs#webhooks)
- [Plugin Architecture](/plugins/architecture-internals#provider-runtime-hooks) — full plugin hook reference
- [Plugin Architecture](/plugins/architecture#provider-runtime-hooks) — full plugin hook reference
- [Configuration](/gateway/configuration-reference#hooks)

View File

@@ -1134,7 +1134,7 @@ openclaw logs --follow
## Configuration reference
Primary reference: [Configuration reference - Discord](/gateway/config-channels#discord).
Primary reference: [Configuration reference - Discord](/gateway/configuration-reference#discord).
<Accordion title="High-signal Discord fields">

View File

@@ -138,7 +138,7 @@ Want “groups can only see folder X” instead of “no host access”? Keep `w
Related:
- Configuration keys and defaults: [Gateway configuration](/gateway/config-agents#agentsdefaultssandbox)
- Configuration keys and defaults: [Gateway configuration](/gateway/configuration-reference#agentsdefaultssandbox)
- Debugging why a tool is blocked: [Sandbox vs Tool Policy vs Elevated](/gateway/sandbox-vs-tool-policy-vs-elevated)
- Bind mounts details: [Sandboxing](/gateway/sandboxing#custom-bind-mounts)

View File

@@ -23,7 +23,7 @@ Status: legacy external CLI integration. Gateway spawns `imsg rpc` and communica
<Card title="Pairing" icon="link" href="/channels/pairing">
iMessage DMs default to pairing mode.
</Card>
<Card title="Configuration reference" icon="settings" href="/gateway/config-channels#imessage">
<Card title="Configuration reference" icon="settings" href="/gateway/configuration-reference#imessage">
Full iMessage field reference.
</Card>
</CardGroup>
@@ -413,7 +413,7 @@ imsg send <handle> "test"
## Configuration reference pointers
- [Configuration reference - iMessage](/gateway/config-channels#imessage)
- [Configuration reference - iMessage](/gateway/configuration-reference#imessage)
- [Gateway configuration](/gateway/configuration)
- [Pairing](/channels/pairing)
- [BlueBubbles](/channels/bluebubbles)

View File

@@ -670,7 +670,7 @@ If multiple Matrix accounts are configured and one account id is `default`, Open
If you configure multiple named accounts, set `defaultAccount` or pass `--account <id>` for CLI commands that rely on implicit account selection.
Pass `--account <id>` to `openclaw matrix verify ...` and `openclaw matrix devices ...` when you want to override that implicit selection for one command.
See [Configuration reference](/gateway/config-channels#multi-account-all-channels) for the shared multi-account pattern.
See [Configuration reference](/gateway/configuration-reference#multi-account-all-channels) for the shared multi-account pattern.
## Private/LAN homeservers

View File

@@ -99,7 +99,7 @@ Example:
}
```
Multi-account support: use `channels.signal.accounts` with per-account config and optional `name`. See [`gateway/configuration`](/gateway/config-channels#multi-account-all-channels) for the shared pattern.
Multi-account support: use `channels.signal.accounts` with per-account config and optional `name`. See [`gateway/configuration`](/gateway/configuration-reference#multi-account-all-channels) for the shared pattern.
## Setup path B: register dedicated bot number (SMS, Linux)

View File

@@ -785,7 +785,7 @@ Same-chat `/approve` also works in Slack channels and DMs that already support c
## Configuration reference
Primary reference: [Configuration reference - Slack](/gateway/config-channels#slack).
Primary reference: [Configuration reference - Slack](/gateway/configuration-reference#slack).
<Accordion title="High-signal Slack fields">

View File

@@ -885,7 +885,7 @@ More help: [Channel troubleshooting](/channels/troubleshooting).
## Configuration reference
Primary reference: [Configuration reference - Telegram](/gateway/config-channels#telegram).
Primary reference: [Configuration reference - Telegram](/gateway/configuration-reference#telegram).
<Accordion title="High-signal Telegram fields">

View File

@@ -558,7 +558,7 @@ Example:
Primary reference:
- [Configuration reference - WhatsApp](/gateway/config-channels#whatsapp)
- [Configuration reference - WhatsApp](/gateway/configuration-reference#whatsapp)
High-signal WhatsApp fields:

View File

@@ -55,8 +55,3 @@ openclaw agent --agent ops --message "Run locally" --local
- `--channel`, `--reply-channel`, and `--reply-account` affect reply delivery, not session routing.
- When this command triggers `models.json` regeneration, SecretRef-managed provider credentials are persisted as non-secret markers (for example env var names, `secretref-env:ENV_VAR_NAME`, or `secretref-managed`), not resolved secret plaintext.
- Marker writes are source-authoritative: OpenClaw persists markers from the active source config snapshot, not from resolved runtime secret values.
## Related
- [CLI reference](/cli)
- [Agent runtime](/concepts/agent)

View File

@@ -37,7 +37,7 @@ Use routing bindings to pin inbound channel traffic to a specific agent.
If you also want different visible skills per agent, configure
`agents.defaults.skills` and `agents.list[].skills` in `openclaw.json`. See
[Skills config](/tools/skills-config) and
[Configuration Reference](/gateway/config-agents#agents-defaults-skills).
[Configuration Reference](/gateway/configuration-reference#agents-defaults-skills).
List bindings:
@@ -218,9 +218,3 @@ Config sample:
},
}
```
## Related
- [CLI reference](/cli)
- [Multi-agent routing](/concepts/multi-agent)
- [Agent workspace](/concepts/agent-workspace)

View File

@@ -183,8 +183,3 @@ Targeting notes:
- `--agent` defaults to `"*"`, which applies to all agents.
- The node host must advertise `system.execApprovals.get/set` (macOS app or headless node host).
- Approvals files are stored per host at `~/.openclaw/exec-approvals.json`.
## Related
- [CLI reference](/cli)
- [Exec approvals](/tools/exec-approvals)

View File

@@ -129,8 +129,3 @@ Notes:
- Use `--kind user|group|auto` to force the target type.
- Resolution prefers active matches when multiple entries share the same name.
- `channels resolve` is read-only. If a selected account is configured via SecretRef but that credential is unavailable in the current command path, the command returns degraded unresolved results with notes instead of aborting the entire run.
## Related
- [CLI reference](/cli)
- [Channels overview](/channels)

View File

@@ -428,8 +428,3 @@ Typical repair loop:
- Apply targeted edits with `openclaw config set` or `openclaw configure`.
- Rerun `openclaw config validate` after each change.
- If validation passes but the runtime is still unhealthy, run `openclaw doctor` or `openclaw doctor --fix` for migration and repair help.
## Related
- [CLI reference](/cli)
- [Configuration](/gateway/configuration)

View File

@@ -15,7 +15,7 @@ Running `openclaw hooks` with no subcommand is equivalent to `openclaw hooks lis
Related:
- Hooks: [Hooks](/automation/hooks)
- Plugin hooks: [Plugin hooks](/plugins/architecture-internals#provider-runtime-hooks)
- Plugin hooks: [Plugin hooks](/plugins/architecture#provider-runtime-hooks)
## List All Hooks
@@ -336,8 +336,3 @@ openclaw hooks enable boot-md
```
**See:** [boot-md documentation](/automation/hooks#boot-md)
## Related
- [CLI reference](/cli)
- [Automation hooks](/automation/hooks)

View File

@@ -279,8 +279,3 @@ openclaw infer audio transcribe --file ./memo.m4a --model openai/whisper-1 --jso
## Notes
- `openclaw capability ...` is an alias for `openclaw infer ...`.
## Related
- [CLI reference](/cli)
- [Models](/concepts/models)

View File

@@ -516,8 +516,3 @@ Current limits:
- HTTP/SSE/streamable-http transport connects to a single remote server; no multiplexed upstream yet
- `permissions_list_open` only includes approvals observed while the bridge is
connected
## Related
- [CLI reference](/cli)
- [Plugins](/cli/plugins)

View File

@@ -142,9 +142,3 @@ Notes:
relative duration such as `365d` or `12h`.
- Anthropic note: Anthropic staff told us OpenClaw-style Claude CLI usage is allowed again, so OpenClaw treats Claude CLI reuse and `claude -p` usage as sanctioned for this integration unless Anthropic publishes a new policy.
- Anthropic `setup-token` / `paste-token` remain available as a supported OpenClaw token path, but OpenClaw now prefers Claude CLI reuse and `claude -p` when available.
## Related
- [CLI reference](/cli)
- [Model selection](/concepts/model-providers)
- [Model failover](/concepts/model-failover)

View File

@@ -64,8 +64,3 @@ Invoke flags:
For shell execution on a node, use the `exec` tool with `host=node` instead of `openclaw nodes run`.
The `nodes` CLI is now capability-focused: direct RPC via `nodes invoke`, plus pairing, camera,
screen, location, canvas, and notifications.
## Related
- [CLI reference](/cli)
- [Nodes](/nodes)

View File

@@ -63,8 +63,3 @@ Options:
- `pairing list` supports `--account <accountId>` for multi-account channels.
- `pairing approve` supports `--account <accountId>` and `--notify`.
- If only one pairing-capable channel is configured, `pairing approve <code>` is allowed.
## Related
- [CLI reference](/cli)
- [Channel pairing](/channels/pairing)

View File

@@ -327,9 +327,3 @@ Marketplace list accepts a local marketplace path, a `marketplace.json` path, a
GitHub shorthand like `owner/repo`, a GitHub repo URL, or a git URL. `--json`
prints the resolved source label plus the parsed marketplace manifest and
plugin entries.
## Related
- [CLI reference](/cli)
- [Building plugins](/plugins/building-plugins)
- [Community plugins](/plugins/community)

View File

@@ -193,8 +193,3 @@ Sandbox settings live in `~/.openclaw/openclaw.json` under `agents.defaults.sand
- [Sandbox Documentation](/gateway/sandboxing)
- [Agent Configuration](/concepts/agent-workspace)
- [Doctor Command](/gateway/doctor) - Check sandbox setup
## Related
- [CLI reference](/cli)
- [Sandboxing](/gateway/sandboxing)

View File

@@ -110,9 +110,4 @@ openclaw sessions cleanup --json
Related:
- Session config: [Configuration reference](/gateway/config-agents#session)
## Related
- [CLI reference](/cli)
- [Session management](/concepts/session)
- Session config: [Configuration reference](/gateway/configuration-reference#session)

View File

@@ -57,8 +57,3 @@ Notes:
- `list`, `info`, and `check` write their rendered output to stdout. With
`--json`, that means the machine-readable payload stays on stdout for pipes
and scripts.
## Related
- [CLI reference](/cli)
- [Skills](/tools/skills)

View File

@@ -34,8 +34,3 @@ Notes:
- If a supported channel SecretRef is configured but unavailable in the current command path, status stays read-only and reports degraded output instead of crashing. Human output shows warnings such as “configured token unavailable in this command path”, and JSON output includes `secretDiagnostics`.
- When command-local SecretRef resolution succeeds, status prefers the resolved snapshot and clears transient “secret unavailable” channel markers from the final output.
- `status --all` includes a Secrets overview row and a diagnosis section that summarizes secret diagnostics (truncated for readability) without stopping report generation.
## Related
- [CLI reference](/cli)
- [Doctor](/gateway/doctor)

View File

@@ -98,7 +98,7 @@ These run inside the agent loop or gateway pipeline:
- **`before_compaction` / `after_compaction`**: observe or annotate compaction cycles.
- **`before_tool_call` / `after_tool_call`**: intercept tool params/results.
- **`before_install`**: inspect built-in scan findings and optionally block skill or plugin installs.
- **`tool_result_persist`**: synchronously transform tool results before they are written to an OpenClaw-owned session transcript.
- **`tool_result_persist`**: synchronously transform tool results before they are written to the session transcript.
- **`message_received` / `message_sending` / `message_sent`**: inbound + outbound message hooks.
- **`session_start` / `session_end`**: session lifecycle boundaries.
- **`gateway_start` / `gateway_stop`**: gateway lifecycle events.
@@ -112,11 +112,7 @@ Hook decision rules for outbound/tool guards:
- `message_sending`: `{ cancel: true }` is terminal and stops lower-priority handlers.
- `message_sending`: `{ cancel: false }` is a no-op and does not clear a prior cancel.
See [Plugin hooks](/plugins/architecture-internals#provider-runtime-hooks) for the hook API and registration details.
Harnesses may adapt these hooks differently. The Codex app-server harness keeps
OpenClaw plugin hooks as the compatibility contract for documented mirrored
surfaces, while Codex native hooks remain a separate lower-level Codex mechanism.
See [Plugin hooks](/plugins/architecture#provider-runtime-hooks) for the hook API and registration details.
## Streaming + partial replies

View File

@@ -113,20 +113,6 @@ the summary:
/compact Focus on the API design decisions
```
## Codex harness compaction
When an embedded agent session uses the Codex app-server harness, Codex owns the
native thread and native compaction operation. OpenClaw keeps a transcript mirror
for channel history and future harness switching, but the canonical compacted
thread stays in Codex.
OpenClaw plugin hooks still expose `before_compaction` and `after_compaction`
for the Codex harness from the app-server compaction item stream. Codex native
`PreCompact` and `PostCompact` hooks, when supported by the installed Codex
app-server, are separate Codex command hooks configured through Codex. They are
useful for low-level Codex audit or policy, but they do not replace the
OpenClaw plugin hook contract.
## Using a different model
By default, compaction uses your agent's primary model. You can use a more

View File

@@ -149,7 +149,7 @@ Outbound message formatting is centralized in `messages`:
- `messages.responsePrefix`, `channels.<channel>.responsePrefix`, and `channels.<channel>.accounts.<id>.responsePrefix` (outbound prefix cascade), plus `channels.whatsapp.messagePrefix` (WhatsApp inbound prefix)
- Reply threading via `replyToMode` and per-channel defaults
Details: [Configuration](/gateway/config-agents#messages) and channel docs.
Details: [Configuration](/gateway/configuration-reference#messages) and channel docs.
## Silent replies

View File

@@ -630,5 +630,5 @@ See also: [/gateway/configuration](/gateway/configuration) for full configuratio
- [Models](/concepts/models) — model configuration and aliases
- [Model Failover](/concepts/model-failover) — fallback chains and retry behavior
- [Configuration Reference](/gateway/config-agents#agent-defaults) — model config keys
- [Configuration Reference](/gateway/configuration-reference#agent-defaults) — model config keys
- [Providers](/providers) — per-provider setup guides

View File

@@ -288,4 +288,4 @@ This applies whenever OpenClaw regenerates `models.json`, including command-driv
- [Image Generation](/tools/image-generation) — image model configuration
- [Music Generation](/tools/music-generation) — music model configuration
- [Video Generation](/tools/video-generation) — video model configuration
- [Configuration Reference](/gateway/config-agents#agent-defaults) — model config keys
- [Configuration Reference](/gateway/configuration-reference#agent-defaults) — model config keys

View File

@@ -83,34 +83,16 @@ you want artifacts without a failing exit code.
The Telegram report and summary include per-reply RTT from the driver message
send request to the observed SUT reply, starting with the canary.
For a transport-real Discord smoke lane, run:
```bash
pnpm openclaw qa discord
```
That lane targets one real private Discord guild channel with two bots: a
driver bot controlled by the harness and a SUT bot started by the child
OpenClaw gateway through the bundled Discord plugin. It requires
`OPENCLAW_QA_DISCORD_GUILD_ID`, `OPENCLAW_QA_DISCORD_CHANNEL_ID`,
`OPENCLAW_QA_DISCORD_DRIVER_BOT_TOKEN`, `OPENCLAW_QA_DISCORD_SUT_BOT_TOKEN`,
and `OPENCLAW_QA_DISCORD_SUT_APPLICATION_ID` when using env credentials.
The lane verifies channel mention handling and checks that the SUT bot has
registered the native `/help` command with Discord.
The command exits non-zero when any scenario fails. Use `--allow-failures` when
you want artifacts without a failing exit code.
Live transport lanes now share one smaller contract instead of each inventing
their own scenario list shape:
`qa-channel` remains the broad synthetic product-behavior suite and is not part
of the live transport coverage matrix.
| Lane | Canary | Mention gating | Allowlist block | Top-level reply | Restart resume | Thread follow-up | Thread isolation | Reaction observation | Help command | Native command registration |
| -------- | ------ | -------------- | --------------- | --------------- | -------------- | ---------------- | ---------------- | -------------------- | ------------ | --------------------------- |
| Matrix | x | x | x | x | x | x | x | x | | |
| Telegram | x | x | | | | | | | x | |
| Discord | x | x | | | | | | | | x |
| Lane | Canary | Mention gating | Allowlist block | Top-level reply | Restart resume | Thread follow-up | Thread isolation | Reaction observation | Help command |
| -------- | ------ | -------------- | --------------- | --------------- | -------------- | ---------------- | ---------------- | -------------------- | ------------ |
| Matrix | x | x | x | x | x | x | x | x | |
| Telegram | x | | | | | | | | x |
This keeps `qa-channel` as the broad product-behavior suite while Matrix,
Telegram, and future live transports share one explicit transport-contract

View File

@@ -1155,8 +1155,7 @@
"plugins/sdk-setup",
"plugins/sdk-testing",
"plugins/manifest",
"plugins/architecture",
"plugins/architecture-internals"
"plugins/architecture"
]
}
]
@@ -1366,8 +1365,6 @@
"pages": [
"gateway/configuration",
"gateway/configuration-reference",
"gateway/config-agents",
"gateway/config-channels",
"gateway/configuration-examples",
"gateway/authentication",
"auth-credential-semantics",

View File

@@ -202,9 +202,3 @@ openclaw models status
Run `openclaw models status` to confirm which profile is expiring. If an
Anthropic token profile is missing or expired, refresh that setup via
setup-token or migrate to an Anthropic API key.
## Related
- [Secrets management](/gateway/secrets)
- [Remote access](/gateway/remote)
- [Auth storage](/concepts/oauth)

File diff suppressed because it is too large Load Diff

View File

@@ -1,878 +0,0 @@
---
summary: "Channel configuration: access control, pairing, per-channel keys across Slack, Discord, Telegram, WhatsApp, Matrix, iMessage, and more"
read_when:
- Configuring a channel plugin (auth, access control, multi-account)
- Troubleshooting per-channel config keys
- Auditing DM policy, group policy, or mention gating
title: "Configuration — channels"
---
Per-channel configuration keys under `channels.*`. Covers DM and group access,
multi-account setups, mention gating, and per-channel keys for Slack, Discord,
Telegram, WhatsApp, Matrix, iMessage, and the other bundled channel plugins.
For agents, tools, gateway runtime, and other top-level keys, see
[Configuration reference](/gateway/configuration-reference).
## Channels
Each channel starts automatically when its config section exists (unless `enabled: false`).
### DM and group access
All channels support DM policies and group policies:
| DM policy | Behavior |
| ------------------- | --------------------------------------------------------------- |
| `pairing` (default) | Unknown senders get a one-time pairing code; owner must approve |
| `allowlist` | Only senders in `allowFrom` (or paired allow store) |
| `open` | Allow all inbound DMs (requires `allowFrom: ["*"]`) |
| `disabled` | Ignore all inbound DMs |
| Group policy | Behavior |
| --------------------- | ------------------------------------------------------ |
| `allowlist` (default) | Only groups matching the configured allowlist |
| `open` | Bypass group allowlists (mention-gating still applies) |
| `disabled` | Block all group/room messages |
<Note>
`channels.defaults.groupPolicy` sets the default when a provider's `groupPolicy` is unset.
Pairing codes expire after 1 hour. Pending DM pairing requests are capped at **3 per channel**.
If a provider block is missing entirely (`channels.<provider>` absent), runtime group policy falls back to `allowlist` (fail-closed) with a startup warning.
</Note>
### Channel model overrides
Use `channels.modelByChannel` to pin specific channel IDs to a model. Values accept `provider/model` or configured model aliases. The channel mapping applies when a session does not already have a model override (for example, set via `/model`).
```json5
{
channels: {
modelByChannel: {
discord: {
"123456789012345678": "anthropic/claude-opus-4-6",
},
slack: {
C1234567890: "openai/gpt-4.1",
},
telegram: {
"-1001234567890": "openai/gpt-4.1-mini",
"-1001234567890:topic:99": "anthropic/claude-sonnet-4-6",
},
},
},
}
```
### Channel defaults and heartbeat
Use `channels.defaults` for shared group-policy and heartbeat behavior across providers:
```json5
{
channels: {
defaults: {
groupPolicy: "allowlist", // open | allowlist | disabled
contextVisibility: "all", // all | allowlist | allowlist_quote
heartbeat: {
showOk: false,
showAlerts: true,
useIndicator: true,
},
},
},
}
```
- `channels.defaults.groupPolicy`: fallback group policy when a provider-level `groupPolicy` is unset.
- `channels.defaults.contextVisibility`: default supplemental context visibility mode for all channels. Values: `all` (default, include all quoted/thread/history context), `allowlist` (only include context from allowlisted senders), `allowlist_quote` (same as allowlist but keep explicit quote/reply context). Per-channel override: `channels.<channel>.contextVisibility`.
- `channels.defaults.heartbeat.showOk`: include healthy channel statuses in heartbeat output.
- `channels.defaults.heartbeat.showAlerts`: include degraded/error statuses in heartbeat output.
- `channels.defaults.heartbeat.useIndicator`: render compact indicator-style heartbeat output.
### WhatsApp
WhatsApp runs through the gateway's web channel (Baileys Web). It starts automatically when a linked session exists.
```json5
{
channels: {
whatsapp: {
dmPolicy: "pairing", // pairing | allowlist | open | disabled
allowFrom: ["+15555550123", "+447700900123"],
textChunkLimit: 4000,
chunkMode: "length", // length | newline
mediaMaxMb: 50,
sendReadReceipts: true, // blue ticks (false in self-chat mode)
groups: {
"*": { requireMention: true },
},
groupPolicy: "allowlist",
groupAllowFrom: ["+15551234567"],
},
},
web: {
enabled: true,
heartbeatSeconds: 60,
reconnect: {
initialMs: 2000,
maxMs: 120000,
factor: 1.4,
jitter: 0.2,
maxAttempts: 0,
},
},
}
```
<Accordion title="Multi-account WhatsApp">
```json5
{
channels: {
whatsapp: {
accounts: {
default: {},
personal: {},
biz: {
// authDir: "~/.openclaw/credentials/whatsapp/biz",
},
},
},
},
}
```
- Outbound commands default to account `default` if present; otherwise the first configured account id (sorted).
- Optional `channels.whatsapp.defaultAccount` overrides that fallback default account selection when it matches a configured account id.
- Legacy single-account Baileys auth dir is migrated by `openclaw doctor` into `whatsapp/default`.
- Per-account overrides: `channels.whatsapp.accounts.<id>.sendReadReceipts`, `channels.whatsapp.accounts.<id>.dmPolicy`, `channels.whatsapp.accounts.<id>.allowFrom`.
</Accordion>
### Telegram
```json5
{
channels: {
telegram: {
enabled: true,
botToken: "your-bot-token",
dmPolicy: "pairing",
allowFrom: ["tg:123456789"],
groups: {
"*": { requireMention: true },
"-1001234567890": {
allowFrom: ["@admin"],
systemPrompt: "Keep answers brief.",
topics: {
"99": {
requireMention: false,
skills: ["search"],
systemPrompt: "Stay on topic.",
},
},
},
},
customCommands: [
{ command: "backup", description: "Git backup" },
{ command: "generate", description: "Create an image" },
],
historyLimit: 50,
replyToMode: "first", // off | first | all | batched
linkPreview: true,
streaming: "partial", // off | partial | block | progress (default: off; opt in explicitly to avoid preview-edit rate limits)
actions: { reactions: true, sendMessage: true },
reactionNotifications: "own", // off | own | all
mediaMaxMb: 100,
retry: {
attempts: 3,
minDelayMs: 400,
maxDelayMs: 30000,
jitter: 0.1,
},
network: {
autoSelectFamily: true,
dnsResultOrder: "ipv4first",
},
proxy: "socks5://localhost:9050",
webhookUrl: "https://example.com/telegram-webhook",
webhookSecret: "secret",
webhookPath: "/telegram-webhook",
},
},
}
```
- Bot token: `channels.telegram.botToken` or `channels.telegram.tokenFile` (regular file only; symlinks rejected), with `TELEGRAM_BOT_TOKEN` as fallback for the default account.
- Optional `channels.telegram.defaultAccount` overrides default account selection when it matches a configured account id.
- In multi-account setups (2+ account ids), set an explicit default (`channels.telegram.defaultAccount` or `channels.telegram.accounts.default`) to avoid fallback routing; `openclaw doctor` warns when this is missing or invalid.
- `configWrites: false` blocks Telegram-initiated config writes (supergroup ID migrations, `/config set|unset`).
- Top-level `bindings[]` entries with `type: "acp"` configure persistent ACP bindings for forum topics (use canonical `chatId:topic:topicId` in `match.peer.id`). Field semantics are shared in [ACP Agents](/tools/acp-agents#channel-specific-settings).
- Telegram stream previews use `sendMessage` + `editMessageText` (works in direct and group chats).
- Retry policy: see [Retry policy](/concepts/retry).
### Discord
```json5
{
channels: {
discord: {
enabled: true,
token: "your-bot-token",
mediaMaxMb: 100,
allowBots: false,
actions: {
reactions: true,
stickers: true,
polls: true,
permissions: true,
messages: true,
threads: true,
pins: true,
search: true,
memberInfo: true,
roleInfo: true,
roles: false,
channelInfo: true,
voiceStatus: true,
events: true,
moderation: false,
},
replyToMode: "off", // off | first | all | batched
dmPolicy: "pairing",
allowFrom: ["1234567890", "123456789012345678"],
dm: { enabled: true, groupEnabled: false, groupChannels: ["openclaw-dm"] },
guilds: {
"123456789012345678": {
slug: "friends-of-openclaw",
requireMention: false,
ignoreOtherMentions: true,
reactionNotifications: "own",
users: ["987654321098765432"],
channels: {
general: { allow: true },
help: {
allow: true,
requireMention: true,
users: ["987654321098765432"],
skills: ["docs"],
systemPrompt: "Short answers only.",
},
},
},
},
historyLimit: 20,
textChunkLimit: 2000,
chunkMode: "length", // length | newline
streaming: "off", // off | partial | block | progress (progress maps to partial on Discord)
maxLinesPerMessage: 17,
ui: {
components: {
accentColor: "#5865F2",
},
},
threadBindings: {
enabled: true,
idleHours: 24,
maxAgeHours: 0,
spawnSubagentSessions: false, // opt-in for sessions_spawn({ thread: true })
},
voice: {
enabled: true,
autoJoin: [
{
guildId: "123456789012345678",
channelId: "234567890123456789",
},
],
daveEncryption: true,
decryptionFailureTolerance: 24,
tts: {
provider: "openai",
openai: { voice: "alloy" },
},
},
execApprovals: {
enabled: "auto", // true | false | "auto"
approvers: ["987654321098765432"],
agentFilter: ["default"],
sessionFilter: ["discord:"],
target: "dm", // dm | channel | both
cleanupAfterResolve: false,
},
retry: {
attempts: 3,
minDelayMs: 500,
maxDelayMs: 30000,
jitter: 0.1,
},
},
},
}
```
- Token: `channels.discord.token`, with `DISCORD_BOT_TOKEN` as fallback for the default account.
- Direct outbound calls that provide an explicit Discord `token` use that token for the call; account retry/policy settings still come from the selected account in the active runtime snapshot.
- Optional `channels.discord.defaultAccount` overrides default account selection when it matches a configured account id.
- Use `user:<id>` (DM) or `channel:<id>` (guild channel) for delivery targets; bare numeric IDs are rejected.
- Guild slugs are lowercase with spaces replaced by `-`; channel keys use the slugged name (no `#`). Prefer guild IDs.
- Bot-authored messages are ignored by default. `allowBots: true` enables them; use `allowBots: "mentions"` to only accept bot messages that mention the bot (own messages still filtered).
- `channels.discord.guilds.<id>.ignoreOtherMentions` (and channel overrides) drops messages that mention another user or role but not the bot (excluding @everyone/@here).
- `maxLinesPerMessage` (default 17) splits tall messages even when under 2000 chars.
- `channels.discord.threadBindings` controls Discord thread-bound routing:
- `enabled`: Discord override for thread-bound session features (`/focus`, `/unfocus`, `/agents`, `/session idle`, `/session max-age`, and bound delivery/routing)
- `idleHours`: Discord override for inactivity auto-unfocus in hours (`0` disables)
- `maxAgeHours`: Discord override for hard max age in hours (`0` disables)
- `spawnSubagentSessions`: opt-in switch for `sessions_spawn({ thread: true })` auto thread creation/binding
- Top-level `bindings[]` entries with `type: "acp"` configure persistent ACP bindings for channels and threads (use channel/thread id in `match.peer.id`). Field semantics are shared in [ACP Agents](/tools/acp-agents#channel-specific-settings).
- `channels.discord.ui.components.accentColor` sets the accent color for Discord components v2 containers.
- `channels.discord.voice` enables Discord voice channel conversations and optional auto-join + TTS overrides.
- `channels.discord.voice.daveEncryption` and `channels.discord.voice.decryptionFailureTolerance` pass through to `@discordjs/voice` DAVE options (`true` and `24` by default).
- OpenClaw additionally attempts voice receive recovery by leaving/rejoining a voice session after repeated decrypt failures.
- `channels.discord.streaming` is the canonical stream mode key. Legacy `streamMode` and boolean `streaming` values are auto-migrated.
- `channels.discord.autoPresence` maps runtime availability to bot presence (healthy => online, degraded => idle, exhausted => dnd) and allows optional status text overrides.
- `channels.discord.dangerouslyAllowNameMatching` re-enables mutable name/tag matching (break-glass compatibility mode).
- `channels.discord.execApprovals`: Discord-native exec approval delivery and approver authorization.
- `enabled`: `true`, `false`, or `"auto"` (default). In auto mode, exec approvals activate when approvers can be resolved from `approvers` or `commands.ownerAllowFrom`.
- `approvers`: Discord user IDs allowed to approve exec requests. Falls back to `commands.ownerAllowFrom` when omitted.
- `agentFilter`: optional agent ID allowlist. Omit to forward approvals for all agents.
- `sessionFilter`: optional session key patterns (substring or regex).
- `target`: where to send approval prompts. `"dm"` (default) sends to approver DMs, `"channel"` sends to the originating channel, `"both"` sends to both. When target includes `"channel"`, buttons are only usable by resolved approvers.
- `cleanupAfterResolve`: when `true`, deletes approval DMs after approval, denial, or timeout.
**Reaction notification modes:** `off` (none), `own` (bot's messages, default), `all` (all messages), `allowlist` (from `guilds.<id>.users` on all messages).
### Google Chat
```json5
{
channels: {
googlechat: {
enabled: true,
serviceAccountFile: "/path/to/service-account.json",
audienceType: "app-url", // app-url | project-number
audience: "https://gateway.example.com/googlechat",
webhookPath: "/googlechat",
botUser: "users/1234567890",
dm: {
enabled: true,
policy: "pairing",
allowFrom: ["users/1234567890"],
},
groupPolicy: "allowlist",
groups: {
"spaces/AAAA": { allow: true, requireMention: true },
},
actions: { reactions: true },
typingIndicator: "message",
mediaMaxMb: 20,
},
},
}
```
- Service account JSON: inline (`serviceAccount`) or file-based (`serviceAccountFile`).
- Service account SecretRef is also supported (`serviceAccountRef`).
- Env fallbacks: `GOOGLE_CHAT_SERVICE_ACCOUNT` or `GOOGLE_CHAT_SERVICE_ACCOUNT_FILE`.
- Use `spaces/<spaceId>` or `users/<userId>` for delivery targets.
- `channels.googlechat.dangerouslyAllowNameMatching` re-enables mutable email principal matching (break-glass compatibility mode).
### Slack
```json5
{
channels: {
slack: {
enabled: true,
botToken: "xoxb-...",
appToken: "xapp-...",
dmPolicy: "pairing",
allowFrom: ["U123", "U456", "*"],
dm: { enabled: true, groupEnabled: false, groupChannels: ["G123"] },
channels: {
C123: { allow: true, requireMention: true, allowBots: false },
"#general": {
allow: true,
requireMention: true,
allowBots: false,
users: ["U123"],
skills: ["docs"],
systemPrompt: "Short answers only.",
},
},
historyLimit: 50,
allowBots: false,
reactionNotifications: "own",
reactionAllowlist: ["U123"],
replyToMode: "off", // off | first | all | batched
thread: {
historyScope: "thread", // thread | channel
inheritParent: false,
},
actions: {
reactions: true,
messages: true,
pins: true,
memberInfo: true,
emojiList: true,
},
slashCommand: {
enabled: true,
name: "openclaw",
sessionPrefix: "slack:slash",
ephemeral: true,
},
typingReaction: "hourglass_flowing_sand",
textChunkLimit: 4000,
chunkMode: "length",
streaming: {
mode: "partial", // off | partial | block | progress
nativeTransport: true, // use Slack native streaming API when mode=partial
},
mediaMaxMb: 20,
execApprovals: {
enabled: "auto", // true | false | "auto"
approvers: ["U123"],
agentFilter: ["default"],
sessionFilter: ["slack:"],
target: "dm", // dm | channel | both
},
},
},
}
```
- **Socket mode** requires both `botToken` and `appToken` (`SLACK_BOT_TOKEN` + `SLACK_APP_TOKEN` for default account env fallback).
- **HTTP mode** requires `botToken` plus `signingSecret` (at root or per-account).
- `botToken`, `appToken`, `signingSecret`, and `userToken` accept plaintext
strings or SecretRef objects.
- Slack account snapshots expose per-credential source/status fields such as
`botTokenSource`, `botTokenStatus`, `appTokenStatus`, and, in HTTP mode,
`signingSecretStatus`. `configured_unavailable` means the account is
configured through SecretRef but the current command/runtime path could not
resolve the secret value.
- `configWrites: false` blocks Slack-initiated config writes.
- Optional `channels.slack.defaultAccount` overrides default account selection when it matches a configured account id.
- `channels.slack.streaming.mode` is the canonical Slack stream mode key. `channels.slack.streaming.nativeTransport` controls Slack's native streaming transport. Legacy `streamMode`, boolean `streaming`, and `nativeStreaming` values are auto-migrated.
- Use `user:<id>` (DM) or `channel:<id>` for delivery targets.
**Reaction notification modes:** `off`, `own` (default), `all`, `allowlist` (from `reactionAllowlist`).
**Thread session isolation:** `thread.historyScope` is per-thread (default) or shared across channel. `thread.inheritParent` copies parent channel transcript to new threads.
- Slack native streaming plus the Slack assistant-style "is typing..." thread status require a reply thread target. Top-level DMs stay off-thread by default, so they use `typingReaction` or normal delivery instead of the thread-style preview.
- `typingReaction` adds a temporary reaction to the inbound Slack message while a reply is running, then removes it on completion. Use a Slack emoji shortcode such as `"hourglass_flowing_sand"`.
- `channels.slack.execApprovals`: Slack-native exec approval delivery and approver authorization. Same schema as Discord: `enabled` (`true`/`false`/`"auto"`), `approvers` (Slack user IDs), `agentFilter`, `sessionFilter`, and `target` (`"dm"`, `"channel"`, or `"both"`).
| Action group | Default | Notes |
| ------------ | ------- | ---------------------- |
| reactions | enabled | React + list reactions |
| messages | enabled | Read/send/edit/delete |
| pins | enabled | Pin/unpin/list |
| memberInfo | enabled | Member info |
| emojiList | enabled | Custom emoji list |
### Mattermost
Mattermost ships as a plugin: `openclaw plugins install @openclaw/mattermost`.
```json5
{
channels: {
mattermost: {
enabled: true,
botToken: "mm-token",
baseUrl: "https://chat.example.com",
dmPolicy: "pairing",
chatmode: "oncall", // oncall | onmessage | onchar
oncharPrefixes: [">", "!"],
groups: {
"*": { requireMention: true },
"team-channel-id": { requireMention: false },
},
commands: {
native: true, // opt-in
nativeSkills: true,
callbackPath: "/api/channels/mattermost/command",
// Optional explicit URL for reverse-proxy/public deployments
callbackUrl: "https://gateway.example.com/api/channels/mattermost/command",
},
textChunkLimit: 4000,
chunkMode: "length",
},
},
}
```
Chat modes: `oncall` (respond on @-mention, default), `onmessage` (every message), `onchar` (messages starting with trigger prefix).
When Mattermost native commands are enabled:
- `commands.callbackPath` must be a path (for example `/api/channels/mattermost/command`), not a full URL.
- `commands.callbackUrl` must resolve to the OpenClaw gateway endpoint and be reachable from the Mattermost server.
- Native slash callbacks are authenticated with the per-command tokens returned
by Mattermost during slash command registration. If registration fails or no
commands are activated, OpenClaw rejects callbacks with
`Unauthorized: invalid command token.`
- For private/tailnet/internal callback hosts, Mattermost may require
`ServiceSettings.AllowedUntrustedInternalConnections` to include the callback host/domain.
Use host/domain values, not full URLs.
- `channels.mattermost.configWrites`: allow or deny Mattermost-initiated config writes.
- `channels.mattermost.requireMention`: require `@mention` before replying in channels.
- `channels.mattermost.groups.<channelId>.requireMention`: per-channel mention-gating override (`"*"` for default).
- Optional `channels.mattermost.defaultAccount` overrides default account selection when it matches a configured account id.
### Signal
```json5
{
channels: {
signal: {
enabled: true,
account: "+15555550123", // optional account binding
dmPolicy: "pairing",
allowFrom: ["+15551234567", "uuid:123e4567-e89b-12d3-a456-426614174000"],
configWrites: true,
reactionNotifications: "own", // off | own | all | allowlist
reactionAllowlist: ["+15551234567", "uuid:123e4567-e89b-12d3-a456-426614174000"],
historyLimit: 50,
},
},
}
```
**Reaction notification modes:** `off`, `own` (default), `all`, `allowlist` (from `reactionAllowlist`).
- `channels.signal.account`: pin channel startup to a specific Signal account identity.
- `channels.signal.configWrites`: allow or deny Signal-initiated config writes.
- Optional `channels.signal.defaultAccount` overrides default account selection when it matches a configured account id.
### BlueBubbles
BlueBubbles is the recommended iMessage path (plugin-backed, configured under `channels.bluebubbles`).
```json5
{
channels: {
bluebubbles: {
enabled: true,
dmPolicy: "pairing",
// serverUrl, password, webhookPath, group controls, and advanced actions:
// see /channels/bluebubbles
},
},
}
```
- Core key paths covered here: `channels.bluebubbles`, `channels.bluebubbles.dmPolicy`.
- Optional `channels.bluebubbles.defaultAccount` overrides default account selection when it matches a configured account id.
- Top-level `bindings[]` entries with `type: "acp"` can bind BlueBubbles conversations to persistent ACP sessions. Use a BlueBubbles handle or target string (`chat_id:*`, `chat_guid:*`, `chat_identifier:*`) in `match.peer.id`. Shared field semantics: [ACP Agents](/tools/acp-agents#channel-specific-settings).
- Full BlueBubbles channel configuration is documented in [BlueBubbles](/channels/bluebubbles).
### iMessage
OpenClaw spawns `imsg rpc` (JSON-RPC over stdio). No daemon or port required.
```json5
{
channels: {
imessage: {
enabled: true,
cliPath: "imsg",
dbPath: "~/Library/Messages/chat.db",
remoteHost: "user@gateway-host",
dmPolicy: "pairing",
allowFrom: ["+15555550123", "user@example.com", "chat_id:123"],
historyLimit: 50,
includeAttachments: false,
attachmentRoots: ["/Users/*/Library/Messages/Attachments"],
remoteAttachmentRoots: ["/Users/*/Library/Messages/Attachments"],
mediaMaxMb: 16,
service: "auto",
region: "US",
},
},
}
```
- Optional `channels.imessage.defaultAccount` overrides default account selection when it matches a configured account id.
- Requires Full Disk Access to the Messages DB.
- Prefer `chat_id:<id>` targets. Use `imsg chats --limit 20` to list chats.
- `cliPath` can point to an SSH wrapper; set `remoteHost` (`host` or `user@host`) for SCP attachment fetching.
- `attachmentRoots` and `remoteAttachmentRoots` restrict inbound attachment paths (default: `/Users/*/Library/Messages/Attachments`).
- SCP uses strict host-key checking, so ensure the relay host key already exists in `~/.ssh/known_hosts`.
- `channels.imessage.configWrites`: allow or deny iMessage-initiated config writes.
- Top-level `bindings[]` entries with `type: "acp"` can bind iMessage conversations to persistent ACP sessions. Use a normalized handle or explicit chat target (`chat_id:*`, `chat_guid:*`, `chat_identifier:*`) in `match.peer.id`. Shared field semantics: [ACP Agents](/tools/acp-agents#channel-specific-settings).
<Accordion title="iMessage SSH wrapper example">
```bash
#!/usr/bin/env bash
exec ssh -T gateway-host imsg "$@"
```
</Accordion>
### Matrix
Matrix is plugin-backed and configured under `channels.matrix`.
```json5
{
channels: {
matrix: {
enabled: true,
homeserver: "https://matrix.example.org",
accessToken: "syt_bot_xxx",
proxy: "http://127.0.0.1:7890",
encryption: true,
initialSyncLimit: 20,
defaultAccount: "ops",
accounts: {
ops: {
name: "Ops",
userId: "@ops:example.org",
accessToken: "syt_ops_xxx",
},
alerts: {
userId: "@alerts:example.org",
password: "secret",
proxy: "http://127.0.0.1:7891",
},
},
},
},
}
```
- Token auth uses `accessToken`; password auth uses `userId` + `password`.
- `channels.matrix.proxy` routes Matrix HTTP traffic through an explicit HTTP(S) proxy. Named accounts can override it with `channels.matrix.accounts.<id>.proxy`.
- `channels.matrix.network.dangerouslyAllowPrivateNetwork` allows private/internal homeservers. `proxy` and this network opt-in are independent controls.
- `channels.matrix.defaultAccount` selects the preferred account in multi-account setups.
- `channels.matrix.autoJoin` defaults to `off`, so invited rooms and fresh DM-style invites are ignored until you set `autoJoin: "allowlist"` with `autoJoinAllowlist` or `autoJoin: "always"`.
- `channels.matrix.execApprovals`: Matrix-native exec approval delivery and approver authorization.
- `enabled`: `true`, `false`, or `"auto"` (default). In auto mode, exec approvals activate when approvers can be resolved from `approvers` or `commands.ownerAllowFrom`.
- `approvers`: Matrix user IDs (e.g. `@owner:example.org`) allowed to approve exec requests.
- `agentFilter`: optional agent ID allowlist. Omit to forward approvals for all agents.
- `sessionFilter`: optional session key patterns (substring or regex).
- `target`: where to send approval prompts. `"dm"` (default), `"channel"` (originating room), or `"both"`.
- Per-account overrides: `channels.matrix.accounts.<id>.execApprovals`.
- `channels.matrix.dm.sessionScope` controls how Matrix DMs group into sessions: `per-user` (default) shares by routed peer, while `per-room` isolates each DM room.
- Matrix status probes and live directory lookups use the same proxy policy as runtime traffic.
- Full Matrix configuration, targeting rules, and setup examples are documented in [Matrix](/channels/matrix).
### Microsoft Teams
Microsoft Teams is plugin-backed and configured under `channels.msteams`.
```json5
{
channels: {
msteams: {
enabled: true,
configWrites: true,
// appId, appPassword, tenantId, webhook, team/channel policies:
// see /channels/msteams
},
},
}
```
- Core key paths covered here: `channels.msteams`, `channels.msteams.configWrites`.
- Full Teams config (credentials, webhook, DM/group policy, per-team/per-channel overrides) is documented in [Microsoft Teams](/channels/msteams).
### IRC
IRC is plugin-backed and configured under `channels.irc`.
```json5
{
channels: {
irc: {
enabled: true,
dmPolicy: "pairing",
configWrites: true,
nickserv: {
enabled: true,
service: "NickServ",
password: "${IRC_NICKSERV_PASSWORD}",
register: false,
registerEmail: "bot@example.com",
},
},
},
}
```
- Core key paths covered here: `channels.irc`, `channels.irc.dmPolicy`, `channels.irc.configWrites`, `channels.irc.nickserv.*`.
- Optional `channels.irc.defaultAccount` overrides default account selection when it matches a configured account id.
- Full IRC channel configuration (host/port/TLS/channels/allowlists/mention gating) is documented in [IRC](/channels/irc).
### Multi-account (all channels)
Run multiple accounts per channel (each with its own `accountId`):
```json5
{
channels: {
telegram: {
accounts: {
default: {
name: "Primary bot",
botToken: "123456:ABC...",
},
alerts: {
name: "Alerts bot",
botToken: "987654:XYZ...",
},
},
},
},
}
```
- `default` is used when `accountId` is omitted (CLI + routing).
- Env tokens only apply to the **default** account.
- Base channel settings apply to all accounts unless overridden per account.
- Use `bindings[].match.accountId` to route each account to a different agent.
- If you add a non-default account via `openclaw channels add` (or channel onboarding) while still on a single-account top-level channel config, OpenClaw promotes account-scoped top-level single-account values into the channel account map first so the original account keeps working. Most channels move them into `channels.<channel>.accounts.default`; Matrix can preserve an existing matching named/default target instead.
- Existing channel-only bindings (no `accountId`) keep matching the default account; account-scoped bindings remain optional.
- `openclaw doctor --fix` also repairs mixed shapes by moving account-scoped top-level single-account values into the promoted account chosen for that channel. Most channels use `accounts.default`; Matrix can preserve an existing matching named/default target instead.
### Other plugin channels
Many plugin channels are configured as `channels.<id>` and documented in their dedicated channel pages (for example Feishu, Matrix, LINE, Nostr, Zalo, Nextcloud Talk, Synology Chat, and Twitch).
See the full channel index: [Channels](/channels).
### Group chat mention gating
Group messages default to **require mention** (metadata mention or safe regex patterns). Applies to WhatsApp, Telegram, Discord, Google Chat, and iMessage group chats.
**Mention types:**
- **Metadata mentions**: Native platform @-mentions. Ignored in WhatsApp self-chat mode.
- **Text patterns**: Safe regex patterns in `agents.list[].groupChat.mentionPatterns`. Invalid patterns and unsafe nested repetition are ignored.
- Mention gating is enforced only when detection is possible (native mentions or at least one pattern).
```json5
{
messages: {
groupChat: { historyLimit: 50 },
},
agents: {
list: [{ id: "main", groupChat: { mentionPatterns: ["@openclaw", "openclaw"] } }],
},
}
```
`messages.groupChat.historyLimit` sets the global default. Channels can override with `channels.<channel>.historyLimit` (or per-account). Set `0` to disable.
#### DM history limits
```json5
{
channels: {
telegram: {
dmHistoryLimit: 30,
dms: {
"123456789": { historyLimit: 50 },
},
},
},
}
```
Resolution: per-DM override → provider default → no limit (all retained).
Supported: `telegram`, `whatsapp`, `discord`, `slack`, `signal`, `imessage`, `msteams`.
#### Self-chat mode
Include your own number in `allowFrom` to enable self-chat mode (ignores native @-mentions, only responds to text patterns):
```json5
{
channels: {
whatsapp: {
allowFrom: ["+15555550123"],
groups: { "*": { requireMention: true } },
},
},
agents: {
list: [
{
id: "main",
groupChat: { mentionPatterns: ["reisponde", "@openclaw"] },
},
],
},
}
```
### Commands (chat command handling)
```json5
{
commands: {
native: "auto", // register native commands when supported
nativeSkills: "auto", // register native skill commands when supported
text: true, // parse /commands in chat messages
bash: false, // allow ! (alias: /bash)
bashForegroundMs: 2000,
config: false, // allow /config
mcp: false, // allow /mcp
plugins: false, // allow /plugins
debug: false, // allow /debug
restart: true, // allow /restart + gateway restart tool
ownerAllowFrom: ["discord:123456789012345678"],
ownerDisplay: "raw", // raw | hash
ownerDisplaySecret: "${OWNER_ID_HASH_SECRET}",
allowFrom: {
"*": ["user1"],
discord: ["user:123"],
},
useAccessGroups: true,
},
}
```
<Accordion title="Command details">
- This block configures command surfaces. For the current built-in + bundled command catalog, see [Slash Commands](/tools/slash-commands).
- This page is a **config-key reference**, not the full command catalog. Channel/plugin-owned commands such as QQ Bot `/bot-ping` `/bot-help` `/bot-logs`, LINE `/card`, device-pair `/pair`, memory `/dreaming`, phone-control `/phone`, and Talk `/voice` are documented in their channel/plugin pages plus [Slash Commands](/tools/slash-commands).
- Text commands must be **standalone** messages with leading `/`.
- `native: "auto"` turns on native commands for Discord/Telegram, leaves Slack off.
- `nativeSkills: "auto"` turns on native skill commands for Discord/Telegram, leaves Slack off.
- Override per channel: `channels.discord.commands.native` (bool or `"auto"`). `false` clears previously registered commands.
- Override native skill registration per channel with `channels.<provider>.commands.nativeSkills`.
- `channels.telegram.customCommands` adds extra Telegram bot menu entries.
- `bash: true` enables `! <cmd>` for host shell. Requires `tools.elevated.enabled` and sender in `tools.elevated.allowFrom.<channel>`.
- `config: true` enables `/config` (reads/writes `openclaw.json`). For gateway `chat.send` clients, persistent `/config set|unset` writes also require `operator.admin`; read-only `/config show` stays available to normal write-scoped operator clients.
- `mcp: true` enables `/mcp` for OpenClaw-managed MCP server config under `mcp.servers`.
- `plugins: true` enables `/plugins` for plugin discovery, install, and enable/disable controls.
- `channels.<provider>.configWrites` gates config mutations per channel (default: true).
- For multi-account channels, `channels.<provider>.accounts.<id>.configWrites` also gates writes that target that account (for example `/allowlist --config --account <id>` or `/config set channels.<provider>.accounts.<id>...`).
- `restart: false` disables `/restart` and gateway restart tool actions. Default: `true`.
- `ownerAllowFrom` is the explicit owner allowlist for owner-only commands/tools. It is separate from `allowFrom`.
- `ownerDisplay: "hash"` hashes owner ids in the system prompt. Set `ownerDisplaySecret` to control hashing.
- `allowFrom` is per-provider. When set, it is the **only** authorization source (channel allowlists/pairing and `useAccessGroups` are ignored).
- `useAccessGroups: false` allows commands to bypass access-group policies when `allowFrom` is not set.
- Command docs map:
- built-in + bundled catalog: [Slash Commands](/tools/slash-commands)
- channel-specific command surfaces: [Channels](/channels)
- QQ Bot commands: [QQ Bot](/channels/qqbot)
- pairing commands: [Pairing](/channels/pairing)
- LINE card command: [LINE](/channels/line)
- memory dreaming: [Dreaming](/concepts/dreaming)
</Accordion>
---
## Related
- [Configuration reference](/gateway/configuration-reference) — top-level keys
- [Configuration — agents](/gateway/config-agents)
- [Channels overview](/channels)

View File

@@ -627,8 +627,3 @@ Only enable direct mutable name/email/nick matching with each channel's `dangero
- Provider IDs differ (phone numbers, user IDs, channel IDs). Use the provider docs to confirm the format.
- Optional sections to add later: `web`, `browser`, `ui`, `discovery`, `canvasHost`, `talk`, `signal`, `imessage`.
- See [Providers](/providers) and [Troubleshooting](/gateway/troubleshooting) for deeper setup notes.
## Related
- [Configuration reference](/gateway/configuration-reference)
- [Configuration](/gateway/configuration)

File diff suppressed because it is too large Load Diff

View File

@@ -165,7 +165,7 @@ is skipped when a candidate contains redacted secret placeholders such as `***`.
For groups, use `groupPolicy` + `groupAllowFrom` or channel-specific allowlists.
See the [full reference](/gateway/config-channels#dm-and-group-access) for per-channel details.
See the [full reference](/gateway/configuration-reference#dm-and-group-access) for per-channel details.
</Accordion>
@@ -194,7 +194,7 @@ is skipped when a candidate contains redacted secret placeholders such as `***`.
- **Metadata mentions**: native @-mentions (WhatsApp tap-to-mention, Telegram @bot, etc.)
- **Text patterns**: safe regex patterns in `mentionPatterns`
- See [full reference](/gateway/config-channels#group-chat-mention-gating) for per-channel overrides and self-chat mode.
- See [full reference](/gateway/configuration-reference#group-chat-mention-gating) for per-channel overrides and self-chat mode.
</Accordion>
@@ -221,7 +221,7 @@ is skipped when a candidate contains redacted secret placeholders such as `***`.
- Omit `agents.list[].skills` to inherit the defaults.
- Set `agents.list[].skills: []` for no skills.
- See [Skills](/tools/skills), [Skills config](/tools/skills-config), and
the [Configuration Reference](/gateway/config-agents#agents-defaults-skills).
the [Configuration Reference](/gateway/configuration-reference#agents-defaults-skills).
</Accordion>
@@ -279,7 +279,7 @@ is skipped when a candidate contains redacted secret placeholders such as `***`.
- `dmScope`: `main` (shared) | `per-peer` | `per-channel-peer` | `per-account-channel-peer`
- `threadBindings`: global defaults for thread-bound session routing (Discord supports `/focus`, `/unfocus`, `/agents`, `/session idle`, and `/session max-age`).
- See [Session Management](/concepts/session) for scoping, identity links, and send policy.
- See [full reference](/gateway/config-agents#session) for all fields.
- See [full reference](/gateway/configuration-reference#session) for all fields.
</Accordion>
@@ -301,7 +301,7 @@ is skipped when a candidate contains redacted secret placeholders such as `***`.
Build the image first: `scripts/sandbox-setup.sh`
See [Sandboxing](/gateway/sandboxing) for the full guide and [full reference](/gateway/config-agents#agentsdefaultssandbox) for all options.
See [Sandboxing](/gateway/sandboxing) for the full guide and [full reference](/gateway/configuration-reference#agentsdefaultssandbox) for all options.
</Accordion>
@@ -459,7 +459,7 @@ is skipped when a candidate contains redacted secret placeholders such as `***`.
}
```
See [Multi-Agent](/concepts/multi-agent) and [full reference](/gateway/config-agents#multi-agent-routing) for binding rules and per-agent access profiles.
See [Multi-Agent](/concepts/multi-agent) and [full reference](/gateway/configuration-reference#multi-agent-routing) for binding rules and per-agent access profiles.
</Accordion>
@@ -685,9 +685,3 @@ For the complete field-by-field reference, see **[Configuration Reference](/gate
---
_Related: [Configuration Examples](/gateway/configuration-examples) · [Configuration Reference](/gateway/configuration-reference) · [Doctor](/gateway/doctor)_
## Related
- [Configuration reference](/gateway/configuration-reference)
- [Configuration examples](/gateway/configuration-examples)
- [Gateway runbook](/gateway)

View File

@@ -139,9 +139,3 @@ The gateway is the source of truth for node/client admission.
- **Gateway**: advertises discovery beacons, owns pairing decisions, and hosts the WS endpoint.
- **macOS app**: helps you pick a gateway, shows pairing prompts, and uses SSH only as a fallback.
- **iOS/Android nodes**: browse Bonjour as a convenience and connect to the paired Gateway WS.
## Related
- [Remote access](/gateway/remote)
- [Tailscale](/gateway/tailscale)
- [Bonjour discovery](/gateway/bonjour)

View File

@@ -573,8 +573,3 @@ if the workspace is not already under git.
See [/concepts/agent-workspace](/concepts/agent-workspace) for a full guide to
workspace structure and git backup (recommended private GitHub or GitLab).
## Related
- [Gateway troubleshooting](/gateway/troubleshooting)
- [Gateway runbook](/gateway)

View File

@@ -61,9 +61,3 @@ Options:
- `--debug`: alias for `--verbose`
The health snapshot includes: `ok` (boolean), `ts` (timestamp), `durationMs` (probe time), per-channel status, agent availability, and session-store summary.
## Related
- [Gateway runbook](/gateway)
- [Diagnostics export](/gateway/diagnostics)
- [Gateway troubleshooting](/gateway/troubleshooting)

View File

@@ -356,10 +356,3 @@ Related:
- [Health](/gateway/health)
- [Doctor](/gateway/doctor)
- [Authentication](/gateway/authentication)
## Related
- [Configuration](/gateway/configuration)
- [Gateway troubleshooting](/gateway/troubleshooting)
- [Remote access](/gateway/remote)
- [Secrets management](/gateway/secrets)

View File

@@ -185,8 +185,3 @@ Compatibility notes for stricter OpenAI-compatible backends:
`compat.supportsTools: false`, then retest. If the server still crashes only
on larger OpenClaw prompts, treat it as an upstream server/model limitation.
- Safety: local models skip provider-side filters; keep agents narrow and compaction on to limit prompt injection blast radius.
## Related
- [Configuration reference](/gateway/configuration-reference)
- [Model failover](/concepts/model-failover)

View File

@@ -172,9 +172,3 @@ Interpretation:
- `gateway status --deep` helps catch stale launchd/systemd/schtasks services from older installs.
- `gateway probe` warning text such as `multiple reachable gateways detected` is expected only when you intentionally run more than one isolated gateway.
## Related
- [Gateway runbook](/gateway)
- [Gateway lock](/gateway/gateway-lock)
- [Configuration](/gateway/configuration)

View File

@@ -21,9 +21,3 @@ process that owns channel connections and the WebSocket control plane.
- `/__openclaw__/a2ui/`
When `gateway.auth` is configured and the Gateway binds beyond loopback, these routes are protected by Gateway auth. Node clients use node-scoped capability URLs tied to their active WS session. See [Gateway configuration](/gateway/configuration) (`canvasHost`, `gateway`).
- Remote use is typically SSH tunnel or tailnet VPN. See [Remote access](/gateway/remote) and [Discovery](/gateway/discovery).
## Related
- [Remote access](/gateway/remote)
- [Trusted proxy auth](/gateway/trusted-proxy-auth)
- [Gateway protocol](/gateway/protocol)

View File

@@ -166,9 +166,3 @@ 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 Gateways store.
## Related
- [Channel pairing](/channels/pairing)
- [Nodes](/nodes)
- [Devices CLI](/cli/devices)

View File

@@ -615,8 +615,3 @@ Migration target:
This protocol exposes the **full gateway API** (status, channels, models, chat,
agent, sessions, nodes, approvals, etc.). The exact surface is defined by the
TypeBox schemas in `src/gateway/protocol/schema.ts`.
## Related
- [Bridge protocol](/gateway/bridge-protocol)
- [Gateway runbook](/gateway)

View File

@@ -249,9 +249,3 @@ launchctl bootout gui/$UID/ai.openclaw.ssh-tunnel
| `ssh -N` | SSH without executing remote commands (port-forwarding only) |
| `KeepAlive` | Automatically restarts the tunnel if it crashes |
| `RunAtLoad` | Starts the tunnel when the LaunchAgent loads at login |
## Related
- [Tailscale](/gateway/tailscale)
- [Authentication](/gateway/authentication)
- [Remote gateway setup](/gateway/remote-gateway-readme)

View File

@@ -480,7 +480,7 @@ See [Multi-Agent Sandbox & Tools](/tools/multi-agent-sandbox-tools) for preceden
## Related docs
- [OpenShell](/gateway/openshell) -- managed sandbox backend setup, workspace modes, and config reference
- [Sandbox Configuration](/gateway/config-agents#agentsdefaultssandbox)
- [Sandbox Configuration](/gateway/configuration-reference#agentsdefaultssandbox)
- [Sandbox vs Tool Policy vs Elevated](/gateway/sandbox-vs-tool-policy-vs-elevated) -- debugging "why is this blocked?"
- [Multi-Agent Sandbox & Tools](/tools/multi-agent-sandbox-tools) -- per-agent overrides and precedence
- [Security](/gateway/security)

View File

@@ -134,9 +134,3 @@ Avoid Funnel for browser control; treat node pairing like operator access.
- `tailscale serve` command: [https://tailscale.com/kb/1242/tailscale-serve](https://tailscale.com/kb/1242/tailscale-serve)
- Tailscale Funnel overview: [https://tailscale.com/kb/1223/tailscale-funnel](https://tailscale.com/kb/1223/tailscale-funnel)
- `tailscale funnel` command: [https://tailscale.com/kb/1311/tailscale-funnel](https://tailscale.com/kb/1311/tailscale-funnel)
## Related
- [Remote access](/gateway/remote)
- [Discovery](/gateway/discovery)
- [Authentication](/gateway/authentication)

View File

@@ -564,9 +564,3 @@ Related:
- [/gateway/pairing](/gateway/pairing)
- [/gateway/authentication](/gateway/authentication)
- [/gateway/background-process](/gateway/background-process)
## Related
- [Gateway runbook](/gateway)
- [Doctor](/gateway/doctor)
- [FAQ](/help/faq)

View File

@@ -1308,7 +1308,7 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS,
Setup walkthrough + example config: [Groups: personal DMs + public groups](/channels/groups#pattern-personal-dms-public-groups-single-agent)
Key config reference: [Gateway configuration](/gateway/config-agents#agentsdefaultssandbox)
Key config reference: [Gateway configuration](/gateway/configuration-reference#agentsdefaultssandbox)
</Accordion>

View File

@@ -309,9 +309,3 @@ This removes the resource group and everything inside it (VM, VNet, NSG, Bastion
- Pair local devices as nodes: [Nodes](/nodes)
- Configure the Gateway: [Gateway configuration](/gateway/configuration)
- For more details on OpenClaw Azure deployment with the GitHub Copilot model provider: [OpenClaw on Azure with GitHub Copilot](https://github.com/johnsonshi/openclaw-azure-github-copilot)
## Related
- [Install overview](/install)
- [GCP](/install/gcp)
- [DigitalOcean](/install/digitalocean)

View File

@@ -51,9 +51,3 @@ bun pm trust @whiskeysockets/baileys protobufjs
## Caveats
Some scripts still hardcode pnpm (for example `docs:build`, `ui:*`, `protocol:check`). Run those via pnpm for now.
## Related
- [Install overview](/install)
- [Node.js](/install/node)
- [Updating](/install/updating)

View File

@@ -129,8 +129,3 @@ Beta and dev builds may **not** include a macOS app release. That is OK:
- The git tag and npm dist-tag can still be published.
- Call out "no macOS build for this beta" in release notes or changelog.
## Related
- [Updating](/install/updating)
- [Installer internals](/install/installer)

View File

@@ -125,10 +125,3 @@ Run a persistent OpenClaw Gateway on a DigitalOcean Droplet.
- [Channels](/channels) -- connect Telegram, WhatsApp, Discord, and more
- [Gateway configuration](/gateway/configuration) -- all config options
- [Updating](/install/updating) -- keep OpenClaw up to date
## Related
- [Install overview](/install)
- [Fly.io](/install/fly)
- [Hetzner](/install/hetzner)
- [VPS hosting](/vps)

View File

@@ -138,9 +138,3 @@ git pull
docker compose build
docker compose up -d
```
## Related
- [Docker](/install/docker)
- [Podman](/install/podman)
- [ClawDock](/install/clawdock)

View File

@@ -129,8 +129,3 @@ openclaw health
```
Guide: [Updating](/install/updating)
## Related
- [Remote gateway](/gateway/remote)
- [Install overview](/install)

View File

@@ -502,10 +502,3 @@ See [Fly.io pricing](https://fly.io/docs/about/pricing/) for details.
- Set up messaging channels: [Channels](/channels)
- Configure the Gateway: [Gateway configuration](/gateway/configuration)
- Keep OpenClaw up to date: [Updating](/install/updating)
## Related
- [Install overview](/install)
- [Hetzner](/install/hetzner)
- [Docker](/install/docker)
- [VPS hosting](/vps)

View File

@@ -413,9 +413,3 @@ See [https://cloud.google.com/iam/docs/understanding-roles](https://cloud.google
- Set up messaging channels: [Channels](/channels)
- Pair local devices as nodes: [Nodes](/nodes)
- Configure the Gateway: [Gateway configuration](/gateway/configuration)
## Related
- [Install overview](/install)
- [Azure](/install/azure)
- [VPS hosting](/vps)

View File

@@ -260,10 +260,3 @@ This approach complements the Docker setup above with reproducible deployments,
- Set up messaging channels: [Channels](/channels)
- Configure the Gateway: [Gateway configuration](/gateway/configuration)
- Keep OpenClaw up to date: [Updating](/install/updating)
## Related
- [Install overview](/install)
- [Fly.io](/install/fly)
- [Docker](/install/docker)
- [VPS hosting](/vps)

View File

@@ -90,9 +90,3 @@ Send "Hi" to your assistant on the channel you connected. OpenClaw will reply an
- [Channels](/channels) -- connect Telegram, WhatsApp, Discord, and more
- [Gateway configuration](/gateway/configuration) -- all config options
## Related
- [Install overview](/install)
- [VPS hosting](/vps)
- [DigitalOcean](/install/digitalocean)

View File

@@ -7,12 +7,6 @@ read_when:
title: "Install"
---
## System requirements
- **Node 24** (recommended) or Node 22.14+ — the installer script handles this automatically
- **macOS, Linux, or Windows** — both native Windows and WSL2 are supported; WSL2 is more stable. See [Windows](/platforms/windows).
- `pnpm` is only needed if you build from source
## Recommended: installer script
The fastest way to install. It detects your OS, installs Node if needed, installs OpenClaw, and launches onboarding.
@@ -47,6 +41,12 @@ To install without running onboarding:
For all flags and CI/automation options, see [Installer internals](/install/installer).
## System requirements
- **Node 24** (recommended) or Node 22.14+ — the installer script handles this automatically
- **macOS, Linux, or Windows** — both native Windows and WSL2 are supported; WSL2 is more stable. See [Windows](/platforms/windows).
- `pnpm` is only needed if you build from source
## Alternative install methods
### Local prefix installer (`install-cli.sh`)

View File

@@ -439,9 +439,3 @@ Use non-interactive flags/env vars for predictable runs.
Usually a PATH issue. See [Node.js troubleshooting](/install/node#troubleshooting).
</Accordion>
</AccordionGroup>
## Related
- [Install overview](/install)
- [Updating](/install/updating)
- [Uninstall](/install/uninstall)

View File

@@ -190,9 +190,3 @@ scripts/k8s/
├── pvc.yaml # 10Gi persistent storage
└── service.yaml # ClusterIP on 18789
```
## Related
- [Docker](/install/docker)
- [Docker VM runtime](/install/docker-vm-runtime)
- [Install overview](/install)

View File

@@ -110,9 +110,3 @@ On the new machine, confirm:
- [ ] Channels are still connected (no re-pairing needed)
- [ ] The dashboard opens and shows existing sessions
- [ ] Workspace files (memory, configs) are present
## Related
- [Install overview](/install)
- [Matrix migration](/install/migrating-matrix)
- [Uninstall](/install/uninstall)

View File

@@ -154,9 +154,3 @@ Then open `http://localhost:18789`.
- [Channels](/channels) -- connect Telegram, WhatsApp, Discord, and more
- [Gateway configuration](/gateway/configuration) -- all config options
- [Updating](/install/updating) -- keep OpenClaw up to date
## Related
- [Install overview](/install)
- [GCP](/install/gcp)
- [VPS hosting](/vps)

View File

@@ -155,9 +155,3 @@ sudo systemctl disable bluetooth
- [Channels](/channels) -- connect Telegram, WhatsApp, Discord, and more
- [Gateway configuration](/gateway/configuration) -- all config options
- [Updating](/install/updating) -- keep OpenClaw up to date
## Related
- [Install overview](/install)
- [Linux server](/vps)
- [Platforms](/platforms)

View File

@@ -124,8 +124,3 @@ If you run from a repo checkout (`git clone` + `openclaw ...` / `bun run opencla
1. Uninstall the gateway service **before** deleting the repo (use the easy path above or manual service removal).
2. Delete the repo directory.
3. Remove state + workspace as shown above.
## Related
- [Install overview](/install)
- [Migration guide](/install/migrating)

View File

@@ -240,9 +240,3 @@ Example configuration:
<Note>
Notification forwarding requires the Android Notification Listener permission. The app prompts for this during setup.
</Note>
## Related
- [iOS app](/platforms/ios)
- [Nodes](/nodes)
- [Android node troubleshooting](/nodes/troubleshooting)

View File

@@ -7,8 +7,7 @@ title: "Platforms"
---
OpenClaw core is written in TypeScript. **Node is the recommended runtime**.
Bun is not recommended for the Gateway — known issues with WhatsApp and
Telegram channels; see [Bun (experimental)](/install/bun) for details.
Bun is not recommended for the Gateway (WhatsApp/Telegram bugs).
Companion apps exist for macOS (menu bar app) and mobile nodes (iOS/Android). Windows and
Linux companion apps are planned, but the Gateway is fully supported today.
@@ -52,9 +51,3 @@ The service target depends on OS:
- macOS: LaunchAgent (`ai.openclaw.gateway` or `ai.openclaw.<profile>`; legacy `com.openclaw.*`)
- Linux/WSL2: systemd user service (`openclaw-gateway[-<profile>].service`)
- Native Windows: Scheduled Task (`OpenClaw Gateway` or `OpenClaw Gateway (<profile>)`), with a per-user Startup-folder login item fallback if task creation is denied
## Related
- [Install overview](/install)
- [macOS app](/platforms/macos)
- [iOS app](/platforms/ios)

View File

@@ -133,9 +133,3 @@ its normal score, usually `0`.
This does not replace normal memory tuning. If a VPS or container repeatedly
kills children, increase the memory limit, reduce concurrency, or add stronger
resource controls such as systemd `MemoryMax=` or container-level memory limits.
## Related
- [Install overview](/install)
- [Linux server](/vps)
- [Raspberry Pi](/platforms/raspberry-pi)

View File

@@ -247,8 +247,3 @@ Full guide: [Getting Started](/start/getting-started)
We do not have a Windows companion app yet. Contributions are welcome if you want
contributions to make it happen.
## Related
- [Install overview](/install)
- [Platforms](/platforms)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -164,7 +164,7 @@ A single plugin can register any number of capabilities via the `api` object:
| Agent tools | `api.registerTool(...)` | Below |
| Custom commands | `api.registerCommand(...)` | [Entry Points](/plugins/sdk-entrypoints) |
| Event hooks | `api.registerHook(...)` | [Entry Points](/plugins/sdk-entrypoints) |
| HTTP routes | `api.registerHttpRoute(...)` | [Internals](/plugins/architecture-internals#gateway-http-routes) |
| HTTP routes | `api.registerHttpRoute(...)` | [Internals](/plugins/architecture#gateway-http-routes) |
| CLI subcommands | `api.registerCli(...)` | [Entry Points](/plugins/sdk-entrypoints) |
For the full registration API, see [SDK Overview](/plugins/sdk-overview#registration-api).

View File

@@ -15,21 +15,19 @@ discovery, native thread resume, native compaction, and app-server execution.
OpenClaw still owns chat channels, session files, model selection, tools,
approvals, media delivery, and the visible transcript mirror.
Native Codex turns keep OpenClaw plugin hooks as the public compatibility layer.
These are in-process OpenClaw hooks, not Codex `hooks.json` command hooks:
Native Codex turns also respect the shared plugin hooks so prompt shims,
compaction-aware automation, tool middleware, and lifecycle observers stay
aligned with the PI harness:
- `before_prompt_build`
- `before_compaction`, `after_compaction`
- `llm_input`, `llm_output`
- `after_tool_call`
- `before_message_write` for mirrored transcript records
- `tool_result`, `after_tool_call`
- `before_message_write`
- `agent_end`
Bundled plugins can also register a Codex app-server extension factory to add
async `tool_result` middleware. That middleware runs for OpenClaw dynamic tools
after OpenClaw executes the tool and before the result is returned to Codex. It
is separate from the public `tool_result_persist` plugin hook, which transforms
OpenClaw-owned transcript tool-result writes.
async `tool_result` middleware.
The harness is off by default. New configs should keep OpenAI model refs
canonical as `openai/gpt-*` and explicitly force
@@ -507,41 +505,6 @@ The command surface requires Codex app-server `0.118.0` or newer. Individual
control methods are reported as `unsupported by this Codex app-server` if a
future or custom app-server does not expose that JSON-RPC method.
## Hook boundaries
The Codex harness has three hook layers:
| Layer | Owner | Purpose |
| ------------------------------------- | ------------------------ | ------------------------------------------------------------------- |
| OpenClaw plugin hooks | OpenClaw | Product/plugin compatibility across PI and Codex harnesses. |
| Codex app-server extension middleware | OpenClaw bundled plugins | Per-turn adapter behavior around OpenClaw dynamic tools. |
| Codex native hooks | Codex | Low-level Codex lifecycle and native tool policy from Codex config. |
OpenClaw does not use project or global Codex `hooks.json` files to route
OpenClaw plugin behavior. Codex native hooks are useful for Codex-owned
operations such as shell policy, native tool result review, stop handling, and
native compaction/model lifecycle, but they are not the OpenClaw plugin API.
For OpenClaw dynamic tools, OpenClaw executes the tool after Codex asks for the
call, so OpenClaw fires the plugin and middleware behavior it owns in the
harness adapter. For Codex-native tools, Codex owns the canonical tool record.
OpenClaw can mirror selected events, but it cannot rewrite the native Codex
thread unless Codex exposes that operation through app-server or native hook
callbacks.
When newer Codex app-server builds expose native compaction and model lifecycle
hook events, OpenClaw version-gates that protocol support and maps events into
the existing OpenClaw hook contract where the semantics are honest. The
OpenClaw `before_compaction`, `after_compaction`, `llm_input`, and `llm_output`
events remain adapter-level observations, not byte-for-byte captures of Codex's
internal request or compaction payloads.
Codex native `PreCompact` and `PostCompact` hooks are lower-level Codex command
hooks. They run inside Codex around native thread compaction, using Codex hook
configuration. OpenClaw's plugin hooks do not require a user or project
`hooks.json`, and OpenClaw does not double-fire `before_compaction` or
`after_compaction` just because native Codex compaction hooks are available.
## Tools, media, and compaction
The Codex harness changes the low-level embedded agent executor only.
@@ -564,16 +527,6 @@ records native compaction start and completion signals. It does not yet expose a
human-readable compaction summary or an auditable list of which entries Codex
kept after compaction.
On Codex app-server builds with native compaction hook support, Codex can also
run its own `PreCompact` and `PostCompact` command hooks around that native
operation. Those hooks are useful for Codex-owned audit and policy. OpenClaw
still treats the app-server compaction item stream as the source for OpenClaw
plugin `before_compaction` and `after_compaction` events.
Because Codex owns the canonical native thread, `tool_result_persist` does not
currently rewrite Codex-native tool result records. It only applies when
OpenClaw is writing an OpenClaw-owned session transcript tool result.
Media generation does not require PI. Image, video, music, PDF, TTS, and media
understanding continue to use the matching provider/model settings such as
`agents.defaults.imageGenerationModel`, `videoGenerationModel`, `pdfModel`, and

View File

@@ -683,7 +683,7 @@ See [Configuration reference](/gateway/configuration) for the full `plugins.*` s
- `channels`, `providers`, `cliBackends`, and `skills` can all be omitted when a plugin does not need them.
- Exclusive plugin kinds are selected through `plugins.slots.*`: `kind: "memory"` via `plugins.slots.memory`, `kind: "context-engine"` via `plugins.slots.contextEngine` (default `legacy`).
- Env-var metadata (`providerAuthEnvVars`, `channelEnvVars`) is declarative only. Status, audit, cron delivery validation, and other read-only surfaces still apply plugin trust and effective activation policy before treating an env var as configured.
- For runtime wizard metadata that requires provider code, see [Provider runtime hooks](/plugins/architecture-internals#provider-runtime-hooks).
- For runtime wizard metadata that requires provider code, see [Provider runtime hooks](/plugins/architecture#provider-runtime-hooks).
- If your plugin depends on native modules, document the build steps and any package-manager allowlist requirements (for example, pnpm `allow-build-scripts` + `pnpm rebuild <package>`).
## Related

View File

@@ -332,5 +332,5 @@ messages where the provider supports those operations.
- [Message CLI](/cli/message)
- [Plugin SDK Overview](/plugins/sdk-overview)
- [Plugin Architecture](/plugins/architecture-internals#message-tool-schemas)
- [Plugin Architecture](/plugins/architecture#message-tool-schemas)
- [Channel Presentation Refactor Plan](/plan/ui-channels)

View File

@@ -631,7 +631,7 @@ Write colocated tests in `src/channel.test.ts`:
<Card title="Message tool integration" icon="puzzle" href="/plugins/architecture#channel-plugins-and-the-shared-message-tool">
describeMessageTool and action discovery
</Card>
<Card title="Target resolution" icon="crosshair" href="/plugins/architecture-internals#channel-target-resolution">
<Card title="Target resolution" icon="crosshair" href="/plugins/architecture#channel-target-resolution">
inferTargetChatType, looksLikeId, resolveTarget
</Card>
<Card title="Runtime helpers" icon="settings" href="/plugins/sdk-runtime">

View File

@@ -474,7 +474,7 @@ API key auth, and dynamic model resolution.
- `resolveConfigApiKey` uses the provider hook when exposed. The bundled `amazon-bedrock` path also has a built-in AWS env-marker resolver here, even though Bedrock runtime auth itself still uses the AWS SDK default chain.
- `resolveSystemPromptContribution` lets a provider inject cache-aware system-prompt guidance for a model family. Prefer it over `before_prompt_build` when the behavior belongs to one provider/model family and should preserve the stable/dynamic cache split.
For detailed descriptions and real-world examples, see [Internals: Provider Runtime Hooks](/plugins/architecture-internals#provider-runtime-hooks).
For detailed descriptions and real-world examples, see [Internals: Provider Runtime Hooks](/plugins/architecture#provider-runtime-hooks).
</Accordion>
</Step>
@@ -717,7 +717,7 @@ providers:
- [Channel Plugins](/plugins/sdk-channel-plugins) — if your plugin also provides a channel
- [SDK Runtime](/plugins/sdk-runtime) — `api.runtime` helpers (TTS, search, subagent)
- [SDK Overview](/plugins/sdk-overview) — full subpath import reference
- [Plugin Internals](/plugins/architecture-internals#provider-runtime-hooks) — hook details and bundled examples
- [Plugin Internals](/plugins/architecture#provider-runtime-hooks) — hook details and bundled examples
## Related

View File

@@ -175,6 +175,7 @@ For the plugin authoring guide, see [Plugin SDK overview](/plugins/sdk-overview)
| `plugin-sdk/json-store` | Small JSON state read/write helpers |
| `plugin-sdk/file-lock` | Re-entrant file-lock helpers |
| `plugin-sdk/persistent-dedupe` | Disk-backed dedupe cache helpers |
| `plugin-sdk/persistent-keyed-store` | Persistent keyed registry helper with TTL, deterministic enumeration, and quarantine-on-corruption behavior for restart-safe lifecycle state |
| `plugin-sdk/acp-runtime` | ACP runtime/session and reply-dispatch helpers |
| `plugin-sdk/acp-binding-resolve-runtime` | Read-only ACP binding resolution without lifecycle startup imports |
| `plugin-sdk/agent-config-primitives` | Narrow agent runtime config-schema primitives |

View File

@@ -108,7 +108,7 @@ Reference image/video mode currently requires **remote http(s) URLs**. Local fil
<Card title="Qwen" href="/providers/qwen" icon="microchip">
Qwen provider setup and DashScope integration.
</Card>
<Card title="Configuration reference" href="/gateway/config-agents#agent-defaults" icon="gear">
<Card title="Configuration reference" href="/gateway/configuration-reference#agent-defaults" icon="gear">
Agent defaults and model configuration.
</Card>
</CardGroup>

View File

@@ -346,7 +346,7 @@ The `image` and `video` sections also support:
<Card title="Provider Directory" href="/providers/index" icon="layers">
Overview of all providers and model refs.
</Card>
<Card title="Configuration reference" href="/gateway/config-agents#agent-defaults" icon="gear">
<Card title="Configuration reference" href="/gateway/configuration-reference#agent-defaults" icon="gear">
Full config reference including agent defaults.
</Card>
</CardGroup>

View File

@@ -107,8 +107,3 @@ Voice Call receives Twilio media as 8 kHz G.711 u-law. The ElevenLabs realtime
provider defaults to `ulaw_8000`, so telephony frames can be forwarded without
transcoding.
</Note>
## Related
- [Text-to-speech](/tools/tts)
- [Model selection](/concepts/model-providers)

View File

@@ -137,7 +137,7 @@ models, including any recently added entries.
<Card title="Video generation" href="/tools/video-generation" icon="video">
Shared video tool parameters and provider selection.
</Card>
<Card title="Configuration reference" href="/gateway/config-agents#agent-defaults" icon="gear">
<Card title="Configuration reference" href="/gateway/configuration-reference#agent-defaults" icon="gear">
Agent defaults including image and video model selection.
</Card>
</CardGroup>

View File

@@ -171,9 +171,3 @@ If setup reports HTTP 401, verify your API key:
### Just-in-time model loading
LM Studio supports just-in-time (JIT) model loading, where models are loaded on first request. Make sure you have this enabled to avoid 'Model not loaded' errors.
## Related
- [Model selection](/concepts/model-providers)
- [Ollama](/providers/ollama)
- [Local models](/gateway/local-models)

View File

@@ -58,9 +58,3 @@ model as `provider/model`.
For the full provider catalog (xAI, Groq, Mistral, etc.) and advanced configuration,
see [Model providers](/concepts/model-providers).
## Related
- [Model selection](/concepts/model-providers)
- [Model failover](/concepts/model-failover)
- [Models CLI](/cli/models)

View File

@@ -9,9 +9,3 @@ read_when:
This page moved to [Qwen](/providers/qwen). See [Qwen](/providers/qwen) for
the canonical provider setup, endpoint details, compatibility aliases, and Wan
video-generation notes.
## Related
- [Alibaba Model Studio](/providers/alibaba)
- [Qwen](/providers/qwen)
- [Model selection](/concepts/model-providers)

View File

@@ -85,7 +85,7 @@ Video-to-video currently requires `runway/gen4_aleph` specifically.
<Card title="Video generation" href="/tools/video-generation" icon="video">
Shared tool parameters, provider selection, and async behavior.
</Card>
<Card title="Configuration reference" href="/gateway/config-agents#agent-defaults" icon="gear">
<Card title="Configuration reference" href="/gateway/configuration-reference#agent-defaults" icon="gear">
Agent default settings including video generation model.
</Card>
</CardGroup>

View File

@@ -166,7 +166,7 @@ Vydra's apex host (`https://vydra.ai/api/v1`) currently redirects to `www`. Some
<Card title="Video generation" href="/tools/video-generation" icon="video">
Shared video tool parameters and provider selection.
</Card>
<Card title="Configuration reference" href="/gateway/config-agents#agent-defaults" icon="gear">
<Card title="Configuration reference" href="/gateway/configuration-reference#agent-defaults" icon="gear">
Agent defaults and model configuration.
</Card>
</CardGroup>

View File

@@ -195,9 +195,3 @@ Skills can store `apiKey` in `skills.entries.<name>.apiKey`. If a skill uses tha
APIs, it can incur costs according to the skills provider.
See [Skills](/tools/skills).
## Related
- [Token use and costs](/reference/token-use)
- [Prompt caching](/reference/prompt-caching)
- [Usage tracking](/concepts/usage-tracking)

View File

@@ -28,8 +28,3 @@ OpenClaw = CLAW + TARDIS, because every space lobster needs a time and space mac
MIT - Free as a lobster in the ocean.
> "We are all just playing with our own prompts." (An AI, probably high on tokens)
## Related
- [Token use and costs](/reference/token-use)
- [Release policy](/reference/RELEASING)

View File

@@ -45,8 +45,3 @@ curl -fsSL "https://raw.githubusercontent.com/kyle-seongwoo-jun/apple-device-ide
```bash
swift build --package-path apps/macos
```
## Related
- [Nodes](/nodes)
- [Node troubleshooting](/nodes/troubleshooting)

View File

@@ -436,7 +436,7 @@ runtime environment.
### Scope
Controls which sessions can receive QMD search results. Same schema as
[`session.sendPolicy`](/gateway/config-agents#session):
[`session.sendPolicy`](/gateway/configuration-reference#session):
```json5
{
@@ -531,9 +531,3 @@ Notes:
- Dreaming writes machine state to `memory/.dreams/`.
- Dreaming writes human-readable narrative output to `DREAMS.md` (or existing `dreams.md`).
- The light/deep/REM phase policy and thresholds are internal behavior, not user-facing config.
## Related
- [Memory overview](/concepts/memory)
- [Memory search](/concepts/memory-search)
- [Configuration reference](/gateway/configuration-reference)

Some files were not shown because too many files have changed in this diff Show More