Merge remote-tracking branch 'origin/main' into feat/add_qwen_official_api

Migrate Model Studio Standard (pay-as-you-go) endpoints to the new
extensions/modelstudio plugin structure after upstream refactor.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
wenmengzhou 2026-03-18 14:51:01 +08:00
commit e20f55bbba
2400 changed files with 106649 additions and 48524 deletions

View File

@ -0,0 +1,62 @@
---
name: parallels-discord-roundtrip
description: Run the macOS Parallels smoke harness with Discord end-to-end roundtrip verification, including guest send, host verification, host reply, and guest readback.
---
# Parallels Discord Roundtrip
Use when macOS Parallels smoke must prove Discord two-way delivery end to end.
## Goal
Cover:
- install on fresh macOS snapshot
- onboard + gateway health
- guest `message send` to Discord
- host sees that message on Discord
- host posts a new Discord message
- guest `message read` sees that new message
## Inputs
- host env var with Discord bot token
- Discord guild ID
- Discord channel ID
- `OPENAI_API_KEY`
## Preferred run
```bash
export OPENCLAW_PARALLELS_DISCORD_TOKEN="$(
ssh peters-mac-studio-1 'jq -r ".channels.discord.token" ~/.openclaw/openclaw.json' | tr -d '\n'
)"
pnpm test:parallels:macos \
--discord-token-env OPENCLAW_PARALLELS_DISCORD_TOKEN \
--discord-guild-id 1456350064065904867 \
--discord-channel-id 1456744319972282449 \
--json
```
## Notes
- Snapshot target: closest to `macOS 26.3.1 fresh`.
- Snapshot resolver now prefers matching `*-poweroff*` clones when the base hint also matches. That lets the harness reuse disk-only recovery snapshots without passing a longer hint.
- If Windows/Linux snapshot restore logs show `PET_QUESTION_SNAPSHOT_STATE_INCOMPATIBLE_CPU`, drop the suspended state once, create a `*-poweroff*` replacement snapshot, and rerun. The smoke scripts now auto-start restored power-off snapshots.
- Harness configures Discord inside the guest; no checked-in token/config.
- Use the `openclaw` wrapper for guest `message send/read`; `node openclaw.mjs message ...` does not expose the lazy message subcommands the same way.
- Write `channels.discord.guilds` in one JSON object (`--strict-json`), not dotted `config set channels.discord.guilds.<snowflake>...` paths; numeric snowflakes get treated like array indexes.
- Avoid `prlctl enter` / expect for long Discord setup scripts; it line-wraps/corrupts long commands. Use `prlctl exec --current-user /bin/sh -lc ...` for the Discord config phase.
- Full 3-OS sweeps: the shared build lock is safe in parallel, but snapshot restore is still a Parallels bottleneck. Prefer serialized Windows/Linux restore-heavy reruns if the host is already under load.
- Harness cleanup deletes the temporary Discord smoke messages at exit.
- Per-phase logs: `/tmp/openclaw-parallels-smoke.*`
- Machine summary: pass `--json`
- If roundtrip flakes, inspect `fresh.discord-roundtrip.log` and `discord-last-readback.json` in the run dir first.
## Pass criteria
- fresh lane or upgrade lane requested passes
- summary reports `discord=pass` for that lane
- guest outbound nonce appears in channel history
- host inbound nonce appears in `openclaw message read` output

4
.github/labeler.yml vendored
View File

@ -314,3 +314,7 @@
- changed-files:
- any-glob-to-any-file:
- "extensions/xiaomi/**"
"extensions: fal":
- changed-files:
- any-glob-to-any-file:
- "extensions/fal/**"

View File

@ -78,6 +78,50 @@ jobs:
node scripts/ci-changed-scope.mjs --base "$BASE" --head HEAD
changed-extensions:
needs: [docs-scope, changed-scope]
if: needs.docs-scope.outputs.docs_only != 'true' && needs.changed-scope.outputs.run_node == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
outputs:
has_changed_extensions: ${{ steps.changed.outputs.has_changed_extensions }}
changed_extensions_matrix: ${{ steps.changed.outputs.changed_extensions_matrix }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 1
fetch-tags: false
submodules: false
- name: Ensure changed-extensions base commit
uses: ./.github/actions/ensure-base-commit
with:
base-sha: ${{ github.event_name == 'push' && github.event.before || github.event.pull_request.base.sha }}
fetch-ref: ${{ github.event_name == 'push' && github.ref_name || github.event.pull_request.base.ref }}
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
install-deps: "false"
use-sticky-disk: "false"
- name: Detect changed extensions
id: changed
env:
BASE_SHA: ${{ github.event_name == 'push' && github.event.before || github.event.pull_request.base.sha }}
run: |
node --input-type=module <<'EOF'
import { appendFileSync } from "node:fs";
import { listChangedExtensionIds } from "./scripts/test-extension.mjs";
const extensionIds = listChangedExtensionIds({ base: process.env.BASE_SHA, head: "HEAD" });
const matrix = JSON.stringify({ include: extensionIds.map((extension) => ({ extension })) });
appendFileSync(process.env.GITHUB_OUTPUT, `has_changed_extensions=${extensionIds.length > 0}\n`, "utf8");
appendFileSync(process.env.GITHUB_OUTPUT, `changed_extensions_matrix=${matrix}\n`, "utf8");
EOF
# Build dist once for Node-relevant changes and share it with downstream jobs.
build-artifacts:
needs: [docs-scope, changed-scope]
@ -162,6 +206,9 @@ jobs:
- runtime: node
task: channels
command: pnpm test:channels
- runtime: node
task: contracts
command: pnpm test:contracts
- runtime: node
task: protocol
command: pnpm protocol:check
@ -205,6 +252,31 @@ jobs:
if: matrix.runtime != 'bun' || github.event_name != 'pull_request'
run: ${{ matrix.command }}
extension-fast:
name: "extension-fast (${{ matrix.extension }})"
needs: [docs-scope, changed-scope, changed-extensions]
if: needs.docs-scope.outputs.docs_only != 'true' && needs.changed-scope.outputs.run_node == 'true' && needs.changed-extensions.outputs.has_changed_extensions == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.changed-extensions.outputs.changed_extensions_matrix) }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
submodules: false
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
use-sticky-disk: "false"
- name: Run changed extension tests
env:
OPENCLAW_CHANGED_EXTENSION: ${{ matrix.extension }}
run: pnpm test:extension "$OPENCLAW_CHANGED_EXTENSION"
# Types, lint, and format check.
check:
name: "check"
@ -232,8 +304,196 @@ jobs:
- name: Enforce safe external URL opening policy
run: pnpm lint:ui:no-raw-window-open
startup-memory:
name: "startup-memory"
plugin-extension-boundary:
name: "plugin-extension-boundary"
needs: [docs-scope, changed-scope]
if: needs.docs-scope.outputs.docs_only != 'true' && needs.changed-scope.outputs.run_node == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
env:
PLUGIN_EXTENSION_BOUNDARY_ENFORCE_AFTER: "2026-03-24T05:00:00Z"
steps:
- name: Checkout
uses: actions/checkout@v6
with:
submodules: false
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
use-sticky-disk: "false"
- name: Run plugin extension boundary guard with grace period
shell: bash
run: |
set -euo pipefail
tmp_output="$(mktemp)"
if pnpm run lint:plugins:no-extension-imports >"$tmp_output" 2>&1; then
cat "$tmp_output"
rm -f "$tmp_output"
exit 0
fi
status=$?
cat "$tmp_output"
rm -f "$tmp_output"
now_epoch="$(date -u +%s)"
enforce_epoch="$(date -u -d "$PLUGIN_EXTENSION_BOUNDARY_ENFORCE_AFTER" +%s)"
fix_instructions="If you are an LLM agent fixing this: run 'pnpm run lint:plugins:no-extension-imports', remove src/plugins/** -> extensions/** imports where possible, and if the remaining inventory is intentional for now update test/fixtures/plugin-extension-import-boundary-inventory.json in the same PR."
if [ "$now_epoch" -lt "$enforce_epoch" ]; then
echo "::warning::Plugin extension import boundary violations are temporarily allowed until ${PLUGIN_EXTENSION_BOUNDARY_ENFORCE_AFTER}. This grace period ends in one week from the rollout date. After that timestamp this job will fail unless the inventory is reduced or the baseline is intentionally updated. ${fix_instructions}"
exit 0
fi
echo "::error::Plugin extension import boundary grace period ended at ${PLUGIN_EXTENSION_BOUNDARY_ENFORCE_AFTER}. ${fix_instructions}"
exit "$status"
web-search-provider-boundary:
name: "web-search-provider-boundary"
needs: [docs-scope, changed-scope]
if: needs.docs-scope.outputs.docs_only != 'true' && needs.changed-scope.outputs.run_node == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
env:
WEB_SEARCH_PROVIDER_BOUNDARY_ENFORCE_AFTER: "2026-03-24T05:00:00Z"
steps:
- name: Checkout
uses: actions/checkout@v6
with:
submodules: false
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
use-sticky-disk: "false"
- name: Run web search provider boundary guard with grace period
shell: bash
run: |
set -euo pipefail
tmp_output="$(mktemp)"
if pnpm run lint:web-search-provider-boundaries >"$tmp_output" 2>&1; then
cat "$tmp_output"
rm -f "$tmp_output"
exit 0
fi
status=$?
cat "$tmp_output"
rm -f "$tmp_output"
now_epoch="$(date -u +%s)"
enforce_epoch="$(date -u -d "$WEB_SEARCH_PROVIDER_BOUNDARY_ENFORCE_AFTER" +%s)"
fix_instructions="If you are an LLM agent fixing this: run 'pnpm run lint:web-search-provider-boundaries', move provider-specific web-search logic out of core, and if the remaining inventory is intentional for now update test/fixtures/web-search-provider-boundary-inventory.json in the same PR."
if [ "$now_epoch" -lt "$enforce_epoch" ]; then
echo "::warning::Web search provider boundary violations are temporarily allowed until ${WEB_SEARCH_PROVIDER_BOUNDARY_ENFORCE_AFTER}. This grace period ends in one week from the rollout date. After that timestamp this job will fail unless the inventory is reduced or the baseline is intentionally updated. ${fix_instructions}"
exit 0
fi
echo "::error::Web search provider boundary grace period ended at ${WEB_SEARCH_PROVIDER_BOUNDARY_ENFORCE_AFTER}. ${fix_instructions}"
exit "$status"
extension-src-outside-plugin-sdk-boundary:
name: "extension-src-outside-plugin-sdk-boundary"
needs: [docs-scope, changed-scope]
if: needs.docs-scope.outputs.docs_only != 'true' && needs.changed-scope.outputs.run_node == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
env:
EXTENSION_PLUGIN_SDK_BOUNDARY_ENFORCE_AFTER: "2026-03-24T05:00:00Z"
steps:
- name: Checkout
uses: actions/checkout@v6
with:
submodules: false
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
use-sticky-disk: "false"
- name: Run extension src boundary guard with grace period
shell: bash
run: |
set -euo pipefail
tmp_output="$(mktemp)"
if pnpm run lint:extensions:no-src-outside-plugin-sdk >"$tmp_output" 2>&1; then
cat "$tmp_output"
rm -f "$tmp_output"
exit 0
fi
status=$?
cat "$tmp_output"
rm -f "$tmp_output"
now_epoch="$(date -u +%s)"
enforce_epoch="$(date -u -d "$EXTENSION_PLUGIN_SDK_BOUNDARY_ENFORCE_AFTER" +%s)"
fix_instructions="If you are an LLM agent fixing this: run 'pnpm run lint:extensions:no-src-outside-plugin-sdk', move extension imports off core src paths and onto src/plugin-sdk/**, and if the remaining inventory is intentional for now update test/fixtures/extension-src-outside-plugin-sdk-inventory.json in the same PR."
if [ "$now_epoch" -lt "$enforce_epoch" ]; then
echo "::warning::Extension src boundary violations are temporarily allowed until ${EXTENSION_PLUGIN_SDK_BOUNDARY_ENFORCE_AFTER}. This grace period ends in one week from the rollout date. After that timestamp this job will fail unless the inventory is reduced or the baseline is intentionally updated. ${fix_instructions}"
exit 0
fi
echo "::error::Extension src boundary grace period ended at ${EXTENSION_PLUGIN_SDK_BOUNDARY_ENFORCE_AFTER}. ${fix_instructions}"
exit "$status"
extension-plugin-sdk-internal-boundary:
name: "extension-plugin-sdk-internal-boundary"
needs: [docs-scope, changed-scope]
if: needs.docs-scope.outputs.docs_only != 'true' && needs.changed-scope.outputs.run_node == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
env:
EXTENSION_PLUGIN_SDK_INTERNAL_ENFORCE_AFTER: "2026-03-24T05:00:00Z"
steps:
- name: Checkout
uses: actions/checkout@v6
with:
submodules: false
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
use-sticky-disk: "false"
- name: Run extension plugin-sdk-internal guard with grace period
shell: bash
run: |
set -euo pipefail
tmp_output="$(mktemp)"
if pnpm run lint:extensions:no-plugin-sdk-internal >"$tmp_output" 2>&1; then
cat "$tmp_output"
rm -f "$tmp_output"
exit 0
fi
status=$?
cat "$tmp_output"
rm -f "$tmp_output"
now_epoch="$(date -u +%s)"
enforce_epoch="$(date -u -d "$EXTENSION_PLUGIN_SDK_INTERNAL_ENFORCE_AFTER" +%s)"
fix_instructions="If you are an LLM agent fixing this: run 'pnpm run lint:extensions:no-plugin-sdk-internal', remove extension imports of src/plugin-sdk-internal/** in favor of src/plugin-sdk/**, and if the remaining inventory is intentional for now update test/fixtures/extension-plugin-sdk-internal-inventory.json in the same PR."
if [ "$now_epoch" -lt "$enforce_epoch" ]; then
echo "::warning::Extension plugin-sdk-internal boundary violations are temporarily allowed until ${EXTENSION_PLUGIN_SDK_INTERNAL_ENFORCE_AFTER}. This grace period ends in one week from the rollout date. After that timestamp this job will fail unless the inventory is reduced or the baseline is intentionally updated. ${fix_instructions}"
exit 0
fi
echo "::error::Extension plugin-sdk-internal boundary grace period ended at ${EXTENSION_PLUGIN_SDK_INTERNAL_ENFORCE_AFTER}. ${fix_instructions}"
exit "$status"
build-smoke:
name: "build-smoke"
needs: [docs-scope, changed-scope]
if: needs.docs-scope.outputs.docs_only != 'true' && needs.changed-scope.outputs.run_node == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
@ -252,9 +512,46 @@ jobs:
- name: Build dist
run: pnpm build
- name: Smoke test CLI launcher help
run: node openclaw.mjs --help
- name: Smoke test CLI launcher status json
run: node openclaw.mjs status --json --timeout 1
- name: Smoke test built bundled plugin singleton
run: pnpm test:build:singleton
- name: Check CLI startup memory
run: pnpm test:startup:memory
gateway-watch-regression:
name: "gateway-watch-regression"
needs: [docs-scope, changed-scope]
if: needs.docs-scope.outputs.docs_only != 'true' && needs.changed-scope.outputs.run_node == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
steps:
- name: Checkout
uses: actions/checkout@v6
with:
submodules: false
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
use-sticky-disk: "false"
- name: Run gateway watch regression harness
run: pnpm test:gateway:watch-regression
- name: Upload gateway watch regression artifacts
if: always()
uses: actions/upload-artifact@v7
with:
name: gateway-watch-regression
path: .local/gateway-watch-regression/
retention-days: 7
# Validate docs (format, lint, broken links) only when docs files changed.
check-docs:
needs: [docs-scope]
@ -382,21 +679,30 @@ jobs:
run: pre-commit run --all-files detect-private-key
- name: Audit changed GitHub workflows with zizmor
env:
BASE_SHA: ${{ github.event_name == 'push' && github.event.before || github.event.pull_request.base.sha }}
run: |
set -euo pipefail
if [ "${{ github.event_name }}" = "push" ]; then
BASE="${{ github.event.before }}"
else
BASE="${{ github.event.pull_request.base.sha }}"
if [ -z "${BASE_SHA:-}" ] || [ "${BASE_SHA}" = "0000000000000000000000000000000000000000" ]; then
echo "No usable base SHA detected; skipping zizmor."
exit 0
fi
mapfile -t workflow_files < <(git diff --name-only "$BASE" HEAD -- '.github/workflows/*.yml' '.github/workflows/*.yaml')
if ! git cat-file -e "${BASE_SHA}^{commit}" 2>/dev/null; then
echo "Base SHA ${BASE_SHA} is unavailable; skipping zizmor."
exit 0
fi
mapfile -t workflow_files < <(
git diff --name-only "${BASE_SHA}" HEAD -- '.github/workflows/*.yml' '.github/workflows/*.yaml'
)
if [ "${#workflow_files[@]}" -eq 0 ]; then
echo "No workflow changes detected; skipping zizmor."
exit 0
fi
printf 'Auditing workflow files:\n%s\n' "${workflow_files[@]}"
pre-commit run zizmor --files "${workflow_files[@]}"
- name: Audit production dependencies

2
.gitignore vendored
View File

@ -4,10 +4,12 @@ node_modules
docker-compose.override.yml
docker-compose.extra.yml
dist
dist-runtime
pnpm-lock.yaml
bun.lock
bun.lockb
coverage
__openclaw_vitest__/
__pycache__/
*.pyc
.tsbuildinfo

View File

@ -1 +1,2 @@
**/node_modules/
docs/.generated/

View File

@ -114,6 +114,7 @@
- Never add `@ts-nocheck` and do not disable `no-explicit-any`; fix root causes and update Oxlint/Oxfmt config only when required.
- Dynamic import guardrail: do not mix `await import("x")` and static `import ... from "x"` for the same module in production code paths. If you need lazy loading, create a dedicated `*.runtime.ts` boundary (that re-exports from `x`) and dynamically import that boundary from lazy callers only.
- Dynamic import verification: after refactors that touch lazy-loading/module boundaries, run `pnpm build` and check for `[INEFFECTIVE_DYNAMIC_IMPORT]` warnings before submitting.
- Extension SDK self-import guardrail: inside an extension package, do not import that same extension via `openclaw/plugin-sdk/<extension>` from production files. Route internal imports through a local barrel such as `./api.ts` or `./runtime-api.ts`, and keep the `plugin-sdk/<extension>` path as the external contract only.
- Never share class behavior via prototype mutation (`applyPrototypeMixins`, `Object.defineProperty` on `.prototype`, or exporting `Class.prototype` for merges). Use explicit inheritance/composition (`A extends B extends C`) or helper composition so TypeScript can typecheck.
- If this pattern is needed, stop and get explicit approval before shipping; default behavior is to split/refactor into an explicit class hierarchy and keep members strongly typed.
- In tests, prefer per-instance stubs over prototype mutation (`SomeClass.prototype.method = ...`) unless a test explicitly documents why prototype-level patching is required.

View File

@ -7,55 +7,68 @@ Docs: https://docs.openclaw.ai
### Changes
- Commands/btw: add `/btw` side questions for quick tool-less answers about the current session without changing future session context, with dismissible in-session TUI answers and explicit BTW replies on external channels. (#45444) Thanks @ngutman.
- Gateway/docs: clarify that empty URL input allowlists are treated as unset, document `allowUrl: false` as the deny-all switch, and add regression coverage for the normalization path.
- Sandbox/runtime: add pluggable sandbox backends, ship an OpenShell backend with `mirror` and `remote` workspace modes, and make sandbox list/recreate/prune backend-aware instead of Docker-only.
- Sandbox/SSH: add a core SSH sandbox backend with secret-backed key, certificate, and known_hosts inputs, move shared remote exec/filesystem tooling into core, and keep OpenShell focused on sandbox lifecycle plus optional `mirror` mode.
- Web tools/Firecrawl: add Firecrawl as an `onboard`/configure search provider via a bundled plugin, expose explicit `firecrawl_search` and `firecrawl_scrape` tools, and align core `web_fetch` fallback behavior with Firecrawl base-URL/env fallback plus guarded endpoint fetches.
- Plugins/bundles: add compatible Codex, Claude, and Cursor bundle discovery/install support, map bundle skills into OpenClaw skills, and apply Claude bundle `settings.json` defaults to embedded Pi with shell overrides sanitized.
- Plugins/providers: move OpenRouter, GitHub Copilot, and OpenAI Codex provider/runtime logic into bundled plugins, including dynamic model fallback, runtime auth exchange, stream wrappers, capability hints, and cache-TTL policy.
- Plugins/agent integrations: broaden the plugin surface for app-server integrations with channel-aware commands, interactive callbacks, inbound claims, and Discord/Telegram conversation binding support. (#45318) Thanks @huntharo and @vincentkoc.
- Install/update: allow package-manager installs from GitHub `main` via `openclaw update --tag main`, installer `--version main`, or direct npm/pnpm git specs.
- Install/update: allow package-manager installs from GitHub `main` via `openclaw update --tag main`, installer `--version main`, or direct npm/pnpm git specs. (#47630) Thanks @vincentkoc.
- Gateway/health monitor: add configurable stale-event thresholds and restart limits, plus per-channel and per-account `healthMonitor.enabled` overrides, while keeping the existing global disable path on `gateway.channelHealthCheckMinutes=0`. (#42107) Thanks @rstar327.
- Android/mobile: add a system-aware dark theme across onboarding and post-onboarding screens so the app follows the device theme through setup, chat, and voice flows. (#46249) Thanks @sibbl.
- Feishu/ACP: add current-conversation ACP and subagent session binding for supported DMs and topic conversations, including completion delivery back to the originating Feishu conversation. (#46819)
- Plugins/marketplaces: add Claude marketplace registry resolution, `plugin@marketplace` installs, marketplace listing, and update support, plus Docker E2E coverage for local and official marketplace flows. Thanks @vincentkoc.
- Feishu/cards: add structured interactive approval and quick-action launcher cards, preserve callback user and conversation context through routing, and keep legacy card-action fallback behavior so common actions can run without typing raw commands. (#47873)
- Feishu/streaming: add `onReasoningStream` and `onReasoningEnd` support to streaming cards, so `/reasoning stream` renders thinking tokens as markdown blockquotes in the same card — matching the Telegram channel's reasoning lane behavior. (#46029)
- Feishu/ACP: add current-conversation ACP and subagent session binding for supported DMs and topic conversations, including completion delivery back to the originating Feishu conversation. (#46819) Thanks @Takhoffman.
- Plugins/marketplaces: add Claude marketplace registry resolution, `plugin@marketplace` installs, marketplace listing, and update support, plus Docker E2E coverage for local and official marketplace flows. (#48058) Thanks @vincentkoc.
- Commands/plugins: add owner-gated `/plugins` and `/plugin` chat commands for plugin list/show and enable/disable flows, alongside explicit `commands.plugins` config gating. Thanks @vincentkoc.
- Feishu/cards: add structured interactive approval and quick-action launcher cards, preserve callback user and conversation context through routing, and keep legacy card-action fallback behavior so common actions can run without typing raw commands. (#47873) Thanks @Takhoffman.
- Feishu/streaming: add `onReasoningStream` and `onReasoningEnd` support to streaming cards, so `/reasoning stream` renders thinking tokens as markdown blockquotes in the same card — matching the Telegram channel's reasoning lane behavior. (#46029) Thanks @day253.
- Feishu/cards: add identity-aware structured card headers and note footers for Feishu replies and direct sends, while keeping that presentation wired through the shared outbound identity path. (#29938) Thanks @nszhsl.
- Android/nodes: add `callLog.search` plus shared Call Log permission wiring so Android nodes can search recent call history through the gateway. (#44073) Thanks @lxk7280.
- Plugins/MiniMax: merge the bundled MiniMax API and MiniMax OAuth plugin surfaces into a single default-on `minimax` plugin, while keeping legacy `minimax-portal-auth` config ids aliased for compatibility.
- Telegram/actions: add `topic-edit` for forum-topic renames and icon updates while sharing the same Telegram topic-edit transport used by the plugin runtime. (#47798) Thanks @obviyus.
- Refactor/channels: remove the legacy channel shim directories and point channel-specific imports directly at the extension-owned implementations. (#45967) thanks @scoootscooob.
- Telegram/error replies: add a default-off `channels.telegram.silentErrorReplies` setting so bot error replies can be delivered silently across regular replies, native commands, and fallback sends. (#19776) Thanks @ImLukeF.
- Refactor/channels: remove the legacy channel shim directories and point channel-specific imports directly at the extension-owned implementations. (#45967) Thanks @scoootscooob.
- Docs/Zalo: clarify the Marketplace-bot support matrix and config guidance so the Zalo channel docs match current Bot Creator behavior more closely. (#47552) Thanks @No898.
- secrets: harden read-only SecretRef command paths and diagnostics. (#47794) Thanks @joshavant.
### Breaking
- Browser/Chrome MCP: remove the legacy Chrome extension relay path, bundled extension assets, `driver: "extension"`, and `browser.relayBindHost`. Run `openclaw doctor --fix` to migrate host-local browser config to `existing-session` / `user`; Docker, headless, sandbox, and remote browser flows still use raw CDP. Thanks @vincentkoc.
- Browser/existing-session: support `browser.profiles.<name>.userDataDir` so Chrome DevTools MCP can attach to Brave, Edge, and other Chromium-based browsers through their own user data directories. (#48170) Thanks @velvet-shark.
- Skills/prompt budget: preserve all registered skills via a compact catalog fallback before dropping entries when the full prompt format exceeds `maxSkillsPromptChars`. (#47553) Thanks @snese.
- Models/OpenAI: add native forward-compat support for `gpt-5.4-mini` and `gpt-5.4-nano` in the OpenAI provider catalog, runtime resolution, and reasoning capability gates. Thanks @vincentkoc.
- Plugins/bundles: make enabled bundle MCP servers expose runnable tools in embedded Pi, and default relative bundle MCP launches to the bundle root so marketplace bundles like Context7 work through Pi instead of stopping at config import.
- Scope message SecretRef resolution and harden doctor/status paths. (#48728) Thanks @joshavant.
- Plugins/testing: add a public `openclaw/plugin-sdk/testing` seam for plugin-author test helpers, and move bundled-extension-only test bridges out of `extensions/` into private repo test helpers.
- Plugins/Chutes: add a bundled Chutes provider with plugin-owned OAuth/API-key auth, dynamic model discovery, and default-on extension wiring. (#41416) Thanks @Veightor.
- Plugins/binding: add `onConversationBindingResolved(...)` so plugins can react immediately after bind approvals or denies without blocking channel interaction acknowledgements. (#48678) Thanks @huntharo.
- CLI/config: expand `config set` with SecretRef and provider builder modes, JSON/batch assignment support, and `--dry-run` validation with structured JSON output. (#49296) Thanks @joshavant.
- Control UI/appearance: unify theme border radii across Claw, Knot, and Dash, and add a Roundness slider to the Appearance settings so users can adjust corner radius from sharp to fully rounded. Thanks @BunsDev.
- Control UI/chat: add an expand-to-canvas button on assistant chat bubbles and in-app session navigation from Sessions and Cron views. Thanks @BunsDev.
- Plugins/context engines: expose `delegateCompactionToRuntime(...)` on the public plugin SDK, refactor the legacy engine to use the shared helper, and clarify `ownsCompaction` delegation semantics for non-owning engines. (#49061) Thanks @jalehman.
### Fixes
- Plugins/bundler TDZ: fix `RESERVED_COMMANDS` temporal dead zone error that prevented device-pair, phone-control, and talk-voice plugins from registering when the bundler placed the commands module after call sites in the same output chunk. Thanks @BunsDev.
- Plugins/imports: fix stale googlechat runtime-api import paths and signal SDK circular re-exports broken by recent plugin-sdk refactors. Thanks @BunsDev.
- Google auth/Node 25: patch `gaxios` to use native fetch without injecting `globalThis.window`, while translating proxy and mTLS transport settings so Google Vertex and Google Chat auth keep working on Node 25. (#47914) Thanks @pdd-cli.
- Gateway/startup: load bundled channel plugins from compiled `dist/extensions` entries in built installs, so gateway boot no longer recompiles bundled extension TypeScript on every startup and WhatsApp-class cold starts drop back to seconds instead of tens of seconds or worse.
- Gateway/startup: load bundled channel plugins from compiled `dist/extensions` entries in built installs, so gateway boot no longer recompiles bundled extension TypeScript on every startup and WhatsApp-class cold starts drop back to seconds instead of tens of seconds or worse. (#47560) Thanks @ngutman.
- Plugins/context engines: enforce owner-aware context-engine registration on both loader and public SDK paths so plugins cannot spoof privileged ownership, claim the core `legacy` engine id, or overwrite an existing engine id through direct SDK imports. (#47595) Thanks @vincentkoc.
- Browser/remote CDP: honor strict browser SSRF policy during remote CDP reachability and `/json/version` discovery checks, redact sensitive `cdpUrl` tokens from status output, and warn when remote CDP targets private/internal hosts.
- Gateway/plugins: pin runtime webhook routes to the gateway startup registry so channel webhooks keep working across plugin-registry churn, and make plugin auth + dispatch resolve routes from the same live HTTP-route registry. Fixes #46924 and #47041.
- Gateway/auth: ignore spoofed loopback hops in trusted forwarding chains and block device approvals that request scopes above the caller session. Thanks @vincentkoc.
- Gateway/plugins: pin runtime webhook routes to the gateway startup registry so channel webhooks keep working across plugin-registry churn, and make plugin auth + dispatch resolve routes from the same live HTTP-route registry. (#47902) Fixes #46924 and #47041. Thanks @steipete.
- Gateway/auth: ignore spoofed loopback hops in trusted forwarding chains and block device approvals that request scopes above the caller session. (#46800) Thanks @vincentkoc.
- Gateway/restart: defer externally signaled unmanaged restarts through the in-process idle drain, and preserve the restored subagent run as remap fallback during orphan recovery so resumed sessions do not duplicate work. (#47719) Thanks @joeykrug.
- Control UI/session routing: preserve established external delivery routes when webchat views or sends in externally originated sessions, so subagent completions still return to the original channel instead of the dashboard. (#47797) Thanks @brokemac79.
- Configure/startup: move outbound send-deps resolution into a lightweight helper so `openclaw configure` no longer stalls after the banner while eagerly loading channel plugins. (#46301) thanks @scoootscooob.
- Configure/startup: move outbound send-deps resolution into a lightweight helper so `openclaw configure` no longer stalls after the banner while eagerly loading channel plugins. (#46301) Thanks @scoootscooob.
- CLI/startup: lazy-load channel add and root help startup paths to trim avoidable RSS and help latency on constrained hosts. (#46784) Thanks @vincentkoc.
- CLI/onboarding: import static provider definitions directly for onboarding model/config helpers so those paths no longer pull provider discovery just for built-in defaults. (#47467) Thanks @vincentkoc.
- CLI/auth choice: lazy-load plugin/provider fallback resolution so mapped auth choices stay on the static path and only unknown choices pay the heavy provider load. (#47495) Thanks @vincentkoc.
- CLI: avoid loading provider discovery during startup model normalization. (#46522) Thanks @ItsAditya-xyz and @vincentkoc.
- Security/device pairing: harden `device.token.rotate` deny handling by keeping public failures generic while logging internal deny reasons and preserving approved-baseline enforcement. (`GHSA-7jrw-x62h-64p8`)
- Inbound policy hardening: tighten callback and webhook sender checks across Mattermost and Google Chat, match Nextcloud Talk rooms by stable room token, and treat explicit empty Twitch allowlists as deny-all. (#46787) Thanks @zpbrent, @ijxpwastaken and @vincentkoc.
- Webhooks/runtime: move auth earlier and tighten pre-auth body limits and timeouts across bundled webhook handlers, including slow-body handling for Mattermost slash commands. Thanks @vincentkoc.
- Email/webhook wrapping: sanitize sender and subject metadata before external-content wrapping so metadata fields cannot break the wrapper structure. Thanks @vincentkoc.
- Tools/apply-patch: revalidate workspace-only delete and directory targets immediately before mutating host paths. Thanks @vincentkoc.
- Gateway/config views: strip embedded credentials from URL-based endpoint fields before returning read-only account and config snapshots. Thanks @vincentkoc.
- Webhooks/runtime: move auth earlier and tighten pre-auth body limits and timeouts across bundled webhook handlers, including slow-body handling for Mattermost slash commands. (#46802) Thanks @vincentkoc.
- Email/webhook wrapping: sanitize sender and subject metadata before external-content wrapping so metadata fields cannot break the wrapper structure. (#46816) Thanks @vincentkoc.
- Tools/apply-patch: revalidate workspace-only delete and directory targets immediately before mutating host paths. (#46803) Thanks @vincentkoc.
- Gateway/config views: strip embedded credentials from URL-based endpoint fields before returning read-only account and config snapshots. (#46799) Thanks @vincentkoc.
- ACP/approvals: use canonical tool identity for prompting decisions and fail closed when conflicting tool identity hints are present. (#46817) Thanks @zpbrent and @vincentkoc.
- ACP: require admin scope for mutating internal actions. (#46789) Thanks @tdjackey and @vincentkoc.
- Subagents/follow-ups: require the same controller ownership checks for `/subagents send` as other control actions, so leaf sessions cannot message nested child runs they do not control. Thanks @vincentkoc.
- Subagents/follow-ups: require the same controller ownership checks for `/subagents send` as other control actions, so leaf sessions cannot message nested child runs they do not control. (#46801) Thanks @vincentkoc.
- macOS/canvas actions: keep unattended local agent actions on trusted in-app canvas surfaces only, and stop exposing the deep-link fallback key to arbitrary page scripts. (#46790) Thanks @vincentkoc.
- Agents/compaction: extend the enclosing run deadline once while compaction is actively in flight, and abort the underlying SDK compaction on timeout/cancel so large-session compactions stop freezing mid-run. (#46889) Thanks @asyncjason.
- Agents/openai-compatible tool calls: deduplicate repeated tool call ids across live assistant messages and replayed history so OpenAI-compatible backends no longer reject duplicate `tool_call_id` values with HTTP 400. (#40996) Thanks @xaeon2026.
@ -63,35 +76,85 @@ Docs: https://docs.openclaw.ai
- Models/OpenRouter runtime capabilities: fetch uncatalogued OpenRouter model metadata on first use so newly added vision models keep image input instead of silently degrading to text-only, with top-level capability field fallbacks for `/api/v1/models`. (#45824) Thanks @DJjjjhao.
- Channels/plugins: keep shared interactive payloads merge-ready by fixing Slack custom callback routing and repeat-click dedupe, allowing interactive-only sends, and preserving ordered Discord shared text blocks. (#47715) Thanks @vincentkoc.
- Slack/interactive replies: preserve `channelData.slack.blocks` through live DM delivery and preview-finalized edits so Block Kit button and select directives render instead of falling back to raw text. (#45890) Thanks @vincentkoc.
- Slack/interactive replies: preserve `channelData.slack.blocks` through live DM delivery and preview-finalized edits so Block Kit button and select directives render instead of falling back to raw text. (#45890) Thanks @vincentkoc.
- Feishu/actions: expand the runtime action surface with message read/edit, explicit thread replies, pinning, and operator-facing chat/member inspection so Feishu can operate more of the workspace directly.
- Feishu/actions: expand the runtime action surface with message read/edit, explicit thread replies, pinning, and operator-facing chat/member inspection so Feishu can operate more of the workspace directly. (#47968) Thanks @Takhoffman.
- Feishu/topic threads: fetch full thread context, including prior bot replies, when starting a topic-thread session so follow-up turns in Feishu topics keep the right conversation state. (#45254) Thanks @Coobiw.
- Feishu/media: keep native image, file, audio, and video/media handling aligned across outbound sends, inbound downloads, thread replies, directory/action aliases, and capability docs so unsupported areas are explicit instead of implied.
- WhatsApp/reconnect: restore the append recency filter in the extension inbox monitor and handle protobuf `Long` timestamps correctly, so fresh post-reconnect append messages are processed while stale history sync stays suppressed. (#42588) thanks @MonkeyLeeT.
- Feishu/media: keep native image, file, audio, and video/media handling aligned across outbound sends, inbound downloads, thread replies, directory/action aliases, and capability docs so unsupported areas are explicit instead of implied. (#47968) Thanks @Takhoffman.
- Feishu/webhooks: harden signed webhook verification to use constant-time signature comparison and keep malformed short signatures fail-closed in webhook E2E coverage.
- WhatsApp/reconnect: restore the append recency filter in the extension inbox monitor and handle protobuf `Long` timestamps correctly, so fresh post-reconnect append messages are processed while stale history sync stays suppressed. (#42588) Thanks @MonkeyLeeT.
- WhatsApp/login: wait for pending creds writes before reopening after Baileys `515` pairing restarts in both QR login and `channels login` flows, and keep the restart coverage pinned to the real wrapped error shape plus per-account creds queues. (#27910) Thanks @asyncjason.
- Telegram/message send: forward `--force-document` through the `sendPayload` path as well as `sendMedia`, so Telegram payload sends with `channelData` keep uploading images as documents instead of silently falling back to compressed photo sends. (#47119) Thanks @thepagent.
- Telegram/message chunking: preserve spaces, paragraph separators, and word boundaries when HTML overflow rechunking splits formatted replies. (#47274)
- Z.AI/onboarding: detect a working default model even for explicit `zai-coding-*` endpoint choices, so Coding Plan setup can keep the selected endpoint while defaulting to `glm-5` when available or `glm-4.7` as fallback. (#45969)
- Telegram/message chunking: preserve spaces, paragraph separators, and word boundaries when HTML overflow rechunking splits formatted replies. (#47274) Thanks @obviyus.
- Z.AI/onboarding: detect a working default model even for explicit `zai-coding-*` endpoint choices, so Coding Plan setup can keep the selected endpoint while defaulting to `glm-5` when available or `glm-4.7` as fallback. (#45969) Thanks @obviyus.
- Z.AI/onboarding: add `glm-5-turbo` to the default Z.AI provider catalog so onboarding-generated configs expose the new model alongside the existing GLM defaults. (#46670) Thanks @tomsun28.
- Zalo Personal/group gating: stop reapplying `dmPolicy.allowFrom` as a sender gate for already-allowlisted groups when `groupAllowFrom` is unset, so any member of an allowed group can trigger replies while DMs stay restricted. (#40146)
- Zalo Personal/group gating: stop reapplying `dmPolicy.allowFrom` as a sender gate for already-allowlisted groups when `groupAllowFrom` is unset, so any member of an allowed group can trigger replies while DMs stay restricted. (#46663) Fixes #40146. Thanks @Takhoffman.
- Zalo/plugin runtime: export `resolveClientIp` from `openclaw/plugin-sdk/zalo` so installed builds no longer crash on startup when the webhook monitor loads from the packaged extension instead of the monorepo source tree. (#46549) Thanks @No898.
- Plugins/install precedence: keep bundled plugins ahead of auto-discovered globals by default, but let an explicitly installed plugin record win its own duplicate-id tie so installed channel plugins load from `~/.openclaw/extensions` after `openclaw plugins install`.
- Plugins/scoped ids: preserve scoped plugin ids during install and config keying, and keep bundled plugins ahead of discovered duplicate ids by default so `@scope/name` plugins no longer collide with unscoped installs. Thanks @vincentkoc.
- Gateway/watch mode: restart on bundled-plugin package and manifest metadata changes, rebuild `dist` for extension source and `tsdown.config.ts` changes, and still ignore extension docs. (#47571) thanks @gumadeiras.
- Docker/live tests: mount external CLI auth homes into writable container copies, derive Codex OAuth expiry from JWT `exp`, refresh synced CLI creds instead of trusting stale cached expiry, and make gateway live probes wait on transcript output so `pnpm test:docker:all` stays green in Linux.
- Plugins/install precedence: keep bundled plugins ahead of auto-discovered globals by default, but let an explicitly installed plugin record win its own duplicate-id tie so installed channel plugins load from `~/.openclaw/extensions` after `openclaw plugins install`. (#46722) Thanks @Takhoffman.
- Control UI/logging: make browser-safe logger imports avoid eager temp-dir resolution so the bundled Control UI no longer crashes to a blank screen when logging reaches `tmp-openclaw-dir`. (#48469) Fixes #48062. Thanks @7inspire.
- Plugins/scoped ids: preserve scoped plugin ids during install and config keying, and keep bundled plugins ahead of discovered duplicate ids by default so `@scope/name` plugins no longer collide with unscoped installs. (#47413) Thanks @vincentkoc.
- Gateway/watch mode: restart on bundled-plugin package and manifest metadata changes, rebuild `dist` for extension source and `tsdown.config.ts` changes, and still ignore extension docs. (#47571) Thanks @gumadeiras.
- Gateway/watch mode: recreate bundled plugin runtime metadata after clean or stale `dist` states, so `pnpm gateway:watch` no longer fails on missing `dist/extensions/*/openclaw.plugin.json` manifests after a rebuild. Thanks @gumadeiras.
- Control UI/chat sessions: show human-readable labels in the grouped session dropdown again, keep unique scoped fallbacks when metadata is missing, and disambiguate duplicate labels only when needed. (#45130) thanks @luzhidong.
- Control UI/chat sessions: show human-readable labels in the grouped session dropdown again, keep unique scoped fallbacks when metadata is missing, and disambiguate duplicate labels only when needed. (#45130) Thanks @luzhidong.
- Control UI: scope persisted session selection per gateway, prevent stale session bleed across tokenized gateway opens, and cap stored gateway session history. (#47453) Thanks @sallyom.
- Control UI/dashboard: preserve structured gateway shutdown reasons across restart disconnects so config-triggered restarts no longer fall back to `disconnected (1006): no reason`. (#46532) Thanks @vincentkoc.
- Control UI/dashboard: preserve structured gateway shutdown reasons across restart disconnects so config-triggered restarts no longer fall back to `disconnected (1006): no reason`. (#46580) Fixes #46532. Thanks @vincentkoc.
- Android/chat: theme the thinking dropdown and TLS trust dialogs explicitly so popup surfaces match the active app theme instead of falling back to mismatched Material defaults.
- Group mention gating: reject invalid and unsafe nested-repetition `mentionPatterns`, reuse the shared safe config-regex compiler across mention stripping and detection, and cache strip-time regex compilation so noisy groups avoid repeated recompiles.
- Browser/profiles: drop the auto-created `chrome-relay` browser profile; users who need the Chrome extension relay must now create their own profile via `openclaw browser create-profile`. (#45777) Thanks @odysseus0.
- Browser/profiles: drop the auto-created `chrome-relay` browser profile; users who need the Chrome extension relay must now create their own profile via `openclaw browser create-profile`. (#46596) Fixes #45777. Thanks @odysseus0.
- CI/channel test routing: move the built-in channel suites into `test:channels` and keep them out of `test:extensions`, so extension CI no longer fails after the channel migration while targeted test routing still sends Slack, Signal, and iMessage suites to the right lane. (#46066) Thanks @scoootscooob.
- Docs/Mintlify: fix MDX marker syntax on Perplexity, Model Providers, Moonshot, and exec approvals pages so local docs preview no longer breaks rendering or leaves stale pages unpublished. (#46695) Thanks @velvet-shark.
- Gateway/config validation: stop treating the implicit default memory slot as a required explicit plugin config, so startup no longer fails with `plugins.slots.memory: plugin not found: memory-core` when `memory-core` was only inferred. (#47494) Thanks @ngutman.
- Tlon: honor explicit empty allowlists and defer cite expansion. (#46788) Thanks @zpbrent and @vincentkoc.
- Tlon/DM auth: defer cited-message expansion until after DM authorization and owner command handling, so unauthorized DMs and owner approval/admin commands no longer trigger cross-channel cite fetches before the deny or command path.
- Docs/security audit: spell out that `gateway.controlUi.allowedOrigins: ["*"]` is an explicit allow-all browser-origin policy and should be avoided outside tightly controlled local testing.
- Gateway/auth: clear self-declared scopes for device-less trusted-proxy Control UI sessions so proxy-authenticated connects cannot claim admin or secrets scopes without a bound device identity.
- Nodes/pending actions: re-check queued foreground actions against the current node command policy before returning them to the node. (#46815) Thanks @zpbrent and @vincentkoc.
- Node/startup: remove leftover debug `console.log("node host PATH: ...")` that printed the resolved PATH on every `openclaw node run` invocation. (#46411)
- Node/startup: remove leftover debug `console.log("node host PATH: ...")` that printed the resolved PATH on every `openclaw node run` invocation. (#46515) Fixes #46411. Thanks @ademczuk.
- CLI/completion: reduce recursive completion-script string churn and fix nested PowerShell command-path matching so generated nested completions resolve on PowerShell too. (#45537) Thanks @yiShanXin and @vincentkoc.
- Slack/startup: harden `@slack/bolt` import interop across current bundled runtime shapes so Slack monitors no longer crash with `App is not a constructor` after plugin-sdk bundling changes. (#45953) Thanks @merc1305.
- Windows/gateway status: accept `schtasks` `Last Result` output as an alias for `Last Run Result`, so running scheduled-task installs no longer show `Runtime: unknown`. (#47844) Thanks @MoerAI.
- ACP/acpx: resolve the bundled plugin root from the actual plugin directory so plugin-local installs stay under `dist/extensions/acpx` instead of escaping to `dist/extensions` and failing runtime setup. (#47601) Thanks @ngutman.
- Gateway/websocket pairing bypass for disabled auth: skip device-pairing enforcement for Control UI operator sessions when `gateway.auth.mode=none`, so reverse-proxied dashboards no longer get stuck on `pairing required` despite auth being explicitly disabled. (#47148) Thanks @ademczuk.
- Control UI/model switching: preserve the selected provider prefix when switching models from the chat dropdown, so multi-provider setups no longer send `anthropic/gpt-5.2`-style mismatches when the user picked `openai/gpt-5.2`. (#47581) Thanks @chrishham.
- Control UI/storage: scope persisted settings keys by gateway base path, with migration from the legacy shared key, so multiple gateways under one domain stop overwriting each other's dashboard preferences. (#47932) Thanks @bobBot-claw.
- Agents/usage tracking: stop forcing `supportsUsageInStreaming: false` on non-native OpenAI-completions providers so compatible backends report token usage and cost again instead of showing all zeros. (#46500) Fixes #46142. Thanks @ademczuk.
- ACP/acpx: keep plugin-local backend installs under `extensions/acpx` in live repo checkouts so rebuilds no longer delete the runtime binary, and avoid package-lock churn during runtime repair.
- Plugins/subagents: preserve gateway-owned plugin subagent access across runtime, tool, and embedded-runner load paths so gateway plugin tools and context engines can still spawn and manage subagents after the loader cache split. (#46648) Thanks @jalehman.
- Control UI/overview: keep the language dropdown aligned with the persisted locale during dashboard startup so refreshing the page does not fall back to English before locale hydration completes. (#48019) Thanks @git-jxj.
- Agents/compaction: rerun transcript repair after `session.compact()` so orphaned `tool_result` blocks cannot survive compaction and break later Anthropic requests. (#16095) thanks @claw-sylphx.
- Agents/compaction: trigger overflow recovery from the tool-result guard once post-compaction context still exceeds the safe threshold, so long tool loops compact before the next model call hard-fails. (#29371) thanks @keshav55.
- macOS/exec approvals: harden exec-host request HMAC verification to use a timing-safe compare and keep malformed or truncated signatures fail-closed in focused IPC auth coverage.
- Gateway/exec approvals: surface requested env override keys in gateway-host approval prompts so operators can review surviving env context without inheriting noisy base host env.
- Telegram/network: preserve sticky IPv4 fallback state across polling restarts so hosts with unstable IPv6 to `api.telegram.org` stop re-triggering repeated Telegram timeouts after each restart. (#48282) Thanks @yassinebkr.
- Plugins/subagents: forward per-run provider and model overrides through gateway plugin subagent dispatch so plugin-launched agent delegations honor explicit model selection again. (#48277) Thanks @jalehman.
- Agents/compaction: write minimal boundary summaries for empty preparations while keeping split-turn prefixes on the normal path, so no-summarizable-message sessions stop retriggering the safeguard loop. (#42215) thanks @lml2468.
- Models/chat commands: keep `/model ...@YYYYMMDD` version suffixes intact by default, but still honor matching stored numeric auth-profile overrides for the same provider. (#48896) Thanks @Alix-007.
### Fixes
- Agents/bootstrap warnings: move bootstrap truncation warnings out of the system prompt and into the per-turn prompt body so prompt-cache reuse stays stable when truncation warnings appear or disappear. (#48753) Thanks @scoootscooob and @obviyus.
- Telegram/DM topic session keys: route named-account DM topics through the same per-account base session key across inbound messages, native commands, and session-state lookups so `/status` and thread recovery stop creating phantom `agent:main:main:thread:...` sessions. (#48204) Thanks @vincentkoc.
- macOS/node service startup: use `openclaw node start/stop --json` from the Mac app instead of the removed `openclaw service node ...` command shape, so current CLI installs expose the full node exec surface again. (#46843) Fixes #43171. Thanks @Br1an67.
- macOS/launch at login: stop emitting `KeepAlive` for the desktop app launch agent so OpenClaw no longer relaunches immediately after a manual quit while launch at login remains enabled. (#40213) Thanks @stablegenius49.
- ACP/gateway startup: use direct Telegram and Discord startup/status helpers instead of routing probes through the plugin runtime, and prepend the selected daemon Node bin dir to service PATH so plugin-local installs can still find `npm` and `pnpm`.
- ACP/configured bindings: reinitialize configured ACP sessions that are stuck in `error` state instead of reusing the failed runtime.
- Mattermost/DM send: retry transient direct-channel creation failures for DM deliveries, with configurable backoff and per-request timeout. (#42398) Thanks @JonathanJing.
- Telegram/network: unify API and media fetches under the same sticky IPv4 and pinned-IP fallback chain, and re-validate pinned override addresses against SSRF policy. (#49148) Thanks @obviyus.
- Agents/prompt composition: append bootstrap truncation warnings to the current-turn prompt and add regression coverage for stable system-prompt cache invariants. (#49237) Thanks @scoootscooob.
- Gateway/auth: add regression coverage that keeps device-less trusted-proxy Control UI sessions off privileged pairing approval RPCs. Thanks @vincentkoc.
- Plugins/runtime-api: pin extension runtime-api export seams with explicit guardrail coverage so future surface creep becomes a deliberate diff. Thanks @vincentkoc.
- Telegram/security: add regression coverage proving pinned fallback host overrides stay bound to Telegram and delegate non-matching hostnames back to the original lookup path. Thanks @vincentkoc.
- Secrets/exec refs: require explicit `--allow-exec` for `secrets apply` write plans that contain exec SecretRefs/providers, and align audit/configure/apply dry-run behavior to skip exec checks unless opted in to prevent unexpected command side effects. (#49417) Thanks @restriction and @joshavant.
- Tools/image generation: add bundled fal image generation support so `image_generate` can target `fal/*` models with `FAL_KEY`, including single-image edit flows via FLUX image-to-image. Thanks @vincentkoc.
- xAI/web search: add missing Grok credential metadata so the bundled provider registration type-checks again. (#49472) thanks @scoootscooob.
- Signal/runtime API: re-export `SignalAccountConfig` so Signal account resolution type-checks again. (#49470) Thanks @scoootscooob.
- Google Chat/runtime API: thin the private runtime barrel onto the curated public SDK surface while keeping public Google Chat exports intact. (#49504) Thanks @scoootscooob.
### Breaking
- Browser/Chrome MCP: remove the legacy Chrome extension relay path, bundled extension assets, `driver: "extension"`, and `browser.relayBindHost`. Run `openclaw doctor --fix` to migrate host-local browser config to `existing-session` / `user`; Docker, headless, sandbox, and remote browser flows still use raw CDP. (#47893) Thanks @vincentkoc.
- Plugins/runtime: remove the public `openclaw/extension-api` surface with no compatibility shim. Bundled plugins must use injected runtime for host-side operations (for example `api.runtime.agent.runEmbeddedPiAgent`) and any remaining direct imports must come from narrow `openclaw/plugin-sdk/*` subpaths instead of the monolithic SDK root.
- Tools/image generation: standardize the stock image create/edit path on the core `image_generate` tool. The old `nano-banana-pro` docs/examples are gone; if you previously copied that sample-skill config, switch to `agents.defaults.imageGenerationModel` for built-in image generation or install a separate third-party skill explicitly.
- Plugins/message discovery: require `ChannelMessageActionAdapter.describeMessageTool(...)` for shared `message` tool discovery. The legacy `listActions`, `getCapabilities`, and `getToolSchema` adapter methods are removed. Plugin authors should migrate message discovery to `describeMessageTool(...)` and keep channel-specific action runtime code inside the owning plugin package. Thanks @gumadeiras.
## 2026.3.13
@ -107,10 +170,6 @@ Docs: https://docs.openclaw.ai
- Cron/sessions: add `sessionTarget: "current"` and `session:<id>` support so cron jobs can bind to the creating session or a persistent named session instead of only `main` or `isolated`. Thanks @kkhomej33-netizen and @ImLukeF.
- Telegram/message send: add `--force-document` so Telegram image and GIF sends can upload as documents without compression. (#45111) Thanks @thepagent.
### Breaking
- **BREAKING:** Agents now load at most one root memory bootstrap file. `MEMORY.md` wins; `memory.md` is only used when `MEMORY.md` is absent. If you intentionally kept both files and depended on both being injected, merge them before upgrade. This also fixes duplicate memory injection on case-insensitive Docker mounts. (#26054) Thanks @Lanfei.
### Fixes
- Dashboard/chat UI: stop reloading full chat history on every live tool result in dashboard v2 so tool-heavy runs no longer trigger UI freeze/re-render storms while the final event still refreshes persisted history. (#45541) Thanks @BunsDev.
@ -170,6 +229,12 @@ Docs: https://docs.openclaw.ai
- Auth/login lockout recovery: clear stale `auth_permanent` and `billing` disabled state for all profiles matching the target provider when `openclaw models auth login` is invoked, so users locked out by expired or revoked OAuth tokens can recover by re-authenticating instead of waiting for the cooldown timer to expire. (#43057)
- Auto-reply/context-engine compaction: persist the exact embedded-run metadata compaction count for main and followup runner session accounting, so metadata-only auto-compactions no longer undercount multi-compaction runs. (#42629) thanks @uf-hy.
- Auth/Codex CLI reuse: sync reused Codex CLI credentials into the supported `openai-codex:default` OAuth profile instead of reviving the deprecated `openai-codex:codex-cli` slot, so doctor cleanup no longer loops. (#45353) thanks @Gugu-sugar.
- Deps/audit: bump the pinned `fast-xml-parser` override to the first patched release so `pnpm audit --prod --audit-level=high` no longer fails on the AWS Bedrock XML builder path. Thanks @vincentkoc.
- Hooks/after_compaction: forward `sessionFile` for direct/manual compaction events and add `sessionFile` plus `sessionKey` to wired auto-compaction hook context so plugins receive the session metadata already declared in the hook types. (#40781) Thanks @jarimustonen.
### Breaking
- **BREAKING:** Agents now load at most one root memory bootstrap file. `MEMORY.md` wins; `memory.md` is only used when `MEMORY.md` is absent. If you intentionally kept both files and depended on both being injected, merge them before upgrade. This also fixes duplicate memory injection on case-insensitive Docker mounts. (#26054) Thanks @Lanfei.
## 2026.3.12
@ -261,13 +326,16 @@ Docs: https://docs.openclaw.ai
- Agents/Anthropic replay: drop replayed assistant thinking blocks for native Anthropic and Bedrock Claude providers so persisted follow-up turns no longer fail on stored thinking blocks. (#44843) Thanks @jmcte.
- Docs/Brave pricing: escape literal dollar signs in Brave Search cost text so the docs render the free credit and per-request pricing correctly. (#44989) Thanks @keelanfh.
- Feishu/file uploads: preserve literal UTF-8 filenames in `im.file.create` so Chinese and other non-ASCII filenames no longer appear percent-encoded in chat. (#34262) Thanks @fabiaodemianyang and @KangShuaiFu.
- Agents/compaction safeguard: trim large kept `toolResult` payloads consistently for budgeting, pruning, and identifier seeding, then restore preserved payloads after prune so oversized safeguard summaries stay stable. (#44133) thanks @SayrWolfridge.
- Agents/compaction: compare post-compaction token sanity checks against full-session pre-compaction totals and skip the check when token estimation fails, so sessions with large bootstrap context keep real token counts instead of falling back to unknown. (#28347) thanks @efe-arv.
- Discord/gateway startup: treat plain-text and transient `/gateway/bot` metadata fetch failures as transient startup errors so Discord gateway boot no longer crashes on unhandled rejections. (#44397) Thanks @jalehman.
- Agents/Ollama overflow: rewrite Ollama `prompt too long` API payloads through the normal context-overflow sanitizer so embedded sessions keep the friendly overflow copy and auto-compaction trigger. (#34019) thanks @lishuaigit.
- Control UI/auth: restore one-time legacy `?token=` imports for shared Control UI links while keeping `#token=` preferred, and carry pending query tokens through gateway URL confirmation so compatibility links still authenticate after confirmation. (#43979) Thanks @stim64045-spec.
- Plugins/context engines: retry legacy lifecycle calls once without `sessionKey` when older plugins reject that field, memoize legacy mode after the first strict-schema fallback, and preserve non-compat runtime errors without retry. (#44779) thanks @hhhhao28.
## 2026.3.11
### Security
- Gateway/WebSocket: enforce browser origin validation for all browser-originated connections regardless of whether proxy headers are present, closing a cross-site WebSocket hijacking path in `trusted-proxy` mode that could grant untrusted origins `operator.admin` access. (GHSA-5wcw-8jjv-m286)
### Changes
- OpenRouter/models: add temporary Hunter Alpha and Healer Alpha entries to the built-in catalog so OpenRouter users can try the new free stealth models during their roughly one-week availability window. (#43642) Thanks @ping-Toven.
@ -289,10 +357,6 @@ Docs: https://docs.openclaw.ai
- Mattermost/reply threading: add `channels.mattermost.replyToMode` for channel and group messages so top-level posts can start thread-scoped sessions without the manual reply-then-thread workaround. (#29587) Thanks @teconomix.
- iOS/push relay: add relay-backed official-build push delivery with App Attest + receipt verification, gateway-bound send delegation, and config-based relay URL setup on the gateway. (#43369) Thanks @ngutman.
### Breaking
- Cron/doctor: tighten isolated cron delivery so cron jobs can no longer notify through ad hoc agent sends or fallback main-session summaries, and add `openclaw doctor --fix` migration for legacy cron storage and legacy notify/webhook delivery metadata. (#40998) Thanks @mbelinky.
### Fixes
- Windows/install: stop auto-installing `node-llama-cpp` during normal npm CLI installs so `openclaw@latest` no longer fails on Windows while building optional local-embedding dependencies.
@ -403,6 +467,15 @@ Docs: https://docs.openclaw.ai
- Memory/QMD Windows: fail closed when `qmd.cmd` or `mcporter.cmd` wrappers cannot be resolved to a direct entrypoint, so memory search no longer falls back to shell execution on Windows.
- macOS/remote gateway: stop PortGuardian from killing Docker Desktop and other external listeners on the gateway port in remote mode, so containerized and tunneled gateway setups no longer lose their port-forward owner on app startup. (#6755) Thanks @teslamint.
- Feishu/streaming recovery: clear stale `streamingStartPromise` when card creation fails (HTTP 400) so subsequent messages can retry streaming instead of silently dropping all future replies. Fixes #43322.
- Exec/env sandbox: block JVM agent injection (`JAVA_TOOL_OPTIONS`, `_JAVA_OPTIONS`, `JDK_JAVA_OPTIONS`), Python breakpoint hijack (`PYTHONBREAKPOINT`), and .NET startup hooks (`DOTNET_STARTUP_HOOKS`) from the host exec environment. (#49025)
### Security
- Gateway/WebSocket: enforce browser origin validation for all browser-originated connections regardless of whether proxy headers are present, closing a cross-site WebSocket hijacking path in `trusted-proxy` mode that could grant untrusted origins `operator.admin` access. (GHSA-5wcw-8jjv-m286)
### Breaking
- Cron/doctor: tighten isolated cron delivery so cron jobs can no longer notify through ad hoc agent sends or fallback main-session summaries, and add `openclaw doctor --fix` migration for legacy cron storage and legacy notify/webhook delivery metadata. (#40998) Thanks @mbelinky.
## 2026.3.8
@ -516,10 +589,6 @@ Docs: https://docs.openclaw.ai
- Google/Gemini 3.1 Flash-Lite: add first-class `google/gemini-3.1-flash-lite-preview` support across model-id normalization, default aliases, media-understanding image lookups, Google Gemini CLI forward-compat fallback, and docs.
- Agents/compaction model override: allow `agents.defaults.compaction.model` to route compaction summarization through a different model than the main session, and document the override across config help/reference surfaces. (#38753) thanks @starbuck100.
### Breaking
- **BREAKING:** Gateway auth now requires explicit `gateway.auth.mode` when both `gateway.auth.token` and `gateway.auth.password` are configured (including SecretRefs). Set `gateway.auth.mode` to `token` or `password` before upgrade to avoid startup/pairing/TUI failures. (#35094) Thanks @joshavant.
### Fixes
- Models/MiniMax: stop advertising removed `MiniMax-M2.5-Lightning` in built-in provider catalogs, onboarding metadata, and docs; keep the supported fast-tier model as `MiniMax-M2.5-highspeed`.
@ -590,6 +659,7 @@ Docs: https://docs.openclaw.ai
- Control UI/markdown fallback regression coverage: add explicit regression assertions for parser-error fallback behavior so malformed markdown no longer risks reintroducing hard-crash rendering paths in future markdown/parser upgrades. (#36445) Thanks @BinHPdev.
- Web UI/config form: treat `additionalProperties: true` object schemas as editable map entries instead of unsupported fields so Accounts-style maps stay editable in form mode. (#35380, supersedes #32072) Thanks @stakeswky and @liuxiaopai-ai.
- Feishu/streaming card delivery synthesis: unify snapshot and delta streaming merge semantics, apply overlap-aware final merge, suppress duplicate final text delivery (including text+media final packets), prefer topic-thread `message.reply` routing when a reply target exists, and tune card print cadence to avoid duplicate incremental rendering. (from #33245, #32896, #33840) Thanks @rexl2018, @kcinzgg, and @aerelune.
- macOS/tray menu: keep injected sessions and device rows below the controls section so toggles and action buttons stay visible even when many sessions are active. (#38079) Thanks @bernesto.
- Feishu/group mention detection: carry startup-probed bot display names through monitor dispatch so `requireMention` checks compare against current bot identity instead of stale config names, fixing missed `@bot` handling in groups while preserving multi-bot false-positive guards. (#36317, #34271) Thanks @liuxiaopai-ai.
- Security/dependency audit: patch transitive Hono vulnerabilities by pinning `hono` to `4.12.5` and `@hono/node-server` to `1.19.10` in production resolution paths. Thanks @shakkernerd.
- Security/dependency audit: bump `tar` to `7.5.10` (from `7.5.9`) to address the high-severity hardlink path traversal advisory (`GHSA-qffp-2rhf-9h96`). Thanks @shakkernerd.
@ -844,6 +914,10 @@ Docs: https://docs.openclaw.ai
- Mattermost/DM media uploads: resolve bare 26-character Mattermost IDs user-first for direct messages so media sends no longer fail with `403 Forbidden` when targets are configured as unprefixed user IDs. (#29925) Thanks @teconomix.
- Voice-call/OpenAI TTS config parity: add missing `speed`, `instructions`, and `baseUrl` fields to the OpenAI TTS config schema and gate `instructions` to supported models so voice-call overrides validate and route cleanly through core TTS. (#39226) Thanks @ademczuk.
### Breaking
- **BREAKING:** Gateway auth now requires explicit `gateway.auth.mode` when both `gateway.auth.token` and `gateway.auth.password` are configured (including SecretRefs). Set `gateway.auth.mode` to `token` or `password` before upgrade to avoid startup/pairing/TUI failures. (#35094) Thanks @joshavant.
## 2026.3.2
### Changes
@ -872,13 +946,6 @@ Docs: https://docs.openclaw.ai
- Gateway/input_image MIME validation: sniff uploaded image bytes before MIME allowlist enforcement again so declared image types cannot mask concrete non-image payloads, while keeping HEIC/HEIF normalization behavior scoped to actual HEIC inputs. Thanks @vincentkoc.
- Zalo Personal plugin (`@openclaw/zalouser`): keep canonical DM routing while preserving legacy DM session continuity on upgrade, and preserve provider-native `g-`/`u-` target ids in outbound send and directory flows so #33992 lands without breaking existing sessions or stored targets. (#33992) Thanks @darkamenosa.
### Breaking
- **BREAKING:** Onboarding now defaults `tools.profile` to `messaging` for new local installs (interactive + non-interactive). New setups no longer start with broad coding/system tools unless explicitly configured.
- **BREAKING:** ACP dispatch now defaults to enabled unless explicitly disabled (`acp.dispatch.enabled=false`). If you need to pause ACP turn routing while keeping `/acp` controls, set `acp.dispatch.enabled=false`. Docs: https://docs.openclaw.ai/tools/acp-agents
- **BREAKING:** Plugin SDK removed `api.registerHttpHandler(...)`. Plugins must register explicit HTTP routes via `api.registerHttpRoute({ path, auth, match, handler })`, and dynamic webhook lifecycles should use `registerPluginHttpRoute(...)`.
- **BREAKING:** Zalo Personal plugin (`@openclaw/zalouser`) no longer depends on external `zca`-compatible CLI binaries (`openzca`, `zca-cli`) for runtime send/listen/login; operators should use `openclaw channels login --channel zalouser` after upgrade to refresh sessions in the new JS-native path.
### Fixes
- Feishu/Outbound render mode: respect Feishu account `renderMode` in outbound sends so card mode (and auto-detected markdown tables/code blocks) uses markdown card delivery instead of always sending plain text. (#31562) Thanks @arkyu2077.
@ -1065,6 +1132,13 @@ Docs: https://docs.openclaw.ai
- Tests/Subagent announce: set `OPENCLAW_TEST_FAST=1` before importing `subagent-announce` format suites so module-level fast-mode constants are captured deterministically on Windows CI, preventing timeout flakes in nested completion announce coverage. (#31370) Thanks @zwffff.
- Control UI/markdown recursion fallback: catch markdown parser failures and safely render escaped plain-text fallback instead of crashing the Control UI on pathological markdown history payloads. (#36445, fixes #36213) Thanks @BinHPdev.
### Breaking
- **BREAKING:** Onboarding now defaults `tools.profile` to `messaging` for new local installs (interactive + non-interactive). New setups no longer start with broad coding/system tools unless explicitly configured.
- **BREAKING:** ACP dispatch now defaults to enabled unless explicitly disabled (`acp.dispatch.enabled=false`). If you need to pause ACP turn routing while keeping `/acp` controls, set `acp.dispatch.enabled=false`. Docs: https://docs.openclaw.ai/tools/acp-agents
- **BREAKING:** Plugin SDK removed `api.registerHttpHandler(...)`. Plugins must register explicit HTTP routes via `api.registerHttpRoute({ path, auth, match, handler })`, and dynamic webhook lifecycles should use `registerPluginHttpRoute(...)`.
- **BREAKING:** Zalo Personal plugin (`@openclaw/zalouser`) no longer depends on external `zca`-compatible CLI binaries (`openzca`, `zca-cli`) for runtime send/listen/login; operators should use `openclaw channels login --channel zalouser` after upgrade to refresh sessions in the new JS-native path.
## 2026.3.1
### Changes
@ -1092,11 +1166,6 @@ Docs: https://docs.openclaw.ai
- OpenAI/WebSocket warm-up: add optional OpenAI Responses WebSocket warm-up (`response.create` with `generate:false`), enable it by default for `openai/*`, and expose `params.openaiWsWarmup` for per-model enable/disable control.
- Agents/Subagents runtime events: replace ad-hoc subagent completion system-message handoff with typed internal completion events (`task_completion`) that are rendered consistently across direct and queued announce paths, with gateway/CLI plumbing for structured `internalEvents`.
### Breaking
- **BREAKING:** Node exec approval payloads now require `systemRunPlan`. `host=node` approval requests without that plan are rejected.
- **BREAKING:** Node `system.run` execution now pins path-token commands to the canonical executable path (`realpath`) in both allowlist and approval execution flows. Integrations/tests that asserted token-form argv (for example `tr`) must now accept canonical paths (for example `/usr/bin/tr`).
### Fixes
- Feishu/Streaming card text fidelity: merge throttled/fragmented partial updates without dropping content and avoid newline injection when stitching chunk-style deltas so card-stream output matches final reply text. (#29616) Thanks @HaoHuaqing.
@ -1191,7 +1260,12 @@ Docs: https://docs.openclaw.ai
- Signal/Sync message null-handling: treat `syncMessage` presence (including `null`) as sync envelope traffic so replayed sentTranscript payloads cannot bypass loop guards after daemon restart. Landed from contributor PR #31138 by @Sid-Qin. Thanks @Sid-Qin.
- Infra/fs-safe: sanitize directory-read failures so raw `EISDIR` text never leaks to messaging surfaces, with regression tests for both root-scoped and direct safe reads. Landed from contributor PR #31205 by @polooooo. Thanks @polooooo.
## Unreleased
### Breaking
- **BREAKING:** Node exec approval payloads now require `systemRunPlan`. `host=node` approval requests without that plan are rejected.
- **BREAKING:** Node `system.run` execution now pins path-token commands to the canonical executable path (`realpath`) in both allowlist and approval execution flows. Integrations/tests that asserted token-form argv (for example `tr`) must now accept canonical paths (for example `/usr/bin/tr`).
## 2026.2.27
### Changes
@ -1466,10 +1540,6 @@ Docs: https://docs.openclaw.ai
- Agents/Config: remind agents to call `config.schema` before config edits or config-field questions to avoid guessing. Thanks @thewilloftheshadow.
- Dependencies: update workspace dependency pins and lockfile (Bedrock SDK `3.998.0`, `@mariozechner/pi-*` `0.55.1`, TypeScript native preview `7.0.0-dev.20260225.1`) while keeping `@buape/carbon` pinned.
### Breaking
- **BREAKING:** Heartbeat direct/DM delivery default is now `allow` again. To keep DM-blocked behavior from `2026.2.24`, set `agents.defaults.heartbeat.directPolicy: "block"` (or per-agent override).
### Fixes
- Slack/Identity: thread agent outbound identity (`chat:write.customize` overrides) through the channel reply delivery path so per-agent username, icon URL, and icon emoji are applied to all Slack replies including media messages. (#27134) Thanks @hou-rong.
@ -1533,6 +1603,10 @@ Docs: https://docs.openclaw.ai
- Tests/Low-memory stability: disable Vitest `vmForks` by default on low-memory local hosts (`<64 GiB`), keep low-profile extension lane parallelism at 4 workers, and align cron isolated-agent tests with `setSessionRuntimeModel` usage to avoid deterministic suite failures. (#26324) Thanks @ngutman.
- Feishu/WebSocket proxy: pass a proxy agent to Feishu WS clients from standard proxy environment variables and include plugin-local runtime dependency wiring so websocket mode works in proxy-constrained installs. (#26397) Thanks @colin719.
### Breaking
- **BREAKING:** Heartbeat direct/DM delivery default is now `allow` again. To keep DM-blocked behavior from `2026.2.24`, set `agents.defaults.heartbeat.directPolicy: "block"` (or per-agent override).
## 2026.2.24
### Changes
@ -1543,11 +1617,6 @@ Docs: https://docs.openclaw.ai
- Security/Audit: add `security.trust_model.multi_user_heuristic` to flag likely shared-user ingress and clarify the personal-assistant trust model, with hardening guidance for intentional multi-user setups (`sandbox.mode="all"`, workspace-scoped FS, reduced tool surface, no personal/private identities on shared runtimes).
- Dependencies: refresh key runtime and tooling packages across the workspace (Bedrock SDK, pi runtime stack, OpenAI, Google auth, and oxlint/oxfmt), while intentionally keeping `@buape/carbon` pinned.
### Breaking
- **BREAKING:** Heartbeat delivery now blocks direct/DM targets when destination parsing identifies a direct chat (for example `user:<id>`, Telegram user chat IDs, or WhatsApp direct numbers/JIDs). Heartbeat runs still execute, but direct-message delivery is skipped and only non-DM destinations (for example channel/group targets) can receive outbound heartbeat messages.
- **BREAKING:** Security/Sandbox: block Docker `network: "container:<id>"` namespace-join mode by default for sandbox and sandbox-browser containers. To keep that behavior intentionally, set `agents.defaults.sandbox.docker.dangerouslyAllowContainerNamespaceJoin: true` (break-glass). Thanks @tdjackey for reporting.
### Fixes
- Routing/Session isolation: harden followup routing so explicit cross-channel origin replies never fall back to the active dispatcher on route failure, preserve queued overflow summary routing metadata (`channel`/`to`/`thread`) across followup drain, and prefer originating channel context over internal provider tags for embedded followup runs. This prevents webchat/control-ui context from hijacking Discord-targeted replies in shared sessions. (#25864) Thanks @Gamedesigner.
@ -1627,6 +1696,11 @@ Docs: https://docs.openclaw.ai
- Agents/Compaction: harden summarization prompts to preserve opaque identifiers verbatim (UUIDs, IDs, tokens, host/IP/port, URLs), reducing post-compaction identifier drift and hallucinated identifier reconstruction.
- Security/Sandbox: canonicalize bind-mount source paths via existing-ancestor realpath so symlink-parent + non-existent-leaf paths cannot bypass allowed-source-roots or blocked-path checks. Thanks @tdjackey.
### Breaking
- **BREAKING:** Heartbeat delivery now blocks direct/DM targets when destination parsing identifies a direct chat (for example `user:<id>`, Telegram user chat IDs, or WhatsApp direct numbers/JIDs). Heartbeat runs still execute, but direct-message delivery is skipped and only non-DM destinations (for example channel/group targets) can receive outbound heartbeat messages.
- **BREAKING:** Security/Sandbox: block Docker `network: "container:<id>"` namespace-join mode by default for sandbox and sandbox-browser containers. To keep that behavior intentionally, set `agents.defaults.sandbox.docker.dangerouslyAllowContainerNamespaceJoin: true` (break-glass). Thanks @tdjackey for reporting.
## 2026.2.23
### Changes
@ -1641,10 +1715,6 @@ Docs: https://docs.openclaw.ai
- Agents/Config: support per-agent `params` overrides merged on top of model defaults (including `cacheRetention`) so mixed-traffic agents can tune cache behavior independently. (#17470, #17112) Thanks @rrenamed.
- Agents/Bootstrap: cache bootstrap file snapshots per session key and clear them on session reset/delete, reducing prompt-cache invalidations from in-session `AGENTS.md`/`MEMORY.md` writes. (#22220) Thanks @anisoptera.
### Breaking
- **BREAKING:** browser SSRF policy now defaults to trusted-network mode (`browser.ssrfPolicy.dangerouslyAllowPrivateNetwork=true` when unset), and canonical config uses `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork` instead of `browser.ssrfPolicy.allowPrivateNetwork`. `openclaw doctor --fix` migrates the legacy key automatically.
### Fixes
- Security/Config: redact sensitive-looking dynamic catchall keys in `config.get` snapshots (for example `env.*` and `skills.entries.*.env.*`) and preserve round-trip restore behavior for those redacted sentinels. Thanks @merc1305.
@ -1690,6 +1760,10 @@ Docs: https://docs.openclaw.ai
- Skills/Python: harden skill script packaging and validation edge cases (self-including `.skill` outputs, CRLF frontmatter parsing, strict `--days` validation, and safer image file loading), with expanded Python regression coverage. Thanks @vincentkoc.
- Skills/Python: add CI + pre-commit linting (`ruff`) and pytest discovery coverage for Python scripts/tests under `skills/`, including package test execution from repo root. Thanks @vincentkoc.
### Breaking
- **BREAKING:** browser SSRF policy now defaults to trusted-network mode (`browser.ssrfPolicy.dangerouslyAllowPrivateNetwork=true` when unset), and canonical config uses `browser.ssrfPolicy.dangerouslyAllowPrivateNetwork` instead of `browser.ssrfPolicy.allowPrivateNetwork`. `openclaw doctor --fix` migrates the legacy key automatically.
## 2026.2.22
### Changes
@ -1714,14 +1788,6 @@ Docs: https://docs.openclaw.ai
- Skills: remove bundled `food-order` skill from this repo; manage/install it from ClawHub instead.
- Docs/Subagents: make thread-bound session guidance channel-first instead of Discord-specific, and list thread-supporting channels explicitly. (#23589) Thanks @osolmaz.
### Breaking
- **BREAKING:** removed Google Antigravity provider support and the bundled `google-antigravity-auth` plugin. Existing `google-antigravity/*` model/profile configs no longer work; migrate to `google-gemini-cli` or other supported providers.
- **BREAKING:** tool-failure replies now hide raw error details by default. OpenClaw still sends a failure summary, but detailed error suffixes (for example provider/runtime messages and local path fragments) now require `/verbose on` or `/verbose full`.
- **BREAKING:** CLI local onboarding now sets `session.dmScope` to `per-channel-peer` by default for new/implicit DM scope configuration. If you depend on shared DM continuity across senders, explicitly set `session.dmScope` to `main`. (#23468) Thanks @bmendonca3.
- **BREAKING:** unify channel preview-streaming config to `channels.<channel>.streaming` with enum values `off | partial | block | progress`, and move Slack native stream toggle to `channels.slack.nativeStreaming`. Legacy keys (`streamMode`, Slack boolean `streaming`) are still read and migrated by `openclaw doctor --fix`, but canonical saved config/docs now use the unified names.
- **BREAKING:** remove legacy Gateway device-auth signature `v1`. Device-auth clients must now sign `v2` payloads with the per-connection `connect.challenge` nonce and send `device.nonce`; nonce-less connects are rejected.
### Fixes
- Sessions/Resilience: ignore invalid persisted `sessionFile` metadata and fall back to the derived safe transcript path instead of aborting session resolution for handlers and tooling. (#16061) Thanks @haoyifan and @vincentkoc.
@ -1948,6 +2014,14 @@ Docs: https://docs.openclaw.ai
- Gateway/Daemon: verify gateway health after daemon restart.
- Agents/UI text: stop rewriting normal assistant billing/payment language outside explicit error contexts. (#17834) Thanks @niceysam.
### Breaking
- **BREAKING:** removed Google Antigravity provider support and the bundled `google-antigravity-auth` plugin. Existing `google-antigravity/*` model/profile configs no longer work; migrate to `google-gemini-cli` or other supported providers.
- **BREAKING:** tool-failure replies now hide raw error details by default. OpenClaw still sends a failure summary, but detailed error suffixes (for example provider/runtime messages and local path fragments) now require `/verbose on` or `/verbose full`.
- **BREAKING:** CLI local onboarding now sets `session.dmScope` to `per-channel-peer` by default for new/implicit DM scope configuration. If you depend on shared DM continuity across senders, explicitly set `session.dmScope` to `main`. (#23468) Thanks @bmendonca3.
- **BREAKING:** unify channel preview-streaming config to `channels.<channel>.streaming` with enum values `off | partial | block | progress`, and move Slack native stream toggle to `channels.slack.nativeStreaming`. Legacy keys (`streamMode`, Slack boolean `streaming`) are still read and migrated by `openclaw doctor --fix`, but canonical saved config/docs now use the unified names.
- **BREAKING:** remove legacy Gateway device-auth signature `v1`. Device-auth clients must now sign `v2` payloads with the per-connection `connect.challenge` nonce and send `device.nonce`; nonce-less connects are rejected.
## 2026.2.21
### Changes
@ -2596,10 +2670,6 @@ Docs: https://docs.openclaw.ai
- Onboarding/Providers: add first-class Hugging Face Inference provider support (provider wiring, onboarding auth choice/API key flow, and default-model selection), and preserve Hugging Face auth intent in auth-choice remapping (`tokenProvider=huggingface` with `authChoice=apiKey`) while skipping env-override prompts when an explicit token is provided. (#13472) Thanks @Josephrp.
- Onboarding/Providers: add `minimax-api-key-cn` auth choice for the MiniMax China API endpoint. (#15191) Thanks @liuy.
### Breaking
- Config/State: removed legacy `.moltbot` auto-detection/migration and `moltbot.json` config candidates. If you still have state/config under `~/.moltbot`, move it to `~/.openclaw` (recommended) or set `OPENCLAW_STATE_DIR` / `OPENCLAW_CONFIG_PATH` explicitly.
### Fixes
- Gateway/Auth: add trusted-proxy mode hardening follow-ups by keeping `OPENCLAW_GATEWAY_*` env compatibility, auto-normalizing invalid setup combinations in interactive `gateway configure` (trusted-proxy forces `bind=lan` and disables Tailscale serve/funnel), and suppressing shared-secret/rate-limit audit findings that do not apply to trusted-proxy deployments. (#15940) Thanks @nickytonline.
@ -2702,6 +2772,10 @@ Docs: https://docs.openclaw.ai
- Docs/Mermaid: remove hardcoded Mermaid init theme blocks from four docs diagrams so dark mode inherits readable theme defaults. (#15157) Thanks @heytulsiprasad.
- Security/Pairing: generate 256-bit base64url device and node pairing tokens and use byte-safe constant-time verification to avoid token-compare edge-case failures. (#16535) Thanks @FaizanKolega, @gumadeiras.
### Breaking
- Config/State: removed legacy `.moltbot` auto-detection/migration and `moltbot.json` config candidates. If you still have state/config under `~/.moltbot`, move it to `~/.openclaw` (recommended) or set `OPENCLAW_STATE_DIR` / `OPENCLAW_CONFIG_PATH` explicitly.
## 2026.2.12
### Changes
@ -2713,10 +2787,6 @@ Docs: https://docs.openclaw.ai
- Discord: add role-based allowlists and role-based agent routing. (#10650) Thanks @Minidoracat.
- Config: avoid redacting `maxTokens`-like fields during config snapshot redaction, preventing round-trip validation failures in `/config`. (#14006) Thanks @constansino.
### Breaking
- Hooks: `POST /hooks/agent` now rejects payload `sessionKey` overrides by default. To keep fixed hook context, set `hooks.defaultSessionKey` (recommended with `hooks.allowedSessionKeyPrefixes: ["hook:"]`). If you need legacy behavior, explicitly set `hooks.allowRequestSessionKey: true`. Thanks @alpernae for reporting.
### Fixes
- Gateway/OpenResponses: harden URL-based `input_file`/`input_image` handling with explicit SSRF deny policy, hostname allowlists (`files.urlAllowlist` / `images.urlAllowlist`), per-request URL input caps (`maxUrlParts`), blocked-fetch audit logging, and regression coverage/docs updates.
@ -2799,6 +2869,10 @@ Docs: https://docs.openclaw.ai
- Tests: update thread ID handling in Slack message collection tests. (#14108) Thanks @swizzmagik.
- Update/Daemon: fix post-update restart compatibility by generating `dist/cli/daemon-cli.js` with alias-aware exports from hashed daemon bundles, preventing `registerDaemonCli` import failures during `openclaw update`.
### Breaking
- Hooks: `POST /hooks/agent` now rejects payload `sessionKey` overrides by default. To keep fixed hook context, set `hooks.defaultSessionKey` (recommended with `hooks.allowedSessionKeyPrefixes: ["hook:"]`). If you need legacy behavior, explicitly set `hooks.allowRequestSessionKey: true`. Thanks @alpernae for reporting.
## 2026.2.9
### Added
@ -2888,6 +2962,12 @@ Docs: https://docs.openclaw.ai
## 2026.2.6
### Added
- Cron: run history deep-links to session chat from the dashboard. (#10776) Thanks @tyler6204.
- Cron: per-run session keys in run log entries and default labels for cron sessions. (#10776) Thanks @tyler6204.
- Cron: legacy payload field compatibility (`deliver`, `channel`, `to`, `bestEffortDeliver`) in schema. (#10776) Thanks @tyler6204.
### Changes
- Cron: default `wakeMode` is now `"now"` for new jobs (was `"next-heartbeat"`). (#10776) Thanks @tyler6204.
@ -2903,12 +2983,6 @@ Docs: https://docs.openclaw.ai
- CI: optimize pipeline throughput (macOS consolidation, Windows perf, workflow concurrency). (#10784) Thanks @mcaxtr.
- Agents: bump pi-mono to 0.52.7; add embedded forward-compat fallback for Opus 4.6 model ids.
### Added
- Cron: run history deep-links to session chat from the dashboard. (#10776) Thanks @tyler6204.
- Cron: per-run session keys in run log entries and default labels for cron sessions. (#10776) Thanks @tyler6204.
- Cron: legacy payload field compatibility (`deliver`, `channel`, `to`, `bestEffortDeliver`) in schema. (#10776) Thanks @tyler6204.
### Fixes
- TTS: add missing OpenAI voices (ballad, cedar, juniper, marin, verse) to the allowlist so they are recognized instead of silently falling back to Edge TTS. (#2393)
@ -3207,10 +3281,6 @@ Docs: https://docs.openclaw.ai
- Docs: keep docs header sticky so navbar stays visible while scrolling. (#2445) Thanks @chenyuan99.
- Docs: update exe.dev install instructions. (#https://github.com/openclaw/openclaw/pull/3047) Thanks @zackerthescar.
### Breaking
- **BREAKING:** Gateway auth mode "none" is removed; gateway now requires token/password (Tailscale Serve identity still allowed).
### Fixes
- Skills: update session-logs paths to use ~/.openclaw. (#4502) Thanks @bonald.
@ -3263,6 +3333,10 @@ Docs: https://docs.openclaw.ai
- Gateway: treat loopback + non-local Host connections as remote unless trusted proxy headers are present.
- Onboarding: remove unsupported gateway auth "off" choice from onboarding/configure flows and CLI flags.
### Breaking
- **BREAKING:** Gateway auth mode "none" is removed; gateway now requires token/password (Tailscale Serve identity still allowed).
## 2026.1.24-3
### Fixes
@ -3494,11 +3568,6 @@ Docs: https://docs.openclaw.ai
- Docs: add /model allowlist troubleshooting note. (#1405)
- Docs: add per-message Gmail search example for gog. (#1220) Thanks @mbelinky.
### Breaking
- **BREAKING:** Control UI now rejects insecure HTTP without device identity by default. Use HTTPS (Tailscale Serve) or set `gateway.controlUi.allowInsecureAuth: true` to allow token-only auth. https://docs.openclaw.ai/web/control-ui#insecure-http
- **BREAKING:** Envelope and system event timestamps now default to host-local time (was UTC) so agents dont have to constantly convert.
### Fixes
- Nodes/macOS: prompt on allowlist miss for node exec approvals, persist allowlist decisions, and flatten node invoke errors. (#1394) Thanks @ngutman.
@ -3521,6 +3590,11 @@ Docs: https://docs.openclaw.ai
- macOS: default distribution packaging to universal binaries. (#1396) Thanks @JustYannicc.
- Embedded runner: forward sender identity into attempt execution so Feishu doc auto-grant receives requester context again. (#32915) Thanks @cszhouwei.
### Breaking
- **BREAKING:** Control UI now rejects insecure HTTP without device identity by default. Use HTTPS (Tailscale Serve) or set `gateway.controlUi.allowInsecureAuth: true` to allow token-only auth. https://docs.openclaw.ai/web/control-ui#insecure-http
- **BREAKING:** Envelope and system event timestamps now default to host-local time (was UTC) so agents dont have to constantly convert.
## 2026.1.20
### Changes
@ -3602,10 +3676,6 @@ Docs: https://docs.openclaw.ai
- macOS: stop syncing Peekaboo in postinstall.
- Swabble: use the tagged Commander Swift package release.
### Breaking
- **BREAKING:** Reject invalid/unknown config entries and refuse to start the gateway for safety. Run `openclaw doctor --fix` to repair, then update plugins (`openclaw plugins update`) if you use any.
### Fixes
- Discovery: shorten Bonjour DNS-SD service type to `_moltbot-gw._tcp` and update discovery clients/docs.
@ -3704,6 +3774,10 @@ Docs: https://docs.openclaw.ai
Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @NicholaiVogel, @RyanLisse, @ThePickle31, @VACInc, @Whoaa512, @YuriNachos, @aaronveklabs, @abdaraxus, @alauppe, @ameno-, @artuskg, @austinm911, @bradleypriest, @cheeeee, @dougvk, @fogboots, @gnarco, @gumadeiras, @jdrhyne, @joelklabo, @longmaba, @mukhtharcm, @odysseus0, @oscargavin, @rhjoh, @sebslight, @sibbl, @sleontenko, @steipete, @suminhthanh, @thewilloftheshadow, @tyler6204, @vignesh07, @visionik, @ysqander, @zerone0x.
### Breaking
- **BREAKING:** Reject invalid/unknown config entries and refuse to start the gateway for safety. Run `openclaw doctor --fix` to repair, then update plugins (`openclaw plugins update`) if you use any.
## 2026.1.16-2
### Changes
@ -3722,15 +3796,6 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic
- Sessions: add `session.identityLinks` for cross-platform DM session li nking. (#1033) — thanks @thewilloftheshadow. https://docs.openclaw.ai/concepts/session
- Web search: add `country`/`language` parameters (schema + Brave API) and docs. (#1046) — thanks @YuriNachos. https://docs.openclaw.ai/tools/web
### Breaking
- **BREAKING:** `openclaw message` and message tool now require `target` (dropping `to`/`channelId` for destinations). (#1034) — thanks @tobalsan.
- **BREAKING:** Channel auth now prefers config over env for Discord/Telegram/Matrix (env is fallback only). (#1040) — thanks @thewilloftheshadow.
- **BREAKING:** Drop legacy `chatType: "room"` support; use `chatType: "channel"`.
- **BREAKING:** remove legacy provider-specific target resolution fallbacks; target resolution is centralized with plugin hints + directory lookups.
- **BREAKING:** `openclaw hooks` is now `openclaw webhooks`; hooks live under `openclaw hooks`. https://docs.openclaw.ai/cli/webhooks
- **BREAKING:** `openclaw plugins install <path>` now copies into `~/.openclaw/extensions` (use `--link` to keep path-based loading).
### Changes
- Plugins: ship bundled plugins disabled by default and allow overrides by installed versions. (#1066) — thanks @ItzR3NO.
@ -3822,6 +3887,15 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic
- Discord: preserve whitespace when chunking long lines so message splits keep spacing intact.
- Skills: fix skills watcher ignored list typing (tsc).
### Breaking
- **BREAKING:** `openclaw message` and message tool now require `target` (dropping `to`/`channelId` for destinations). (#1034) — thanks @tobalsan.
- **BREAKING:** Channel auth now prefers config over env for Discord/Telegram/Matrix (env is fallback only). (#1040) — thanks @thewilloftheshadow.
- **BREAKING:** Drop legacy `chatType: "room"` support; use `chatType: "channel"`.
- **BREAKING:** remove legacy provider-specific target resolution fallbacks; target resolution is centralized with plugin hints + directory lookups.
- **BREAKING:** `openclaw hooks` is now `openclaw webhooks`; hooks live under `openclaw hooks`. https://docs.openclaw.ai/cli/webhooks
- **BREAKING:** `openclaw plugins install <path>` now copies into `~/.openclaw/extensions` (use `--link` to keep path-based loading).
## 2026.1.15
### Highlights
@ -3831,11 +3905,6 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic
- Heartbeat: per-agent configuration + 24h duplicate suppression. (#980) — thanks @voidserf.
- Security: audit warns on weak model tiers; app nodes store auth tokens encrypted (Keychain/SecurePrefs).
### Breaking
- **BREAKING:** iOS minimum version is now 18.0 to support Textual markdown rendering in native chat. (#702)
- **BREAKING:** Microsoft Teams is now a plugin; install `@openclaw/msteams` via `openclaw plugins install @openclaw/msteams`.
### Changes
- UI/Apps: move channel/config settings to schema-driven forms and rename Connections → Channels. (#1040) — thanks @thewilloftheshadow.
@ -3908,6 +3977,11 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic
- Fix: allow local Tailscale Serve hostnames without treating tailnet clients as direct. (#885) — thanks @oswalpalash.
- Fix: reset sessions after role-ordering conflicts to recover from consecutive user turns. (#998)
### Breaking
- **BREAKING:** iOS minimum version is now 18.0 to support Textual markdown rendering in native chat. (#702)
- **BREAKING:** Microsoft Teams is now a plugin; install `@openclaw/msteams` via `openclaw plugins install @openclaw/msteams`.
## 2026.1.14-1
### Highlights
@ -4044,10 +4118,6 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic
- Gateway: allow Tailscale Serve identity headers to satisfy token auth; rebuild Control UI assets when protocol schema is newer. (#823) — thanks @roshanasingh4; (#786) — thanks @meaningfool.
- Heartbeat: default `ackMaxChars` to 300 so short `HEARTBEAT_OK` replies stay internal.
### Installer
- Install: run `openclaw doctor --non-interactive` after git installs/updates and nudge daemon restarts when detected.
### Fixes
- Doctor: warn on pnpm workspace mismatches, missing Control UI assets, and missing tsx binaries; offer UI rebuilds.
@ -4073,6 +4143,10 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic
- Tools/UI: harden tool input schemas for strict providers; drop null-only union variants for Gemini schema cleanup; treat `maxChars: 0` as unlimited; keep TUI last streamed response instead of "(no output)". (#782) — thanks @AbhisekBasu1; (#796) — thanks @gabriel-trigo; (#747) — thanks @thewilloftheshadow.
- Connections UI: polish multi-account account cards. (#816) — thanks @steipete.
### Installer
- Install: run `openclaw doctor --non-interactive` after git installs/updates and nudge daemon restarts when detected.
### Maintenance
- Dependencies: bump Pi packages to 0.45.3 and refresh patched pi-ai.
@ -4124,15 +4198,6 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic
- Gateway: require `client.id` in WebSocket connect params; use `client.instanceId` for presence de-dupe; update docs/tests.
- macOS: remove the attach-only gateway setting; local mode now always manages launchd while still attaching to an existing gateway if present.
### Installer
- Postinstall: replace `git apply` with builtin JS patcher (works npm/pnpm/bun; no git dependency) plus regression tests.
- Postinstall: skip pnpm patch fallback when the new patcher is active.
- Installer tests: add root+non-root docker smokes, CI workflow to fetch openclaw.ai scripts and run install sh/cli with onboarding skipped.
- Installer UX: support `CLAWDBOT_NO_ONBOARD=1` for non-interactive installs; fix npm prefix on Linux and auto-install git.
- Installer UX: add `install.sh --help` with flags/env and git install hint.
- Installer UX: add `--install-method git|npm` and auto-detect source checkouts (prompt to update git checkout vs migrate to npm).
### Fixes
- Models/Onboarding: configure MiniMax (minimax.io) via Anthropic-compatible `/anthropic` endpoint by default (keep `minimax-api` as a legacy alias).
@ -4171,6 +4236,15 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic
- Sandbox/Gateway: treat `agent:<id>:main` as a main-session alias when `session.mainKey` is customized (backwards compatible).
- Auto-reply: fast-path allowlisted slash commands (inline `/help`/`/commands`/`/status`/`/whoami` stripped before model).
### Installer
- Postinstall: replace `git apply` with builtin JS patcher (works npm/pnpm/bun; no git dependency) plus regression tests.
- Postinstall: skip pnpm patch fallback when the new patcher is active.
- Installer tests: add root+non-root docker smokes, CI workflow to fetch openclaw.ai scripts and run install sh/cli with onboarding skipped.
- Installer UX: support `CLAWDBOT_NO_ONBOARD=1` for non-interactive installs; fix npm prefix on Linux and auto-install git.
- Installer UX: add `install.sh --help` with flags/env and git install hint.
- Installer UX: add `--install-method git|npm` and auto-detect source checkouts (prompt to update git checkout vs migrate to npm).
## 2026.1.10
### Highlights
@ -4279,11 +4353,6 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic
- Auto-reply + status: block-streaming controls, reasoning handling, usage/cost reporting.
- Control UI/TUI: queued messages, session links, reasoning view, mobile polish, logs UX.
### Breaking
- CLI: `openclaw message` now subcommands (`message send|poll|...`) and requires `--provider` unless only one provider configured.
- Commands/Tools: `/restart` and gateway restart tool disabled by default; enable with `commands.restart=true`.
### New Features and Changes
- Models/Auth: OpenCode Zen onboarding (#623) — thanks @magimetal; MiniMax Anthropic-compatible API + hosted onboarding (#590, #495) — thanks @mneves75, @tobiasbischoff.
@ -4325,6 +4394,11 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic
- Onboarding/Configure: QuickStart single-select provider picker; avoid Codex CLI false-expiry warnings; clarify WhatsApp owner prompt; fix Minimax hosted onboarding (agents.defaults + msteams heartbeat target); remove configure Control UI prompt; honor gateway --dev flag.
- Agent loop: guard overflow compaction throws and restore compaction hooks for engine-owned context engines. (#41361) — thanks @davidrudduck
### Breaking
- CLI: `openclaw message` now subcommands (`message send|poll|...`) and requires `--provider` unless only one provider configured.
- Commands/Tools: `/restart` and gateway restart tool disabled by default; enable with `commands.restart=true`.
### Maintenance
- Dependencies: bump pi-\* stack to 0.42.2.
@ -4344,6 +4418,18 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic
- Control UI: logs tab, streaming stability, focus mode, and large-output rendering fixes.
- CLI/Gateway/Doctor: daemon/logs/status, auth migration, and diagnostics significantly expanded.
### Fixes
- **CLI/Gateway/Doctor:** daemon runtime selection + improved logs/status/health/errors; auth/password handling for local CLI; richer close/timeout details; auto-migrate legacy config/sessions/state; integrity checks + repair prompts; `--yes`/`--non-interactive`; `--deep` gateway scans; better restart/service hints.
- **Agent loop + compaction:** compaction/pruning tuning, overflow handling, safer bootstrap context, and per-provider threading/confirmations; opt-in tool-result pruning + compact tracking.
- **Sandbox + tools:** per-agent sandbox overrides, workspaceAccess controls, session tool visibility, tool policy overrides, process isolation, and tool schema/timeout/reaction unification.
- **Providers (Telegram/WhatsApp/Discord/Slack/Signal/iMessage):** retry/backoff, threading, reactions, media groups/attachments, mention gating, typing behavior, and error/log stability; long polling + forum topic isolation for Telegram.
- **Gateway/CLI UX:** `openclaw logs`, cron list colors/aliases, docs search, agents list/add/delete flows, status usage snapshots, runtime/auth source display, and `/status`/commands auth unification.
- **Control UI/Web:** logs tab, focus mode polish, config form resilience, streaming stability, tool output caps, windowed chat history, and reconnect/password URL auth.
- **macOS/Android/TUI/Build:** macOS gateway races, QR bundling, JSON5 config safety, Voice Wake hardening; Android EXIF rotation + APK naming/versioning; TUI key handling; tooling/bundling fixes.
- **Packaging/compat:** npm dist folder coverage, Node 25 qrcode-terminal import fixes, Bun/Playwright/WebSocket patches, and Docker Bun install.
- **Docs:** new FAQ/ClawHub/config examples/showcase entries and clarified auth, sandbox, and systemd docs.
### Breaking
- **SECURITY (update ASAP):** inbound DMs are now **locked down by default** on Telegram/WhatsApp/Signal/iMessage/Discord/Slack.
@ -4359,18 +4445,6 @@ Thanks @AlexMikhalev, @CoreyH, @John-Rood, @KrauseFx, @MaudeBot, @Nachx639, @Nic
- Auto-reply: removed `autoReply` from Discord/Slack/Telegram channel configs; use `requireMention` instead (Telegram topics now support `requireMention` overrides).
- CLI: remove `update`, `gateway-daemon`, `gateway {install|uninstall|start|stop|restart|daemon status|wake|send|agent}`, and `telegram` commands; move `login/logout` to `providers login/logout` (top-level aliases hidden); use `daemon` for service control, `send`/`agent`/`wake` for RPC, and `nodes canvas` for canvas ops.
### Fixes
- **CLI/Gateway/Doctor:** daemon runtime selection + improved logs/status/health/errors; auth/password handling for local CLI; richer close/timeout details; auto-migrate legacy config/sessions/state; integrity checks + repair prompts; `--yes`/`--non-interactive`; `--deep` gateway scans; better restart/service hints.
- **Agent loop + compaction:** compaction/pruning tuning, overflow handling, safer bootstrap context, and per-provider threading/confirmations; opt-in tool-result pruning + compact tracking.
- **Sandbox + tools:** per-agent sandbox overrides, workspaceAccess controls, session tool visibility, tool policy overrides, process isolation, and tool schema/timeout/reaction unification.
- **Providers (Telegram/WhatsApp/Discord/Slack/Signal/iMessage):** retry/backoff, threading, reactions, media groups/attachments, mention gating, typing behavior, and error/log stability; long polling + forum topic isolation for Telegram.
- **Gateway/CLI UX:** `openclaw logs`, cron list colors/aliases, docs search, agents list/add/delete flows, status usage snapshots, runtime/auth source display, and `/status`/commands auth unification.
- **Control UI/Web:** logs tab, focus mode polish, config form resilience, streaming stability, tool output caps, windowed chat history, and reconnect/password URL auth.
- **macOS/Android/TUI/Build:** macOS gateway races, QR bundling, JSON5 config safety, Voice Wake hardening; Android EXIF rotation + APK naming/versioning; TUI key handling; tooling/bundling fixes.
- **Packaging/compat:** npm dist folder coverage, Node 25 qrcode-terminal import fixes, Bun/Playwright/WebSocket patches, and Docker Bun install.
- **Docs:** new FAQ/ClawHub/config examples/showcase entries and clarified auth, sandbox, and systemd docs.
### Maintenance
- Skills additions (Himalaya email, CodexBar, 1Password).

View File

@ -47,7 +47,7 @@ Welcome to the lobster tank! 🦞
- **Christoph Nakazawa** - JS Infra
- GitHub: [@cpojer](https://github.com/cpojer) · X: [@cnakazawa](https://x.com/cnakazawa)
- **Gustavo Madeira Santana** - Multi-agents, CLI, web UI
- **Gustavo Madeira Santana** - Multi-agents, CLI, Performance, Plugins, Matrix
- GitHub: [@gumadeiras](https://github.com/gumadeiras) · X: [@gumadeiras](https://x.com/gumadeiras)
- **Onur Solmaz** - Agents, dev workflows, ACP integrations, MS Teams
@ -89,6 +89,12 @@ Welcome to the lobster tank! 🦞
- Test locally with your OpenClaw instance
- Run tests: `pnpm build && pnpm check && pnpm test`
- For extension/plugin changes, run the fast local lane first:
- `pnpm test:extension <extension-name>`
- `pnpm test:extension --list` to see valid extension ids
- If you changed shared plugin or channel surfaces, run `pnpm test:contracts`
- For targeted shared-surface work, use `pnpm test:contracts:channels` or `pnpm test:contracts:plugins`
- If you changed broader runtime behavior, still run the relevant wider lanes (`pnpm test:extensions`, `pnpm test:channels`, or `pnpm test`) before asking for review
- If you have access to Codex, run `codex review --base origin/main` locally before opening or updating your PR. Treat this as the current highest standard of AI review, even if GitHub Codex review also runs.
- Ensure CI checks pass
- Keep PRs focused (one thing per PR; do not mix unrelated concerns)

View File

@ -23,10 +23,10 @@ It answers you on the channels you already use (WhatsApp, Telegram, Slack, Disco
If you want a personal, single-user assistant that feels local, fast, and always-on, this is it.
[Website](https://openclaw.ai) · [Docs](https://docs.openclaw.ai) · [Vision](VISION.md) · [DeepWiki](https://deepwiki.com/openclaw/openclaw) · [Getting Started](https://docs.openclaw.ai/start/getting-started) · [Updating](https://docs.openclaw.ai/install/updating) · [Showcase](https://docs.openclaw.ai/start/showcase) · [FAQ](https://docs.openclaw.ai/help/faq) · [Wizard](https://docs.openclaw.ai/start/wizard) · [Nix](https://github.com/openclaw/nix-openclaw) · [Docker](https://docs.openclaw.ai/install/docker) · [Discord](https://discord.gg/clawd)
[Website](https://openclaw.ai) · [Docs](https://docs.openclaw.ai) · [Vision](VISION.md) · [DeepWiki](https://deepwiki.com/openclaw/openclaw) · [Getting Started](https://docs.openclaw.ai/start/getting-started) · [Updating](https://docs.openclaw.ai/install/updating) · [Showcase](https://docs.openclaw.ai/start/showcase) · [FAQ](https://docs.openclaw.ai/help/faq) · [Onboarding](https://docs.openclaw.ai/start/wizard) · [Nix](https://github.com/openclaw/nix-openclaw) · [Docker](https://docs.openclaw.ai/install/docker) · [Discord](https://discord.gg/clawd)
Preferred setup: run the onboarding wizard (`openclaw onboard`) in your terminal.
The wizard guides you step by step through setting up the gateway, workspace, channels, and skills. The CLI wizard is the recommended path and works on **macOS, Linux, and Windows (via WSL2; strongly recommended)**.
Preferred setup: run `openclaw onboard` in your terminal.
OpenClaw Onboard guides you step by step through setting up the gateway, workspace, channels, and skills. It is the recommended CLI setup path and works on **macOS, Linux, and Windows (via WSL2; strongly recommended)**.
Works with npm, pnpm, or bun.
New install? Start here: [Getting started](https://docs.openclaw.ai/start/getting-started)
@ -58,7 +58,7 @@ npm install -g openclaw@latest
openclaw onboard --install-daemon
```
The wizard installs the Gateway daemon (launchd/systemd user service) so it stays running.
OpenClaw Onboard installs the Gateway daemon (launchd/systemd user service) so it stays running.
## Quick start (TL;DR)
@ -132,7 +132,7 @@ Run `openclaw doctor` to surface risky/misconfigured DM policies.
- **[Live Canvas](https://docs.openclaw.ai/platforms/mac/canvas)** — agent-driven visual workspace with [A2UI](https://docs.openclaw.ai/platforms/mac/canvas#canvas-a2ui).
- **[First-class tools](https://docs.openclaw.ai/tools)** — browser, canvas, nodes, cron, sessions, and Discord/Slack actions.
- **[Companion apps](https://docs.openclaw.ai/platforms/macos)** — macOS menu bar app + iOS/Android [nodes](https://docs.openclaw.ai/nodes).
- **[Onboarding](https://docs.openclaw.ai/start/wizard) + [skills](https://docs.openclaw.ai/tools/skills)** — wizard-driven setup with bundled/managed/workspace skills.
- **[Onboarding](https://docs.openclaw.ai/start/wizard) + [skills](https://docs.openclaw.ai/tools/skills)** — onboarding-driven setup with bundled/managed/workspace skills.
## Star History
@ -143,7 +143,7 @@ Run `openclaw doctor` to surface risky/misconfigured DM policies.
### Core platform
- [Gateway WS control plane](https://docs.openclaw.ai/gateway) with sessions, presence, config, cron, webhooks, [Control UI](https://docs.openclaw.ai/web), and [Canvas host](https://docs.openclaw.ai/platforms/mac/canvas#canvas-a2ui).
- [CLI surface](https://docs.openclaw.ai/tools/agent-send): gateway, agent, send, [wizard](https://docs.openclaw.ai/start/wizard), and [doctor](https://docs.openclaw.ai/gateway/doctor).
- [CLI surface](https://docs.openclaw.ai/tools/agent-send): gateway, agent, send, [onboarding](https://docs.openclaw.ai/start/wizard), and [doctor](https://docs.openclaw.ai/gateway/doctor).
- [Pi agent runtime](https://docs.openclaw.ai/concepts/agent) in RPC mode with tool streaming and block streaming.
- [Session model](https://docs.openclaw.ai/concepts/session): `main` for direct chats, group isolation, activation modes, queue modes, reply-back. Group rules: [Groups](https://docs.openclaw.ai/channels/groups).
- [Media pipeline](https://docs.openclaw.ai/nodes/images): images/audio/video, transcription hooks, size caps, temp file lifecycle. Audio details: [Audio](https://docs.openclaw.ai/nodes/audio).
@ -364,7 +364,7 @@ Details: [Security guide](https://docs.openclaw.ai/gateway/security) · [Docker
### [Discord](https://docs.openclaw.ai/channels/discord)
- Set `DISCORD_BOT_TOKEN` or `channels.discord.token` (env wins).
- Set `DISCORD_BOT_TOKEN` or `channels.discord.token`.
- Optional: set `commands.native`, `commands.text`, or `commands.useAccessGroups`, plus `channels.discord.allowFrom`, `channels.discord.guilds`, or `channels.discord.mediaMaxMb` as needed.
```json5
@ -422,7 +422,7 @@ Use these when youre past the onboarding flow and want the deeper reference.
- [Run the Gateway by the book with the operational runbook.](https://docs.openclaw.ai/gateway)
- [Learn how the Control UI/Web surfaces work and how to expose them safely.](https://docs.openclaw.ai/web)
- [Understand remote access over SSH tunnels or tailnets.](https://docs.openclaw.ai/gateway/remote)
- [Follow the onboarding wizard flow for a guided setup.](https://docs.openclaw.ai/start/wizard)
- [Follow OpenClaw Onboard for a guided setup.](https://docs.openclaw.ai/start/wizard)
- [Wire external triggers via the webhook surface.](https://docs.openclaw.ai/automation/webhook)
- [Set up Gmail Pub/Sub triggers.](https://docs.openclaw.ai/automation/gmail-pubsub)
- [Learn the macOS menu bar companion details.](https://docs.openclaw.ai/platforms/mac/menu-bar)

View File

@ -18,14 +18,13 @@ import kotlinx.coroutines.launch
class MainActivity : ComponentActivity() {
private val viewModel: MainViewModel by viewModels()
private lateinit var permissionRequester: PermissionRequester
private var didAttachRuntimeUi = false
private var didStartNodeService = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
permissionRequester = PermissionRequester(this)
viewModel.camera.attachLifecycleOwner(this)
viewModel.camera.attachPermissionRequester(permissionRequester)
viewModel.sms.attachPermissionRequester(permissionRequester)
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
@ -39,6 +38,20 @@ class MainActivity : ComponentActivity() {
}
}
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.runtimeInitialized.collect { ready ->
if (!ready || didAttachRuntimeUi) return@collect
viewModel.attachRuntimeUi(owner = this@MainActivity, permissionRequester = permissionRequester)
didAttachRuntimeUi = true
if (!didStartNodeService) {
NodeForegroundService.start(this@MainActivity)
didStartNodeService = true
}
}
}
}
setContent {
OpenClawTheme {
Surface(modifier = Modifier) {
@ -46,9 +59,6 @@ class MainActivity : ComponentActivity() {
}
}
}
// Keep startup path lean: start foreground service after first frame.
window.decorView.post { NodeForegroundService.start(this) }
}
override fun onStart() {

View File

@ -2,209 +2,268 @@ package ai.openclaw.app
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import ai.openclaw.app.gateway.GatewayEndpoint
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.viewModelScope
import ai.openclaw.app.chat.ChatMessage
import ai.openclaw.app.chat.ChatPendingToolCall
import ai.openclaw.app.chat.ChatSessionEntry
import ai.openclaw.app.chat.OutgoingAttachment
import ai.openclaw.app.gateway.GatewayEndpoint
import ai.openclaw.app.node.CameraCaptureManager
import ai.openclaw.app.node.CanvasController
import ai.openclaw.app.node.SmsManager
import ai.openclaw.app.voice.VoiceConversationEntry
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn
@OptIn(ExperimentalCoroutinesApi::class)
class MainViewModel(app: Application) : AndroidViewModel(app) {
private val runtime: NodeRuntime = (app as NodeApp).runtime
private val nodeApp = app as NodeApp
private val prefs = nodeApp.prefs
private val runtimeRef = MutableStateFlow<NodeRuntime?>(null)
private var foreground = true
val canvas: CanvasController = runtime.canvas
val canvasCurrentUrl: StateFlow<String?> = runtime.canvas.currentUrl
val canvasA2uiHydrated: StateFlow<Boolean> = runtime.canvasA2uiHydrated
val canvasRehydratePending: StateFlow<Boolean> = runtime.canvasRehydratePending
val canvasRehydrateErrorText: StateFlow<String?> = runtime.canvasRehydrateErrorText
val camera: CameraCaptureManager = runtime.camera
val sms: SmsManager = runtime.sms
private fun ensureRuntime(): NodeRuntime {
runtimeRef.value?.let { return it }
val runtime = nodeApp.ensureRuntime()
runtime.setForeground(foreground)
runtimeRef.value = runtime
return runtime
}
val gateways: StateFlow<List<GatewayEndpoint>> = runtime.gateways
val discoveryStatusText: StateFlow<String> = runtime.discoveryStatusText
private fun <T> runtimeState(
initial: T,
selector: (NodeRuntime) -> StateFlow<T>,
): StateFlow<T> =
runtimeRef
.flatMapLatest { runtime -> runtime?.let(selector) ?: flowOf(initial) }
.stateIn(viewModelScope, SharingStarted.Eagerly, initial)
val isConnected: StateFlow<Boolean> = runtime.isConnected
val isNodeConnected: StateFlow<Boolean> = runtime.nodeConnected
val statusText: StateFlow<String> = runtime.statusText
val serverName: StateFlow<String?> = runtime.serverName
val remoteAddress: StateFlow<String?> = runtime.remoteAddress
val pendingGatewayTrust: StateFlow<NodeRuntime.GatewayTrustPrompt?> = runtime.pendingGatewayTrust
val isForeground: StateFlow<Boolean> = runtime.isForeground
val seamColorArgb: StateFlow<Long> = runtime.seamColorArgb
val mainSessionKey: StateFlow<String> = runtime.mainSessionKey
val runtimeInitialized: StateFlow<Boolean> =
runtimeRef
.flatMapLatest { runtime -> flowOf(runtime != null) }
.stateIn(viewModelScope, SharingStarted.Eagerly, false)
val cameraHud: StateFlow<CameraHudState?> = runtime.cameraHud
val cameraFlashToken: StateFlow<Long> = runtime.cameraFlashToken
val canvasCurrentUrl: StateFlow<String?> = runtimeState(initial = null) { it.canvas.currentUrl }
val canvasA2uiHydrated: StateFlow<Boolean> = runtimeState(initial = false) { it.canvasA2uiHydrated }
val canvasRehydratePending: StateFlow<Boolean> = runtimeState(initial = false) { it.canvasRehydratePending }
val canvasRehydrateErrorText: StateFlow<String?> = runtimeState(initial = null) { it.canvasRehydrateErrorText }
val instanceId: StateFlow<String> = runtime.instanceId
val displayName: StateFlow<String> = runtime.displayName
val cameraEnabled: StateFlow<Boolean> = runtime.cameraEnabled
val locationMode: StateFlow<LocationMode> = runtime.locationMode
val locationPreciseEnabled: StateFlow<Boolean> = runtime.locationPreciseEnabled
val preventSleep: StateFlow<Boolean> = runtime.preventSleep
val micEnabled: StateFlow<Boolean> = runtime.micEnabled
val micCooldown: StateFlow<Boolean> = runtime.micCooldown
val micStatusText: StateFlow<String> = runtime.micStatusText
val micLiveTranscript: StateFlow<String?> = runtime.micLiveTranscript
val micIsListening: StateFlow<Boolean> = runtime.micIsListening
val micQueuedMessages: StateFlow<List<String>> = runtime.micQueuedMessages
val micConversation: StateFlow<List<VoiceConversationEntry>> = runtime.micConversation
val micInputLevel: StateFlow<Float> = runtime.micInputLevel
val micIsSending: StateFlow<Boolean> = runtime.micIsSending
val speakerEnabled: StateFlow<Boolean> = runtime.speakerEnabled
val manualEnabled: StateFlow<Boolean> = runtime.manualEnabled
val manualHost: StateFlow<String> = runtime.manualHost
val manualPort: StateFlow<Int> = runtime.manualPort
val manualTls: StateFlow<Boolean> = runtime.manualTls
val gatewayToken: StateFlow<String> = runtime.gatewayToken
val onboardingCompleted: StateFlow<Boolean> = runtime.onboardingCompleted
val canvasDebugStatusEnabled: StateFlow<Boolean> = runtime.canvasDebugStatusEnabled
val gateways: StateFlow<List<GatewayEndpoint>> = runtimeState(initial = emptyList()) { it.gateways }
val discoveryStatusText: StateFlow<String> = runtimeState(initial = "Searching…") { it.discoveryStatusText }
val chatSessionKey: StateFlow<String> = runtime.chatSessionKey
val chatSessionId: StateFlow<String?> = runtime.chatSessionId
val chatMessages = runtime.chatMessages
val chatError: StateFlow<String?> = runtime.chatError
val chatHealthOk: StateFlow<Boolean> = runtime.chatHealthOk
val chatThinkingLevel: StateFlow<String> = runtime.chatThinkingLevel
val chatStreamingAssistantText: StateFlow<String?> = runtime.chatStreamingAssistantText
val chatPendingToolCalls = runtime.chatPendingToolCalls
val chatSessions = runtime.chatSessions
val pendingRunCount: StateFlow<Int> = runtime.pendingRunCount
val isConnected: StateFlow<Boolean> = runtimeState(initial = false) { it.isConnected }
val isNodeConnected: StateFlow<Boolean> = runtimeState(initial = false) { it.nodeConnected }
val statusText: StateFlow<String> = runtimeState(initial = "Offline") { it.statusText }
val serverName: StateFlow<String?> = runtimeState(initial = null) { it.serverName }
val remoteAddress: StateFlow<String?> = runtimeState(initial = null) { it.remoteAddress }
val pendingGatewayTrust: StateFlow<NodeRuntime.GatewayTrustPrompt?> = runtimeState(initial = null) { it.pendingGatewayTrust }
val seamColorArgb: StateFlow<Long> = runtimeState(initial = 0xFF0EA5E9) { it.seamColorArgb }
val mainSessionKey: StateFlow<String> = runtimeState(initial = "main") { it.mainSessionKey }
val cameraHud: StateFlow<CameraHudState?> = runtimeState(initial = null) { it.cameraHud }
val cameraFlashToken: StateFlow<Long> = runtimeState(initial = 0L) { it.cameraFlashToken }
val instanceId: StateFlow<String> = prefs.instanceId
val displayName: StateFlow<String> = prefs.displayName
val cameraEnabled: StateFlow<Boolean> = prefs.cameraEnabled
val locationMode: StateFlow<LocationMode> = prefs.locationMode
val locationPreciseEnabled: StateFlow<Boolean> = prefs.locationPreciseEnabled
val preventSleep: StateFlow<Boolean> = prefs.preventSleep
val manualEnabled: StateFlow<Boolean> = prefs.manualEnabled
val manualHost: StateFlow<String> = prefs.manualHost
val manualPort: StateFlow<Int> = prefs.manualPort
val manualTls: StateFlow<Boolean> = prefs.manualTls
val gatewayToken: StateFlow<String> = prefs.gatewayToken
val onboardingCompleted: StateFlow<Boolean> = prefs.onboardingCompleted
val canvasDebugStatusEnabled: StateFlow<Boolean> = prefs.canvasDebugStatusEnabled
val speakerEnabled: StateFlow<Boolean> = prefs.speakerEnabled
val micEnabled: StateFlow<Boolean> = prefs.talkEnabled
val micCooldown: StateFlow<Boolean> = runtimeState(initial = false) { it.micCooldown }
val micStatusText: StateFlow<String> = runtimeState(initial = "Mic off") { it.micStatusText }
val micLiveTranscript: StateFlow<String?> = runtimeState(initial = null) { it.micLiveTranscript }
val micIsListening: StateFlow<Boolean> = runtimeState(initial = false) { it.micIsListening }
val micQueuedMessages: StateFlow<List<String>> = runtimeState(initial = emptyList()) { it.micQueuedMessages }
val micConversation: StateFlow<List<VoiceConversationEntry>> = runtimeState(initial = emptyList()) { it.micConversation }
val micInputLevel: StateFlow<Float> = runtimeState(initial = 0f) { it.micInputLevel }
val micIsSending: StateFlow<Boolean> = runtimeState(initial = false) { it.micIsSending }
val chatSessionKey: StateFlow<String> = runtimeState(initial = "main") { it.chatSessionKey }
val chatSessionId: StateFlow<String?> = runtimeState(initial = null) { it.chatSessionId }
val chatMessages: StateFlow<List<ChatMessage>> = runtimeState(initial = emptyList()) { it.chatMessages }
val chatError: StateFlow<String?> = runtimeState(initial = null) { it.chatError }
val chatHealthOk: StateFlow<Boolean> = runtimeState(initial = false) { it.chatHealthOk }
val chatThinkingLevel: StateFlow<String> = runtimeState(initial = "off") { it.chatThinkingLevel }
val chatStreamingAssistantText: StateFlow<String?> = runtimeState(initial = null) { it.chatStreamingAssistantText }
val chatPendingToolCalls: StateFlow<List<ChatPendingToolCall>> = runtimeState(initial = emptyList()) { it.chatPendingToolCalls }
val chatSessions: StateFlow<List<ChatSessionEntry>> = runtimeState(initial = emptyList()) { it.chatSessions }
val pendingRunCount: StateFlow<Int> = runtimeState(initial = 0) { it.pendingRunCount }
init {
if (prefs.onboardingCompleted.value) {
ensureRuntime()
}
}
val canvas: CanvasController
get() = ensureRuntime().canvas
val camera: CameraCaptureManager
get() = ensureRuntime().camera
val sms: SmsManager
get() = ensureRuntime().sms
fun attachRuntimeUi(owner: LifecycleOwner, permissionRequester: PermissionRequester) {
val runtime = runtimeRef.value ?: return
runtime.camera.attachLifecycleOwner(owner)
runtime.camera.attachPermissionRequester(permissionRequester)
runtime.sms.attachPermissionRequester(permissionRequester)
}
fun setForeground(value: Boolean) {
runtime.setForeground(value)
foreground = value
runtimeRef.value?.setForeground(value)
}
fun setDisplayName(value: String) {
runtime.setDisplayName(value)
prefs.setDisplayName(value)
}
fun setCameraEnabled(value: Boolean) {
runtime.setCameraEnabled(value)
prefs.setCameraEnabled(value)
}
fun setLocationMode(mode: LocationMode) {
runtime.setLocationMode(mode)
prefs.setLocationMode(mode)
}
fun setLocationPreciseEnabled(value: Boolean) {
runtime.setLocationPreciseEnabled(value)
prefs.setLocationPreciseEnabled(value)
}
fun setPreventSleep(value: Boolean) {
runtime.setPreventSleep(value)
prefs.setPreventSleep(value)
}
fun setManualEnabled(value: Boolean) {
runtime.setManualEnabled(value)
prefs.setManualEnabled(value)
}
fun setManualHost(value: String) {
runtime.setManualHost(value)
prefs.setManualHost(value)
}
fun setManualPort(value: Int) {
runtime.setManualPort(value)
prefs.setManualPort(value)
}
fun setManualTls(value: Boolean) {
runtime.setManualTls(value)
prefs.setManualTls(value)
}
fun setGatewayToken(value: String) {
runtime.setGatewayToken(value)
prefs.setGatewayToken(value)
}
fun setGatewayBootstrapToken(value: String) {
runtime.setGatewayBootstrapToken(value)
prefs.setGatewayBootstrapToken(value)
}
fun setGatewayPassword(value: String) {
runtime.setGatewayPassword(value)
prefs.setGatewayPassword(value)
}
fun setOnboardingCompleted(value: Boolean) {
runtime.setOnboardingCompleted(value)
if (value) {
ensureRuntime()
}
prefs.setOnboardingCompleted(value)
}
fun setCanvasDebugStatusEnabled(value: Boolean) {
runtime.setCanvasDebugStatusEnabled(value)
prefs.setCanvasDebugStatusEnabled(value)
}
fun setVoiceScreenActive(active: Boolean) {
runtime.setVoiceScreenActive(active)
ensureRuntime().setVoiceScreenActive(active)
}
fun setMicEnabled(enabled: Boolean) {
runtime.setMicEnabled(enabled)
ensureRuntime().setMicEnabled(enabled)
}
fun setSpeakerEnabled(enabled: Boolean) {
runtime.setSpeakerEnabled(enabled)
ensureRuntime().setSpeakerEnabled(enabled)
}
fun refreshGatewayConnection() {
runtime.refreshGatewayConnection()
ensureRuntime().refreshGatewayConnection()
}
fun connect(endpoint: GatewayEndpoint) {
runtime.connect(endpoint)
ensureRuntime().connect(endpoint)
}
fun connectManual() {
runtime.connectManual()
ensureRuntime().connectManual()
}
fun disconnect() {
runtime.disconnect()
runtimeRef.value?.disconnect()
}
fun acceptGatewayTrustPrompt() {
runtime.acceptGatewayTrustPrompt()
runtimeRef.value?.acceptGatewayTrustPrompt()
}
fun declineGatewayTrustPrompt() {
runtime.declineGatewayTrustPrompt()
runtimeRef.value?.declineGatewayTrustPrompt()
}
fun handleCanvasA2UIActionFromWebView(payloadJson: String) {
runtime.handleCanvasA2UIActionFromWebView(payloadJson)
ensureRuntime().handleCanvasA2UIActionFromWebView(payloadJson)
}
fun requestCanvasRehydrate(source: String = "screen_tab") {
runtime.requestCanvasRehydrate(source = source, force = true)
ensureRuntime().requestCanvasRehydrate(source = source, force = true)
}
fun refreshHomeCanvasOverviewIfConnected() {
runtime.refreshHomeCanvasOverviewIfConnected()
ensureRuntime().refreshHomeCanvasOverviewIfConnected()
}
fun loadChat(sessionKey: String) {
runtime.loadChat(sessionKey)
ensureRuntime().loadChat(sessionKey)
}
fun refreshChat() {
runtime.refreshChat()
ensureRuntime().refreshChat()
}
fun refreshChatSessions(limit: Int? = null) {
runtime.refreshChatSessions(limit = limit)
ensureRuntime().refreshChatSessions(limit = limit)
}
fun setChatThinkingLevel(level: String) {
runtime.setChatThinkingLevel(level)
ensureRuntime().setChatThinkingLevel(level)
}
fun switchChatSession(sessionKey: String) {
runtime.switchChatSession(sessionKey)
ensureRuntime().switchChatSession(sessionKey)
}
fun abortChat() {
runtime.abortChat()
ensureRuntime().abortChat()
}
fun sendChat(message: String, thinking: String, attachments: List<OutgoingAttachment>) {
runtime.sendChat(message = message, thinking = thinking, attachments = attachments)
ensureRuntime().sendChat(message = message, thinking = thinking, attachments = attachments)
}
}

View File

@ -4,7 +4,18 @@ import android.app.Application
import android.os.StrictMode
class NodeApp : Application() {
val runtime: NodeRuntime by lazy { NodeRuntime(this) }
val prefs: SecurePrefs by lazy { SecurePrefs(this) }
@Volatile private var runtimeInstance: NodeRuntime? = null
fun ensureRuntime(): NodeRuntime {
runtimeInstance?.let { return it }
return synchronized(this) {
runtimeInstance ?: NodeRuntime(this, prefs).also { runtimeInstance = it }
}
}
fun peekRuntime(): NodeRuntime? = runtimeInstance
override fun onCreate() {
super.onCreate()

View File

@ -28,7 +28,11 @@ class NodeForegroundService : Service() {
val initial = buildNotification(title = "OpenClaw Node", text = "Starting…")
startForegroundWithTypes(notification = initial)
val runtime = (application as NodeApp).runtime
val runtime = (application as NodeApp).peekRuntime()
if (runtime == null) {
stopSelf()
return
}
notificationJob =
scope.launch {
combine(
@ -59,7 +63,7 @@ class NodeForegroundService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
when (intent?.action) {
ACTION_STOP -> {
(application as NodeApp).runtime.disconnect()
(application as NodeApp).peekRuntime()?.disconnect()
stopSelf()
return START_NOT_STICKY
}

View File

@ -43,11 +43,12 @@ import kotlinx.serialization.json.buildJsonObject
import java.util.UUID
import java.util.concurrent.atomic.AtomicLong
class NodeRuntime(context: Context) {
class NodeRuntime(
context: Context,
val prefs: SecurePrefs = SecurePrefs(context.applicationContext),
) {
private val appContext = context.applicationContext
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
val prefs = SecurePrefs(appContext)
private val deviceAuthStore = DeviceAuthStore(prefs)
val canvas = CanvasController()
val camera = CameraCaptureManager(appContext)

View File

@ -265,7 +265,7 @@ class ChatController(
}
val historyJson = session.request("chat.history", """{"sessionKey":"$key"}""")
val history = parseHistory(historyJson, sessionKey = key)
val history = parseHistory(historyJson, sessionKey = key, previousMessages = _messages.value)
_messages.value = history.messages
_sessionId.value = history.sessionId
history.thinkingLevel?.trim()?.takeIf { it.isNotEmpty() }?.let { _thinkingLevel.value = it }
@ -336,7 +336,7 @@ class ChatController(
try {
val historyJson =
session.request("chat.history", """{"sessionKey":"${_sessionKey.value}"}""")
val history = parseHistory(historyJson, sessionKey = _sessionKey.value)
val history = parseHistory(historyJson, sessionKey = _sessionKey.value, previousMessages = _messages.value)
_messages.value = history.messages
_sessionId.value = history.sessionId
history.thinkingLevel?.trim()?.takeIf { it.isNotEmpty() }?.let { _thinkingLevel.value = it }
@ -450,7 +450,11 @@ class ChatController(
}
}
private fun parseHistory(historyJson: String, sessionKey: String): ChatHistory {
private fun parseHistory(
historyJson: String,
sessionKey: String,
previousMessages: List<ChatMessage>,
): ChatHistory {
val root = json.parseToJsonElement(historyJson).asObjectOrNull() ?: return ChatHistory(sessionKey, null, null, emptyList())
val sid = root["sessionId"].asStringOrNull()
val thinkingLevel = root["thinkingLevel"].asStringOrNull()
@ -470,7 +474,12 @@ class ChatController(
)
}
return ChatHistory(sessionKey = sessionKey, sessionId = sid, thinkingLevel = thinkingLevel, messages = messages)
return ChatHistory(
sessionKey = sessionKey,
sessionId = sid,
thinkingLevel = thinkingLevel,
messages = reconcileMessageIds(previous = previousMessages, incoming = messages),
)
}
private fun parseMessageContent(el: JsonElement): ChatMessageContent? {
@ -519,6 +528,47 @@ class ChatController(
}
}
internal fun reconcileMessageIds(previous: List<ChatMessage>, incoming: List<ChatMessage>): List<ChatMessage> {
if (previous.isEmpty() || incoming.isEmpty()) return incoming
val idsByKey = LinkedHashMap<String, ArrayDeque<String>>()
for (message in previous) {
val key = messageIdentityKey(message) ?: continue
idsByKey.getOrPut(key) { ArrayDeque() }.addLast(message.id)
}
return incoming.map { message ->
val key = messageIdentityKey(message) ?: return@map message
val ids = idsByKey[key] ?: return@map message
val reusedId = ids.removeFirstOrNull() ?: return@map message
if (ids.isEmpty()) {
idsByKey.remove(key)
}
if (reusedId == message.id) return@map message
message.copy(id = reusedId)
}
}
internal fun messageIdentityKey(message: ChatMessage): String? {
val role = message.role.trim().lowercase()
if (role.isEmpty()) return null
val timestamp = message.timestampMs?.toString().orEmpty()
val contentFingerprint =
message.content.joinToString(separator = "\u001E") { part ->
listOf(
part.type.trim().lowercase(),
part.text?.trim().orEmpty(),
part.mimeType?.trim()?.lowercase().orEmpty(),
part.fileName?.trim().orEmpty(),
part.base64?.hashCode()?.toString().orEmpty(),
).joinToString(separator = "\u001F")
}
if (timestamp.isEmpty() && contentFingerprint.isEmpty()) return null
return listOf(role, timestamp, contentFingerprint).joinToString(separator = "|")
}
private fun JsonElement?.asObjectOrNull(): JsonObject? = this as? JsonObject
private fun JsonElement?.asArrayOrNull(): JsonArray? = this as? JsonArray

View File

@ -1,7 +1,5 @@
package ai.openclaw.app.ui.chat
import android.graphics.BitmapFactory
import android.util.Base64
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@ -28,8 +26,7 @@ internal fun rememberBase64ImageState(base64: String): Base64ImageState {
image =
withContext(Dispatchers.Default) {
try {
val bytes = Base64.decode(base64, Base64.DEFAULT)
val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size) ?: return@withContext null
val bitmap = decodeBase64Bitmap(base64) ?: return@withContext null
bitmap.asImageBitmap()
} catch (_: Throwable) {
null

View File

@ -0,0 +1,150 @@
package ai.openclaw.app.ui.chat
import android.content.ContentResolver
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.util.Base64
import android.util.LruCache
import androidx.core.graphics.scale
import ai.openclaw.app.node.JpegSizeLimiter
import java.io.ByteArrayOutputStream
import kotlin.math.max
import kotlin.math.roundToInt
private const val CHAT_ATTACHMENT_MAX_WIDTH = 1600
private const val CHAT_ATTACHMENT_MAX_BASE64_CHARS = 300 * 1024
private const val CHAT_ATTACHMENT_START_QUALITY = 85
private const val CHAT_DECODE_MAX_DIMENSION = 1600
private const val CHAT_IMAGE_CACHE_BYTES = 16 * 1024 * 1024
private val decodedBitmapCache =
object : LruCache<String, Bitmap>(CHAT_IMAGE_CACHE_BYTES) {
override fun sizeOf(key: String, value: Bitmap): Int = value.byteCount.coerceAtLeast(1)
}
internal fun loadSizedImageAttachment(resolver: ContentResolver, uri: Uri): PendingImageAttachment {
val fileName = normalizeAttachmentFileName((uri.lastPathSegment ?: "image").substringAfterLast('/'))
val bitmap = decodeScaledBitmap(resolver, uri, maxDimension = CHAT_ATTACHMENT_MAX_WIDTH)
if (bitmap == null) {
throw IllegalStateException("unsupported attachment")
}
val maxBytes = (CHAT_ATTACHMENT_MAX_BASE64_CHARS / 4) * 3
val encoded =
JpegSizeLimiter.compressToLimit(
initialWidth = bitmap.width,
initialHeight = bitmap.height,
startQuality = CHAT_ATTACHMENT_START_QUALITY,
maxBytes = maxBytes,
minSize = 240,
encode = { width, height, quality ->
val working =
if (width == bitmap.width && height == bitmap.height) {
bitmap
} else {
bitmap.scale(width, height, true)
}
try {
val out = ByteArrayOutputStream()
if (!working.compress(Bitmap.CompressFormat.JPEG, quality, out)) {
throw IllegalStateException("attachment encode failed")
}
out.toByteArray()
} finally {
if (working !== bitmap) {
working.recycle()
}
}
},
)
val base64 = Base64.encodeToString(encoded.bytes, Base64.NO_WRAP)
return PendingImageAttachment(
id = uri.toString() + "#" + System.currentTimeMillis().toString(),
fileName = fileName,
mimeType = "image/jpeg",
base64 = base64,
)
}
internal fun decodeBase64Bitmap(base64: String, maxDimension: Int = CHAT_DECODE_MAX_DIMENSION): Bitmap? {
val cacheKey = "$maxDimension:${base64.length}:${base64.hashCode()}"
decodedBitmapCache.get(cacheKey)?.let { return it }
val bytes = Base64.decode(base64, Base64.DEFAULT)
if (bytes.isEmpty()) return null
val bounds = BitmapFactory.Options().apply { inJustDecodeBounds = true }
BitmapFactory.decodeByteArray(bytes, 0, bytes.size, bounds)
if (bounds.outWidth <= 0 || bounds.outHeight <= 0) return null
val bitmap =
BitmapFactory.decodeByteArray(
bytes,
0,
bytes.size,
BitmapFactory.Options().apply {
inSampleSize = computeInSampleSize(bounds.outWidth, bounds.outHeight, maxDimension)
inPreferredConfig = Bitmap.Config.RGB_565
},
) ?: return null
decodedBitmapCache.put(cacheKey, bitmap)
return bitmap
}
internal fun computeInSampleSize(width: Int, height: Int, maxDimension: Int): Int {
if (width <= 0 || height <= 0 || maxDimension <= 0) return 1
var sample = 1
var longestEdge = max(width, height)
while (longestEdge > maxDimension && sample < 64) {
sample *= 2
longestEdge = max(width / sample, height / sample)
}
return sample.coerceAtLeast(1)
}
internal fun normalizeAttachmentFileName(raw: String): String {
val trimmed = raw.trim()
if (trimmed.isEmpty()) return "image.jpg"
val stem = trimmed.substringBeforeLast('.', missingDelimiterValue = trimmed).ifEmpty { "image" }
return "$stem.jpg"
}
private fun decodeScaledBitmap(
resolver: ContentResolver,
uri: Uri,
maxDimension: Int,
): Bitmap? {
val bounds = BitmapFactory.Options().apply { inJustDecodeBounds = true }
resolver.openInputStream(uri).use { input ->
if (input == null) return null
BitmapFactory.decodeStream(input, null, bounds)
}
if (bounds.outWidth <= 0 || bounds.outHeight <= 0) return null
val decoded =
resolver.openInputStream(uri).use { input ->
if (input == null) return null
BitmapFactory.decodeStream(
input,
null,
BitmapFactory.Options().apply {
inSampleSize = computeInSampleSize(bounds.outWidth, bounds.outHeight, maxDimension)
inPreferredConfig = Bitmap.Config.ARGB_8888
},
)
} ?: return null
val longestEdge = max(decoded.width, decoded.height)
if (longestEdge <= maxDimension) return decoded
val scale = maxDimension.toDouble() / longestEdge.toDouble()
val targetWidth = max(1, (decoded.width * scale).roundToInt())
val targetHeight = max(1, (decoded.height * scale).roundToInt())
val scaled = decoded.scale(targetWidth, targetHeight, true)
if (scaled !== decoded) {
decoded.recycle()
}
return scaled
}

View File

@ -6,12 +6,14 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@ -34,11 +36,19 @@ fun ChatMessageListCard(
modifier: Modifier = Modifier,
) {
val listState = rememberLazyListState()
val displayMessages = remember(messages) { messages.asReversed() }
val stream = streamingAssistantText?.trim()
// With reverseLayout the newest item is at index 0 (bottom of screen).
LaunchedEffect(messages.size, pendingRunCount, pendingToolCalls.size, streamingAssistantText) {
// New list items/tool rows should animate into view, but token streaming should not restart
// that animation on every delta.
LaunchedEffect(messages.size, pendingRunCount, pendingToolCalls.size) {
listState.animateScrollToItem(index = 0)
}
LaunchedEffect(stream) {
if (!stream.isNullOrEmpty()) {
listState.scrollToItem(index = 0)
}
}
Box(modifier = modifier.fillMaxWidth()) {
LazyColumn(
@ -50,8 +60,6 @@ fun ChatMessageListCard(
) {
// With reverseLayout = true, index 0 renders at the BOTTOM.
// So we emit newest items first: streaming → tools → typing → messages (newest→oldest).
val stream = streamingAssistantText?.trim()
if (!stream.isNullOrEmpty()) {
item(key = "stream") {
ChatStreamingAssistantBubble(text = stream)
@ -70,8 +78,8 @@ fun ChatMessageListCard(
}
}
items(count = messages.size, key = { idx -> messages[messages.size - 1 - idx].id }) { idx ->
ChatMessageBubble(message = messages[messages.size - 1 - idx])
items(items = displayMessages, key = { it.id }) { message ->
ChatMessageBubble(message = message)
}
}

View File

@ -1,8 +1,5 @@
package ai.openclaw.app.ui.chat
import android.content.ContentResolver
import android.net.Uri
import android.util.Base64
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.BorderStroke
@ -47,7 +44,6 @@ import ai.openclaw.app.ui.mobileDanger
import ai.openclaw.app.ui.mobileDangerSoft
import ai.openclaw.app.ui.mobileText
import ai.openclaw.app.ui.mobileTextSecondary
import java.io.ByteArrayOutputStream
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -83,7 +79,7 @@ fun ChatSheetContent(viewModel: MainViewModel) {
val next =
uris.take(8).mapNotNull { uri ->
try {
loadImageAttachment(resolver, uri)
loadSizedImageAttachment(resolver, uri)
} catch (_: Throwable) {
null
}
@ -160,7 +156,10 @@ private fun ChatThreadSelector(
mainSessionKey: String,
onSelectSession: (String) -> Unit,
) {
val sessionOptions = resolveSessionChoices(sessionKey, sessions, mainSessionKey = mainSessionKey)
val sessionOptions =
remember(sessionKey, sessions, mainSessionKey) {
resolveSessionChoices(sessionKey, sessions, mainSessionKey = mainSessionKey)
}
Row(
modifier = Modifier.fillMaxWidth().horizontalScroll(rememberScrollState()),
@ -214,24 +213,3 @@ data class PendingImageAttachment(
val mimeType: String,
val base64: String,
)
private suspend fun loadImageAttachment(resolver: ContentResolver, uri: Uri): PendingImageAttachment {
val mimeType = resolver.getType(uri) ?: "image/*"
val fileName = (uri.lastPathSegment ?: "image").substringAfterLast('/')
val bytes =
withContext(Dispatchers.IO) {
resolver.openInputStream(uri)?.use { input ->
val out = ByteArrayOutputStream()
input.copyTo(out)
out.toByteArray()
} ?: ByteArray(0)
}
if (bytes.isEmpty()) throw IllegalStateException("empty attachment")
val base64 = Base64.encodeToString(bytes, Base64.NO_WRAP)
return PendingImageAttachment(
id = uri.toString() + "#" + System.currentTimeMillis().toString(),
fileName = fileName,
mimeType = mimeType,
base64 = base64,
)
}

View File

@ -0,0 +1,81 @@
package ai.openclaw.app.chat
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
import org.junit.Test
class ChatControllerMessageIdentityTest {
@Test
fun reconcileMessageIdsReusesMatchingIdsAcrossHistoryReload() {
val previous =
listOf(
ChatMessage(
id = "msg-1",
role = "assistant",
content = listOf(ChatMessageContent(type = "text", text = "hello")),
timestampMs = 1000L,
),
ChatMessage(
id = "msg-2",
role = "user",
content = listOf(ChatMessageContent(type = "text", text = "hi")),
timestampMs = 2000L,
),
)
val incoming =
listOf(
ChatMessage(
id = "new-1",
role = "assistant",
content = listOf(ChatMessageContent(type = "text", text = "hello")),
timestampMs = 1000L,
),
ChatMessage(
id = "new-2",
role = "user",
content = listOf(ChatMessageContent(type = "text", text = "hi")),
timestampMs = 2000L,
),
)
val reconciled = reconcileMessageIds(previous = previous, incoming = incoming)
assertEquals(listOf("msg-1", "msg-2"), reconciled.map { it.id })
}
@Test
fun reconcileMessageIdsLeavesNewMessagesUntouched() {
val previous =
listOf(
ChatMessage(
id = "msg-1",
role = "assistant",
content = listOf(ChatMessageContent(type = "text", text = "hello")),
timestampMs = 1000L,
),
)
val incoming =
listOf(
ChatMessage(
id = "new-1",
role = "assistant",
content = listOf(ChatMessageContent(type = "text", text = "hello")),
timestampMs = 1000L,
),
ChatMessage(
id = "new-2",
role = "assistant",
content = listOf(ChatMessageContent(type = "text", text = "new reply")),
timestampMs = 3000L,
),
)
val reconciled = reconcileMessageIds(previous = previous, incoming = incoming)
assertEquals("msg-1", reconciled[0].id)
assertEquals("new-2", reconciled[1].id)
assertNotEquals(reconciled[0].id, reconciled[1].id)
}
}

View File

@ -0,0 +1,18 @@
package ai.openclaw.app.ui.chat
import org.junit.Assert.assertEquals
import org.junit.Test
class ChatImageCodecTest {
@Test
fun computeInSampleSizeCapsLongestEdge() {
assertEquals(4, computeInSampleSize(width = 4032, height = 3024, maxDimension = 1600))
assertEquals(1, computeInSampleSize(width = 800, height = 600, maxDimension = 1600))
}
@Test
fun normalizeAttachmentFileNameForcesJpegExtension() {
assertEquals("photo.jpg", normalizeAttachmentFileName("photo.png"))
assertEquals("image.jpg", normalizeAttachmentFileName(""))
}
}

View File

@ -81,22 +81,23 @@ final class CanvasSchemeHandler: NSObject, WKURLSchemeHandler {
return self.html("Not Found", title: "Canvas: 404")
}
// Directory traversal guard: served files must live under the session root.
let standardizedRoot = sessionRoot.standardizedFileURL
let standardizedFile = fileURL.standardizedFileURL
guard standardizedFile.path.hasPrefix(standardizedRoot.path) else {
// Resolve symlinks before enforcing the session-root boundary so links inside
// the canvas tree cannot escape to arbitrary host files.
let resolvedRoot = sessionRoot.resolvingSymlinksInPath().standardizedFileURL
let resolvedFile = fileURL.resolvingSymlinksInPath().standardizedFileURL
guard self.isFileURL(resolvedFile, withinDirectory: resolvedRoot) else {
return self.html("Forbidden", title: "Canvas: 403")
}
do {
let data = try Data(contentsOf: standardizedFile)
let mime = CanvasScheme.mimeType(forExtension: standardizedFile.pathExtension)
let servedPath = standardizedFile.path
let data = try Data(contentsOf: resolvedFile)
let mime = CanvasScheme.mimeType(forExtension: resolvedFile.pathExtension)
let servedPath = resolvedFile.path
canvasLogger.debug(
"served \(session, privacy: .public)/\(path, privacy: .public) -> \(servedPath, privacy: .public)")
return CanvasResponse(mime: mime, data: data)
} catch {
let failedPath = standardizedFile.path
let failedPath = resolvedFile.path
let errorText = error.localizedDescription
canvasLogger
.error(
@ -145,6 +146,11 @@ final class CanvasSchemeHandler: NSObject, WKURLSchemeHandler {
return nil
}
private func isFileURL(_ fileURL: URL, withinDirectory rootURL: URL) -> Bool {
let rootPath = rootURL.path.hasSuffix("/") ? rootURL.path : rootURL.path + "/"
return fileURL.path == rootURL.path || fileURL.path.hasPrefix(rootPath)
}
private func html(_ body: String, title: String = "Canvas") -> CanvasResponse {
let html = """
<!doctype html>

View File

@ -89,6 +89,20 @@ private func readLineFromHandle(_ handle: FileHandle, maxBytes: Int) throws -> S
return String(data: lineData, encoding: .utf8)
}
func timingSafeHexStringEquals(_ lhs: String, _ rhs: String) -> Bool {
let lhsBytes = Array(lhs.utf8)
let rhsBytes = Array(rhs.utf8)
guard lhsBytes.count == rhsBytes.count else {
return false
}
var diff: UInt8 = 0
for index in lhsBytes.indices {
diff |= lhsBytes[index] ^ rhsBytes[index]
}
return diff == 0
}
enum ExecApprovalsSocketClient {
private struct TimeoutError: LocalizedError {
var message: String
@ -854,7 +868,7 @@ private final class ExecApprovalsSocketServer: @unchecked Sendable {
error: ExecHostError(code: "INVALID_REQUEST", message: "expired request", reason: "ttl"))
}
let expected = self.hmacHex(nonce: request.nonce, ts: request.ts, requestJson: request.requestJson)
if expected != request.hmac {
if !timingSafeHexStringEquals(expected, request.hmac) {
return ExecHostResponse(
type: "exec-res",
id: request.id,

View File

@ -23,7 +23,12 @@ enum HostEnvSecurityPolicy {
"PS4",
"GCONV_PATH",
"IFS",
"SSLKEYLOGFILE"
"SSLKEYLOGFILE",
"JAVA_TOOL_OPTIONS",
"_JAVA_OPTIONS",
"JDK_JAVA_OPTIONS",
"PYTHONBREAKPOINT",
"DOTNET_STARTUP_HOOKS"
]
static let blockedOverrideKeys: Set<String> = [

View File

@ -26,7 +26,12 @@ enum LaunchAgentManager {
}
private static func writePlist(bundlePath: String) {
let plist = """
let plist = self.plistContents(bundlePath: bundlePath)
try? plist.write(to: self.plistURL, atomically: true, encoding: .utf8)
}
static func plistContents(bundlePath: String) -> String {
"""
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
@ -41,8 +46,6 @@ enum LaunchAgentManager {
<string>\(FileManager().homeDirectoryForCurrentUser.path)</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
@ -55,7 +58,6 @@ enum LaunchAgentManager {
</dict>
</plist>
"""
try? plist.write(to: self.plistURL, atomically: true, encoding: .utf8)
}
@discardableResult

View File

@ -1099,38 +1099,33 @@ extension MenuSessionsInjector {
// MARK: - Width + placement
private func findInsertIndex(in menu: NSMenu) -> Int? {
// Insert right before the separator above "Send Heartbeats".
if let idx = menu.items.firstIndex(where: { $0.title == "Send Heartbeats" }) {
if let sepIdx = menu.items[..<idx].lastIndex(where: { $0.isSeparatorItem }) {
return sepIdx
}
return idx
}
if let sepIdx = menu.items.firstIndex(where: { $0.isSeparatorItem }) {
return sepIdx
}
if menu.items.count >= 1 { return 1 }
return menu.items.count
self.findDynamicSectionInsertIndex(in: menu)
}
private func findNodesInsertIndex(in menu: NSMenu) -> Int? {
if let idx = menu.items.firstIndex(where: { $0.title == "Send Heartbeats" }) {
if let sepIdx = menu.items[..<idx].lastIndex(where: { $0.isSeparatorItem }) {
return sepIdx
}
return idx
self.findDynamicSectionInsertIndex(in: menu)
}
private func findDynamicSectionInsertIndex(in menu: NSMenu) -> Int? {
// Keep controls and action buttons visible by inserting dynamic rows at the
// built-in footer boundary, not by matching localized menu item titles.
if let footerSeparatorIndex = menu.items.lastIndex(where: { item in
item.isSeparatorItem && !self.isInjectedItem(item)
}) {
return footerSeparatorIndex
}
if let sepIdx = menu.items.firstIndex(where: { $0.isSeparatorItem }) {
return sepIdx
if let firstBaseItemIndex = menu.items.firstIndex(where: { !self.isInjectedItem($0) }) {
return min(firstBaseItemIndex + 1, menu.items.count)
}
if menu.items.count >= 1 { return 1 }
return menu.items.count
}
private func isInjectedItem(_ item: NSMenuItem) -> Bool {
item.tag == self.tag || item.tag == self.nodesTag
}
private func initialWidth(for menu: NSMenu) -> CGFloat {
if let openWidth = self.menuOpenWidth {
return max(300, openWidth)
@ -1236,5 +1231,13 @@ extension MenuSessionsInjector {
func injectForTesting(into menu: NSMenu) {
self.inject(into: menu)
}
func testingFindInsertIndex(in menu: NSMenu) -> Int? {
self.findInsertIndex(in: menu)
}
func testingFindNodesInsertIndex(in menu: NSMenu) -> Int? {
self.findNodesInsertIndex(in: menu)
}
}
#endif

View File

@ -6,7 +6,7 @@ enum NodeServiceManager {
static func start() async -> String? {
let result = await self.runServiceCommandResult(
["node", "start"],
["start"],
timeout: 20,
quiet: false)
if let error = self.errorMessage(from: result, treatNotLoadedAsError: true) {
@ -18,7 +18,7 @@ enum NodeServiceManager {
static func stop() async -> String? {
let result = await self.runServiceCommandResult(
["node", "stop"],
["stop"],
timeout: 15,
quiet: false)
if let error = self.errorMessage(from: result, treatNotLoadedAsError: false) {
@ -30,6 +30,14 @@ enum NodeServiceManager {
}
extension NodeServiceManager {
private static func serviceCommand(_ args: [String]) -> [String] {
CommandResolver.openclawCommand(
subcommand: "node",
extraArgs: self.withJsonFlag(args),
// Service management must always run locally, even if remote mode is configured.
configRoot: ["gateway": ["mode": "local"]])
}
private struct CommandResult {
let success: Bool
let payload: Data?
@ -52,11 +60,7 @@ extension NodeServiceManager {
timeout: Double,
quiet: Bool) async -> CommandResult
{
let command = CommandResolver.openclawCommand(
subcommand: "service",
extraArgs: self.withJsonFlag(args),
// Service management must always run locally, even if remote mode is configured.
configRoot: ["gateway": ["mode": "local"]])
let command = self.serviceCommand(args)
var env = ProcessInfo.processInfo.environment
env["PATH"] = CommandResolver.preferredPaths().joined(separator: ":")
let response = await ShellExecutor.runDetailed(command: command, cwd: nil, env: env, timeout: timeout)
@ -136,3 +140,11 @@ extension NodeServiceManager {
TextSummarySupport.summarizeLastLine(text)
}
}
#if DEBUG
extension NodeServiceManager {
static func _testServiceCommand(_ args: [String]) -> [String] {
self.serviceCommand(args)
}
}
#endif

View File

@ -515,6 +515,8 @@ public struct PollParams: Codable, Sendable {
public struct AgentParams: Codable, Sendable {
public let message: String
public let agentid: String?
public let provider: String?
public let model: String?
public let to: String?
public let replyto: String?
public let sessionid: String?
@ -542,6 +544,8 @@ public struct AgentParams: Codable, Sendable {
public init(
message: String,
agentid: String?,
provider: String?,
model: String?,
to: String?,
replyto: String?,
sessionid: String?,
@ -568,6 +572,8 @@ public struct AgentParams: Codable, Sendable {
{
self.message = message
self.agentid = agentid
self.provider = provider
self.model = model
self.to = to
self.replyto = replyto
self.sessionid = sessionid
@ -596,6 +602,8 @@ public struct AgentParams: Codable, Sendable {
private enum CodingKeys: String, CodingKey {
case message
case agentid = "agentId"
case provider
case model
case to
case replyto = "replyTo"
case sessionid = "sessionId"

View File

@ -0,0 +1,21 @@
import Testing
@testable import OpenClaw
struct ExecApprovalsSocketAuthTests {
@Test
func `timing safe hex compare matches equal strings`() {
#expect(timingSafeHexStringEquals(String(repeating: "a", count: 64), String(repeating: "a", count: 64)))
}
@Test
func `timing safe hex compare rejects mismatched strings`() {
let expected = String(repeating: "a", count: 63) + "b"
let provided = String(repeating: "a", count: 63) + "c"
#expect(!timingSafeHexStringEquals(expected, provided))
}
@Test
func `timing safe hex compare rejects different length strings`() {
#expect(!timingSafeHexStringEquals(String(repeating: "a", count: 64), "deadbeef"))
}
}

View File

@ -0,0 +1,19 @@
import Foundation
import Testing
@testable import OpenClaw
struct LaunchAgentManagerTests {
@Test func `launch at login plist does not keep app alive after manual quit`() throws {
let plist = LaunchAgentManager.plistContents(bundlePath: "/Applications/OpenClaw.app")
let data = try #require(plist.data(using: .utf8))
let object = try #require(
PropertyListSerialization.propertyList(from: data, format: nil) as? [String: Any]
)
#expect(object["RunAtLoad"] as? Bool == true)
#expect(object["KeepAlive"] == nil)
let args = try #require(object["ProgramArguments"] as? [String])
#expect(args == ["/Applications/OpenClaw.app/Contents/MacOS/OpenClaw"])
}
}

View File

@ -216,6 +216,32 @@ struct LowCoverageHelperTests {
#expect(handler._testTextEncodingName(for: "application/octet-stream") == nil)
}
@Test @MainActor func `canvas scheme handler blocks symlink escapes`() throws {
let root = FileManager().temporaryDirectory
.appendingPathComponent("canvas-\(UUID().uuidString)", isDirectory: true)
defer { try? FileManager().removeItem(at: root) }
try FileManager().createDirectory(at: root, withIntermediateDirectories: true)
let session = root.appendingPathComponent("main", isDirectory: true)
try FileManager().createDirectory(at: session, withIntermediateDirectories: true)
let outside = root.deletingLastPathComponent().appendingPathComponent("canvas-secret-\(UUID().uuidString).txt")
defer { try? FileManager().removeItem(at: outside) }
try "top-secret".write(to: outside, atomically: true, encoding: .utf8)
let symlink = session.appendingPathComponent("index.html")
try FileManager().createSymbolicLink(at: symlink, withDestinationURL: outside)
let handler = CanvasSchemeHandler(root: root)
let url = try #require(CanvasScheme.makeURL(session: "main", path: "index.html"))
let response = handler._testResponse(for: url)
let body = String(data: response.data, encoding: .utf8) ?? ""
#expect(response.mime == "text/html")
#expect(body.contains("Forbidden"))
#expect(!body.contains("top-secret"))
}
@Test @MainActor func `menu context card injector inserts and finds index`() {
let injector = MenuContextCardInjector()
let menu = NSMenu()

View File

@ -5,7 +5,26 @@ import Testing
@Suite(.serialized)
@MainActor
struct MenuSessionsInjectorTests {
@Test func `injects disconnected message`() {
@Test func anchorsDynamicRowsBelowControlsAndActions() throws {
let injector = MenuSessionsInjector()
let menu = NSMenu()
menu.addItem(NSMenuItem(title: "Header", action: nil, keyEquivalent: ""))
menu.addItem(.separator())
menu.addItem(NSMenuItem(title: "Send Heartbeats", action: nil, keyEquivalent: ""))
menu.addItem(NSMenuItem(title: "Browser Control", action: nil, keyEquivalent: ""))
menu.addItem(.separator())
menu.addItem(NSMenuItem(title: "Open Dashboard", action: nil, keyEquivalent: ""))
menu.addItem(NSMenuItem(title: "Open Chat", action: nil, keyEquivalent: ""))
menu.addItem(.separator())
menu.addItem(NSMenuItem(title: "Settings…", action: nil, keyEquivalent: ""))
let footerSeparatorIndex = try #require(menu.items.lastIndex(where: { $0.isSeparatorItem }))
#expect(injector.testingFindInsertIndex(in: menu) == footerSeparatorIndex)
#expect(injector.testingFindNodesInsertIndex(in: menu) == footerSeparatorIndex)
}
@Test func injectsDisconnectedMessage() {
let injector = MenuSessionsInjector()
injector.setTestingControlChannelConnected(false)
injector.setTestingSnapshot(nil, errorText: nil)
@ -19,7 +38,7 @@ struct MenuSessionsInjectorTests {
#expect(menu.items.contains { $0.tag == 9_415_557 })
}
@Test func `injects session rows`() {
@Test func injectsSessionRows() throws {
let injector = MenuSessionsInjector()
injector.setTestingControlChannelConnected(true)
@ -88,10 +107,22 @@ struct MenuSessionsInjectorTests {
menu.addItem(NSMenuItem(title: "Header", action: nil, keyEquivalent: ""))
menu.addItem(.separator())
menu.addItem(NSMenuItem(title: "Send Heartbeats", action: nil, keyEquivalent: ""))
menu.addItem(NSMenuItem(title: "Browser Control", action: nil, keyEquivalent: ""))
menu.addItem(.separator())
menu.addItem(NSMenuItem(title: "Open Dashboard", action: nil, keyEquivalent: ""))
menu.addItem(.separator())
menu.addItem(NSMenuItem(title: "Settings…", action: nil, keyEquivalent: ""))
injector.injectForTesting(into: menu)
#expect(menu.items.contains { $0.tag == 9_415_557 })
#expect(menu.items.contains { $0.tag == 9_415_557 && $0.isSeparatorItem })
let sendHeartbeatsIndex = try #require(menu.items.firstIndex(where: { $0.title == "Send Heartbeats" }))
let openDashboardIndex = try #require(menu.items.firstIndex(where: { $0.title == "Open Dashboard" }))
let firstInjectedIndex = try #require(menu.items.firstIndex(where: { $0.tag == 9_415_557 }))
let settingsIndex = try #require(menu.items.firstIndex(where: { $0.title == "Settings…" }))
#expect(sendHeartbeatsIndex < firstInjectedIndex)
#expect(openDashboardIndex < firstInjectedIndex)
#expect(firstInjectedIndex < settingsIndex)
}
@Test func `cost usage submenu does not use injector delegate`() {

View File

@ -0,0 +1,19 @@
import Foundation
import Testing
@testable import OpenClaw
@Suite(.serialized) struct NodeServiceManagerTests {
@Test func `builds node service commands with current CLI shape`() throws {
let tmp = try makeTempDirForTests()
CommandResolver.setProjectRoot(tmp.path)
let openclawPath = tmp.appendingPathComponent("node_modules/.bin/openclaw")
try makeExecutableForTests(at: openclawPath)
let start = NodeServiceManager._testServiceCommand(["start"])
#expect(start == [openclawPath.path, "node", "start", "--json"])
let stop = NodeServiceManager._testServiceCommand(["stop"])
#expect(stop == [openclawPath.path, "node", "stop", "--json"])
}
}

View File

@ -515,6 +515,8 @@ public struct PollParams: Codable, Sendable {
public struct AgentParams: Codable, Sendable {
public let message: String
public let agentid: String?
public let provider: String?
public let model: String?
public let to: String?
public let replyto: String?
public let sessionid: String?
@ -542,6 +544,8 @@ public struct AgentParams: Codable, Sendable {
public init(
message: String,
agentid: String?,
provider: String?,
model: String?,
to: String?,
replyto: String?,
sessionid: String?,
@ -568,6 +572,8 @@ public struct AgentParams: Codable, Sendable {
{
self.message = message
self.agentid = agentid
self.provider = provider
self.model = model
self.to = to
self.replyto = replyto
self.sessionid = sessionid
@ -596,6 +602,8 @@ public struct AgentParams: Codable, Sendable {
private enum CodingKeys: String, CodingKey {
case message
case agentid = "agentId"
case provider
case model
case to
case replyto = "replyTo"
case sessionid = "sessionId"

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
{"generatedBy":"scripts/generate-config-doc-baseline.ts","recordType":"meta","totalPaths":5098}
{"generatedBy":"scripts/generate-config-doc-baseline.ts","recordType":"meta","totalPaths":5476}
{"recordType":"path","path":"acp","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"ACP","help":"ACP runtime controls for enabling dispatch, selecting backends, constraining allowed agent targets, and tuning streamed turn projection behavior.","hasChildren":true}
{"recordType":"path","path":"acp.allowedAgents","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"ACP Allowed Agents","help":"Allowlist of ACP target agent ids permitted for ACP runtime sessions. Empty means no additional allowlist restriction.","hasChildren":true}
{"recordType":"path","path":"acp.allowedAgents.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@ -150,6 +150,10 @@
{"recordType":"path","path":"agents.defaults.humanDelay.maxMs","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance"],"label":"Human Delay Max (ms)","help":"Maximum delay in ms for custom humanDelay (default: 2500).","hasChildren":false}
{"recordType":"path","path":"agents.defaults.humanDelay.minMs","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Human Delay Min (ms)","help":"Minimum delay in ms for custom humanDelay (default: 800).","hasChildren":false}
{"recordType":"path","path":"agents.defaults.humanDelay.mode","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Human Delay Mode","help":"Delay style for block replies (\"off\", \"natural\", \"custom\").","hasChildren":false}
{"recordType":"path","path":"agents.defaults.imageGenerationModel","kind":"core","type":["object","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"agents.defaults.imageGenerationModel.fallbacks","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["media","reliability"],"label":"Image Generation Model Fallbacks","help":"Ordered fallback image-generation models (provider/model).","hasChildren":true}
{"recordType":"path","path":"agents.defaults.imageGenerationModel.fallbacks.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"agents.defaults.imageGenerationModel.primary","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["media"],"label":"Image Generation Model","help":"Optional image-generation model (provider/model) used by the shared image generation capability.","hasChildren":false}
{"recordType":"path","path":"agents.defaults.imageMaxDimensionPx","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["media","performance"],"label":"Image Max Dimension (px)","help":"Max image side length in pixels when sanitizing transcript/tool-result image payloads (default: 1200).","hasChildren":false}
{"recordType":"path","path":"agents.defaults.imageModel","kind":"core","type":["object","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"agents.defaults.imageModel.fallbacks","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["media","models","reliability"],"label":"Image Model Fallbacks","help":"Ordered fallback image models (provider/model).","hasChildren":true}
@ -707,7 +711,8 @@
{"recordType":"path","path":"browser.profiles.*.cdpPort","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"Browser Profile CDP Port","help":"Per-profile local CDP port used when connecting to browser instances by port instead of URL. Use unique ports per profile to avoid connection collisions.","hasChildren":false}
{"recordType":"path","path":"browser.profiles.*.cdpUrl","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"Browser Profile CDP URL","help":"Per-profile CDP websocket URL used for explicit remote browser routing by profile name. Use this when profile connections terminate on remote hosts or tunnels.","hasChildren":false}
{"recordType":"path","path":"browser.profiles.*.color","kind":"core","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"Browser Profile Accent Color","help":"Per-profile accent color for visual differentiation in dashboards and browser-related UI hints. Use distinct colors for high-signal operator recognition of active profiles.","hasChildren":false}
{"recordType":"path","path":"browser.profiles.*.driver","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"Browser Profile Driver","help":"Per-profile browser driver mode. Use \"openclaw\" (or legacy \"clawd\") for CDP-based profiles, or use \"existing-session\" for host-local Chrome MCP attachment.","hasChildren":false}
{"recordType":"path","path":"browser.profiles.*.driver","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"Browser Profile Driver","help":"Per-profile browser driver mode. Use \"openclaw\" (or legacy \"clawd\") for CDP-based profiles, or use \"existing-session\" for host-local Chrome DevTools MCP attachment.","hasChildren":false}
{"recordType":"path","path":"browser.profiles.*.userDataDir","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"Browser Profile User Data Dir","help":"Per-profile Chromium user data directory for existing-session attachment through Chrome DevTools MCP. Use this for host-local Brave, Edge, Chromium, or non-default Chrome profiles when the built-in auto-connect path would pick the wrong browser data directory.","hasChildren":false}
{"recordType":"path","path":"browser.remoteCdpHandshakeTimeoutMs","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance"],"label":"Remote CDP Handshake Timeout (ms)","help":"Timeout in milliseconds for post-connect CDP handshake readiness checks against remote browser targets. Raise this for slow-start remote browsers and lower to fail fast in automation loops.","hasChildren":false}
{"recordType":"path","path":"browser.remoteCdpTimeoutMs","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance"],"label":"Remote CDP Timeout (ms)","help":"Timeout in milliseconds for connecting to a remote CDP endpoint before failing the browser attach attempt. Increase for high-latency tunnels, or lower for faster failure detection.","hasChildren":false}
{"recordType":"path","path":"browser.snapshotDefaults","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Browser Snapshot Defaults","help":"Default snapshot capture configuration used when callers do not provide explicit snapshot options. Tune this for consistent capture behavior across channels and automation paths.","hasChildren":true}
@ -1046,6 +1051,17 @@
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.elevenlabs.voiceSettings.useSpeakerBoost","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.maxTextLength","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.lang","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.outputFormat","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.pitch","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.proxy","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.rate","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.saveSubtitles","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.timeoutMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.voice","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.microsoft.volume","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.mode","kind":"channel","type":"string","required":false,"enumValues":["final","all"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.modelOverrides","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.modelOverrides.allowModelId","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@ -1067,7 +1083,7 @@
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.openai.speed","kind":"channel","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.openai.voice","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.prefsPath","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.provider","kind":"channel","type":"string","required":false,"enumValues":["elevenlabs","openai","edge"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.provider","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.summaryModel","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.accounts.*.voice.tts.timeoutMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.ackReaction","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@ -1301,6 +1317,17 @@
{"recordType":"path","path":"channels.discord.voice.tts.elevenlabs.voiceSettings.useSpeakerBoost","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.maxTextLength","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.microsoft","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.lang","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.outputFormat","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.pitch","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.proxy","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.rate","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.saveSubtitles","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.timeoutMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.voice","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.microsoft.volume","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.mode","kind":"channel","type":"string","required":false,"enumValues":["final","all"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.modelOverrides","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"channels.discord.voice.tts.modelOverrides.allowModelId","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@ -1322,7 +1349,7 @@
{"recordType":"path","path":"channels.discord.voice.tts.openai.speed","kind":"channel","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.openai.voice","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.prefsPath","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.provider","kind":"channel","type":"string","required":false,"enumValues":["elevenlabs","openai","edge"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.provider","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.summaryModel","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.discord.voice.tts.timeoutMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.feishu","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["channels","network"],"label":"Feishu","help":"飞书/Lark enterprise messaging.","hasChildren":true}
@ -2059,6 +2086,11 @@
{"recordType":"path","path":"channels.mattermost.accounts.*.commands.nativeSkills","kind":"channel","type":["boolean","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.mattermost.accounts.*.configWrites","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.mattermost.accounts.*.dangerouslyAllowNameMatching","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.mattermost.accounts.*.dmChannelRetry","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"channels.mattermost.accounts.*.dmChannelRetry.initialDelayMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.mattermost.accounts.*.dmChannelRetry.maxDelayMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.mattermost.accounts.*.dmChannelRetry.maxRetries","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.mattermost.accounts.*.dmChannelRetry.timeoutMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.mattermost.accounts.*.dmPolicy","kind":"channel","type":"string","required":true,"enumValues":["pairing","allowlist","open","disabled"],"defaultValue":"pairing","deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.mattermost.accounts.*.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.mattermost.accounts.*.groupAllowFrom","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
@ -2103,6 +2135,11 @@
{"recordType":"path","path":"channels.mattermost.configWrites","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["channels","network"],"label":"Mattermost Config Writes","help":"Allow Mattermost to write config in response to channel events/commands (default: true).","hasChildren":false}
{"recordType":"path","path":"channels.mattermost.dangerouslyAllowNameMatching","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.mattermost.defaultAccount","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.mattermost.dmChannelRetry","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"channels.mattermost.dmChannelRetry.initialDelayMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.mattermost.dmChannelRetry.maxDelayMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.mattermost.dmChannelRetry.maxRetries","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.mattermost.dmChannelRetry.timeoutMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.mattermost.dmPolicy","kind":"channel","type":"string","required":true,"enumValues":["pairing","allowlist","open","disabled"],"defaultValue":"pairing","deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.mattermost.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.mattermost.groupAllowFrom","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
@ -2903,6 +2940,7 @@
{"recordType":"path","path":"channels.telegram.accounts.*.retry.jitter","kind":"channel","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.retry.maxDelayMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.retry.minDelayMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.silentErrorReplies","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.streaming","kind":"channel","type":["boolean","string"],"required":false,"enumValues":["off","partial","block","progress"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.streamMode","kind":"channel","type":"string","required":false,"enumValues":["off","partial","block"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.textChunkLimit","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@ -3080,6 +3118,7 @@
{"recordType":"path","path":"channels.telegram.retry.jitter","kind":"channel","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":["channels","network","reliability"],"label":"Telegram Retry Jitter","help":"Jitter factor (0-1) applied to Telegram retry delays.","hasChildren":false}
{"recordType":"path","path":"channels.telegram.retry.maxDelayMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["channels","network","performance","reliability"],"label":"Telegram Retry Max Delay (ms)","help":"Maximum retry delay cap in ms for Telegram outbound calls.","hasChildren":false}
{"recordType":"path","path":"channels.telegram.retry.minDelayMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["channels","network","reliability"],"label":"Telegram Retry Min Delay (ms)","help":"Minimum retry delay in ms for Telegram outbound calls.","hasChildren":false}
{"recordType":"path","path":"channels.telegram.silentErrorReplies","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["channels","network"],"label":"Telegram Silent Error Replies","help":"When true, Telegram bot replies marked as errors are sent silently (no notification sound). Default: false.","hasChildren":false}
{"recordType":"path","path":"channels.telegram.streaming","kind":"channel","type":["boolean","string"],"required":false,"enumValues":["off","partial","block","progress"],"deprecated":false,"sensitive":false,"tags":["channels","network"],"label":"Telegram Streaming Mode","help":"Unified Telegram stream preview mode: \"off\" | \"partial\" | \"block\" | \"progress\" (default: \"partial\"). \"progress\" maps to \"partial\" on Telegram. Legacy boolean/streamMode keys are auto-mapped.","hasChildren":false}
{"recordType":"path","path":"channels.telegram.streamMode","kind":"channel","type":"string","required":false,"enumValues":["off","partial","block"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.textChunkLimit","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@ -3369,7 +3408,7 @@
{"recordType":"path","path":"channels.zalouser.accounts.*.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.zalouser.accounts.*.groupAllowFrom","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"channels.zalouser.accounts.*.groupAllowFrom.*","kind":"channel","type":["number","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.zalouser.accounts.*.groupPolicy","kind":"channel","type":"string","required":false,"enumValues":["open","disabled","allowlist"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.zalouser.accounts.*.groupPolicy","kind":"channel","type":"string","required":true,"enumValues":["open","disabled","allowlist"],"defaultValue":"allowlist","deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.zalouser.accounts.*.groups","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"channels.zalouser.accounts.*.groups.*","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"channels.zalouser.accounts.*.groups.*.allow","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@ -3397,7 +3436,7 @@
{"recordType":"path","path":"channels.zalouser.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.zalouser.groupAllowFrom","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"channels.zalouser.groupAllowFrom.*","kind":"channel","type":["number","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.zalouser.groupPolicy","kind":"channel","type":"string","required":false,"enumValues":["open","disabled","allowlist"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.zalouser.groupPolicy","kind":"channel","type":"string","required":true,"enumValues":["open","disabled","allowlist"],"defaultValue":"allowlist","deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.zalouser.groups","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"channels.zalouser.groups.*","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"channels.zalouser.groups.*.allow","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@ -3428,12 +3467,14 @@
{"recordType":"path","path":"commands.bashForegroundMs","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Bash Foreground Window (ms)","help":"How long bash waits before backgrounding (default: 2000; 0 backgrounds immediately).","hasChildren":false}
{"recordType":"path","path":"commands.config","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Allow /config","help":"Allow /config chat command to read/write config on disk (default: false).","hasChildren":false}
{"recordType":"path","path":"commands.debug","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Allow /debug","help":"Allow /debug chat command for runtime-only overrides (default: false).","hasChildren":false}
{"recordType":"path","path":"commands.mcp","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Allow /mcp","help":"Allow /mcp chat command to manage OpenClaw MCP server config under mcp.servers (default: false).","hasChildren":false}
{"recordType":"path","path":"commands.native","kind":"core","type":["boolean","string"],"required":true,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Native Commands","help":"Registers native slash/menu commands with channels that support command registration (Discord, Slack, Telegram). Keep enabled for discoverability unless you intentionally run text-only command workflows.","hasChildren":false}
{"recordType":"path","path":"commands.nativeSkills","kind":"core","type":["boolean","string"],"required":true,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Native Skill Commands","help":"Registers native skill commands so users can invoke skills directly from provider command menus where supported. Keep aligned with your skill policy so exposed commands match what operators expect.","hasChildren":false}
{"recordType":"path","path":"commands.ownerAllowFrom","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Command Owners","help":"Explicit owner allowlist for owner-only tools/commands. Use channel-native IDs (optionally prefixed like \"whatsapp:+15551234567\"). '*' is ignored.","hasChildren":true}
{"recordType":"path","path":"commands.ownerAllowFrom.*","kind":"core","type":["number","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"commands.ownerDisplay","kind":"core","type":"string","required":true,"enumValues":["raw","hash"],"defaultValue":"raw","deprecated":false,"sensitive":false,"tags":["access"],"label":"Owner ID Display","help":"Controls how owner IDs are rendered in the system prompt. Allowed values: raw, hash. Default: raw.","hasChildren":false}
{"recordType":"path","path":"commands.ownerDisplaySecret","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":true,"tags":["access","auth","security"],"label":"Owner ID Hash Secret","help":"Optional secret used to HMAC hash owner IDs when ownerDisplay=hash. Prefer env substitution.","hasChildren":false}
{"recordType":"path","path":"commands.plugins","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Allow /plugins","help":"Allow /plugins chat command to list discovered plugins and toggle plugin enablement in config (default: false).","hasChildren":false}
{"recordType":"path","path":"commands.restart","kind":"core","type":"boolean","required":true,"defaultValue":true,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Allow Restart","help":"Allow /restart and gateway restart tool actions (default: true).","hasChildren":false}
{"recordType":"path","path":"commands.text","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Text Commands","help":"Enables text-command parsing in chat input in addition to native command surfaces where available. Keep this enabled for compatibility across channels that do not support native command registration.","hasChildren":false}
{"recordType":"path","path":"commands.useAccessGroups","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Use Access Groups","help":"Enforce access-group allowlists/policies for commands.","hasChildren":false}
@ -3532,7 +3573,7 @@
{"recordType":"path","path":"gateway.channelMaxRestartsPerHour","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["network","performance"],"label":"Gateway Channel Max Restarts Per Hour","help":"Maximum number of health-monitor-initiated channel restarts allowed within a rolling one-hour window. Once hit, further restarts are skipped until the window expires. Default: 10.","hasChildren":false}
{"recordType":"path","path":"gateway.channelStaleEventThresholdMinutes","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["network"],"label":"Gateway Channel Stale Event Threshold (min)","help":"How many minutes a connected channel can go without receiving any event before the health monitor treats it as a stale socket and triggers a restart. Default: 30.","hasChildren":false}
{"recordType":"path","path":"gateway.controlUi","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["network"],"label":"Control UI","help":"Control UI hosting settings including enablement, pathing, and browser-origin/auth hardening behavior. Keep UI exposure minimal and pair with strong auth controls before internet-facing deployments.","hasChildren":true}
{"recordType":"path","path":"gateway.controlUi.allowedOrigins","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access","network"],"label":"Control UI Allowed Origins","help":"Allowed browser origins for Control UI/WebChat websocket connections (full origins only, e.g. https://control.example.com). Required for non-loopback Control UI deployments unless dangerous Host-header fallback is explicitly enabled.","hasChildren":true}
{"recordType":"path","path":"gateway.controlUi.allowedOrigins","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access","network"],"label":"Control UI Allowed Origins","help":"Allowed browser origins for Control UI/WebChat websocket connections (full origins only, e.g. https://control.example.com). Required for non-loopback Control UI deployments unless dangerous Host-header fallback is explicitly enabled. Setting [\"*\"] means allow any browser origin and should be avoided outside tightly controlled local testing.","hasChildren":true}
{"recordType":"path","path":"gateway.controlUi.allowedOrigins.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"gateway.controlUi.allowInsecureAuth","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access","advanced","network","security"],"label":"Insecure Control UI Auth Toggle","help":"Loosens strict browser auth checks for Control UI when you must run a non-standard setup. Keep this off unless you trust your network and proxy path, because impersonation risk is higher.","hasChildren":false}
{"recordType":"path","path":"gateway.controlUi.basePath","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["network","storage"],"label":"Control UI Base Path","help":"Optional URL prefix where the Control UI is served (e.g. /openclaw).","hasChildren":false}
@ -3548,11 +3589,11 @@
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["media","network"],"label":"OpenAI Chat Completions Image Limits","help":"Image fetch/validation controls for OpenAI-compatible `image_url` parts.","hasChildren":true}
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.allowedMimes","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access","media","network"],"label":"OpenAI Chat Completions Image MIME Allowlist","help":"Allowed MIME types for `image_url` parts (case-insensitive list).","hasChildren":true}
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.allowedMimes.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.allowUrl","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access","media","network"],"label":"OpenAI Chat Completions Allow Image URLs","help":"Allow server-side URL fetches for `image_url` parts (default: false; data URIs remain supported).","hasChildren":false}
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.allowUrl","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access","media","network"],"label":"OpenAI Chat Completions Allow Image URLs","help":"Allow server-side URL fetches for `image_url` parts (default: false; data URIs remain supported). Set this to `false` to disable URL fetching entirely.","hasChildren":false}
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.maxBytes","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["media","network","performance"],"label":"OpenAI Chat Completions Image Max Bytes","help":"Max bytes per fetched/decoded `image_url` image (default: 10MB).","hasChildren":false}
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.maxRedirects","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["media","network","performance","storage"],"label":"OpenAI Chat Completions Image Max Redirects","help":"Max HTTP redirects allowed when fetching `image_url` URLs (default: 3).","hasChildren":false}
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.timeoutMs","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["media","network","performance"],"label":"OpenAI Chat Completions Image Timeout (ms)","help":"Timeout in milliseconds for `image_url` URL fetches (default: 10000).","hasChildren":false}
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.urlAllowlist","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access","media","network"],"label":"OpenAI Chat Completions Image URL Allowlist","help":"Optional hostname allowlist for `image_url` URL fetches; supports exact hosts and `*.example.com` wildcards.","hasChildren":true}
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.urlAllowlist","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access","media","network"],"label":"OpenAI Chat Completions Image URL Allowlist","help":"Optional hostname allowlist for `image_url` URL fetches; supports exact hosts and `*.example.com` wildcards. Empty or omitted lists mean no hostname allowlist restriction.","hasChildren":true}
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.images.urlAllowlist.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.maxBodyBytes","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["network","performance"],"label":"OpenAI Chat Completions Max Body Bytes","help":"Max request body size in bytes for `/v1/chat/completions` (default: 20MB).","hasChildren":false}
{"recordType":"path","path":"gateway.http.endpoints.chatCompletions.maxImageParts","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["media","network","performance"],"label":"OpenAI Chat Completions Max Image Parts","help":"Max number of `image_url` parts accepted from the latest user message (default: 8).","hasChildren":false}
@ -3636,7 +3677,7 @@
{"recordType":"path","path":"gateway.trustedProxies","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["network"],"label":"Gateway Trusted Proxy CIDRs","help":"CIDR/IP allowlist of upstream proxies permitted to provide forwarded client identity headers. Keep this list narrow so untrusted hops cannot impersonate users.","hasChildren":true}
{"recordType":"path","path":"gateway.trustedProxies.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"hooks","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Hooks","help":"Inbound webhook automation surface for mapping external events into wake or agent actions in OpenClaw. Keep this locked down with explicit token/session/agent controls before exposing it beyond trusted networks.","hasChildren":true}
{"recordType":"path","path":"hooks.allowedAgentIds","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Hooks Allowed Agent IDs","help":"Allowlist of agent IDs that hook mappings are allowed to target when selecting execution agents. Use this to constrain automation events to dedicated service agents.","hasChildren":true}
{"recordType":"path","path":"hooks.allowedAgentIds","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Hooks Allowed Agent IDs","help":"Allowlist of agent IDs that hook mappings are allowed to target when selecting execution agents. Use this to constrain automation events to dedicated service agents and reduce blast radius if a hook token is exposed.","hasChildren":true}
{"recordType":"path","path":"hooks.allowedAgentIds.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"hooks.allowedSessionKeyPrefixes","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access","storage"],"label":"Hooks Allowed Session Key Prefixes","help":"Allowlist of accepted session-key prefixes for inbound hook requests when caller-provided keys are enabled. Use narrow prefixes to prevent arbitrary session-key injection.","hasChildren":true}
{"recordType":"path","path":"hooks.allowedSessionKeyPrefixes.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@ -3723,7 +3764,7 @@
{"recordType":"path","path":"hooks.path","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"Hooks Endpoint Path","help":"HTTP path used by the hooks endpoint (for example `/hooks`) on the gateway control server. Use a non-guessable path and combine it with token validation for defense in depth.","hasChildren":false}
{"recordType":"path","path":"hooks.presets","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Hooks Presets","help":"Named hook preset bundles applied at load time to seed standard mappings and behavior defaults. Keep preset usage explicit so operators can audit which automations are active.","hasChildren":true}
{"recordType":"path","path":"hooks.presets.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"hooks.token","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":true,"tags":["auth","security"],"label":"Hooks Auth Token","help":"Shared bearer token checked by hooks ingress for request authentication before mappings run. Use environment substitution and rotate regularly when webhook endpoints are internet-accessible.","hasChildren":false}
{"recordType":"path","path":"hooks.token","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":true,"tags":["auth","security"],"label":"Hooks Auth Token","help":"Shared bearer token checked by hooks ingress for request authentication before mappings run. Treat holders as full-trust callers for the hook ingress surface, not as a separate non-owner role. Use environment substitution and rotate regularly when webhook endpoints are internet-accessible.","hasChildren":false}
{"recordType":"path","path":"hooks.transformsDir","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"Hooks Transforms Directory","help":"Base directory for hook transform modules referenced by mapping transform.module paths. Use a controlled repo directory so dynamic imports remain reviewable and predictable.","hasChildren":false}
{"recordType":"path","path":"logging","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Logging","help":"Logging behavior controls for severity, output destinations, formatting, and sensitive-data redaction. Keep levels and redaction strict enough for production while preserving useful diagnostics.","hasChildren":true}
{"recordType":"path","path":"logging.consoleLevel","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["observability"],"label":"Console Log Level","help":"Console-specific log threshold: \"silent\", \"fatal\", \"error\", \"warn\", \"info\", \"debug\", or \"trace\" for terminal output control. Use this to keep local console quieter while retaining richer file logging if needed.","hasChildren":false}
@ -3734,6 +3775,18 @@
{"recordType":"path","path":"logging.redactPatterns","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["observability","privacy"],"label":"Custom Redaction Patterns","help":"Additional custom redact regex patterns applied to log output before emission/storage. Use this to mask org-specific tokens and identifiers not covered by built-in redaction rules.","hasChildren":true}
{"recordType":"path","path":"logging.redactPatterns.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"logging.redactSensitive","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["observability","privacy"],"label":"Sensitive Data Redaction Mode","help":"Sensitive redaction mode: \"off\" disables built-in masking, while \"tools\" redacts sensitive tool/config payload fields. Keep \"tools\" in shared logs unless you have isolated secure log sinks.","hasChildren":false}
{"recordType":"path","path":"mcp","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"MCP","help":"Global MCP server definitions managed by OpenClaw. Embedded Pi and other runtime adapters can consume these servers without storing them inside Pi-owned project settings.","hasChildren":true}
{"recordType":"path","path":"mcp.servers","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"MCP Servers","help":"Named MCP server definitions. OpenClaw stores them in its own config and runtime adapters decide which transports are supported at execution time.","hasChildren":true}
{"recordType":"path","path":"mcp.servers.*","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"mcp.servers.*.*","kind":"core","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"mcp.servers.*.args","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"mcp.servers.*.args.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"mcp.servers.*.command","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"mcp.servers.*.cwd","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"mcp.servers.*.env","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"mcp.servers.*.env.*","kind":"core","type":["boolean","number","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"mcp.servers.*.url","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"mcp.servers.*.workingDirectory","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"media","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Media","help":"Top-level media behavior shared across providers and tools that handle inbound files. Keep defaults unless you need stable filenames for external processing pipelines or longer-lived inbound media retention.","hasChildren":true}
{"recordType":"path","path":"media.preserveFilenames","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"Preserve Media Filenames","help":"When enabled, uploaded media keeps its original filename instead of a generated temp-safe name. Turn this on when downstream automations depend on stable names, and leave off to reduce accidental filename leakage.","hasChildren":false}
{"recordType":"path","path":"media.ttlHours","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Media Retention TTL (hours)","help":"Optional retention window in hours for persisted inbound media cleanup across the full media tree. Leave unset to preserve legacy behavior, or set values like 24 (1 day) or 168 (7 days) when you want automatic cleanup.","hasChildren":false}
@ -3864,6 +3917,17 @@
{"recordType":"path","path":"messages.tts.elevenlabs.voiceSettings.useSpeakerBoost","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.enabled","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.maxTextLength","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.microsoft","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"messages.tts.microsoft.enabled","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.microsoft.lang","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.microsoft.outputFormat","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.microsoft.pitch","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.microsoft.proxy","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.microsoft.rate","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.microsoft.saveSubtitles","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.microsoft.timeoutMs","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.microsoft.voice","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.microsoft.volume","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.mode","kind":"core","type":"string","required":false,"enumValues":["final","all"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.modelOverrides","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"messages.tts.modelOverrides.allowModelId","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@ -3885,7 +3949,7 @@
{"recordType":"path","path":"messages.tts.openai.speed","kind":"core","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.openai.voice","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.prefsPath","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.provider","kind":"core","type":"string","required":false,"enumValues":["elevenlabs","openai","edge"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.provider","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.summaryModel","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"messages.tts.timeoutMs","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"meta","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Metadata","help":"Metadata fields automatically maintained by OpenClaw to record write/version history for this config file. Keep these values system-managed and avoid manual edits unless debugging migration history.","hasChildren":true}
@ -3966,6 +4030,10 @@
{"recordType":"path","path":"plugins.entries.*.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Enabled","help":"Per-plugin enablement override for a specific entry, applied on top of global plugin policy (restart required). Use this to stage plugin rollout gradually across environments.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.*.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.*.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.*.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.*.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.*.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.*.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.acpx","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"ACPX Runtime","help":"ACP runtime backend powered by acpx with configurable command path and version policy. (plugin: acpx)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.acpx.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"ACPX Runtime Config","help":"Plugin-defined config payload for acpx.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.acpx.config.command","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"acpx Command","help":"Optional path/command override for acpx (for example /home/user/repos/acpx/dist/cli.js). Leave unset to use plugin-local bundled acpx.","hasChildren":false}
@ -3986,52 +4054,101 @@
{"recordType":"path","path":"plugins.entries.acpx.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable ACPX Runtime","hasChildren":false}
{"recordType":"path","path":"plugins.entries.acpx.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.acpx.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.acpx.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.acpx.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.acpx.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.acpx.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.amazon-bedrock","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/amazon-bedrock-provider","help":"OpenClaw Amazon Bedrock provider plugin (plugin: amazon-bedrock)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/amazon-bedrock-provider Config","help":"Plugin-defined config payload for amazon-bedrock.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/amazon-bedrock-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.anthropic","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/anthropic-provider","help":"OpenClaw Anthropic provider plugin (plugin: anthropic)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.anthropic.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/anthropic-provider Config","help":"Plugin-defined config payload for anthropic.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.anthropic.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/anthropic-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.anthropic.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.anthropic.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.anthropic.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.anthropic.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.anthropic.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.anthropic.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.bluebubbles","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/bluebubbles","help":"OpenClaw BlueBubbles channel plugin (plugin: bluebubbles)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.bluebubbles.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/bluebubbles Config","help":"Plugin-defined config payload for bluebubbles.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.bluebubbles.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/bluebubbles","hasChildren":false}
{"recordType":"path","path":"plugins.entries.bluebubbles.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.bluebubbles.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.bluebubbles.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.bluebubbles.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.bluebubbles.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.bluebubbles.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.brave","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/brave-plugin","help":"OpenClaw Brave plugin (plugin: brave)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.brave.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/brave-plugin Config","help":"Plugin-defined config payload for brave.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.brave.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/brave-plugin","hasChildren":false}
{"recordType":"path","path":"plugins.entries.brave.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.brave.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.brave.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.brave.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.brave.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.brave.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.byteplus","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/byteplus-provider","help":"OpenClaw BytePlus provider plugin (plugin: byteplus)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.byteplus.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/byteplus-provider Config","help":"Plugin-defined config payload for byteplus.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.byteplus.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/byteplus-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.byteplus.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.byteplus.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.byteplus.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.byteplus.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.byteplus.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.byteplus.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.chutes","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/chutes-provider","help":"OpenClaw Chutes.ai provider plugin (plugin: chutes)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.chutes.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/chutes-provider Config","help":"Plugin-defined config payload for chutes.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.chutes.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/chutes-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.chutes.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.chutes.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.chutes.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.chutes.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.chutes.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.chutes.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/cloudflare-ai-gateway-provider","help":"OpenClaw Cloudflare AI Gateway provider plugin (plugin: cloudflare-ai-gateway)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/cloudflare-ai-gateway-provider Config","help":"Plugin-defined config payload for cloudflare-ai-gateway.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/cloudflare-ai-gateway-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.cloudflare-ai-gateway.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.copilot-proxy","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/copilot-proxy","help":"OpenClaw Copilot Proxy provider plugin (plugin: copilot-proxy)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.copilot-proxy.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/copilot-proxy Config","help":"Plugin-defined config payload for copilot-proxy.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.copilot-proxy.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/copilot-proxy","hasChildren":false}
{"recordType":"path","path":"plugins.entries.copilot-proxy.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.copilot-proxy.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.copilot-proxy.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.copilot-proxy.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.copilot-proxy.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.copilot-proxy.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.device-pair","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Device Pairing","help":"Generate setup codes and approve device pairing requests. (plugin: device-pair)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.device-pair.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Device Pairing Config","help":"Plugin-defined config payload for device-pair.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.device-pair.config.publicUrl","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Gateway URL","help":"Public WebSocket URL used for /pair setup codes (ws/wss or http/https).","hasChildren":false}
{"recordType":"path","path":"plugins.entries.device-pair.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable Device Pairing","hasChildren":false}
{"recordType":"path","path":"plugins.entries.device-pair.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.device-pair.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.device-pair.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.device-pair.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.device-pair.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.device-pair.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.diagnostics-otel","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["observability"],"label":"@openclaw/diagnostics-otel","help":"OpenClaw diagnostics OpenTelemetry exporter (plugin: diagnostics-otel)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.diagnostics-otel.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["observability"],"label":"@openclaw/diagnostics-otel Config","help":"Plugin-defined config payload for diagnostics-otel.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.diagnostics-otel.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["observability"],"label":"Enable @openclaw/diagnostics-otel","hasChildren":false}
{"recordType":"path","path":"plugins.entries.diagnostics-otel.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.diagnostics-otel.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.diagnostics-otel.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.diagnostics-otel.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.diagnostics-otel.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.diagnostics-otel.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.diffs","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Diffs","help":"Read-only diff viewer and file renderer for agents. (plugin: diffs)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.diffs.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Diffs Config","help":"Plugin-defined config payload for diffs.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.diffs.config.defaults","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
@ -4059,66 +4176,127 @@
{"recordType":"path","path":"plugins.entries.diffs.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable Diffs","hasChildren":false}
{"recordType":"path","path":"plugins.entries.diffs.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.diffs.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.diffs.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.diffs.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.diffs.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.diffs.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.discord","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/discord","help":"OpenClaw Discord channel plugin (plugin: discord)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.discord.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/discord Config","help":"Plugin-defined config payload for discord.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.discord.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/discord","hasChildren":false}
{"recordType":"path","path":"plugins.entries.discord.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.discord.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.discord.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.discord.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.discord.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.discord.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.elevenlabs","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/elevenlabs-speech","help":"OpenClaw ElevenLabs speech plugin (plugin: elevenlabs)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.elevenlabs.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/elevenlabs-speech Config","help":"Plugin-defined config payload for elevenlabs.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.elevenlabs.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/elevenlabs-speech","hasChildren":false}
{"recordType":"path","path":"plugins.entries.elevenlabs.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.elevenlabs.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.elevenlabs.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.elevenlabs.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.elevenlabs.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.elevenlabs.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.feishu","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/feishu","help":"OpenClaw Feishu/Lark channel plugin (community maintained by @m1heng) (plugin: feishu)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.feishu.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/feishu Config","help":"Plugin-defined config payload for feishu.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.feishu.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/feishu","hasChildren":false}
{"recordType":"path","path":"plugins.entries.feishu.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.feishu.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.feishu.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.feishu.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.feishu.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.feishu.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.firecrawl","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/firecrawl-plugin","help":"OpenClaw Firecrawl plugin (plugin: firecrawl)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.firecrawl.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/firecrawl-plugin Config","help":"Plugin-defined config payload for firecrawl.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.firecrawl.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/firecrawl-plugin","hasChildren":false}
{"recordType":"path","path":"plugins.entries.firecrawl.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.firecrawl.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.firecrawl.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.firecrawl.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.firecrawl.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.firecrawl.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.github-copilot","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/github-copilot-provider","help":"OpenClaw GitHub Copilot provider plugin (plugin: github-copilot)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.github-copilot.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/github-copilot-provider Config","help":"Plugin-defined config payload for github-copilot.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.github-copilot.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/github-copilot-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.github-copilot.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.github-copilot.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.github-copilot.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.github-copilot.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.github-copilot.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.github-copilot.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.google","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/google-plugin","help":"OpenClaw Google plugin (plugin: google)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.google.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/google-plugin Config","help":"Plugin-defined config payload for google.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.google.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/google-plugin","hasChildren":false}
{"recordType":"path","path":"plugins.entries.google.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.google.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.google.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.google.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.google.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.google.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.googlechat","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/googlechat","help":"OpenClaw Google Chat channel plugin (plugin: googlechat)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.googlechat.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/googlechat Config","help":"Plugin-defined config payload for googlechat.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.googlechat.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/googlechat","hasChildren":false}
{"recordType":"path","path":"plugins.entries.googlechat.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.googlechat.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.googlechat.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.googlechat.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.googlechat.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.googlechat.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.huggingface","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/huggingface-provider","help":"OpenClaw Hugging Face provider plugin (plugin: huggingface)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.huggingface.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/huggingface-provider Config","help":"Plugin-defined config payload for huggingface.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.huggingface.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/huggingface-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.huggingface.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.huggingface.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.huggingface.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.huggingface.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.huggingface.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.huggingface.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.imessage","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/imessage","help":"OpenClaw iMessage channel plugin (plugin: imessage)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.imessage.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/imessage Config","help":"Plugin-defined config payload for imessage.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.imessage.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/imessage","hasChildren":false}
{"recordType":"path","path":"plugins.entries.imessage.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.imessage.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.imessage.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.imessage.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.imessage.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.imessage.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.irc","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/irc","help":"OpenClaw IRC channel plugin (plugin: irc)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.irc.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/irc Config","help":"Plugin-defined config payload for irc.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.irc.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/irc","hasChildren":false}
{"recordType":"path","path":"plugins.entries.irc.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.irc.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.irc.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.irc.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.irc.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.irc.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.kilocode","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/kilocode-provider","help":"OpenClaw Kilo Gateway provider plugin (plugin: kilocode)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.kilocode.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/kilocode-provider Config","help":"Plugin-defined config payload for kilocode.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.kilocode.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/kilocode-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.kilocode.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.kilocode.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.kimi-coding","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/kimi-coding-provider","help":"OpenClaw Kimi Coding provider plugin (plugin: kimi-coding)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.kimi-coding.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/kimi-coding-provider Config","help":"Plugin-defined config payload for kimi-coding.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.kimi-coding.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/kimi-coding-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.kimi-coding.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.kimi-coding.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.kilocode.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.kilocode.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.kilocode.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.kilocode.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.kimi","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/kimi-provider","help":"OpenClaw Kimi provider plugin (plugin: kimi)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.kimi.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/kimi-provider Config","help":"Plugin-defined config payload for kimi.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.kimi.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/kimi-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.kimi.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.kimi.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.kimi.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.kimi.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.kimi.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.kimi.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.line","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/line","help":"OpenClaw LINE channel plugin (plugin: line)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.line.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/line Config","help":"Plugin-defined config payload for line.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.line.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/line","hasChildren":false}
{"recordType":"path","path":"plugins.entries.line.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.line.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.line.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.line.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.line.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.line.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.llm-task","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"LLM Task","help":"Generic JSON-only LLM tool for structured tasks callable from workflows. (plugin: llm-task)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.llm-task.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"LLM Task Config","help":"Plugin-defined config payload for llm-task.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.llm-task.config.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
@ -4131,26 +4309,46 @@
{"recordType":"path","path":"plugins.entries.llm-task.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable LLM Task","hasChildren":false}
{"recordType":"path","path":"plugins.entries.llm-task.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.llm-task.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.llm-task.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.llm-task.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.llm-task.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.llm-task.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.lobster","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Lobster","help":"Typed workflow tool with resumable approvals. (plugin: lobster)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.lobster.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Lobster Config","help":"Plugin-defined config payload for lobster.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.lobster.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable Lobster","hasChildren":false}
{"recordType":"path","path":"plugins.entries.lobster.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.lobster.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.lobster.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.lobster.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.lobster.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.lobster.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.matrix","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/matrix","help":"OpenClaw Matrix channel plugin (plugin: matrix)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.matrix.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/matrix Config","help":"Plugin-defined config payload for matrix.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.matrix.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/matrix","hasChildren":false}
{"recordType":"path","path":"plugins.entries.matrix.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.matrix.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.matrix.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.matrix.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.matrix.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.matrix.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.mattermost","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/mattermost","help":"OpenClaw Mattermost channel plugin (plugin: mattermost)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.mattermost.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/mattermost Config","help":"Plugin-defined config payload for mattermost.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.mattermost.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/mattermost","hasChildren":false}
{"recordType":"path","path":"plugins.entries.mattermost.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.mattermost.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.mattermost.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.mattermost.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.mattermost.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.mattermost.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.memory-core","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/memory-core","help":"OpenClaw core memory search plugin (plugin: memory-core)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.memory-core.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/memory-core Config","help":"Plugin-defined config payload for memory-core.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.memory-core.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/memory-core","hasChildren":false}
{"recordType":"path","path":"plugins.entries.memory-core.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.memory-core.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.memory-core.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.memory-core.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.memory-core.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.memory-core.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.memory-lancedb","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"@openclaw/memory-lancedb","help":"OpenClaw LanceDB-backed long-term memory plugin with auto-recall/capture (plugin: memory-lancedb)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.memory-lancedb.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"@openclaw/memory-lancedb Config","help":"Plugin-defined config payload for memory-lancedb.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.memory-lancedb.config.autoCapture","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"Auto-Capture","help":"Automatically capture important information from conversations","hasChildren":false}
@ -4165,76 +4363,145 @@
{"recordType":"path","path":"plugins.entries.memory-lancedb.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"Enable @openclaw/memory-lancedb","hasChildren":false}
{"recordType":"path","path":"plugins.entries.memory-lancedb.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.memory-lancedb.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.memory-lancedb.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.memory-lancedb.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.memory-lancedb.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.memory-lancedb.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.microsoft","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/microsoft-speech","help":"OpenClaw Microsoft speech plugin (plugin: microsoft)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.microsoft.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/microsoft-speech Config","help":"Plugin-defined config payload for microsoft.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.microsoft.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/microsoft-speech","hasChildren":false}
{"recordType":"path","path":"plugins.entries.microsoft.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.microsoft.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.microsoft.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.microsoft.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.microsoft.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.microsoft.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.minimax","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["performance"],"label":"@openclaw/minimax-provider","help":"OpenClaw MiniMax provider and OAuth plugin (plugin: minimax)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.minimax.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["performance"],"label":"@openclaw/minimax-provider Config","help":"Plugin-defined config payload for minimax.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.minimax.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["performance"],"label":"Enable @openclaw/minimax-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.minimax.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.minimax.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.minimax.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.minimax.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.minimax.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.minimax.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.mistral","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/mistral-provider","help":"OpenClaw Mistral provider plugin (plugin: mistral)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.mistral.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/mistral-provider Config","help":"Plugin-defined config payload for mistral.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.mistral.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/mistral-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.mistral.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.mistral.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.mistral.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.mistral.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.mistral.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.mistral.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.modelstudio","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/modelstudio-provider","help":"OpenClaw Model Studio provider plugin (plugin: modelstudio)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.modelstudio.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/modelstudio-provider Config","help":"Plugin-defined config payload for modelstudio.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.modelstudio.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/modelstudio-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.modelstudio.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.modelstudio.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.modelstudio.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.modelstudio.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.modelstudio.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.modelstudio.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.moonshot","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/moonshot-provider","help":"OpenClaw Moonshot provider plugin (plugin: moonshot)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.moonshot.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/moonshot-provider Config","help":"Plugin-defined config payload for moonshot.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.moonshot.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/moonshot-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.moonshot.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.moonshot.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.moonshot.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.moonshot.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.moonshot.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.moonshot.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.msteams","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/msteams","help":"OpenClaw Microsoft Teams channel plugin (plugin: msteams)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.msteams.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/msteams Config","help":"Plugin-defined config payload for msteams.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.msteams.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/msteams","hasChildren":false}
{"recordType":"path","path":"plugins.entries.msteams.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.msteams.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.msteams.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.msteams.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.msteams.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.msteams.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.nextcloud-talk","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/nextcloud-talk","help":"OpenClaw Nextcloud Talk channel plugin (plugin: nextcloud-talk)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.nextcloud-talk.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/nextcloud-talk Config","help":"Plugin-defined config payload for nextcloud-talk.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.nextcloud-talk.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/nextcloud-talk","hasChildren":false}
{"recordType":"path","path":"plugins.entries.nextcloud-talk.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.nextcloud-talk.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.nextcloud-talk.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.nextcloud-talk.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.nextcloud-talk.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.nextcloud-talk.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.nostr","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/nostr","help":"OpenClaw Nostr channel plugin for NIP-04 encrypted DMs (plugin: nostr)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.nostr.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/nostr Config","help":"Plugin-defined config payload for nostr.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.nostr.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/nostr","hasChildren":false}
{"recordType":"path","path":"plugins.entries.nostr.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.nostr.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.nostr.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.nostr.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.nostr.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.nostr.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.nvidia","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/nvidia-provider","help":"OpenClaw NVIDIA provider plugin (plugin: nvidia)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.nvidia.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/nvidia-provider Config","help":"Plugin-defined config payload for nvidia.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.nvidia.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/nvidia-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.nvidia.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.nvidia.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.nvidia.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.nvidia.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.nvidia.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.nvidia.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.ollama","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/ollama-provider","help":"OpenClaw Ollama provider plugin (plugin: ollama)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.ollama.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/ollama-provider Config","help":"Plugin-defined config payload for ollama.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.ollama.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/ollama-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.ollama.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.ollama.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.ollama.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.ollama.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.ollama.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.ollama.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.open-prose","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"OpenProse","help":"OpenProse VM skill pack with a /prose slash command. (plugin: open-prose)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.open-prose.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"OpenProse Config","help":"Plugin-defined config payload for open-prose.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.open-prose.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable OpenProse","hasChildren":false}
{"recordType":"path","path":"plugins.entries.open-prose.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.open-prose.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.open-prose.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.open-prose.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.open-prose.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.open-prose.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.openai","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/openai-provider","help":"OpenClaw OpenAI provider plugins (plugin: openai)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.openai.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/openai-provider Config","help":"Plugin-defined config payload for openai.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.openai.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/openai-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.openai.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.openai.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.openai.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.openai.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.openai.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.openai.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.opencode","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/opencode-provider","help":"OpenClaw OpenCode Zen provider plugin (plugin: opencode)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.opencode-go","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/opencode-go-provider","help":"OpenClaw OpenCode Go provider plugin (plugin: opencode-go)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.opencode-go.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/opencode-go-provider Config","help":"Plugin-defined config payload for opencode-go.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.opencode-go.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/opencode-go-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.opencode-go.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.opencode-go.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.opencode-go.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.opencode-go.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.opencode-go.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.opencode-go.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.opencode.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/opencode-provider Config","help":"Plugin-defined config payload for opencode.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.opencode.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/opencode-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.opencode.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.opencode.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.opencode.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.opencode.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.opencode.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.opencode.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.openrouter","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/openrouter-provider","help":"OpenClaw OpenRouter provider plugin (plugin: openrouter)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.openrouter.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/openrouter-provider Config","help":"Plugin-defined config payload for openrouter.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.openrouter.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/openrouter-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.openrouter.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.openrouter.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.openrouter.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.openrouter.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.openrouter.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.openrouter.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.openshell","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"OpenShell Sandbox","help":"Sandbox backend powered by OpenShell with mirrored local workspaces and SSH-based command execution. (plugin: openshell)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.openshell.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"OpenShell Sandbox Config","help":"Plugin-defined config payload for openshell.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.openshell.config.autoProviders","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Auto-create Providers","help":"When enabled, pass --auto-providers during sandbox create.","hasChildren":false}
@ -4252,61 +4519,109 @@
{"recordType":"path","path":"plugins.entries.openshell.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable OpenShell Sandbox","hasChildren":false}
{"recordType":"path","path":"plugins.entries.openshell.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.openshell.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.openshell.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.openshell.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.openshell.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.openshell.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.perplexity","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/perplexity-plugin","help":"OpenClaw Perplexity plugin (plugin: perplexity)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.perplexity.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/perplexity-plugin Config","help":"Plugin-defined config payload for perplexity.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.perplexity.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/perplexity-plugin","hasChildren":false}
{"recordType":"path","path":"plugins.entries.perplexity.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.perplexity.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.perplexity.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.perplexity.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.perplexity.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.perplexity.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.phone-control","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Phone Control","help":"Arm/disarm high-risk phone node commands (camera/screen/writes) with an optional auto-expiry. (plugin: phone-control)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.phone-control.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Phone Control Config","help":"Plugin-defined config payload for phone-control.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.phone-control.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable Phone Control","hasChildren":false}
{"recordType":"path","path":"plugins.entries.phone-control.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.phone-control.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.phone-control.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.phone-control.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.phone-control.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.phone-control.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.qianfan","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/qianfan-provider","help":"OpenClaw Qianfan provider plugin (plugin: qianfan)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.qianfan.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/qianfan-provider Config","help":"Plugin-defined config payload for qianfan.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.qianfan.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/qianfan-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.qianfan.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.qianfan.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.qianfan.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.qianfan.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.qianfan.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.qianfan.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.qwen-portal-auth","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"qwen-portal-auth","help":"Plugin entry for qwen-portal-auth.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.qwen-portal-auth.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"qwen-portal-auth Config","help":"Plugin-defined config payload for qwen-portal-auth.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.qwen-portal-auth.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable qwen-portal-auth","hasChildren":false}
{"recordType":"path","path":"plugins.entries.qwen-portal-auth.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.qwen-portal-auth.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.qwen-portal-auth.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.qwen-portal-auth.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.qwen-portal-auth.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.qwen-portal-auth.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.sglang","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/sglang-provider","help":"OpenClaw SGLang provider plugin (plugin: sglang)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.sglang.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/sglang-provider Config","help":"Plugin-defined config payload for sglang.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.sglang.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/sglang-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.sglang.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.sglang.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.sglang.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.sglang.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.sglang.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.sglang.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.signal","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/signal","help":"OpenClaw Signal channel plugin (plugin: signal)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.signal.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/signal Config","help":"Plugin-defined config payload for signal.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.signal.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/signal","hasChildren":false}
{"recordType":"path","path":"plugins.entries.signal.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.signal.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.signal.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.signal.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.signal.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.signal.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.slack","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/slack","help":"OpenClaw Slack channel plugin (plugin: slack)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.slack.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/slack Config","help":"Plugin-defined config payload for slack.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.slack.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/slack","hasChildren":false}
{"recordType":"path","path":"plugins.entries.slack.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.slack.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.slack.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.slack.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.slack.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.slack.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.synology-chat","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/synology-chat","help":"Synology Chat channel plugin for OpenClaw (plugin: synology-chat)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.synology-chat.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/synology-chat Config","help":"Plugin-defined config payload for synology-chat.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.synology-chat.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/synology-chat","hasChildren":false}
{"recordType":"path","path":"plugins.entries.synology-chat.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.synology-chat.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.synology-chat.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.synology-chat.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.synology-chat.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.synology-chat.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.synthetic","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/synthetic-provider","help":"OpenClaw Synthetic provider plugin (plugin: synthetic)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.synthetic.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/synthetic-provider Config","help":"Plugin-defined config payload for synthetic.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.synthetic.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/synthetic-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.synthetic.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.synthetic.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.synthetic.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.synthetic.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.synthetic.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.synthetic.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.talk-voice","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Talk Voice","help":"Manage Talk voice selection (list/set). (plugin: talk-voice)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.talk-voice.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Talk Voice Config","help":"Plugin-defined config payload for talk-voice.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.talk-voice.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable Talk Voice","hasChildren":false}
{"recordType":"path","path":"plugins.entries.talk-voice.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.talk-voice.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.talk-voice.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.talk-voice.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.talk-voice.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.talk-voice.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.telegram","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/telegram","help":"OpenClaw Telegram channel plugin (plugin: telegram)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.telegram.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/telegram Config","help":"Plugin-defined config payload for telegram.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.telegram.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/telegram","hasChildren":false}
{"recordType":"path","path":"plugins.entries.telegram.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.telegram.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.telegram.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.telegram.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.telegram.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.telegram.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.thread-ownership","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Thread Ownership","help":"Prevents multiple agents from responding in the same Slack thread. Uses HTTP calls to the slack-forwarder ownership API. (plugin: thread-ownership)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.thread-ownership.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Thread Ownership Config","help":"Plugin-defined config payload for thread-ownership.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.thread-ownership.config.abTestChannels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"A/B Test Channels","help":"Slack channel IDs where thread ownership is enforced","hasChildren":true}
@ -4315,36 +4630,64 @@
{"recordType":"path","path":"plugins.entries.thread-ownership.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Enable Thread Ownership","hasChildren":false}
{"recordType":"path","path":"plugins.entries.thread-ownership.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.thread-ownership.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.thread-ownership.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.thread-ownership.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.thread-ownership.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.thread-ownership.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.tlon","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/tlon","help":"OpenClaw Tlon/Urbit channel plugin (plugin: tlon)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.tlon.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/tlon Config","help":"Plugin-defined config payload for tlon.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.tlon.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/tlon","hasChildren":false}
{"recordType":"path","path":"plugins.entries.tlon.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.tlon.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.tlon.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.tlon.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.tlon.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.tlon.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.together","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/together-provider","help":"OpenClaw Together provider plugin (plugin: together)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.together.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/together-provider Config","help":"Plugin-defined config payload for together.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.together.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/together-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.together.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.together.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.together.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.together.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.together.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.together.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.twitch","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/twitch","help":"OpenClaw Twitch channel plugin (plugin: twitch)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.twitch.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/twitch Config","help":"Plugin-defined config payload for twitch.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.twitch.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/twitch","hasChildren":false}
{"recordType":"path","path":"plugins.entries.twitch.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.twitch.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.twitch.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.twitch.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.twitch.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.twitch.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.venice","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/venice-provider","help":"OpenClaw Venice provider plugin (plugin: venice)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.venice.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/venice-provider Config","help":"Plugin-defined config payload for venice.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.venice.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/venice-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.venice.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.venice.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.venice.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.venice.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.venice.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.venice.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/vercel-ai-gateway-provider","help":"OpenClaw Vercel AI Gateway provider plugin (plugin: vercel-ai-gateway)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/vercel-ai-gateway-provider Config","help":"Plugin-defined config payload for vercel-ai-gateway.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/vercel-ai-gateway-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.vercel-ai-gateway.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.vllm","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/vllm-provider","help":"OpenClaw vLLM provider plugin (plugin: vllm)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.vllm.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/vllm-provider Config","help":"Plugin-defined config payload for vllm.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.vllm.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/vllm-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.vllm.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.vllm.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.vllm.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.vllm.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.vllm.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.vllm.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.voice-call","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/voice-call","help":"OpenClaw voice-call plugin (plugin: voice-call)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.voice-call.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/voice-call Config","help":"Plugin-defined config payload for voice-call.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.voice-call.config.allowFrom","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Inbound Allowlist","hasChildren":true}
@ -4446,7 +4789,7 @@
{"recordType":"path","path":"plugins.entries.voice-call.config.tts.openai.speed","kind":"plugin","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.voice-call.config.tts.openai.voice","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced","media"],"label":"OpenAI TTS Voice","hasChildren":false}
{"recordType":"path","path":"plugins.entries.voice-call.config.tts.prefsPath","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.voice-call.config.tts.provider","kind":"plugin","type":"string","required":false,"enumValues":["openai","elevenlabs","edge"],"deprecated":false,"sensitive":false,"tags":["advanced","media"],"label":"TTS Provider Override","help":"Deep-merges with messages.tts (Edge is ignored for calls).","hasChildren":false}
{"recordType":"path","path":"plugins.entries.voice-call.config.tts.provider","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced","media"],"label":"TTS Provider Override","help":"Deep-merges with messages.tts (Microsoft is ignored for calls).","hasChildren":false}
{"recordType":"path","path":"plugins.entries.voice-call.config.tts.summaryModel","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.voice-call.config.tts.timeoutMs","kind":"plugin","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.voice-call.config.tunnel","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
@ -4466,46 +4809,81 @@
{"recordType":"path","path":"plugins.entries.voice-call.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/voice-call","hasChildren":false}
{"recordType":"path","path":"plugins.entries.voice-call.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.voice-call.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.voice-call.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.voice-call.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.voice-call.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.voice-call.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.volcengine","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/volcengine-provider","help":"OpenClaw Volcengine provider plugin (plugin: volcengine)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.volcengine.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/volcengine-provider Config","help":"Plugin-defined config payload for volcengine.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.volcengine.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/volcengine-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.volcengine.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.volcengine.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.volcengine.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.volcengine.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.volcengine.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.volcengine.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.whatsapp","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/whatsapp","help":"OpenClaw WhatsApp channel plugin (plugin: whatsapp)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.whatsapp.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/whatsapp Config","help":"Plugin-defined config payload for whatsapp.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.whatsapp.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/whatsapp","hasChildren":false}
{"recordType":"path","path":"plugins.entries.whatsapp.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.whatsapp.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.whatsapp.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.whatsapp.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.whatsapp.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.whatsapp.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xai","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/xai-plugin","help":"OpenClaw xAI plugin (plugin: xai)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.xai.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/xai-plugin Config","help":"Plugin-defined config payload for xai.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xai.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/xai-plugin","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xai.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.xai.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xai.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.xai.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.xai.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.xai.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xiaomi","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/xiaomi-provider","help":"OpenClaw Xiaomi provider plugin (plugin: xiaomi)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.xiaomi.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/xiaomi-provider Config","help":"Plugin-defined config payload for xiaomi.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xiaomi.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/xiaomi-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xiaomi.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.xiaomi.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xiaomi.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.xiaomi.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.xiaomi.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.xiaomi.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.zai","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/zai-provider","help":"OpenClaw Z.AI provider plugin (plugin: zai)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.zai.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/zai-provider Config","help":"Plugin-defined config payload for zai.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.zai.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/zai-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.zai.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.zai.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.zai.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.zai.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.zai.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.zai.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.zalo","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/zalo","help":"OpenClaw Zalo channel plugin (plugin: zalo)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.zalo.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/zalo Config","help":"Plugin-defined config payload for zalo.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.zalo.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/zalo","hasChildren":false}
{"recordType":"path","path":"plugins.entries.zalo.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.zalo.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.zalo.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.zalo.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.zalo.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.zalo.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.zalouser","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/zalouser","help":"OpenClaw Zalo Personal Account plugin via native zca-js integration (plugin: zalouser)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.zalouser.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/zalouser Config","help":"Plugin-defined config payload for zalouser.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.zalouser.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/zalouser","hasChildren":false}
{"recordType":"path","path":"plugins.entries.zalouser.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.zalouser.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.zalouser.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.zalouser.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.zalouser.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.zalouser.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.installs","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Install Records","help":"CLI-managed install metadata (used by `openclaw plugins update` to locate install sources).","hasChildren":true}
{"recordType":"path","path":"plugins.installs.*","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"plugins.installs.*.installedAt","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Install Time","help":"ISO timestamp of last install/update.","hasChildren":false}
{"recordType":"path","path":"plugins.installs.*.installPath","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["storage"],"label":"Plugin Install Path","help":"Resolved install directory (usually ~/.openclaw/extensions/<id>).","hasChildren":false}
{"recordType":"path","path":"plugins.installs.*.integrity","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Resolved Integrity","help":"Resolved npm dist integrity hash for the fetched artifact (if reported by npm).","hasChildren":false}
{"recordType":"path","path":"plugins.installs.*.marketplaceName","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Marketplace Name","help":"Marketplace display name recorded for marketplace-backed plugin installs (if available).","hasChildren":false}
{"recordType":"path","path":"plugins.installs.*.marketplacePlugin","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Marketplace Plugin","help":"Plugin entry name inside the source marketplace, used for later updates.","hasChildren":false}
{"recordType":"path","path":"plugins.installs.*.marketplaceSource","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Marketplace Source","help":"Original marketplace source used to resolve the install (for example a repo path or Git URL).","hasChildren":false}
{"recordType":"path","path":"plugins.installs.*.resolvedAt","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Resolution Time","help":"ISO timestamp when npm package metadata was last resolved for this install record.","hasChildren":false}
{"recordType":"path","path":"plugins.installs.*.resolvedName","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Resolved Package Name","help":"Resolved npm package name from the fetched artifact.","hasChildren":false}
{"recordType":"path","path":"plugins.installs.*.resolvedSpec","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Resolved Package Spec","help":"Resolved exact npm spec (<name>@<version>) from the fetched artifact.","hasChildren":false}

View File

@ -47,6 +47,10 @@
"source": "Quick Start",
"target": "快速开始"
},
{
"source": "Capability Cookbook",
"target": "能力扩展手册"
},
{
"source": "Setup Wizard Reference",
"target": "设置向导参考"

View File

@ -38,6 +38,7 @@ Every request must include the hook token. Prefer headers:
- `Authorization: Bearer <token>` (recommended)
- `x-openclaw-token: <token>`
- Query-string tokens are rejected (`?token=...` returns `400`).
- Treat `hooks.token` holders as full-trust callers for the hook ingress surface on that gateway. Hook payload content is still untrusted, but this is not a separate non-owner auth boundary.
## Endpoints
@ -205,6 +206,7 @@ curl -X POST http://127.0.0.1:18789/hooks/gmail \
- Keep hook endpoints behind loopback, tailnet, or trusted reverse proxy.
- Use a dedicated hook token; do not reuse gateway auth tokens.
- Prefer a dedicated hook agent with strict `tools.profile` and sandboxing so hook ingress has a narrower blast radius.
- Repeated auth failures are rate-limited per client address to slow brute-force attempts.
- If you use multi-agent routing, set `hooks.allowedAgentIds` to limit explicit `agentId` selection.
- Keep `hooks.allowRequestSessionKey=false` unless you require caller-selected sessions.

View File

@ -20,11 +20,21 @@ OpenClaw supports Brave Search API as a `web_search` provider.
```json5
{
plugins: {
entries: {
brave: {
config: {
webSearch: {
apiKey: "BRAVE_API_KEY_HERE",
},
},
},
},
},
tools: {
web: {
search: {
provider: "brave",
apiKey: "BRAVE_API_KEY_HERE",
maxResults: 5,
timeoutSeconds: 30,
},
@ -33,6 +43,9 @@ OpenClaw supports Brave Search API as a `web_search` provider.
}
```
Provider-specific Brave search settings now live under `plugins.entries.brave.config.webSearch.*`.
Legacy `tools.web.search.apiKey` still loads through the compatibility shim, but it is no longer the canonical config path.
## Tool parameters
| Parameter | Description |

View File

@ -126,7 +126,7 @@ launchctl load ~/Library/LaunchAgents/com.user.poke-messages.plist
## Onboarding
BlueBubbles is available in the interactive setup wizard:
BlueBubbles is available in interactive onboarding:
```
openclaw onboard

View File

@ -96,8 +96,10 @@ You will need to create a new application with a bot, add the bot to your server
Your Discord bot token is a secret (like a password). Set it on the machine running OpenClaw before messaging your agent.
```bash
openclaw config set channels.discord.token '"YOUR_BOT_TOKEN"' --json
openclaw config set channels.discord.enabled true --json
export DISCORD_BOT_TOKEN="YOUR_BOT_TOKEN"
openclaw config set channels.discord.token --ref-provider default --ref-source env --ref-id DISCORD_BOT_TOKEN --dry-run
openclaw config set channels.discord.token --ref-provider default --ref-source env --ref-id DISCORD_BOT_TOKEN
openclaw config set channels.discord.enabled true --strict-json
openclaw gateway
```
@ -121,7 +123,11 @@ openclaw gateway
channels: {
discord: {
enabled: true,
token: "YOUR_BOT_TOKEN",
token: {
source: "env",
provider: "default",
id: "DISCORD_BOT_TOKEN",
},
},
},
}
@ -133,7 +139,7 @@ openclaw gateway
DISCORD_BOT_TOKEN=...
```
SecretRef values are also supported for `channels.discord.token` (env/file/exec providers). See [Secrets Management](/gateway/secrets).
Plaintext `token` values are supported. SecretRef values are also supported for `channels.discord.token` across env/file/exec providers. See [Secrets Management](/gateway/secrets).
</Tab>
</Tabs>
@ -168,7 +174,7 @@ openclaw pairing approve discord <CODE>
<Note>
Token resolution is account-aware. Config token values win over env fallback. `DISCORD_BOT_TOKEN` is only used for the default account.
For advanced outbound calls (message tool/channel actions), an explicit per-call `token` is used for that call. Account policy/retry settings still come from the selected account in the active runtime snapshot.
For advanced outbound calls (message tool/channel actions), an explicit per-call `token` is used for that call. This applies to send and read/probe-style actions (for example read/search/fetch/thread/pins/permissions). Account policy/retry settings still come from the selected account in the active runtime snapshot.
</Note>
## Recommended: Set up a guild workspace

View File

@ -30,9 +30,9 @@ openclaw plugins install @openclaw/feishu
There are two ways to add the Feishu channel:
### Method 1: setup wizard (recommended)
### Method 1: onboarding (recommended)
If you just installed OpenClaw, run the setup wizard:
If you just installed OpenClaw, run onboarding:
```bash
openclaw onboard

View File

@ -191,6 +191,35 @@ OpenClaw resolves them **user-first**:
If you need deterministic behavior, always use the explicit prefixes (`user:<id>` / `channel:<id>`).
## DM channel retry
When OpenClaw sends to a Mattermost DM target and needs to resolve the direct channel first, it
retries transient direct-channel creation failures by default.
Use `channels.mattermost.dmChannelRetry` to tune that behavior globally for the Mattermost plugin,
or `channels.mattermost.accounts.<id>.dmChannelRetry` for one account.
```json5
{
channels: {
mattermost: {
dmChannelRetry: {
maxRetries: 3,
initialDelayMs: 1000,
maxDelayMs: 10000,
timeoutMs: 30000,
},
},
},
}
```
Notes:
- This applies only to DM channel creation (`/api/v4/channels/direct`), not every Mattermost API call.
- Retries apply to transient failures such as rate limits, 5xx responses, and network or timeout errors.
- 4xx client errors other than `429` are treated as permanent and are not retried.
## Reactions (message tool)
- Use `message action=react` with `channel=mattermost`.

View File

@ -16,7 +16,7 @@ Nostr is a decentralized protocol for social networking. This channel enables Op
### Onboarding (recommended)
- The setup wizard (`openclaw onboard`) and `openclaw channels add` list optional channel plugins.
- Onboarding (`openclaw onboard`) and `openclaw channels add` list optional channel plugins.
- Selecting Nostr prompts you to install the plugin on demand.
Install defaults:

View File

@ -115,7 +115,7 @@ Token resolution order is account-aware. In practice, config values win over env
`channels.telegram.allowFrom` accepts numeric Telegram user IDs. `telegram:` / `tg:` prefixes are accepted and normalized.
`dmPolicy: "allowlist"` with empty `allowFrom` blocks all DMs and is rejected by config validation.
The setup wizard accepts `@username` input and resolves it to numeric IDs.
Onboarding accepts `@username` input and resolves it to numeric IDs.
If you upgraded and your config contains `@username` allowlist entries, run `openclaw doctor --fix` to resolve them (best-effort; requires a Telegram bot token).
If you previously relied on pairing-store allowlist files, `openclaw doctor --fix` can recover entries into `channels.telegram.allowFrom` in allowlist flows (for example when `dmPolicy: "allowlist"` has no explicit IDs yet).

View File

@ -8,7 +8,7 @@ title: "acp"
# acp
Run the [Agent Client Protocol (ACP)](https://agentclientprotocol.com/) bridge that talks to a OpenClaw Gateway.
Run the [Agent Client Protocol (ACP)](https://agentclientprotocol.com/) bridge that talks to an OpenClaw Gateway.
This command speaks ACP over stdio for IDEs and forwards prompts to the Gateway
over WebSocket. It keeps ACP sessions mapped to Gateway session keys.
@ -102,7 +102,7 @@ Permission model (client debug mode):
## How to use this
Use ACP when an IDE (or other client) speaks Agent Client Protocol and you want
it to drive a OpenClaw Gateway session.
it to drive an OpenClaw Gateway session.
1. Ensure the Gateway is running (local or remote).
2. Configure the Gateway target (config or flags).

View File

@ -91,6 +91,7 @@ Use the built-in `user` profile, or create your own `existing-session` profile:
```bash
openclaw browser --browser-profile user tabs
openclaw browser create-profile --name chrome-live --driver existing-session
openclaw browser create-profile --name brave-live --driver existing-session --user-data-dir "~/Library/Application Support/BraveSoftware/Brave-Browser"
openclaw browser --browser-profile chrome-live tabs
```

View File

@ -7,9 +7,9 @@ title: "config"
# `openclaw config`
Config helpers: get/set/unset/validate values by path and print the active
config file. Run without a subcommand to open
the configure wizard (same as `openclaw configure`).
Config helpers for non-interactive edits in `openclaw.json`: get/set/unset/validate
values by path and print the active config file. Run without a subcommand to
open the configure wizard (same as `openclaw configure`).
## Examples
@ -19,7 +19,10 @@ openclaw config get browser.executablePath
openclaw config set browser.executablePath "/usr/bin/google-chrome"
openclaw config set agents.defaults.heartbeat.every "2h"
openclaw config set agents.list[0].tools.exec.node "node-id-or-name"
openclaw config unset tools.web.search.apiKey
openclaw config set channels.discord.token --ref-provider default --ref-source env --ref-id DISCORD_BOT_TOKEN
openclaw config set secrets.providers.vaultfile --provider-source file --provider-path /etc/openclaw/secrets.json --provider-mode json
openclaw config unset plugins.entries.brave.config.webSearch.apiKey
openclaw config set channels.discord.token --ref-provider default --ref-source env --ref-id DISCORD_BOT_TOKEN --dry-run
openclaw config validate
openclaw config validate --json
```
@ -51,6 +54,230 @@ openclaw config set gateway.port 19001 --strict-json
openclaw config set channels.whatsapp.groups '["*"]' --strict-json
```
## `config set` modes
`openclaw config set` supports four assignment styles:
1. Value mode: `openclaw config set <path> <value>`
2. SecretRef builder mode:
```bash
openclaw config set channels.discord.token \
--ref-provider default \
--ref-source env \
--ref-id DISCORD_BOT_TOKEN
```
3. Provider builder mode (`secrets.providers.<alias>` path only):
```bash
openclaw config set secrets.providers.vault \
--provider-source exec \
--provider-command /usr/local/bin/openclaw-vault \
--provider-arg read \
--provider-arg openai/api-key \
--provider-timeout-ms 5000
```
4. Batch mode (`--batch-json` or `--batch-file`):
```bash
openclaw config set --batch-json '[
{
"path": "secrets.providers.default",
"provider": { "source": "env" }
},
{
"path": "channels.discord.token",
"ref": { "source": "env", "provider": "default", "id": "DISCORD_BOT_TOKEN" }
}
]'
```
```bash
openclaw config set --batch-file ./config-set.batch.json --dry-run
```
Batch parsing always uses the batch payload (`--batch-json`/`--batch-file`) as the source of truth.
`--strict-json` / `--json` do not change batch parsing behavior.
JSON path/value mode remains supported for both SecretRefs and providers:
```bash
openclaw config set channels.discord.token \
'{"source":"env","provider":"default","id":"DISCORD_BOT_TOKEN"}' \
--strict-json
openclaw config set secrets.providers.vaultfile \
'{"source":"file","path":"/etc/openclaw/secrets.json","mode":"json"}' \
--strict-json
```
## Provider Builder Flags
Provider builder targets must use `secrets.providers.<alias>` as the path.
Common flags:
- `--provider-source <env|file|exec>`
- `--provider-timeout-ms <ms>` (`file`, `exec`)
Env provider (`--provider-source env`):
- `--provider-allowlist <ENV_VAR>` (repeatable)
File provider (`--provider-source file`):
- `--provider-path <path>` (required)
- `--provider-mode <singleValue|json>`
- `--provider-max-bytes <bytes>`
Exec provider (`--provider-source exec`):
- `--provider-command <path>` (required)
- `--provider-arg <arg>` (repeatable)
- `--provider-no-output-timeout-ms <ms>`
- `--provider-max-output-bytes <bytes>`
- `--provider-json-only`
- `--provider-env <KEY=VALUE>` (repeatable)
- `--provider-pass-env <ENV_VAR>` (repeatable)
- `--provider-trusted-dir <path>` (repeatable)
- `--provider-allow-insecure-path`
- `--provider-allow-symlink-command`
Hardened exec provider example:
```bash
openclaw config set secrets.providers.vault \
--provider-source exec \
--provider-command /usr/local/bin/openclaw-vault \
--provider-arg read \
--provider-arg openai/api-key \
--provider-json-only \
--provider-pass-env VAULT_TOKEN \
--provider-trusted-dir /usr/local/bin \
--provider-timeout-ms 5000
```
## Dry run
Use `--dry-run` to validate changes without writing `openclaw.json`.
```bash
openclaw config set channels.discord.token \
--ref-provider default \
--ref-source env \
--ref-id DISCORD_BOT_TOKEN \
--dry-run
openclaw config set channels.discord.token \
--ref-provider default \
--ref-source env \
--ref-id DISCORD_BOT_TOKEN \
--dry-run \
--json
openclaw config set channels.discord.token \
--ref-provider vault \
--ref-source exec \
--ref-id discord/token \
--dry-run \
--allow-exec
```
Dry-run behavior:
- Builder mode: runs SecretRef resolvability checks for changed refs/providers.
- JSON mode (`--strict-json`, `--json`, or batch mode): runs schema validation plus SecretRef resolvability checks.
- Exec SecretRef checks are skipped by default during dry-run to avoid command side effects.
- Use `--allow-exec` with `--dry-run` to opt in to exec SecretRef checks (this may execute provider commands).
- `--allow-exec` is dry-run only and errors if used without `--dry-run`.
`--dry-run --json` prints a machine-readable report:
- `ok`: whether dry-run passed
- `operations`: number of assignments evaluated
- `checks`: whether schema/resolvability checks ran
- `checks.resolvabilityComplete`: whether resolvability checks ran to completion (false when exec refs are skipped)
- `refsChecked`: number of refs actually resolved during dry-run
- `skippedExecRefs`: number of exec refs skipped because `--allow-exec` was not set
- `errors`: structured schema/resolvability failures when `ok=false`
### JSON Output Shape
```json5
{
ok: boolean,
operations: number,
configPath: string,
inputModes: ["value" | "json" | "builder", ...],
checks: {
schema: boolean,
resolvability: boolean,
resolvabilityComplete: boolean,
},
refsChecked: number,
skippedExecRefs: number,
errors?: [
{
kind: "schema" | "resolvability",
message: string,
ref?: string, // present for resolvability errors
},
],
}
```
Success example:
```json
{
"ok": true,
"operations": 1,
"configPath": "~/.openclaw/openclaw.json",
"inputModes": ["builder"],
"checks": {
"schema": false,
"resolvability": true,
"resolvabilityComplete": true
},
"refsChecked": 1,
"skippedExecRefs": 0
}
```
Failure example:
```json
{
"ok": false,
"operations": 1,
"configPath": "~/.openclaw/openclaw.json",
"inputModes": ["builder"],
"checks": {
"schema": false,
"resolvability": true,
"resolvabilityComplete": true
},
"refsChecked": 1,
"skippedExecRefs": 0,
"errors": [
{
"kind": "resolvability",
"message": "Error: Environment variable \"MISSING_TEST_SECRET\" is not set.",
"ref": "env:default:MISSING_TEST_SECRET"
}
]
}
```
If dry-run fails:
- `config schema validation failed`: your post-change config shape is invalid; fix path/value or provider/ref object shape.
- `SecretRef assignment(s) could not be resolved`: referenced provider/ref currently cannot resolve (missing env var, invalid file pointer, exec provider failure, or provider/source mismatch).
- `Dry run note: skipped <n> exec SecretRef resolvability check(s)`: dry-run skipped exec refs; rerun with `--allow-exec` if you need exec resolvability validation.
- For batch mode, fix failing entries and rerun `--dry-run` before writing.
## Subcommands
- `config file`: Print the active config file path (resolved from `OPENCLAW_CONFIG_PATH` or default location).

View File

@ -32,6 +32,8 @@ Notes:
- Doctor includes a memory-search readiness check and can recommend `openclaw configure --section model` when embedding credentials are missing.
- If sandbox mode is enabled but Docker is unavailable, doctor reports a high-signal warning with remediation (`install Docker` or `openclaw config set agents.defaults.sandbox.mode off`).
- If `gateway.auth.token`/`gateway.auth.password` are SecretRef-managed and unavailable in the current command path, doctor reports a read-only warning and does not write plaintext fallback credentials.
- If channel SecretRef inspection fails in a fix path, doctor continues and reports a warning instead of exiting early.
- Telegram `allowFrom` username auto-resolution (`doctor --fix`) requires a resolvable Telegram token in the current command path. If token inspection is unavailable, doctor reports a warning and skips auto-resolution for that pass.
## macOS: `launchctl` env overrides

View File

@ -101,6 +101,8 @@ openclaw [--dev] [--profile <name>] <command>
get
set
unset
file
validate
completion
doctor
dashboard
@ -274,17 +276,18 @@ Note: plugins can add additional top-level commands (for example `openclaw voice
## Secrets
- `openclaw secrets reload` — re-resolve refs and atomically swap the runtime snapshot.
- `openclaw secrets audit` — scan for plaintext residues, unresolved refs, and precedence drift.
- `openclaw secrets configure` — interactive helper for provider setup + SecretRef mapping + preflight/apply.
- `openclaw secrets apply --from <plan.json>` — apply a previously generated plan (`--dry-run` supported).
- `openclaw secrets audit` — scan for plaintext residues, unresolved refs, and precedence drift (`--allow-exec` to execute exec providers during audit).
- `openclaw secrets configure` — interactive helper for provider setup + SecretRef mapping + preflight/apply (`--allow-exec` to execute exec providers during preflight and exec-containing apply flows).
- `openclaw secrets apply --from <plan.json>` — apply a previously generated plan (`--dry-run` supported; use `--allow-exec` to permit exec providers in dry-run and exec-containing write plans).
## Plugins
Manage extensions and their config:
- `openclaw plugins list` — discover plugins (use `--json` for machine output).
- `openclaw plugins info <id>` — show details for a plugin.
- `openclaw plugins install <path|.tgz|npm-spec>` — install a plugin (or add a plugin path to `plugins.load.paths`).
- `openclaw plugins inspect <id>` — show details for a plugin (`info` is an alias).
- `openclaw plugins install <path|.tgz|npm-spec|plugin@marketplace>` — install a plugin (or add a plugin path to `plugins.load.paths`).
- `openclaw plugins marketplace list <marketplace>` — list marketplace entries before install.
- `openclaw plugins enable <id>` / `disable <id>` — toggle `plugins.entries.<id>.enabled`.
- `openclaw plugins doctor` — report plugin load errors.
@ -317,22 +320,22 @@ Initialize config + workspace.
Options:
- `--workspace <dir>`: agent workspace path (default `~/.openclaw/workspace`).
- `--wizard`: run the setup wizard.
- `--non-interactive`: run wizard without prompts.
- `--mode <local|remote>`: wizard mode.
- `--wizard`: run onboarding.
- `--non-interactive`: run onboarding without prompts.
- `--mode <local|remote>`: onboard mode.
- `--remote-url <url>`: remote Gateway URL.
- `--remote-token <token>`: remote Gateway token.
Wizard auto-runs when any wizard flags are present (`--non-interactive`, `--mode`, `--remote-url`, `--remote-token`).
Onboarding auto-runs when any onboarding flags are present (`--non-interactive`, `--mode`, `--remote-url`, `--remote-token`).
### `onboard`
Interactive wizard to set up gateway, workspace, and skills.
Interactive onboarding for gateway, workspace, and skills.
Options:
- `--workspace <dir>`
- `--reset` (reset config + credentials + sessions before wizard)
- `--reset` (reset config + credentials + sessions before onboarding)
- `--reset-scope <config|config+creds+sessions|full>` (default `config+creds+sessions`; use `full` to also remove workspace)
- `--non-interactive`
- `--mode <local|remote>`
@ -392,7 +395,15 @@ subcommand launches the wizard.
Subcommands:
- `config get <path>`: print a config value (dot/bracket path).
- `config set <path> <value>`: set a value (JSON5 or raw string).
- `config set`: supports four assignment modes:
- value mode: `config set <path> <value>` (JSON5-or-string parsing)
- SecretRef builder mode: `config set <path> --ref-provider <provider> --ref-source <source> --ref-id <id>`
- provider builder mode: `config set secrets.providers.<alias> --provider-source <env|file|exec> ...`
- batch mode: `config set --batch-json '<json>'` or `config set --batch-file <path>`
- `config set --dry-run`: validate assignments without writing `openclaw.json` (exec SecretRef checks are skipped by default).
- `config set --allow-exec --dry-run`: opt in to exec SecretRef dry-run checks (may execute provider commands).
- `config set --dry-run --json`: emit machine-readable dry-run output (checks + completeness signal, operations, refs checked/skipped, errors).
- `config set --strict-json`: require JSON5 parsing for path/value input. `--json` remains a legacy alias for strict parsing outside dry-run output mode.
- `config unset <path>`: remove a value.
- `config file`: print the active config file path.
- `config validate`: validate the current config against the schema without starting the gateway.

View File

@ -50,6 +50,16 @@ Name lookup:
- `--dry-run`
- `--verbose`
## SecretRef behavior
- `openclaw message` resolves supported channel SecretRefs before running the selected action.
- Resolution is scoped to the active action target when possible:
- channel-scoped when `--channel` is set (or inferred from prefixed targets like `discord:...`)
- account-scoped when `--account` is set (channel globals + selected account surfaces)
- when `--account` is omitted, OpenClaw does not force a `default` account SecretRef scope
- Unresolved SecretRefs on unrelated channels do not block a targeted message action.
- If the selected channel/account SecretRef is unresolved, the command fails closed for that action.
## Actions
### Core

View File

@ -1,5 +1,5 @@
---
summary: "CLI reference for `openclaw onboard` (interactive setup wizard)"
summary: "CLI reference for `openclaw onboard` (interactive onboarding)"
read_when:
- You want guided setup for gateway, workspace, auth, channels, and skills
title: "onboard"
@ -7,11 +7,11 @@ title: "onboard"
# `openclaw onboard`
Interactive setup wizard (local or remote Gateway setup).
Interactive onboarding for local or remote Gateway setup.
## Related guides
- CLI onboarding hub: [Setup Wizard (CLI)](/start/wizard)
- CLI onboarding hub: [Onboarding (CLI)](/start/wizard)
- Onboarding overview: [Onboarding Overview](/start/onboarding-overview)
- CLI onboarding reference: [CLI Setup Reference](/start/wizard-cli-reference)
- CLI automation: [CLI Automation](/start/wizard-cli-automation)

View File

@ -1,5 +1,5 @@
---
summary: "CLI reference for `openclaw plugins` (list, install, uninstall, enable/disable, doctor)"
summary: "CLI reference for `openclaw plugins` (list, install, marketplace, uninstall, enable/disable, doctor)"
read_when:
- You want to install or manage Gateway plugins or compatible bundles
- You want to debug plugin load failures
@ -21,13 +21,15 @@ Related:
```bash
openclaw plugins list
openclaw plugins info <id>
openclaw plugins install <path-or-spec>
openclaw plugins inspect <id>
openclaw plugins enable <id>
openclaw plugins disable <id>
openclaw plugins uninstall <id>
openclaw plugins doctor
openclaw plugins update <id>
openclaw plugins update --all
openclaw plugins marketplace list <marketplace>
```
Bundled plugins ship with OpenClaw but start disabled. Use `plugins enable` to
@ -46,6 +48,8 @@ capabilities.
```bash
openclaw plugins install <path-or-spec>
openclaw plugins install <npm-spec> --pin
openclaw plugins install <plugin>@<marketplace>
openclaw plugins install <plugin> --marketplace <marketplace>
```
Security note: treat plugin installs like running code. Prefer pinned versions.
@ -65,6 +69,31 @@ name, use an explicit scoped spec (for example `@scope/diffs`).
Supported archives: `.zip`, `.tgz`, `.tar.gz`, `.tar`.
Claude marketplace installs are also supported.
Use `plugin@marketplace` shorthand when the marketplace name exists in Claude's
local registry cache at `~/.claude/plugins/known_marketplaces.json`:
```bash
openclaw plugins marketplace list <marketplace-name>
openclaw plugins install <plugin-name>@<marketplace-name>
```
Use `--marketplace` when you want to pass the marketplace source explicitly:
```bash
openclaw plugins install <plugin-name> --marketplace <marketplace-name>
openclaw plugins install <plugin-name> --marketplace <owner/repo>
openclaw plugins install <plugin-name> --marketplace ./my-marketplace
```
Marketplace sources can be:
- a Claude known-marketplace name from `~/.claude/plugins/known_marketplaces.json`
- a local marketplace root or `marketplace.json` path
- a GitHub repo shorthand such as `owner/repo`
- a git URL
For local paths and archives, OpenClaw auto-detects:
- native OpenClaw plugins (`openclaw.plugin.json`)
@ -114,8 +143,34 @@ openclaw plugins update --all
openclaw plugins update <id> --dry-run
```
Updates only apply to plugins installed from npm (tracked in `plugins.installs`).
Updates apply to tracked installs in `plugins.installs`, currently npm and
marketplace installs.
When a stored integrity hash exists and the fetched artifact hash changes,
OpenClaw prints a warning and asks for confirmation before proceeding. Use
global `--yes` to bypass prompts in CI/non-interactive runs.
### Inspect
```bash
openclaw plugins inspect <id>
openclaw plugins inspect <id> --json
```
Deep introspection for a single plugin. Shows identity, load status, source,
registered capabilities, hooks, tools, commands, services, gateway methods,
HTTP routes, policy flags, diagnostics, and install metadata.
Each plugin is classified by what it actually registers at runtime:
- **plain-capability** — one capability type (e.g. a provider-only plugin)
- **hybrid-capability** — multiple capability types (e.g. text + speech + images)
- **hook-only** — only hooks, no capabilities or surfaces
- **non-capability** — tools/commands/services but no capabilities
See [Plugins](/tools/plugin#plugin-shapes) for more on the capability model.
The `--json` flag outputs a machine-readable report suitable for scripting and
auditing.
`info` is an alias for `inspect`.

View File

@ -14,9 +14,9 @@ Use `openclaw secrets` to manage SecretRefs and keep the active runtime snapshot
Command roles:
- `reload`: gateway RPC (`secrets.reload`) that re-resolves refs and swaps runtime snapshot only on full success (no config writes).
- `audit`: read-only scan of configuration/auth/generated-model stores and legacy residues for plaintext, unresolved refs, and precedence drift.
- `audit`: read-only scan of configuration/auth/generated-model stores and legacy residues for plaintext, unresolved refs, and precedence drift (exec refs are skipped unless `--allow-exec` is set).
- `configure`: interactive planner for provider setup, target mapping, and preflight (TTY required).
- `apply`: execute a saved plan (`--dry-run` for validation only), then scrub targeted plaintext residues.
- `apply`: execute a saved plan (`--dry-run` for validation only; dry-run skips exec checks by default, and write mode rejects exec-containing plans unless `--allow-exec` is set), then scrub targeted plaintext residues.
Recommended operator loop:
@ -29,6 +29,8 @@ openclaw secrets audit --check
openclaw secrets reload
```
If your plan includes `exec` SecretRefs/providers, pass `--allow-exec` on both dry-run and write apply commands.
Exit code note for CI/gates:
- `audit --check` returns `1` on findings.
@ -73,6 +75,7 @@ Header residue note:
openclaw secrets audit
openclaw secrets audit --check
openclaw secrets audit --json
openclaw secrets audit --allow-exec
```
Exit behavior:
@ -83,6 +86,7 @@ Exit behavior:
Report shape highlights:
- `status`: `clean | findings | unresolved`
- `resolution`: `refsChecked`, `skippedExecRefs`, `resolvabilityComplete`
- `summary`: `plaintextCount`, `unresolvedRefCount`, `shadowedRefCount`, `legacyResidueCount`
- finding codes:
- `PLAINTEXT_FOUND`
@ -115,6 +119,7 @@ Flags:
- `--providers-only`: configure `secrets.providers` only, skip credential mapping.
- `--skip-provider-setup`: skip provider setup and map credentials to existing providers.
- `--agent <id>`: scope `auth-profiles.json` target discovery and writes to one agent store.
- `--allow-exec`: allow exec SecretRef checks during preflight/apply (may execute provider commands).
Notes:
@ -124,6 +129,7 @@ Notes:
- `configure` supports creating new `auth-profiles.json` mappings directly in the picker flow.
- Canonical supported surface: [SecretRef Credential Surface](/reference/secretref-credential-surface).
- It performs preflight resolution before apply.
- If preflight/apply includes exec refs, keep `--allow-exec` set for both steps.
- Generated plans default to scrub options (`scrubEnv`, `scrubAuthProfilesForProviderTargets`, `scrubLegacyAuthJson` all enabled).
- Apply path is one-way for scrubbed plaintext values.
- Without `--apply`, CLI still prompts `Apply this plan now?` after preflight.
@ -141,10 +147,19 @@ Apply or preflight a plan generated previously:
```bash
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json --allow-exec
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json --dry-run
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json --dry-run --allow-exec
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json --json
```
Exec behavior:
- `--dry-run` validates preflight without writing files.
- exec SecretRef checks are skipped by default in dry-run.
- write mode rejects plans that contain exec SecretRefs/providers unless `--allow-exec` is set.
- Use `--allow-exec` to opt in to exec provider checks/execution in either mode.
Plan contract details (allowed target paths, validation rules, and failure semantics):
- [Secrets Apply Plan Contract](/gateway/secrets-plan-contract)

View File

@ -30,7 +30,7 @@ This is for cooperative/shared inbox hardening. A single Gateway shared by mutua
It also emits `security.trust_model.multi_user_heuristic` when config suggests likely shared-user ingress (for example open DM/group policy, configured group targets, or wildcard sender rules), and reminds you that OpenClaw is a personal-assistant trust model by default.
For intentional shared-user setups, the audit guidance is to sandbox all sessions, keep filesystem access workspace-scoped, and keep personal/private identities or credentials off that runtime.
It also warns when small models (`<=300B`) are used without sandboxing and with web/browser tools enabled.
For webhook ingress, it warns when `hooks.defaultSessionKey` is unset, when request `sessionKey` overrides are enabled, and when overrides are enabled without `hooks.allowedSessionKeyPrefixes`.
For webhook ingress, it warns when `hooks.token` reuses the Gateway token, when `hooks.defaultSessionKey` is unset, when `hooks.allowedAgentIds` is unrestricted, when request `sessionKey` overrides are enabled, and when overrides are enabled without `hooks.allowedSessionKeyPrefixes`.
It also warns when sandbox Docker settings are configured while sandbox mode is off, when `gateway.nodes.denyCommands` uses ineffective pattern-like/unknown entries (exact node command-name matching only, not shell-text filtering), when `gateway.nodes.allowCommands` explicitly enables dangerous node commands, when global `tools.profile="minimal"` is overridden by agent tool profiles, when open groups expose runtime/filesystem tools without sandbox/workspace guards, and when installed extension plugin tools may be reachable under permissive tool policy.
It also flags `gateway.allowRealIpFallback=true` (header-spoofing risk if proxies are misconfigured) and `discovery.mdns.mode="full"` (metadata leakage via mDNS TXT records).
It also warns when sandbox browser uses Docker `bridge` network without `sandbox.browser.cdpSourceRange`.

View File

@ -1,7 +1,7 @@
---
summary: "CLI reference for `openclaw setup` (initialize config + workspace)"
read_when:
- Youre doing first-run setup without the full setup wizard
- Youre doing first-run setup without full CLI onboarding
- You want to set the default workspace path
title: "setup"
---
@ -13,7 +13,7 @@ Initialize `~/.openclaw/openclaw.json` and the agent workspace.
Related:
- Getting started: [Getting started](/start/getting-started)
- Wizard: [Onboarding](/start/onboarding)
- CLI onboarding: [Onboarding (CLI)](/start/wizard)
## Examples
@ -22,7 +22,7 @@ openclaw setup
openclaw setup --workspace ~/.openclaw/workspace
```
To run the wizard via setup:
To run onboarding via setup:
```bash
openclaw setup --wizard

View File

@ -27,3 +27,4 @@ Notes:
- Read-only status surfaces (`status`, `status --json`, `status --all`) resolve supported SecretRefs for their targeted config paths when possible.
- 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.

View File

@ -97,6 +97,25 @@ compaction and can run alongside it.
See [OpenAI provider](/providers/openai) for model params and overrides.
## Custom context engines
Compaction behavior is owned by the active
[context engine](/concepts/context-engine). The legacy engine uses the built-in
summarization described above. Plugin engines (selected via
`plugins.slots.contextEngine`) can implement any compaction strategy — DAG
summaries, vector retrieval, incremental condensation, etc.
When a plugin engine sets `ownsCompaction: true`, OpenClaw delegates all
compaction decisions to the engine and does not run built-in auto-compaction.
When `ownsCompaction` is `false` or unset, OpenClaw may still use Pi's
built-in in-attempt auto-compaction, but the active engine's `compact()` method
still handles `/compact` and overflow recovery. There is no automatic fallback
to the legacy engine's compaction path.
If you are building a non-owning context engine, implement `compact()` by
calling `delegateCompactionToRuntime(...)` from `openclaw/plugin-sdk/core`.
## Tips
- Use `/compact` when sessions feel stale or context is bloated.

View File

@ -0,0 +1,268 @@
---
summary: "Context engine: pluggable context assembly, compaction, and subagent lifecycle"
read_when:
- You want to understand how OpenClaw assembles model context
- You are switching between the legacy engine and a plugin engine
- You are building a context engine plugin
title: "Context Engine"
---
# Context Engine
A **context engine** controls how OpenClaw builds model context for each run.
It decides which messages to include, how to summarize older history, and how
to manage context across subagent boundaries.
OpenClaw ships with a built-in `legacy` engine. Plugins can register
alternative engines that replace the active context-engine lifecycle.
## Quick start
Check which engine is active:
```bash
openclaw doctor
# or inspect config directly:
cat ~/.openclaw/openclaw.json | jq '.plugins.slots.contextEngine'
```
### Installing a context engine plugin
Context engine plugins are installed like any other OpenClaw plugin. Install
first, then select the engine in the slot:
```bash
# Install from npm
openclaw plugins install @martian-engineering/lossless-claw
# Or install from a local path (for development)
openclaw plugins install -l ./my-context-engine
```
Then enable the plugin and select it as the active engine in your config:
```json5
// openclaw.json
{
plugins: {
slots: {
contextEngine: "lossless-claw", // must match the plugin's registered engine id
},
entries: {
"lossless-claw": {
enabled: true,
// Plugin-specific config goes here (see the plugin's docs)
},
},
},
}
```
Restart the gateway after installing and configuring.
To switch back to the built-in engine, set `contextEngine` to `"legacy"` (or
remove the key entirely — `"legacy"` is the default).
## How it works
Every time OpenClaw runs a model prompt, the context engine participates at
four lifecycle points:
1. **Ingest** — called when a new message is added to the session. The engine
can store or index the message in its own data store.
2. **Assemble** — called before each model run. The engine returns an ordered
set of messages (and an optional `systemPromptAddition`) that fit within
the token budget.
3. **Compact** — called when the context window is full, or when the user runs
`/compact`. The engine summarizes older history to free space.
4. **After turn** — called after a run completes. The engine can persist state,
trigger background compaction, or update indexes.
### Subagent lifecycle (optional)
OpenClaw currently calls one subagent lifecycle hook:
- **onSubagentEnded** — clean up when a subagent session completes or is swept.
The `prepareSubagentSpawn` hook is part of the interface for future use, but
the runtime does not invoke it yet.
### System prompt addition
The `assemble` method can return a `systemPromptAddition` string. OpenClaw
prepends this to the system prompt for the run. This lets engines inject
dynamic recall guidance, retrieval instructions, or context-aware hints
without requiring static workspace files.
## The legacy engine
The built-in `legacy` engine preserves OpenClaw's original behavior:
- **Ingest**: no-op (the session manager handles message persistence directly).
- **Assemble**: pass-through (the existing sanitize → validate → limit pipeline
in the runtime handles context assembly).
- **Compact**: delegates to the built-in summarization compaction, which creates
a single summary of older messages and keeps recent messages intact.
- **After turn**: no-op.
The legacy engine does not register tools or provide a `systemPromptAddition`.
When no `plugins.slots.contextEngine` is set (or it's set to `"legacy"`), this
engine is used automatically.
## Plugin engines
A plugin can register a context engine using the plugin API:
```ts
export default function register(api) {
api.registerContextEngine("my-engine", () => ({
info: {
id: "my-engine",
name: "My Context Engine",
ownsCompaction: true,
},
async ingest({ sessionId, message, isHeartbeat }) {
// Store the message in your data store
return { ingested: true };
},
async assemble({ sessionId, messages, tokenBudget }) {
// Return messages that fit the budget
return {
messages: buildContext(messages, tokenBudget),
estimatedTokens: countTokens(messages),
systemPromptAddition: "Use lcm_grep to search history...",
};
},
async compact({ sessionId, force }) {
// Summarize older context
return { ok: true, compacted: true };
},
}));
}
```
Then enable it in config:
```json5
{
plugins: {
slots: {
contextEngine: "my-engine",
},
entries: {
"my-engine": {
enabled: true,
},
},
},
}
```
### The ContextEngine interface
Required members:
| Member | Kind | Purpose |
| ------------------ | -------- | -------------------------------------------------------- |
| `info` | Property | Engine id, name, version, and whether it owns compaction |
| `ingest(params)` | Method | Store a single message |
| `assemble(params)` | Method | Build context for a model run (returns `AssembleResult`) |
| `compact(params)` | Method | Summarize/reduce context |
`assemble` returns an `AssembleResult` with:
- `messages` — the ordered messages to send to the model.
- `estimatedTokens` (required, `number`) — the engine's estimate of total
tokens in the assembled context. OpenClaw uses this for compaction threshold
decisions and diagnostic reporting.
- `systemPromptAddition` (optional, `string`) — prepended to the system prompt.
Optional members:
| Member | Kind | Purpose |
| ------------------------------ | ------ | --------------------------------------------------------------------------------------------------------------- |
| `bootstrap(params)` | Method | Initialize engine state for a session. Called once when the engine first sees a session (e.g., import history). |
| `ingestBatch(params)` | Method | Ingest a completed turn as a batch. Called after a run completes, with all messages from that turn at once. |
| `afterTurn(params)` | Method | Post-run lifecycle work (persist state, trigger background compaction). |
| `prepareSubagentSpawn(params)` | Method | Set up shared state for a child session. |
| `onSubagentEnded(params)` | Method | Clean up after a subagent ends. |
| `dispose()` | Method | Release resources. Called during gateway shutdown or plugin reload — not per-session. |
### ownsCompaction
`ownsCompaction` controls whether Pi's built-in in-attempt auto-compaction stays
enabled for the run:
- `true` — the engine owns compaction behavior. OpenClaw disables Pi's built-in
auto-compaction for that run, and the engine's `compact()` implementation is
responsible for `/compact`, overflow recovery compaction, and any proactive
compaction it wants to do in `afterTurn()`.
- `false` or unset — Pi's built-in auto-compaction may still run during prompt
execution, but the active engine's `compact()` method is still called for
`/compact` and overflow recovery.
`ownsCompaction: false` does **not** mean OpenClaw automatically falls back to
the legacy engine's compaction path.
That means there are two valid plugin patterns:
- **Owning mode** — implement your own compaction algorithm and set
`ownsCompaction: true`.
- **Delegating mode** — set `ownsCompaction: false` and have `compact()` call
`delegateCompactionToRuntime(...)` from `openclaw/plugin-sdk/core` to use
OpenClaw's built-in compaction behavior.
A no-op `compact()` is unsafe for an active non-owning engine because it
disables the normal `/compact` and overflow-recovery compaction path for that
engine slot.
## Configuration reference
```json5
{
plugins: {
slots: {
// Select the active context engine. Default: "legacy".
// Set to a plugin id to use a plugin engine.
contextEngine: "legacy",
},
},
}
```
The slot is exclusive at run time — only one registered context engine is
resolved for a given run or compaction operation. Other enabled
`kind: "context-engine"` plugins can still load and run their registration
code; `plugins.slots.contextEngine` only selects which registered engine id
OpenClaw resolves when it needs a context engine.
## Relationship to compaction and memory
- **Compaction** is one responsibility of the context engine. The legacy engine
delegates to OpenClaw's built-in summarization. Plugin engines can implement
any compaction strategy (DAG summaries, vector retrieval, etc.).
- **Memory plugins** (`plugins.slots.memory`) are separate from context engines.
Memory plugins provide search/retrieval; context engines control what the
model sees. They can work together — a context engine might use memory
plugin data during assembly.
- **Session pruning** (trimming old tool results in-memory) still runs
regardless of which context engine is active.
## Tips
- Use `openclaw doctor` to verify your engine is loading correctly.
- If switching engines, existing sessions continue with their current history.
The new engine takes over for future runs.
- Engine errors are logged and surfaced in diagnostics. If a plugin engine
fails to register or the selected engine id cannot be resolved, OpenClaw
does not fall back automatically; runs fail until you fix the plugin or
switch `plugins.slots.contextEngine` back to `"legacy"`.
- For development, use `openclaw plugins install -l ./my-engine` to link a
local plugin directory without copying.
See also: [Compaction](/concepts/compaction), [Context](/concepts/context),
[Plugins](/tools/plugin), [Plugin manifest](/plugins/manifest).

View File

@ -157,7 +157,10 @@ By default, OpenClaw uses the built-in `legacy` context engine for assembly and
compaction. If you install a plugin that provides `kind: "context-engine"` and
select it with `plugins.slots.contextEngine`, OpenClaw delegates context
assembly, `/compact`, and related subagent context lifecycle hooks to that
engine instead.
engine instead. `ownsCompaction: false` does not auto-fallback to the legacy
engine; the active engine must still implement `compact()` correctly. See
[Context Engine](/concepts/context-engine) for the full
pluggable interface, lifecycle hooks, and configuration.
## What `/context` actually reports

View File

@ -32,6 +32,10 @@ For model selection rules, see [/concepts/models](/concepts/models).
`supportsXHighThinking`, `resolveDefaultThinkingLevel`,
`isModernModelRef`, `prepareRuntimeAuth`, `resolveUsageAuth`, and
`fetchUsageSnapshot`.
- Note: provider runtime `capabilities` is shared runner metadata (provider
family, transcript/tooling quirks, transport/cache hints). It is not the
same as the [public capability model](/tools/plugin#public-capability-model)
which describes what a plugin registers (text inference, speech, etc.).
## Plugin-owned provider behavior

View File

@ -26,6 +26,7 @@ Related:
- `agents.defaults.models` is the allowlist/catalog of models OpenClaw can use (plus aliases).
- `agents.defaults.imageModel` is used **only when** the primary model cant accept images.
- `agents.defaults.imageGenerationModel` is used by the shared image-generation capability. If omitted, `image_generate` can still infer a provider default from compatible auth-backed image-generation plugins.
- Per-agent defaults can override `agents.defaults.model` via `agents.list[].model` plus bindings (see [/concepts/multi-agent](/concepts/multi-agent)).
## Quick model policy
@ -34,9 +35,9 @@ Related:
- Use fallbacks for cost/latency-sensitive tasks and lower-stakes chat.
- For tool-enabled agents or untrusted inputs, avoid older/weaker model tiers.
## Setup wizard (recommended)
## Onboarding (recommended)
If you dont want to hand-edit config, run the setup wizard:
If you dont want to hand-edit config, run onboarding:
```bash
openclaw onboard
@ -49,6 +50,7 @@ subscription** (OAuth) and **Anthropic** (API key or `claude setup-token`).
- `agents.defaults.model.primary` and `agents.defaults.model.fallbacks`
- `agents.defaults.imageModel.primary` and `agents.defaults.imageModel.fallbacks`
- `agents.defaults.imageGenerationModel.primary` and `agents.defaults.imageGenerationModel.fallbacks`
- `agents.defaults.models` (allowlist + aliases + provider params)
- `models.providers` (custom providers written into `models.json`)

View File

@ -59,6 +59,10 @@
"source": "/compaction",
"destination": "/concepts/compaction"
},
{
"source": "/context-engine",
"destination": "/concepts/context-engine"
},
{
"source": "/cron",
"destination": "/cron-jobs"
@ -952,6 +956,7 @@
"concepts/agent-loop",
"concepts/system-prompt",
"concepts/context",
"concepts/context-engine",
"concepts/agent-workspace",
"concepts/oauth"
]
@ -1050,6 +1055,7 @@
"plugins/zalouser",
"plugins/manifest",
"plugins/agent-tools",
"tools/capability-cookbook",
"prose"
]
},

View File

@ -49,7 +49,7 @@ openclaw models status
openclaw doctor
```
If youd rather not manage env vars yourself, the setup wizard can store
If youd rather not manage env vars yourself, onboarding can store
API keys for daemon use: `openclaw onboard`.
See [Help](/help) for details on env inheritance (`env.shellEnv`,

View File

@ -434,7 +434,7 @@ Save to `~/.openclaw/openclaw.json` and you can DM the bot from that number.
nodeManager: "npm",
},
entries: {
"nano-banana-pro": {
"image-lab": {
enabled: true,
apiKey: "GEMINI_KEY_HERE",
env: { GEMINI_API_KEY: "GEMINI_KEY_HERE" },

View File

@ -875,6 +875,10 @@ Time format in system prompt. Default: `auto` (OS preference).
primary: "openrouter/qwen/qwen-2.5-vl-72b-instruct:free",
fallbacks: ["openrouter/google/gemini-2.0-flash-vision:free"],
},
imageGenerationModel: {
primary: "openai/gpt-image-1",
fallbacks: ["google/gemini-3.1-flash-image-preview"],
},
pdfModel: {
primary: "anthropic/claude-opus-4-6",
fallbacks: ["openai/gpt-5-mini"],
@ -899,6 +903,9 @@ Time format in system prompt. Default: `auto` (OS preference).
- `imageModel`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`).
- Used by the `image` tool path as its vision-model config.
- Also used as fallback routing when the selected/default model cannot accept image input.
- `imageGenerationModel`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`).
- Used by the shared image-generation capability and any future tool/plugin surface that generates images.
- If omitted, `image_generate` can still infer a best-effort provider default from compatible auth-backed image-generation providers.
- `pdfModel`: accepts either a string (`"provider/model"`) or an object (`{ primary, fallbacks }`).
- Used by the `pdf` tool for model routing.
- If omitted, the PDF tool falls back to `imageModel`, then to best-effort provider defaults.
@ -2365,7 +2372,7 @@ See [Local Models](/gateway/local-models). TL;DR: run MiniMax M2.5 via LM Studio
nodeManager: "npm", // npm | pnpm | yarn
},
entries: {
"nano-banana-pro": {
"image-lab": {
apiKey: { source: "env", provider: "default", id: "GEMINI_API_KEY" }, // or plaintext string
env: { GEMINI_API_KEY: "GEMINI_KEY_HERE" },
},
@ -2413,6 +2420,8 @@ See [Local Models](/gateway/local-models). TL;DR: run MiniMax M2.5 via LM Studio
- `plugins.entries.<id>.apiKey`: plugin-level API key convenience field (when supported by the plugin).
- `plugins.entries.<id>.env`: plugin-scoped env var map.
- `plugins.entries.<id>.hooks.allowPromptInjection`: when `false`, core blocks `before_prompt_build` and ignores prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride`. Applies to native plugin hooks and supported bundle-provided hook directories.
- `plugins.entries.<id>.subagent.allowModelOverride`: explicitly trust this plugin to request per-run `provider` and `model` overrides for background subagent runs.
- `plugins.entries.<id>.subagent.allowedModels`: optional allowlist of canonical `provider/model` targets for trusted subagent overrides. Use `"*"` only when you intentionally want to allow any model.
- `plugins.entries.<id>.config`: plugin-defined config object (validated by native OpenClaw plugin schema when available).
- Enabled Claude bundle plugins can also contribute embedded Pi defaults from `settings.json`; OpenClaw applies those as sanitized agent settings, not as raw OpenClaw config patches.
- `plugins.slots.memory`: pick the active memory plugin id, or `"none"` to disable memory plugins.
@ -2443,6 +2452,12 @@ See [Plugins](/tools/plugin).
openclaw: { cdpPort: 18800, color: "#FF4500" },
work: { cdpPort: 18801, color: "#0066CC" },
user: { driver: "existing-session", attachOnly: true, color: "#00AA00" },
brave: {
driver: "existing-session",
attachOnly: true,
userDataDir: "~/Library/Application Support/BraveSoftware/Brave-Browser",
color: "#FB542B",
},
remote: { cdpUrl: "http://10.0.0.42:9222", color: "#00AA00" },
},
color: "#FF4500",
@ -2463,6 +2478,8 @@ See [Plugins](/tools/plugin).
- In strict mode, use `ssrfPolicy.hostnameAllowlist` and `ssrfPolicy.allowedHostnames` for explicit exceptions.
- Remote profiles are attach-only (start/stop/reset disabled).
- `existing-session` profiles are host-only and use Chrome MCP instead of CDP.
- `existing-session` profiles can set `userDataDir` to target a specific
Chromium-based browser profile such as Brave or Edge.
- Auto-detect order: default browser if Chromium-based → Chrome → Brave → Edge → Chromium → Chrome Canary.
- Control service: loopback only (port derived from `gateway.port`, default `18791`).
- `extraArgs` appends extra launch flags to local Chromium startup (for example
@ -2598,6 +2615,8 @@ See [Plugins](/tools/plugin).
- `gateway.http.endpoints.responses.maxUrlParts`
- `gateway.http.endpoints.responses.files.urlAllowlist`
- `gateway.http.endpoints.responses.images.urlAllowlist`
Empty allowlists are treated as unset; use `gateway.http.endpoints.responses.files.allowUrl=false`
and/or `gateway.http.endpoints.responses.images.allowUrl=false` to disable URL fetching.
- Optional response hardening header:
- `gateway.http.securityHeaders.strictTransportSecurity` (set only for HTTPS origins you control; see [Trusted Proxy Auth](/gateway/trusted-proxy-auth#tls-termination-and-hsts))
@ -2942,7 +2961,7 @@ Notes:
## Wizard
Metadata written by CLI wizards (`onboard`, `configure`, `doctor`):
Metadata written by CLI guided setup flows (`onboard`, `configure`, `doctor`):
```json5
{

View File

@ -38,7 +38,7 @@ See the [full reference](/gateway/configuration-reference) for every available f
<Tabs>
<Tab title="Interactive wizard">
```bash
openclaw onboard # full setup wizard
openclaw onboard # full onboarding flow
openclaw configure # config wizard
```
</Tab>
@ -46,7 +46,7 @@ See the [full reference](/gateway/configuration-reference) for every available f
```bash
openclaw config get agents.defaults.workspace
openclaw config set agents.defaults.heartbeat.every "2h"
openclaw config unset tools.web.search.apiKey
openclaw config unset plugins.entries.brave.config.webSearch.apiKey
```
</Tab>
<Tab title="Control UI">
@ -597,11 +597,11 @@ Rules:
},
skills: {
entries: {
"nano-banana-pro": {
"image-lab": {
apiKey: {
source: "file",
provider: "filemain",
id: "/skills/entries/nano-banana-pro/apiKey",
id: "/skills/entries/image-lab/apiKey",
},
},
},

View File

@ -155,18 +155,20 @@ normalizes it to the current host-local Chrome MCP attach model:
Doctor also audits the host-local Chrome MCP path when you use `defaultProfile:
"user"` or a configured `existing-session` profile:
- checks whether Google Chrome is installed on the same host
- checks whether Google Chrome is installed on the same host for default
auto-connect profiles
- checks the detected Chrome version and warns when it is below Chrome 144
- reminds you to enable remote debugging in Chrome at
`chrome://inspect/#remote-debugging`
- reminds you to enable remote debugging in the browser inspect page (for
example `chrome://inspect/#remote-debugging`, `brave://inspect/#remote-debugging`,
or `edge://inspect/#remote-debugging`)
Doctor cannot enable the Chrome-side setting for you. Host-local Chrome MCP
still requires:
- Google Chrome 144+ on the gateway/node host
- Chrome running locally
- remote debugging enabled in Chrome
- approving the first attach consent prompt in Chrome
- a Chromium-based browser 144+ on the gateway/node host
- the browser running locally
- remote debugging enabled in that browser
- approving the first attach consent prompt in the browser
This check does **not** apply to Docker, sandbox, remote-browser, or other
headless flows. Those continue to use raw CDP.

View File

@ -144,6 +144,8 @@ URL fetch defaults:
- Optional hostname allowlists are supported per input type (`files.urlAllowlist`, `images.urlAllowlist`).
- Exact host: `"cdn.example.com"`
- Wildcard subdomains: `"*.assets.example.com"` (does not match apex)
- Empty or omitted allowlists mean no hostname allowlist restriction.
- To disable URL-based fetches entirely, set `files.allowUrl: false` and/or `images.allowUrl: false`.
## File + image limits (config)

View File

@ -81,6 +81,12 @@ Invalid plan target path for models.providers.apiKey: models.providers.openai.ba
No writes are committed for an invalid plan.
## Exec provider consent behavior
- `--dry-run` skips exec SecretRef checks by default.
- Plans containing exec SecretRefs/providers are rejected in write mode unless `--allow-exec` is set.
- When validating/applying exec-containing plans, pass `--allow-exec` in both dry-run and write commands.
## Runtime and audit scope notes
- Ref-only `auth-profiles.json` entries (`keyRef`/`tokenRef`) are included in runtime resolution and audit coverage.
@ -94,6 +100,10 @@ openclaw secrets apply --from /tmp/openclaw-secrets-plan.json --dry-run
# Then apply for real
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json
# For exec-containing plans, opt in explicitly in both modes
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json --dry-run --allow-exec
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json --allow-exec
```
If apply fails with an invalid target path message, regenerate the plan with `openclaw secrets configure` or fix the target path to a supported shape above.

View File

@ -414,6 +414,11 @@ Findings include:
- precedence shadowing (`auth-profiles.json` taking priority over `openclaw.json` refs)
- legacy residues (`auth.json`, OAuth reminders)
Exec note:
- By default, audit skips exec SecretRef resolvability checks to avoid command side effects.
- Use `openclaw secrets audit --allow-exec` to execute exec providers during audit.
Header residue note:
- Sensitive provider header detection is name-heuristic based (common auth/credential header names and fragments such as `authorization`, `x-api-key`, `token`, `secret`, `password`, and `credential`).
@ -429,6 +434,11 @@ Interactive helper that:
- runs preflight resolution
- can apply immediately
Exec note:
- Preflight skips exec SecretRef checks unless `--allow-exec` is set.
- If you apply directly from `configure --apply` and the plan includes exec refs/providers, keep `--allow-exec` set for the apply step too.
Helpful modes:
- `openclaw secrets configure --providers-only`
@ -447,9 +457,16 @@ Apply a saved plan:
```bash
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json --allow-exec
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json --dry-run
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json --dry-run --allow-exec
```
Exec note:
- dry-run skips exec checks unless `--allow-exec` is set.
- write mode rejects plans containing exec SecretRefs/providers unless `--allow-exec` is set.
For strict target/path contract details and exact rejection rules, see:
- [Secrets Apply Plan Contract](/gateway/secrets-plan-contract)

View File

@ -243,7 +243,10 @@ High-signal `checkId` values you will most likely see in real deployments (not e
| `gateway.real_ip_fallback_enabled` | warn/critical | Trusting `X-Real-IP` fallback can enable source-IP spoofing via proxy misconfig | `gateway.allowRealIpFallback`, `gateway.trustedProxies` | no |
| `discovery.mdns_full_mode` | warn/critical | mDNS full mode advertises `cliPath`/`sshPort` metadata on local network | `discovery.mdns.mode`, `gateway.bind` | no |
| `config.insecure_or_dangerous_flags` | warn | Any insecure/dangerous debug flags enabled | multiple keys (see finding detail) | no |
| `hooks.token_reuse_gateway_token` | critical | Hook ingress token also unlocks Gateway auth | `hooks.token`, `gateway.auth.token` | no |
| `hooks.token_too_short` | warn | Easier brute force on hook ingress | `hooks.token` | no |
| `hooks.default_session_key_unset` | warn | Hook agent runs fan out into generated per-request sessions | `hooks.defaultSessionKey` | no |
| `hooks.allowed_agent_ids_unrestricted` | warn/critical | Authenticated hook callers may route to any configured agent | `hooks.allowedAgentIds` | no |
| `hooks.request_session_key_enabled` | warn/critical | External caller can choose sessionKey | `hooks.allowRequestSessionKey` | no |
| `hooks.request_session_key_prefixes_missing` | warn/critical | No bound on external session key shapes | `hooks.allowedSessionKeyPrefixes` | no |
| `logging.redact_off` | warn | Sensitive values leak to logs/status | `logging.redactSensitive` | yes |
@ -355,6 +358,7 @@ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- If the gateway itself terminates HTTPS, you can set `gateway.http.securityHeaders.strictTransportSecurity` to emit the HSTS header from OpenClaw responses.
- Detailed deployment guidance is in [Trusted Proxy Auth](/gateway/trusted-proxy-auth#tls-termination-and-hsts).
- For non-loopback Control UI deployments, `gateway.controlUi.allowedOrigins` is required by default.
- `gateway.controlUi.allowedOrigins: ["*"]` is an explicit allow-all browser-origin policy, not a hardened default. Avoid it outside tightly controlled local testing.
- `gateway.controlUi.dangerouslyAllowHostHeaderOriginFallback=true` enables Host-header origin fallback mode; treat it as a dangerous operator-selected policy.
- Treat DNS rebinding and proxy-host header behavior as deployment hardening concerns; keep `trustedProxies` tight and avoid exposing the gateway directly to the public internet.
@ -568,6 +572,8 @@ tool calls. Reduce the blast radius by:
- For OpenResponses URL inputs (`input_file` / `input_image`), set tight
`gateway.http.endpoints.responses.files.urlAllowlist` and
`gateway.http.endpoints.responses.images.urlAllowlist`, and keep `maxUrlParts` low.
Empty allowlists are treated as unset; use `files.allowUrl: false` / `images.allowUrl: false`
if you want to disable URL fetching entirely.
- Enabling sandboxing and strict tool allowlists for any agent that touches untrusted input.
- Keeping secrets out of prompts; pass them via env/config on the gateway host instead.
@ -738,7 +744,7 @@ In minimal mode, the Gateway still broadcasts enough for device discovery (`role
Gateway auth is **required by default**. If no token/password is configured,
the Gateway refuses WebSocket connections (failclosed).
The setup wizard generates a token by default (even for loopback) so
Onboarding generates a token by default (even for loopback) so
local clients must authenticate.
Set a token so **all** WS clients must authenticate:

View File

@ -36,7 +36,7 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS,
- [How do I install OpenClaw on a VPS?](#how-do-i-install-openclaw-on-a-vps)
- [Where are the cloud/VPS install guides?](#where-are-the-cloudvps-install-guides)
- [Can I ask OpenClaw to update itself?](#can-i-ask-openclaw-to-update-itself)
- [What does the setup wizard actually do?](#what-does-the-setup-wizard-actually-do)
- [What does onboarding actually do?](#what-does-onboarding-actually-do)
- [Do I need a Claude or OpenAI subscription to run this?](#do-i-need-a-claude-or-openai-subscription-to-run-this)
- [Can I use Claude Max subscription without an API key](#can-i-use-claude-max-subscription-without-an-api-key)
- [How does Anthropic "setup-token" auth work?](#how-does-anthropic-setuptoken-auth-work)
@ -317,7 +317,7 @@ Install docs: [Install](/install), [Installer flags](/install/installer), [Updat
### What's the recommended way to install and set up OpenClaw
The repo recommends running from source and using the setup wizard:
The repo recommends running from source and using onboarding:
```bash
curl -fsSL https://openclaw.ai/install.sh | bash
@ -627,7 +627,7 @@ More detail: [Install](/install) and [Installer flags](/install/installer).
### How do I install OpenClaw on Linux
Short answer: follow the Linux guide, then run the setup wizard.
Short answer: follow the Linux guide, then run onboarding.
- Linux quick path + service install: [Linux](/platforms/linux).
- Full walkthrough: [Getting Started](/start/getting-started).
@ -685,7 +685,7 @@ openclaw gateway restart
Docs: [Update](/cli/update), [Updating](/install/updating).
### What does the setup wizard actually do
### What does onboarding actually do
`openclaw onboard` is the recommended setup path. In **local mode** it walks you through:
@ -723,7 +723,7 @@ If you want the clearest and safest supported path for production, use an Anthro
### How does Anthropic setuptoken auth work
`claude setup-token` generates a **token string** via the Claude Code CLI (it is not available in the web console). You can run it on **any machine**. Choose **Anthropic token (paste setup-token)** in the wizard or paste it with `openclaw models auth paste-token --provider anthropic`. The token is stored as an auth profile for the **anthropic** provider and used like an API key (no auto-refresh). More detail: [OAuth](/concepts/oauth).
`claude setup-token` generates a **token string** via the Claude Code CLI (it is not available in the web console). You can run it on **any machine**. Choose **Anthropic token (paste setup-token)** in onboarding or paste it with `openclaw models auth paste-token --provider anthropic`. The token is stored as an auth profile for the **anthropic** provider and used like an API key (no auto-refresh). More detail: [OAuth](/concepts/oauth).
### Where do I find an Anthropic setuptoken
@ -733,7 +733,7 @@ It is **not** in the Anthropic Console. The setup-token is generated by the **Cl
claude setup-token
```
Copy the token it prints, then choose **Anthropic token (paste setup-token)** in the wizard. If you want to run it on the gateway host, use `openclaw models auth setup-token --provider anthropic`. If you ran `claude setup-token` elsewhere, paste it on the gateway host with `openclaw models auth paste-token --provider anthropic`. See [Anthropic](/providers/anthropic).
Copy the token it prints, then choose **Anthropic token (paste setup-token)** in onboarding. If you want to run it on the gateway host, use `openclaw models auth setup-token --provider anthropic`. If you ran `claude setup-token` elsewhere, paste it on the gateway host with `openclaw models auth paste-token --provider anthropic`. See [Anthropic](/providers/anthropic).
### Do you support Claude subscription auth (Claude Pro or Max)
@ -767,15 +767,15 @@ Yes - via pi-ai's **Amazon Bedrock (Converse)** provider with **manual config**.
### How does Codex auth work
OpenClaw supports **OpenAI Code (Codex)** via OAuth (ChatGPT sign-in). The wizard can run the OAuth flow and will set the default model to `openai-codex/gpt-5.4` when appropriate. See [Model providers](/concepts/model-providers) and [Wizard](/start/wizard).
OpenClaw supports **OpenAI Code (Codex)** via OAuth (ChatGPT sign-in). Onboarding can run the OAuth flow and will set the default model to `openai-codex/gpt-5.4` when appropriate. See [Model providers](/concepts/model-providers) and [Onboarding (CLI)](/start/wizard).
### Do you support OpenAI subscription auth Codex OAuth
Yes. OpenClaw fully supports **OpenAI Code (Codex) subscription OAuth**.
OpenAI explicitly allows subscription OAuth usage in external tools/workflows
like OpenClaw. The setup wizard can run the OAuth flow for you.
like OpenClaw. Onboarding can run the OAuth flow for you.
See [OAuth](/concepts/oauth), [Model providers](/concepts/model-providers), and [Wizard](/start/wizard).
See [OAuth](/concepts/oauth), [Model providers](/concepts/model-providers), and [Onboarding (CLI)](/start/wizard).
### How do I set up Gemini CLI OAuth
@ -844,7 +844,7 @@ without WhatsApp/Telegram.
`channels.telegram.allowFrom` is **the human sender's Telegram user ID** (numeric). It is not the bot username.
The setup wizard accepts `@username` input and resolves it to a numeric ID, but OpenClaw authorization uses numeric IDs only.
Onboarding accepts `@username` input and resolves it to a numeric ID, but OpenClaw authorization uses numeric IDs only.
Safer (no third-party bot):
@ -1505,12 +1505,22 @@ Environment alternatives:
```json5
{
plugins: {
entries: {
brave: {
config: {
webSearch: {
apiKey: "BRAVE_API_KEY_HERE",
},
},
},
},
},
tools: {
web: {
search: {
enabled: true,
provider: "brave",
apiKey: "BRAVE_API_KEY_HERE",
maxResults: 5,
},
fetch: {
@ -1521,6 +1531,9 @@ Environment alternatives:
}
```
Provider-specific web-search config now lives under `plugins.entries.<plugin>.config.webSearch.*`.
Legacy `tools.web.search.*` provider paths still load temporarily for compatibility, but they should not be used for new configs.
Notes:
- If you use allowlists, add `web_search`/`web_fetch` or `group:web`.
@ -1909,7 +1922,7 @@ openclaw onboard --install-daemon
Notes:
- The setup wizard also offers **Reset** if it sees an existing config. See [Wizard](/start/wizard).
- Onboarding also offers **Reset** if it sees an existing config. See [Onboarding (CLI)](/start/wizard).
- If you used profiles (`--profile` / `OPENCLAW_PROFILE`), reset each state dir (defaults are `~/.openclaw-<profile>`).
- Dev reset: `openclaw gateway --dev --reset` (dev-only; wipes dev config + credentials + sessions + workspace).

View File

@ -52,6 +52,17 @@ Think of the suites as “increasing realism” (and increasing flakiness/cost):
- Runs in CI
- No real keys required
- Should be fast and stable
- Embedded runner note:
- When you change message-tool discovery inputs or compaction runtime context,
keep both levels of coverage.
- Add focused helper regressions for pure routing/normalization seams.
- Also keep the embedded runner integration suites healthy:
`src/agents/pi-embedded-runner/compact.hooks.test.ts`,
`src/agents/pi-embedded-runner/run.overflow-compaction.test.ts`, and
`src/agents/pi-embedded-runner/run.overflow-compaction.loop.test.ts`.
- Those suites verify that scoped ids and compaction behavior still flow
through the real `run.ts` / `compact.ts` paths; helper-only tests are not a
sufficient substitute for those seams.
- Pool note:
- OpenClaw uses Vitest `vmForks` on Node 22, 23, and 24 for faster unit shards.
- On Node 25+, OpenClaw automatically falls back to regular `forks` until the repo is re-validated there.
@ -360,9 +371,33 @@ If you want to rely on env keys (e.g. exported in your `~/.profile`), run local
- Enable: `BYTEPLUS_API_KEY=... BYTEPLUS_LIVE_TEST=1 pnpm test:live src/agents/byteplus.live.test.ts`
- Optional model override: `BYTEPLUS_CODING_MODEL=ark-code-latest`
## Image generation live
- Test: `src/image-generation/runtime.live.test.ts`
- Command: `pnpm test:live src/image-generation/runtime.live.test.ts`
- Scope:
- Enumerates every registered image-generation provider plugin
- Loads missing provider env vars from your login shell (`~/.profile`) before probing
- Uses live/env API keys ahead of stored auth profiles by default, so stale test keys in `auth-profiles.json` do not mask real shell credentials
- Skips providers with no usable auth/profile/model
- Runs the stock image-generation variants through the shared runtime capability:
- `google:flash-generate`
- `google:pro-generate`
- `google:pro-edit`
- `openai:default-generate`
- Current bundled providers covered:
- `openai`
- `google`
- Optional narrowing:
- `OPENCLAW_LIVE_IMAGE_GENERATION_PROVIDERS="openai,google"`
- `OPENCLAW_LIVE_IMAGE_GENERATION_MODELS="openai/gpt-image-1,google/gemini-3.1-flash-image-preview"`
- `OPENCLAW_LIVE_IMAGE_GENERATION_CASES="google:flash-generate,google:pro-edit"`
- Optional auth behavior:
- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` to force profile-store auth and ignore env-only overrides
## Docker runners (optional “works in Linux” checks)
These run `pnpm test:live` inside the repo Docker image, mounting your local config dir and workspace (and sourcing `~/.profile` if mounted). They also bind-mount CLI auth homes like `~/.codex`, `~/.claude`, `~/.qwen`, and `~/.minimax` when present so external-CLI OAuth stays available in-container:
These run `pnpm test:live` inside the repo Docker image, mounting your local config dir and workspace (and sourcing `~/.profile` if mounted). They also bind-mount CLI auth homes like `~/.codex`, `~/.claude`, `~/.qwen`, and `~/.minimax` when present, then copy them into the container home before the run so external-CLI OAuth can refresh tokens without mutating the host auth store:
- Direct models: `pnpm test:docker:live-models` (script: `scripts/test-live-models-docker.sh`)
- Gateway + dev agent: `pnpm test:docker:live-gateway` (script: `scripts/test-live-gateway-models-docker.sh`)
@ -373,6 +408,9 @@ These run `pnpm test:live` inside the repo Docker image, mounting your local con
The live-model Docker runners also bind-mount the current checkout read-only and
stage it into a temporary workdir inside the container. This keeps the runtime
image slim while still running Vitest against your exact local source/config.
`test:docker:live-models` still runs `pnpm test:live`, so pass through
`OPENCLAW_LIVE_GATEWAY_*` as well when you need to narrow or exclude gateway
live coverage from that Docker lane.
Manual ACP plain-language thread smoke (not CI):
@ -384,8 +422,9 @@ Useful env vars:
- `OPENCLAW_CONFIG_DIR=...` (default: `~/.openclaw`) mounted to `/home/node/.openclaw`
- `OPENCLAW_WORKSPACE_DIR=...` (default: `~/.openclaw/workspace`) mounted to `/home/node/.openclaw/workspace`
- `OPENCLAW_PROFILE_FILE=...` (default: `~/.profile`) mounted to `/home/node/.profile` and sourced before running tests
- External CLI auth dirs under `$HOME` (`.codex`, `.claude`, `.qwen`, `.minimax`) are mounted read-only to the matching `/home/node/...` paths when present
- External CLI auth dirs under `$HOME` (`.codex`, `.claude`, `.qwen`, `.minimax`) are mounted read-only under `/host-auth/...`, then copied into `/home/node/...` before tests start
- `OPENCLAW_LIVE_GATEWAY_MODELS=...` / `OPENCLAW_LIVE_MODELS=...` to narrow the run
- `OPENCLAW_LIVE_GATEWAY_PROVIDERS=...` / `OPENCLAW_LIVE_PROVIDERS=...` to filter providers in-container
- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` to ensure creds come from the profile store (not env)
## Docs sanity

View File

@ -33,7 +33,7 @@ title: "OpenClaw"
<Card title="Get Started" href="/start/getting-started" icon="rocket">
Install OpenClaw and bring up the Gateway in minutes.
</Card>
<Card title="Run the Wizard" href="/start/wizard" icon="sparkles">
<Card title="Run Onboarding" href="/start/wizard" icon="sparkles">
Guided setup with `openclaw onboard` and pairing flows.
</Card>
<Card title="Open the Control UI" href="/web/control-ui" icon="layout-dashboard">

View File

@ -51,7 +51,7 @@ From repo root:
This script:
- builds the gateway image locally (or pulls a remote image if `OPENCLAW_IMAGE` is set)
- runs the setup wizard
- runs onboarding
- prints optional provider setup hints
- starts the gateway via Docker Compose
- generates a gateway token and writes it to `.env`

View File

@ -33,7 +33,7 @@ For VPS/cloud hosts, avoid third-party "1-click" marketplace images when possibl
<AccordionGroup>
<Accordion title="Installer script" icon="rocket" defaultOpen>
Downloads the CLI, installs it globally via npm, and launches the setup wizard.
Downloads the CLI, installs it globally via npm, and launches onboarding.
<Tabs>
<Tab title="macOS / Linux / WSL2">

View File

@ -1,5 +1,5 @@
---
summary: "Move (migrate) a OpenClaw install from one machine to another"
summary: "Move (migrate) an OpenClaw install from one machine to another"
read_when:
- You are moving OpenClaw to a new laptop/server
- You want to preserve sessions, auth, and channel logins (WhatsApp, etc.)
@ -8,7 +8,7 @@ title: "Migration Guide"
# Migrating OpenClaw to a new machine
This guide migrates a OpenClaw Gateway from one machine to another **without redoing onboarding**.
This guide migrates an OpenClaw Gateway from one machine to another **without redoing onboarding**.
The migration is simple conceptually:

View File

@ -21,7 +21,7 @@ and you configure everything via the `/setup` web wizard.
## What you get
- Hosted OpenClaw Gateway + Control UI
- Web setup wizard at `/setup` (no terminal commands)
- Web setup at `/setup` (no terminal commands)
- Persistent storage via Northflank Volume (`/data`) so config/credentials/workspace survive redeploys
## Setup flow
@ -32,7 +32,7 @@ and you configure everything via the `/setup` web wizard.
4. Click **Run setup**.
5. Open the Control UI at `https://<your-northflank-domain>/openclaw`
If Telegram DMs are set to pairing, the setup wizard can approve the pairing code.
If Telegram DMs are set to pairing, web setup can approve the pairing code.
## Getting chat tokens

View File

@ -29,13 +29,13 @@ Railway will either:
Then open:
- `https://<your-railway-domain>/setup` — setup wizard (password protected)
- `https://<your-railway-domain>/setup` — web setup (password protected)
- `https://<your-railway-domain>/openclaw` — Control UI
## What you get
- Hosted OpenClaw Gateway + Control UI
- Web setup wizard at `/setup` (no terminal commands)
- Web setup at `/setup` (no terminal commands)
- Persistent storage via Railway Volume (`/data`) so config/credentials/workspace survive redeploys
- Backup export at `/setup/export` to migrate off Railway later
@ -70,7 +70,7 @@ Set these variables on the service:
3. (Optional) Add Telegram/Discord/Slack tokens.
4. Click **Run setup**.
If Telegram DMs are set to pairing, the setup wizard can approve the pairing code.
If Telegram DMs are set to pairing, web setup can approve the pairing code.
## Getting chat tokens

View File

@ -73,7 +73,7 @@ The Blueprint defaults to `starter`. To use free tier, change `plan: free` in yo
## After deployment
### Complete the setup wizard
### Complete web setup
1. Navigate to `https://<your-service>.onrender.com/setup`
2. Enter your `SETUP_PASSWORD`

View File

@ -22,7 +22,7 @@ curl -fsSL https://openclaw.ai/install.sh | bash
Notes:
- Add `--no-onboard` if you dont want the setup wizard to run again.
- Add `--no-onboard` if you dont want onboarding to run again.
- For **source installs**, use:
```bash

View File

@ -67,7 +67,7 @@ openclaw agents add <name>
</Note>
<Tip>
推奨:エージェントが `web_search` を使用できるように、Brave Search APIキーを設定してください`web_fetch` はキーなしで動作します)。最も簡単な方法:`openclaw configure --section web` を実行すると `tools.web.search.apiKey` が保存されます。ドキュメント:[Webツール](/tools/web)。
推奨:エージェントが `web_search` を使用できるように、Brave Search APIキーを設定してください`web_fetch` はキーなしで動作します)。最も簡単な方法:`openclaw configure --section web` を実行すると `plugins.entries.brave.config.webSearch.apiKey` に保存されます。旧 `tools.web.search.apiKey` パスは互換用に引き続き読み込まれますが、新しい設定では使用しないでください。ドキュメント:[Webツール](/tools/web)。
</Tip>
## 関連ドキュメント

View File

@ -10,6 +10,10 @@ title: "Media Understanding"
OpenClaw can **summarize inbound media** (image/audio/video) before the reply pipeline runs. It autodetects when local tools or provider keys are available, and can be disabled or customized. If understanding is off, models still receive the original files/URLs as usual.
Vendor-specific media behavior is registered by vendor plugins, while OpenClaw
core owns the shared `tools.media` config, fallback order, and reply-pipeline
integration.
## Goals
- Optional: predigest inbound media into short text for faster routing + better command parsing.
@ -184,7 +188,10 @@ If you set `capabilities`, the entry only runs for those media types. For shared
lists, OpenClaw can infer defaults:
- `openai`, `anthropic`, `minimax`: **image**
- `moonshot`: **image + video**
- `google` (Gemini API): **image + audio + video**
- `mistral`: **audio**
- `zai`: **image**
- `groq`: **audio**
- `deepgram`: **audio**
@ -193,11 +200,11 @@ If you omit `capabilities`, the entry is eligible for the list it appears in.
## Provider support matrix (OpenClaw integrations)
| Capability | Provider integration | Notes |
| ---------- | ------------------------------------------------ | --------------------------------------------------------- |
| Image | OpenAI / Anthropic / Google / others via `pi-ai` | Any image-capable model in the registry works. |
| Audio | OpenAI, Groq, Deepgram, Google, Mistral | Provider transcription (Whisper/Deepgram/Gemini/Voxtral). |
| Video | Google (Gemini API) | Provider video understanding. |
| Capability | Provider integration | Notes |
| ---------- | -------------------------------------------------- | ----------------------------------------------------------------------- |
| Image | OpenAI, Anthropic, Google, MiniMax, Moonshot, Z.AI | Vendor plugins register image support against core media understanding. |
| Audio | OpenAI, Groq, Deepgram, Google, Mistral | Provider transcription (Whisper/Deepgram/Gemini/Voxtral). |
| Video | Google, Moonshot | Provider video understanding via vendor plugins. |
## Model selection guidance

View File

@ -12,7 +12,7 @@ OpenClaw supports Perplexity Search API as a `web_search` provider.
It returns structured results with `title`, `url`, and `snippet` fields.
For compatibility, OpenClaw also supports legacy Perplexity Sonar/OpenRouter setups.
If you use `OPENROUTER_API_KEY`, an `sk-or-...` key in `tools.web.search.perplexity.apiKey`, or set `tools.web.search.perplexity.baseUrl` / `model`, the provider switches to the chat-completions path and returns AI-synthesized answers with citations instead of structured Search API results.
If you use `OPENROUTER_API_KEY`, an `sk-or-...` key in `plugins.entries.perplexity.config.webSearch.apiKey`, or set `plugins.entries.perplexity.config.webSearch.baseUrl` / `model`, the provider switches to the chat-completions path and returns AI-synthesized answers with citations instead of structured Search API results.
## Getting a Perplexity API key
@ -22,12 +22,12 @@ If you use `OPENROUTER_API_KEY`, an `sk-or-...` key in `tools.web.search.perplex
## OpenRouter compatibility
If you were already using OpenRouter for Perplexity Sonar, keep `provider: "perplexity"` and set `OPENROUTER_API_KEY` in the Gateway environment, or store an `sk-or-...` key in `tools.web.search.perplexity.apiKey`.
If you were already using OpenRouter for Perplexity Sonar, keep `provider: "perplexity"` and set `OPENROUTER_API_KEY` in the Gateway environment, or store an `sk-or-...` key in `plugins.entries.perplexity.config.webSearch.apiKey`.
Optional legacy controls:
Optional compatibility controls:
- `tools.web.search.perplexity.baseUrl`
- `tools.web.search.perplexity.model`
- `plugins.entries.perplexity.config.webSearch.baseUrl`
- `plugins.entries.perplexity.config.webSearch.model`
## Config examples
@ -35,13 +35,21 @@ Optional legacy controls:
```json5
{
plugins: {
entries: {
perplexity: {
config: {
webSearch: {
apiKey: "pplx-...",
},
},
},
},
},
tools: {
web: {
search: {
provider: "perplexity",
perplexity: {
apiKey: "pplx-...",
},
},
},
},
@ -52,15 +60,23 @@ Optional legacy controls:
```json5
{
plugins: {
entries: {
perplexity: {
config: {
webSearch: {
apiKey: "<openrouter-api-key>",
baseUrl: "https://openrouter.ai/api/v1",
model: "perplexity/sonar-pro",
},
},
},
},
},
tools: {
web: {
search: {
provider: "perplexity",
perplexity: {
apiKey: "<openrouter-api-key>",
baseUrl: "https://openrouter.ai/api/v1",
model: "perplexity/sonar-pro",
},
},
},
},
@ -70,7 +86,7 @@ Optional legacy controls:
## Where to set the key
**Via config:** run `openclaw configure --section web`. It stores the key in
`~/.openclaw/openclaw.json` under `tools.web.search.perplexity.apiKey`.
`~/.openclaw/openclaw.json` under `plugins.entries.perplexity.config.webSearch.apiKey`.
That field also accepts SecretRef objects.
**Via environment:** set `PERPLEXITY_API_KEY` or `OPENROUTER_API_KEY`
@ -151,7 +167,7 @@ await web_search({
## Notes
- Perplexity Search API returns structured web search results (`title`, `url`, `snippet`)
- OpenRouter or explicit `baseUrl` / `model` switches Perplexity back to Sonar chat completions for compatibility
- OpenRouter or explicit `plugins.entries.perplexity.config.webSearch.baseUrl` / `model` switches Perplexity back to Sonar chat completions for compatibility
- Results are cached for 15 minutes by default (configurable via `cacheTtlMinutes`)
See [Web tools](/tools/web) for the full web_search configuration.

View File

@ -119,19 +119,24 @@ src/agents/
│ ├── browser-tool.ts
│ ├── canvas-tool.ts
│ ├── cron-tool.ts
│ ├── discord-actions*.ts
│ ├── gateway-tool.ts
│ ├── image-tool.ts
│ ├── message-tool.ts
│ ├── nodes-tool.ts
│ ├── session*.ts
│ ├── slack-actions.ts
│ ├── telegram-actions.ts
│ ├── web-*.ts
│ └── whatsapp-actions.ts
│ └── ...
└── ...
```
Channel-specific message action runtimes now live in the plugin-owned extension
directories instead of under `src/agents/tools`, for example:
- `extensions/discord/src/actions/runtime*.ts`
- `extensions/slack/src/action-runtime.ts`
- `extensions/telegram/src/action-runtime.ts`
- `extensions/whatsapp/src/action-runtime.ts`
## Core Integration Flow
### 1. Running an Embedded Agent

View File

@ -7,7 +7,7 @@ title: "Remote Control"
# Remote OpenClaw (macOS ⇄ remote host)
This flow lets the macOS app act as a full remote control for a OpenClaw gateway running on another host (desktop/server). Its the apps **Remote over SSH** (remote run) feature. All features—health checks, Voice Wake forwarding, and Web Chat—reuse the same remote SSH configuration from _Settings → General_.
This flow lets the macOS app act as a full remote control for an OpenClaw gateway running on another host (desktop/server). Its the apps **Remote over SSH** (remote run) feature. All features—health checks, Voice Wake forwarding, and Web Chat—reuse the same remote SSH configuration from _Settings → General_.
## Modes

View File

@ -321,7 +321,7 @@ Since the Pi is just the Gateway (models run in the cloud), use API-based models
## Auto-Start on Boot
The setup wizard sets this up, but to verify:
Onboarding sets this up, but to verify:
```bash
# Check service is enabled

View File

@ -19,7 +19,7 @@ Today that means three closely related ecosystems:
- Cursor bundles
OpenClaw shows all of them as `Format: bundle` in `openclaw plugins list`.
Verbose output and `openclaw plugins info <id>` also show the subtype
Verbose output and `openclaw plugins inspect <id>` also show the subtype
(`codex`, `claude`, or `cursor`).
Related:
@ -104,11 +104,15 @@ loader. Cursor command markdown works through the same path.
- `HOOK.md`
- `handler.ts` or `handler.js`
#### MCP for CLI backends
#### MCP for Pi
- enabled bundles can contribute MCP server config
- current runtime wiring is used by the `claude-cli` backend
- OpenClaw merges bundle MCP config into the backend `--mcp-config` file
- OpenClaw merges bundle MCP config into the effective embedded Pi settings as
`mcpServers`
- OpenClaw also exposes supported bundle MCP tools during embedded Pi agent
turns by launching supported stdio MCP servers as subprocesses
- project-local Pi settings still apply after bundle defaults, so workspace
settings can override bundle MCP entries when needed
#### Embedded Pi settings
@ -133,12 +137,11 @@ diagnostics/info output, but OpenClaw does not run them yet:
- Cursor `.cursor/agents`
- Cursor `.cursor/hooks.json`
- Cursor `.cursor/rules`
- Cursor `mcpServers` outside the current mapped runtime paths
- Codex inline/app metadata beyond capability reporting
## Capability reporting
`openclaw plugins info <id>` shows bundle capabilities from the normalized
`openclaw plugins inspect <id>` shows bundle capabilities from the normalized
bundle record.
Supported capabilities are loaded quietly. Unsupported capabilities produce a
@ -153,7 +156,8 @@ Current exceptions:
- Claude `commands` is considered supported because it maps to skills
- Claude `settings` is considered supported because it maps to embedded Pi settings
- Cursor `commands` is considered supported because it maps to skills
- bundle MCP is considered supported where OpenClaw actually imports it
- bundle MCP is considered supported because it maps into embedded Pi settings
and exposes supported stdio tools to embedded Pi
- Codex `hooks` is considered supported only for OpenClaw hook-pack layouts
## Format differences
@ -195,6 +199,8 @@ Claude-specific notes:
- `commands/` is treated like skill content
- `settings.json` is imported into embedded Pi settings
- `.mcp.json` and manifest `mcpServers` can expose supported stdio tools to
embedded Pi
- `hooks/hooks.json` is detected, but not executed as Claude automation
### Cursor
@ -246,7 +252,9 @@ Current behavior:
- bundle discovery reads files inside the plugin root with boundary checks
- skills and hook-pack paths must stay inside the plugin root
- bundle settings files are read with the same boundary checks
- OpenClaw does not execute arbitrary bundle runtime code in-process
- supported stdio bundle MCP servers may be launched as subprocesses for
embedded Pi tool calls
- OpenClaw does not load arbitrary bundle runtime modules in-process
This makes bundle support safer by default than native plugin modules, but you
should still treat third-party bundles as trusted content for the features they
@ -259,17 +267,24 @@ openclaw plugins install ./my-codex-bundle
openclaw plugins install ./my-claude-bundle
openclaw plugins install ./my-cursor-bundle
openclaw plugins install ./my-bundle.tgz
openclaw plugins info my-bundle
openclaw plugins marketplace list <marketplace-name>
openclaw plugins install <plugin-name>@<marketplace-name>
openclaw plugins inspect my-bundle
```
If the directory is a native OpenClaw plugin/package, the native install path
still wins.
For Claude marketplace names, OpenClaw reads the local Claude known-marketplace
registry at `~/.claude/plugins/known_marketplaces.json`. Marketplace entries
can resolve to bundle-compatible directories/archives or to native plugin
sources; after resolution, the normal install rules still apply.
## Troubleshooting
### Bundle is detected but capabilities do not run
Check `openclaw plugins info <id>`.
Check `openclaw plugins inspect <id>`.
If the capability is listed but OpenClaw says it is not wired yet, that is a
real product limit, not a broken install.

View File

@ -1,7 +1,7 @@
---
summary: "Plugin manifest + JSON schema requirements (strict config validation)"
read_when:
- You are building a OpenClaw plugin
- You are building an OpenClaw plugin
- You need to ship a plugin config schema or debug plugin validation errors
title: "Plugin Manifest"
---
@ -32,6 +32,8 @@ Every native OpenClaw plugin **must** ship a `openclaw.plugin.json` file in the
plugin errors and block config validation.
See the full plugin system guide: [Plugins](/tools/plugin).
For the native capability model and current external-compatibility guidance:
[Capability model](/tools/plugin#public-capability-model).
## Required fields
@ -54,8 +56,8 @@ Required keys:
Optional keys:
- `kind` (string): plugin kind (examples: `"memory"`, `"context-engine"`).
- `channels` (array): channel ids registered by this plugin (example: `["matrix"]`).
- `providers` (array): provider ids registered by this plugin.
- `channels` (array): channel ids registered by this plugin (channel capability; example: `["matrix"]`).
- `providers` (array): provider ids registered by this plugin (text inference capability).
- `providerAuthEnvVars` (object): auth env vars keyed by provider id. Use this
when OpenClaw should resolve provider credentials from env without loading
plugin runtime first.
@ -119,6 +121,8 @@ Example:
- If plugin config exists but the plugin is **disabled**, the config is kept and
a **warning** is surfaced in Doctor + logs.
See [Configuration reference](/configuration) for the full `plugins.*` schema.
## Notes
- The manifest is **required for native OpenClaw plugins**, including local filesystem loads.
@ -129,7 +133,9 @@ Example:
runtime just to inspect env names.
- `providerAuthChoices` is the cheap metadata path for auth-choice pickers,
`--auth-choice` resolution, preferred-provider mapping, and simple onboarding
CLI flag registration before provider runtime loads.
CLI flag registration before provider runtime loads. For runtime wizard
metadata that requires provider code, see
[Provider runtime hooks](/tools/plugin#provider-runtime-hooks).
- Exclusive plugin kinds are selected through `plugins.slots.*`.
- `kind: "memory"` is selected by `plugins.slots.memory`.
- `kind: "context-engine"` is selected by `plugins.slots.contextEngine`

View File

@ -204,7 +204,7 @@ Example with a stable public host:
## TTS for calls
Voice Call uses the core `messages.tts` configuration (OpenAI or ElevenLabs) for
Voice Call uses the core `messages.tts` configuration for
streaming speech on calls. You can override it under the plugin config with the
**same shape** — it deepmerges with `messages.tts`.
@ -222,7 +222,7 @@ streaming speech on calls. You can override it under the plugin config with the
Notes:
- **Edge TTS is ignored for voice calls** (telephony audio needs PCM; Edge output is unreliable).
- **Microsoft speech is ignored for voice calls** (telephony audio needs PCM; the current Microsoft transport does not expose telephony PCM output).
- Core TTS is used when Twilio media streaming is enabled; otherwise calls fall back to provider native voices.
### More examples

View File

@ -47,6 +47,7 @@ Looking for chat channel docs (WhatsApp/Telegram/Discord/Slack/Mattermost (plugi
- [Vercel AI Gateway](/providers/vercel-ai-gateway)
- [Venice (Venice AI, privacy-focused)](/providers/venice)
- [vLLM (local models)](/providers/vllm)
- [xAI](/providers/xai)
- [Xiaomi](/providers/xiaomi)
- [Z.AI](/providers/zai)

View File

@ -39,6 +39,7 @@ model as `provider/model`.
- [Venice (Venice AI)](/providers/venice)
- [Amazon Bedrock](/providers/bedrock)
- [Qianfan](/providers/qianfan)
- [xAI](/providers/xai)
For the full provider catalog (xAI, Groq, Mistral, etc.) and advanced configuration,
see [Model providers](/concepts/model-providers).

View File

@ -16,15 +16,15 @@ Ollama is a local LLM runtime that makes it easy to run open-source models on yo
## Quick start
### Onboarding wizard (recommended)
### Onboarding (recommended)
The fastest way to set up Ollama is through the setup wizard:
The fastest way to set up Ollama is through onboarding:
```bash
openclaw onboard
```
Select **Ollama** from the provider list. The wizard will:
Select **Ollama** from the provider list. Onboarding will:
1. Ask for the Ollama base URL where your instance can be reached (default `http://127.0.0.1:11434`).
2. Let you choose **Cloud + Local** (cloud models and local models) or **Local** (local models only).

61
docs/providers/xai.md Normal file
View File

@ -0,0 +1,61 @@
---
summary: "Use xAI Grok models in OpenClaw"
read_when:
- You want to use Grok models in OpenClaw
- You are configuring xAI auth or model ids
title: "xAI"
---
# xAI
OpenClaw ships a bundled `xai` provider plugin for Grok models.
## Setup
1. Create an API key in the xAI console.
2. Set `XAI_API_KEY`, or run:
```bash
openclaw onboard --auth-choice xai-api-key
```
3. Pick a model such as:
```json5
{
agents: { defaults: { model: { primary: "xai/grok-4" } } },
}
```
## Current bundled model catalog
OpenClaw now includes these xAI model families out of the box:
- `grok-4`, `grok-4-0709`
- `grok-4-fast-reasoning`, `grok-4-fast-non-reasoning`
- `grok-4-1-fast-reasoning`, `grok-4-1-fast-non-reasoning`
- `grok-4.20-experimental-beta-0304-reasoning`
- `grok-4.20-experimental-beta-0304-non-reasoning`
- `grok-code-fast-1`
The plugin also forward-resolves newer `grok-4*` and `grok-code-fast*` ids when
they follow the same API shape.
## Web search
The bundled `grok` web-search provider uses `XAI_API_KEY` too:
```bash
openclaw config set tools.web.search.provider grok
```
## Known limits
- Auth is API-key only today. There is no xAI OAuth/device-code flow in OpenClaw yet.
- `grok-4.20-multi-agent-experimental-beta-0304` is not supported on the normal xAI provider path because it requires a different upstream API surface than the standard OpenClaw xAI transport.
- Native xAI server-side tools such as `x_search` and `code_execution` are not yet first-class model-provider features in the bundled plugin.
## Notes
- OpenClaw applies xAI-specific tool-schema and tool-call compatibility fixes automatically on the shared runner path.
- For the broader provider overview, see [Model providers](/providers/index).

View File

@ -111,7 +111,7 @@ Strong examples:
- `extensions/matrix/src/setup-surface.ts`
- `extensions/irc/src/setup-surface.ts`
Existing helper seam:
Existing helper surface:
- `src/channels/plugins/setup-wizard-helpers.ts`
@ -187,7 +187,7 @@ Strong examples:
- `extensions/telegram/src/channel.ts`
- `extensions/nextcloud-talk/src/channel.ts`
Existing helper seam:
Existing helper surface:
- `src/plugin-sdk/channel-lifecycle.ts`

View File

@ -2,7 +2,7 @@
summary: "Design for an opt-in Firecrawl extension that adds search/scrape value without hardwiring Firecrawl into core defaults"
read_when:
- Designing Firecrawl integration work
- Evaluating web_search/web_fetch plugin seams
- Evaluating web_search/web_fetch plugin extension surfaces
- Deciding whether Firecrawl belongs in core or as an extension
title: "Firecrawl Extension Design"
---
@ -38,7 +38,7 @@ That combination argues for an extension, not more Firecrawl-specific logic in t
- **Opt-in, vendor-scoped**: no auto-enable, no setup hijack, no default tool-profile widening.
- **Extension owns Firecrawl-specific config**: prefer plugin config over growing `tools.web.*` again.
- **Useful on day one**: works even if core `web_search` / `web_fetch` seams stay unchanged.
- **Useful on day one**: works even if core `web_search` / `web_fetch` extension surfaces stay unchanged.
- **Security-first**: endpoint fetches use the same guarded networking posture as other web tools.
- **Self-hosted-friendly**: config + env fallback, explicit base URL, no hosted-only assumptions.
@ -208,15 +208,15 @@ Recommended shape:
- allow any registered plugin provider id at runtime,
- validate provider-specific config via the provider plugin or a generic provider bag.
### Phase 3: optional `web_fetch` provider seam
### Phase 3: optional `web_fetch` provider capability
Do this only if maintainers want vendor-specific fetch backends to participate in `web_fetch`.
Needed core addition:
- `registerWebFetchProvider` or equivalent fetch-backend seam
- `registerWebFetchProvider` or equivalent fetch-backend extension surface
Without that seam, the extension should keep `firecrawl_scrape` as an explicit tool rather than trying to patch built-in `web_fetch`.
Without that capability, the extension should keep `firecrawl_scrape` as an explicit tool rather than trying to patch built-in `web_fetch`.
## Security requirements
@ -249,7 +249,7 @@ This belongs as an extension, not a prompt-only skill.
- Self-hosted Firecrawl works with config/env fallback.
- Extension endpoint fetches use guarded networking.
- No new Firecrawl-specific core onboarding/default behavior.
- Core can later adopt plugin-native `web_search` / `web_fetch` seams without redesigning the extension.
- Core can later adopt plugin-native `web_search` / `web_fetch` extension surfaces without redesigning the extension.
## Recommended implementation order
@ -257,4 +257,4 @@ This belongs as an extension, not a prompt-only skill.
2. Build `firecrawl_search`
3. Add docs and examples
4. If desired, generalize `web_search` provider loading so the extension can back `web_search`
5. Only then consider a true `web_fetch` provider seam
5. Only then consider a true `web_fetch` provider capability

View File

@ -213,7 +213,33 @@ Notes:
Related docs: [Plugins](/tools/plugin), [Channels](/channels/index), [Configuration](/gateway/configuration).
## Implemented channel-owned seams
## Capability plan alignment
The plugin SDK refactor now aligns with the public capability model documented
in [Plugins](/tools/plugin#public-capability-model).
Key decisions:
- Capabilities are the public plugin model. Registration is explicit and typed.
- Legacy hook-only plugins remain supported without migration.
- Plugin shapes (plain-capability, hybrid-capability, hook-only, non-capability)
are classified from actual registration behavior.
- `openclaw plugins inspect` provides canonical deep introspection for any
loaded plugin, showing shape, capabilities, hooks, tools, and diagnostics.
- Export boundary: export capabilities, not implementation convenience. Trim
non-contract helper exports.
Required test matrix for the capability model:
- hook-only legacy plugin fixture
- plain capability plugin fixture
- hybrid capability plugin fixture
- real-world legacy hook-style plugin fixture
- `before_agent_start` still works
- typed hooks remain additive
- capability usage and plugin shape are inspectable
## Implemented channel-owned capabilities
Recent refactor work widened the channel plugin contract so core can stop owning
channel-specific UX and routing behavior:
@ -234,5 +260,5 @@ channel-specific UX and routing behavior:
config mutation/removal
- `allowlist.supportsScope`: channel-owned allowlist scope advertisement
These hooks should be preferred over new `channel === "discord"` / `telegram`
branches in shared core flows.
These capabilities should be preferred over new `channel === "discord"` /
`telegram` branches in shared core flows.

View File

@ -79,11 +79,13 @@ See [Memory](/concepts/memory).
`web_search` uses API keys and may incur usage charges depending on your provider:
- **Brave Search API**: `BRAVE_API_KEY` or `tools.web.search.apiKey`
- **Gemini (Google Search)**: `GEMINI_API_KEY` or `tools.web.search.gemini.apiKey`
- **Grok (xAI)**: `XAI_API_KEY` or `tools.web.search.grok.apiKey`
- **Kimi (Moonshot)**: `KIMI_API_KEY`, `MOONSHOT_API_KEY`, or `tools.web.search.kimi.apiKey`
- **Perplexity Search API**: `PERPLEXITY_API_KEY`, `OPENROUTER_API_KEY`, or `tools.web.search.perplexity.apiKey`
- **Brave Search API**: `BRAVE_API_KEY` or `plugins.entries.brave.config.webSearch.apiKey`
- **Gemini (Google Search)**: `GEMINI_API_KEY` or `plugins.entries.google.config.webSearch.apiKey`
- **Grok (xAI)**: `XAI_API_KEY` or `plugins.entries.xai.config.webSearch.apiKey`
- **Kimi (Moonshot)**: `KIMI_API_KEY`, `MOONSHOT_API_KEY`, or `plugins.entries.moonshot.config.webSearch.apiKey`
- **Perplexity Search API**: `PERPLEXITY_API_KEY`, `OPENROUTER_API_KEY`, or `plugins.entries.perplexity.config.webSearch.apiKey`
Legacy `tools.web.search.*` provider paths still load through the temporary compatibility shim, but they are no longer the recommended config surface.
**Brave Search free credit:** Each Brave plan includes \$5/month in renewing
free credit. The Search plan costs \$5 per 1,000 requests, so the credit covers

View File

@ -32,11 +32,12 @@ Scope intent:
- `messages.tts.elevenlabs.apiKey`
- `messages.tts.openai.apiKey`
- `tools.web.fetch.firecrawl.apiKey`
- `tools.web.search.apiKey`
- `tools.web.search.gemini.apiKey`
- `tools.web.search.grok.apiKey`
- `tools.web.search.kimi.apiKey`
- `tools.web.search.perplexity.apiKey`
- `plugins.entries.brave.config.webSearch.apiKey`
- `plugins.entries.google.config.webSearch.apiKey`
- `plugins.entries.xai.config.webSearch.apiKey`
- `plugins.entries.moonshot.config.webSearch.apiKey`
- `plugins.entries.perplexity.config.webSearch.apiKey`
- `plugins.entries.firecrawl.config.webSearch.apiKey`
- `gateway.auth.password`
- `gateway.auth.token`
- `gateway.remote.token`
@ -108,6 +109,7 @@ Notes:
- In explicit provider mode (`tools.web.search.provider` set), only the selected provider key is active.
- In auto mode (`tools.web.search.provider` unset), only the first provider key that resolves by precedence is active.
- In auto mode, non-selected provider refs are treated as inactive until selected.
- Legacy `tools.web.search.*` provider paths still resolve during the compatibility window, but the canonical SecretRef surface is `plugins.entries.<plugin>.config.webSearch.*`.
## Unsupported credentials

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