Compare commits

..

1 Commits

Author SHA1 Message Date
Vincent Koc
f2f893c14a refactor(agents): extract code mode runtime package 2026-05-30 14:55:20 +01:00
4036 changed files with 33763 additions and 111804 deletions

View File

@@ -223,21 +223,6 @@ Read the JSON summary and the Testbox line. Useful fields:
- Actions run URL/id from the Testbox output
- `exitCode`
Use provider-backed cache volumes only for rebuildable caches, not secrets or
checkout state. On Blacksmith, Crabbox forwards them as sticky disks:
```sh
node scripts/crabbox-wrapper.mjs run \
--provider blacksmith-testbox \
--cache-volume pnpm-store=openclaw-node24-pnpm-lock:/tmp/openclaw-pnpm-store \
--timing-json \
-- \
corepack pnpm check:changed
```
The selected provider must advertise cache-volume support. If not, omit
`--cache-volume` and rely on kept-lease caches.
`blacksmith testbox list` may hide hydrating or ready boxes. Use:
```sh
@@ -605,8 +590,7 @@ Crabbox Blacksmith backend delegates setup to:
The hydration workflow owns checkout, Node/pnpm setup, dependency install,
secrets, ready marker, and keepalive. Crabbox owns dispatch, sync, SSH command
execution, timing, logs/results, cleanup, and cache-volume requests. Blacksmith
implements cache volumes as sticky disks.
execution, timing, logs/results, and cleanup.
Minimal Blacksmith-backed Crabbox run, from repo root:
@@ -701,7 +685,6 @@ crabbox events <run_id> --json
crabbox logs <run_id>
crabbox results <run_id>
crabbox cache stats --id <id-or-slug>
crabbox cache volumes
crabbox ssh --id <id-or-slug>
blacksmith testbox list
```

View File

@@ -52,29 +52,17 @@ attribution.
- keep `#issue`, `(#PR)`, `Fixes #...`, and `Thanks @...`
- every human-authored merged PR represented by a user-facing entry needs
its PR ref and `Thanks @author`, even when the PR had no linked issue
- every human issue reporter for a `Fixes #...` or referenced bug issue
represented by a user-facing entry needs `Thanks @reporter` unless the
same handle is already thanked in that bullet
- every human `Co-authored-by` contributor on represented user-facing work
needs `Thanks @handle` when a GitHub handle is known
- when grouping multiple PRs/issues in one bullet, include every relevant
PR/issue ref and every human contributor handle in that same bullet
- multiple `Thanks @...` handles in one bullet are expected; do not drop or
collapse contributor credit just because the note is grouped
- if one grouped bullet covers both direct commits and PRs, keep all PR refs
and thanks, plus any issue refs from the direct commits
- before finalizing, audit the final release-note body:
- extract all `#NNN` refs from the notes
- resolve which refs are PRs and collect human PR authors
- resolve issue refs used as bug/report refs and collect human reporters
- scan represented commits for `Co-authored-by`
- compare those handles to the final `Thanks @...` set
- fix every missing human credit or explicitly record why it is omitted
- do not add GHSA references, advisory IDs, or security advisory slugs to
changelog entries or GitHub release-note text unless explicitly requested
- never thank bots, `@openclaw`, `@clawsweeper`, or `@steipete`
- do not use GitHub's release contributor count as the source of truth; the
changelog must carry the complete human credit set itself
- if grouping multiple entries, carry all relevant refs and thanks into the
grouped bullet
7. Sorting preference:
- security/data-loss and content-boundary fixes
- transcript/replay/reply delivery correctness

View File

@@ -7,16 +7,8 @@ queries:
- uses: ./.github/codeql/openclaw-boundary/queries/managed-proxy-runtime-mutation.ql
paths:
- src/cli/gateway-cli/run-loop.ts
- src/infra/gateway-lock.ts
- src/infra/jsonl-socket.ts
- src/infra/net
- src/infra/push-apns-http2.ts
- src/infra/ssh-tunnel.ts
- src/proxy-capture
- extensions/codex-supervisor/src/json-rpc-client.ts
- extensions/irc/src
- extensions/qa-lab/src
- src
- extensions
- packages/net-policy/src
paths-ignore:

5
.github/labeler.yml vendored
View File

@@ -132,11 +132,6 @@
- any-glob-to-any-file:
- "extensions/slack/**"
- "docs/channels/slack.md"
"channel: sms":
- changed-files:
- any-glob-to-any-file:
- "extensions/sms/**"
- "docs/channels/sms.md"
"channel: synology-chat":
- changed-files:
- any-glob-to-any-file:

View File

@@ -27,7 +27,7 @@ jobs:
timeout-minutes: 35
steps:
- name: Begin Testbox
uses: useblacksmith/begin-testbox@233448af4bfdc6fca509a7f0974411ac6d8a8043
uses: useblacksmith/begin-testbox@d0e04585c26905fdd92c94a09c159544c7ee1b67
with:
testbox_id: ${{ inputs.testbox_id }}
@@ -231,7 +231,7 @@ jobs:
run: bash scripts/ci-hydrate-testbox-env.sh
- name: Run Testbox
uses: useblacksmith/run-testbox@3f60ff9ceb2c10c3feefa87dc0c6490cffae059d
uses: useblacksmith/run-testbox@5ca05834db1d3813554d1dd109e5f2087a8d7cbc
if: success()
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"

View File

@@ -15,9 +15,6 @@ permissions:
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
PNPM_CONFIG_MODULES_DIR: "/tmp/openclaw-pnpm-node-modules"
PNPM_CONFIG_STORE_DIR: "/tmp/openclaw-pnpm-store"
PNPM_CONFIG_VIRTUAL_STORE_DIR: "/tmp/openclaw-pnpm-virtual-store"
jobs:
check:
@@ -29,7 +26,7 @@ jobs:
timeout-minutes: 30
steps:
- name: Begin Testbox
uses: useblacksmith/begin-testbox@233448af4bfdc6fca509a7f0974411ac6d8a8043
uses: useblacksmith/begin-testbox@d0e04585c26905fdd92c94a09c159544c7ee1b67
with:
testbox_id: ${{ inputs.testbox_id }}
- name: Checkout
@@ -136,7 +133,7 @@ jobs:
run: bash scripts/ci-hydrate-testbox-env.sh
- name: Run Testbox
uses: useblacksmith/run-testbox@3f60ff9ceb2c10c3feefa87dc0c6490cffae059d
uses: useblacksmith/run-testbox@5ca05834db1d3813554d1dd109e5f2087a8d7cbc
if: success()
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"

View File

@@ -601,7 +601,7 @@ jobs:
uses: actions/cache@v5
with:
path: .artifacts/build-all-cache
key: ${{ runner.os }}-build-all-v3-${{ hashFiles('package.json', 'pnpm-lock.yaml', 'npm-shrinkwrap.json', 'packages/plugin-sdk/package.json', 'packages/llm-core/package.json', 'packages/model-catalog-core/package.json', 'packages/memory-host-sdk/package.json', 'scripts/build-all.mjs', 'scripts/write-plugin-sdk-entry-dts.ts', 'scripts/lib/plugin-sdk-entries.mjs', 'tsconfig.json', 'tsconfig.plugin-sdk.dts.json', 'src/plugin-sdk/**', 'packages/llm-core/src/**', 'packages/model-catalog-core/src/**', 'packages/memory-host-sdk/src/**', 'src/types/**', 'src/video-generation/dashscope-compatible.ts', 'src/video-generation/types.ts', 'scripts/copy-export-html-templates.ts', 'scripts/lib/copy-assets.ts', 'src/auto-reply/reply/export-html/**') }}
key: ${{ runner.os }}-build-all-v3-${{ hashFiles('package.json', 'pnpm-lock.yaml', 'npm-shrinkwrap.json', 'packages/plugin-sdk/package.json', 'packages/llm-core/package.json', 'packages/memory-host-sdk/package.json', 'scripts/build-all.mjs', 'scripts/write-plugin-sdk-entry-dts.ts', 'scripts/lib/plugin-sdk-entries.mjs', 'tsconfig.json', 'tsconfig.plugin-sdk.dts.json', 'src/plugin-sdk/**', 'packages/llm-core/src/**', 'packages/memory-host-sdk/src/**', 'src/types/**', 'src/video-generation/dashscope-compatible.ts', 'src/video-generation/types.ts', 'scripts/copy-export-html-templates.ts', 'scripts/lib/copy-assets.ts', 'src/auto-reply/reply/export-html/**') }}
restore-keys: |
${{ runner.os }}-build-all-v3-
@@ -834,10 +834,10 @@ jobs:
;;
contracts-plugins-ci-routing)
pnpm test:contracts:plugins
pnpm test src/commands/status.scan-result.test.ts src/scripts/ci-changed-scope.test.ts test/scripts/changed-lanes.test.ts test/scripts/run-vitest.test.ts test/scripts/test-projects.test.ts
pnpm test src/commands/status.scan-result.test.ts src/scripts/ci-changed-scope.test.ts test/scripts/test-projects.test.ts
;;
ci-routing)
pnpm test src/commands/status.scan-result.test.ts src/scripts/ci-changed-scope.test.ts test/scripts/changed-lanes.test.ts test/scripts/run-vitest.test.ts test/scripts/test-projects.test.ts
pnpm test src/commands/status.scan-result.test.ts src/scripts/ci-changed-scope.test.ts test/scripts/test-projects.test.ts
;;
bun-launcher)
OPENCLAW_TEST_BUN_LAUNCHER=1 pnpm test test/openclaw-launcher.e2e.test.ts
@@ -1151,7 +1151,6 @@ jobs:
OPENCLAW_NODE_TEST_CONFIGS_JSON: ${{ toJson(matrix.configs) }}
OPENCLAW_NODE_TEST_INCLUDE_PATTERNS_JSON: ${{ toJson(matrix.includePatterns) }}
OPENCLAW_VITEST_SHARD_NAME: ${{ matrix.shard_name }}
OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS: "900000"
OPENCLAW_TEST_PROJECTS_PARALLEL: "2"
shell: bash
run: |
@@ -1404,7 +1403,7 @@ jobs:
packages/plugin-sdk/dist
extensions/*/dist/.boundary-tsc.tsbuildinfo
extensions/*/dist/.boundary-tsc.stamp
key: ${{ runner.os }}-extension-package-boundary-v1-${{ hashFiles('tsconfig.json', 'tsconfig.plugin-sdk.dts.json', 'packages/plugin-sdk/tsconfig.json', 'packages/llm-core/package.json', 'packages/model-catalog-core/package.json', 'scripts/check-extension-package-tsc-boundary.mjs', 'scripts/prepare-extension-package-boundary-artifacts.mjs', 'scripts/write-plugin-sdk-entry-dts.ts', 'scripts/lib/plugin-sdk-entrypoints.json', 'scripts/lib/plugin-sdk-entries.mjs', 'src/plugin-sdk/**', 'src/auto-reply/**', 'packages/llm-core/src/**', 'packages/model-catalog-core/src/**', 'src/video-generation/dashscope-compatible.ts', 'src/video-generation/types.ts', 'src/types/**', 'extensions/**', 'extensions/tsconfig.package-boundary*.json', 'package.json', 'pnpm-lock.yaml') }}
key: ${{ runner.os }}-extension-package-boundary-v1-${{ hashFiles('tsconfig.json', 'tsconfig.plugin-sdk.dts.json', 'packages/plugin-sdk/tsconfig.json', 'packages/llm-core/package.json', 'scripts/check-extension-package-tsc-boundary.mjs', 'scripts/prepare-extension-package-boundary-artifacts.mjs', 'scripts/write-plugin-sdk-entry-dts.ts', 'scripts/lib/plugin-sdk-entrypoints.json', 'scripts/lib/plugin-sdk-entries.mjs', 'src/plugin-sdk/**', 'src/auto-reply/**', 'packages/llm-core/src/**', 'src/video-generation/dashscope-compatible.ts', 'src/video-generation/types.ts', 'src/types/**', 'extensions/**', 'extensions/tsconfig.package-boundary*.json', 'package.json', 'pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-extension-package-boundary-v1-
@@ -1426,17 +1425,11 @@ jobs:
-type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.mts' -o -name '*.cts' -o -name '*.js' -o -name '*.mjs' -o -name '*.json' \) \
-exec touch -t 200001010000 {} +
fi
if [ -d packages/model-catalog-core/src ]; then
find packages/model-catalog-core/src \
-type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.mts' -o -name '*.cts' -o -name '*.js' -o -name '*.mjs' -o -name '*.json' \) \
-exec touch -t 200001010000 {} +
fi
cache_inputs=(
tsconfig.json \
tsconfig.plugin-sdk.dts.json \
packages/plugin-sdk/tsconfig.json \
packages/llm-core/package.json \
packages/model-catalog-core/package.json \
scripts/check-extension-package-tsc-boundary.mjs \
scripts/prepare-extension-package-boundary-artifacts.mjs \
scripts/write-plugin-sdk-entry-dts.ts \
@@ -1972,21 +1965,6 @@ jobs:
done
exit 1
- name: OpenClawKit Talk-trait opt-out (no ElevenLabsKit when default traits disabled)
run: |
set -euo pipefail
# Guard: chat-only consumers build OpenClawKit with the Talk trait
# disabled and must NOT link ElevenLabsKit. Assert that future sources
# under OpenClawKit cannot silently reintroduce an unconditional
# ElevenLabsKit dependency while the manifest still looks correct.
deps="$(swift package --package-path apps/shared/OpenClawKit show-dependencies --disable-default-traits)"
echo "$deps"
if grep -qi 'elevenlabs' <<<"$deps"; then
echo "::error::ElevenLabsKit resolved with the Talk trait disabled; keep it gated behind the Talk trait."
exit 1
fi
swift build --package-path apps/shared/OpenClawKit --target OpenClawKit --disable-default-traits
- name: Swift test
run: |
set -euo pipefail

View File

@@ -210,9 +210,6 @@ jobs:
else
while IFS= read -r file; do
case "${file}" in
.github/codeql/codeql-network-runtime-boundary-critical-quality.yml|.github/codeql/openclaw-boundary/queries/raw-socket-callsite-classification.ql|.github/codeql/openclaw-boundary/queries/managed-proxy-runtime-mutation.ql)
network_runtime=true
;;
.github/codeql/*|.github/workflows/codeql-critical-quality.yml)
agent=true
channel=true
@@ -225,6 +222,7 @@ jobs:
plugin_sdk_package=true
plugin_sdk_reply=true
provider=true
network_runtime=true
session_diagnostics=true
;;
src/agents/sessions/tools/*)
@@ -304,9 +302,7 @@ jobs:
esac
case "${file}" in
src/**/*.test.ts|src/**/*.test.tsx|extensions/**/*.test.ts|extensions/**/*.test.tsx)
;;
packages/net-policy/src/*|packages/net-policy/src/**/*|src/cli/gateway-cli/run-loop.ts|src/infra/net/*|src/infra/net/**/*|src/infra/ssh-tunnel.ts|src/infra/gateway-lock.ts|src/infra/jsonl-socket.ts|src/infra/push-apns-http2.ts|src/proxy-capture/*|src/proxy-capture/**/*|extensions/codex-supervisor/src/json-rpc-client.ts|extensions/irc/src/*|extensions/qa-lab/src/*)
src/*.ts|src/**/*.ts|extensions/*.ts|extensions/**/*.ts|packages/net-policy/src/*|packages/net-policy/src/**/*)
network_runtime=true
;;
esac
@@ -433,33 +429,7 @@ jobs:
with:
submodules: false
- name: Fast PR network boundary diff scan
if: ${{ github.event_name == 'pull_request' }}
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
REPOSITORY: ${{ github.repository }}
run: |
set -euo pipefail
added_lines="$(mktemp)"
gh api --paginate "repos/${REPOSITORY}/pulls/${PR_NUMBER}/files" --jq '
.[]
| select(.filename | test("^(src/cli/gateway-cli/run-loop\\.ts|src/infra/(gateway-lock|jsonl-socket|push-apns-http2|ssh-tunnel)\\.ts|src/infra/net/|src/proxy-capture/|extensions/codex-supervisor/src/json-rpc-client\\.ts|extensions/irc/src/|extensions/qa-lab/src/|packages/net-policy/src/)"))
| .filename as $file
| (.patch // "")
| split("\n")[]
| select(startswith("+") and (startswith("+++") | not))
| "\($file): \(.)"
' > "$added_lines"
if grep -En '(from|require\().*["'\''](node:)?(net|tls|http2)["'\'']|\b(net|tls|http2)\.(connect|createConnection)\b|new Socket\(|HTTP_PROXY|HTTPS_PROXY|NO_PROXY|GLOBAL_AGENT_|OPENCLAW_PROXY_' "$added_lines"; then
echo "Network runtime boundary-sensitive added lines require full CodeQL review." >&2
exit 1
fi
- name: Initialize CodeQL
if: ${{ github.event_name != 'pull_request' }}
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
languages: javascript-typescript
@@ -467,14 +437,12 @@ jobs:
- name: Analyze
id: analyze
if: ${{ github.event_name != 'pull_request' }}
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4
with:
output: sarif-results
category: "/codeql-critical-quality/network-runtime-boundary"
- name: Fail on network runtime boundary findings
if: ${{ github.event_name != 'pull_request' }}
env:
SARIF_OUTPUT: sarif-results
run: |

View File

@@ -51,8 +51,7 @@ jobs:
# so this source workflow can stay focused on OIDC publish only.
preflight_openclaw_npm:
if: ${{ inputs.preflight_only }}
# Preflight builds the full release package before publish; ubuntu-latest can OOM in tsdown.
runs-on: blacksmith-16vcpu-ubuntu-2404
runs-on: ubuntu-latest
permissions:
contents: read
steps:
@@ -373,11 +372,6 @@ jobs:
actions: read
contents: read
steps:
- name: Checkout
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Require trusted workflow ref for publish
env:
RELEASE_TAG: ${{ inputs.tag }}
@@ -435,13 +429,12 @@ jobs:
echo "Direct OpenClaw npm publish; relying on this workflow's npm-release environment approval."
exit 0
fi
direct_recovery=false
if [[ "${GITHUB_ACTOR}" != "github-actions[bot]" ]]; then
direct_recovery=true
echo "Direct OpenClaw npm recovery with release_publish_run_id; relying on this workflow's npm-release environment approval."
echo "OpenClaw npm publish must be dispatched by the OpenClaw Release Publish workflow, not directly by ${GITHUB_ACTOR}." >&2
exit 1
fi
RUN_JSON="$(gh run view "$RELEASE_PUBLISH_RUN_ID" --repo "$GITHUB_REPOSITORY" --json workflowName,headBranch,event,status,conclusion,url)"
printf '%s' "$RUN_JSON" | DIRECT_RELEASE_RECOVERY="${direct_recovery}" node scripts/validate-release-publish-approval.mjs
printf '%s' "$RUN_JSON" | node -e 'const fs = require("node:fs"); const run = JSON.parse(fs.readFileSync(0, "utf8")); const checks = [["workflowName", "OpenClaw Release Publish"], ["headBranch", process.env.EXPECTED_WORKFLOW_BRANCH], ["event", "workflow_dispatch"]]; for (const [key, expected] of checks) { if (run[key] !== expected) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must have ${key}=${expected}, got ${run[key] ?? "<missing>"}.`); process.exit(1); } } if (run.status !== "in_progress") { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must still be in_progress, got ${run.status ?? "<missing>"}.`); process.exit(1); } if (run.conclusion) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} already concluded ${run.conclusion}.`); process.exit(1); } console.log(`Using release publish approval run ${process.env.RELEASE_PUBLISH_RUN_ID}: ${run.url}`);'
publish_openclaw_npm:
# KEEP THE REAL RELEASE/PUBLISH PATH ON A GITHUB-HOSTED RUNNER.

View File

@@ -1075,7 +1075,7 @@ jobs:
needs: [resolve_target]
if: contains(fromJSON('["all","qa","qa-live"]'), needs.resolve_target.outputs.rerun_group) && needs.resolve_target.outputs.qa_live_matrix_enabled == 'true'
continue-on-error: true
runs-on: blacksmith-16vcpu-ubuntu-2404
runs-on: ubuntu-24.04
timeout-minutes: 60
permissions:
contents: read

View File

@@ -207,11 +207,6 @@ jobs:
actions: read
contents: read
steps:
- name: Checkout
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Validate release publish approval run
env:
GH_TOKEN: ${{ github.token }}
@@ -227,13 +222,12 @@ jobs:
echo "Direct Plugin ClawHub Release dispatch; relying on this workflow's clawhub-plugin-release environment approval."
exit 0
fi
direct_recovery=false
if [[ "${GITHUB_ACTOR}" != "github-actions[bot]" ]]; then
direct_recovery=true
echo "Direct Plugin ClawHub Release recovery with release_publish_run_id; relying on this workflow's clawhub-plugin-release environment approval."
echo "Plugin ClawHub publish must be dispatched by the OpenClaw Release Publish workflow, not directly by ${GITHUB_ACTOR}." >&2
exit 1
fi
RUN_JSON="$(gh run view "$RELEASE_PUBLISH_RUN_ID" --repo "$GITHUB_REPOSITORY" --json workflowName,headBranch,event,status,conclusion,url)"
printf '%s' "$RUN_JSON" | DIRECT_RELEASE_RECOVERY="${direct_recovery}" node scripts/validate-release-publish-approval.mjs
printf '%s' "$RUN_JSON" | node -e 'const fs = require("node:fs"); const run = JSON.parse(fs.readFileSync(0, "utf8")); const checks = [["workflowName", "OpenClaw Release Publish"], ["headBranch", process.env.EXPECTED_WORKFLOW_BRANCH], ["event", "workflow_dispatch"]]; for (const [key, expected] of checks) { if (run[key] !== expected) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must have ${key}=${expected}, got ${run[key] ?? "<missing>"}.`); process.exit(1); } } if (run.status !== "in_progress") { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must still be in_progress, got ${run.status ?? "<missing>"}.`); process.exit(1); } if (run.conclusion) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} already concluded ${run.conclusion}.`); process.exit(1); } console.log(`Using release publish approval run ${process.env.RELEASE_PUBLISH_RUN_ID}: ${run.url}`);'
preview_plugin_pack:
needs: preview_plugins_clawhub

View File

@@ -184,11 +184,6 @@ jobs:
actions: read
contents: read
steps:
- name: Checkout
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Validate release publish approval run
env:
GH_TOKEN: ${{ github.token }}
@@ -204,13 +199,12 @@ jobs:
echo "Direct Plugin NPM Release dispatch; relying on this workflow's npm-release environment approval."
exit 0
fi
direct_recovery=false
if [[ "${GITHUB_ACTOR}" != "github-actions[bot]" ]]; then
direct_recovery=true
echo "Direct Plugin NPM Release recovery with release_publish_run_id; relying on this workflow's npm-release environment approval."
echo "Plugin npm publish must be dispatched by the OpenClaw Release Publish workflow, not directly by ${GITHUB_ACTOR}." >&2
exit 1
fi
RUN_JSON="$(gh run view "$RELEASE_PUBLISH_RUN_ID" --repo "$GITHUB_REPOSITORY" --json workflowName,headBranch,event,status,conclusion,url)"
printf '%s' "$RUN_JSON" | DIRECT_RELEASE_RECOVERY="${direct_recovery}" node scripts/validate-release-publish-approval.mjs
printf '%s' "$RUN_JSON" | node -e 'const fs = require("node:fs"); const run = JSON.parse(fs.readFileSync(0, "utf8")); const checks = [["workflowName", "OpenClaw Release Publish"], ["headBranch", process.env.EXPECTED_WORKFLOW_BRANCH], ["event", "workflow_dispatch"]]; for (const [key, expected] of checks) { if (run[key] !== expected) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must have ${key}=${expected}, got ${run[key] ?? "<missing>"}.`); process.exit(1); } } if (run.status !== "in_progress") { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} must still be in_progress, got ${run.status ?? "<missing>"}.`); process.exit(1); } if (run.conclusion) { console.error(`Referenced release publish run ${process.env.RELEASE_PUBLISH_RUN_ID} already concluded ${run.conclusion}.`); process.exit(1); } console.log(`Using release publish approval run ${process.env.RELEASE_PUBLISH_RUN_ID}: ${run.url}`);'
preview_plugin_pack:
needs: preview_plugins_npm

View File

@@ -197,4 +197,4 @@ jobs:
- name: Testbox action marker
if: ${{ false }}
uses: useblacksmith/run-testbox@3f60ff9ceb2c10c3feefa87dc0c6490cffae059d
uses: useblacksmith/run-testbox@5ca05834db1d3813554d1dd109e5f2087a8d7cbc

View File

@@ -20,44 +20,34 @@
"eslint/no-multi-str": "error",
"eslint/no-new": "error",
"eslint/no-object-constructor": "error",
"eslint/no-param-reassign": "error",
"eslint/no-proto": "error",
"eslint/no-regex-spaces": "error",
"eslint/no-return-assign": "error",
"eslint/no-sequences": "error",
"eslint/no-self-compare": "error",
"eslint/no-shadow": "off",
"eslint/no-implicit-coercion": "error",
"eslint/no-var": "error",
"eslint/no-useless-call": "error",
"eslint/no-useless-computed-key": "error",
"eslint/no-useless-concat": "error",
"eslint/no-useless-constructor": "error",
"eslint/no-useless-rename": "error",
"eslint/no-useless-return": "error",
"eslint/no-unused-vars": "off",
"eslint/no-warning-comments": "error",
"eslint/no-unmodified-loop-condition": "error",
"eslint/no-new-wrappers": "error",
"eslint/no-else-return": "error",
"eslint/no-lonely-if": "error",
"eslint/no-case-declarations": "error",
"eslint/default-case-last": "error",
"eslint/default-param-last": "error",
"eslint/prefer-exponentiation-operator": "error",
"eslint/prefer-const": "error",
"eslint/prefer-numeric-literals": "error",
"eslint/prefer-object-has-own": "error",
"eslint/object-shorthand": "error",
"eslint/prefer-rest-params": "error",
"eslint/prefer-spread": "error",
"eslint/radix": "error",
"eslint/unicode-bom": "error",
"eslint/yoda": "error",
"import/no-absolute-path": "error",
"import/first": "error",
"import/no-empty-named-blocks": "error",
"import/no-duplicates": "error",
"import/no-self-import": "error",
"node/no-exports-assign": "error",
"eslint-plugin-unicorn/prefer-set-size": "error",
@@ -76,9 +66,7 @@
"typescript/no-empty-object-type": ["error", { "allowInterfaces": "with-single-extends" }],
"typescript/no-explicit-any": "error",
"typescript/no-extraneous-class": "error",
"typescript/no-import-type-side-effects": "error",
"typescript/no-meaningless-void-operator": "error",
"typescript/no-inferrable-types": "error",
"typescript/no-non-null-asserted-nullish-coalescing": "error",
"typescript/no-unnecessary-qualifier": "error",
"typescript/no-unnecessary-type-assertion": "error",
@@ -98,7 +86,6 @@
"typescript/prefer-namespace-keyword": "error",
"typescript/prefer-return-this-type": "error",
"typescript/prefer-find": "error",
"typescript/prefer-for-of": "error",
"typescript/prefer-function-type": "error",
"typescript/prefer-includes": "error",
"typescript/prefer-reduce-type-parameter": "error",
@@ -119,17 +106,14 @@
"unicorn/no-new-buffer": "error",
"unicorn/no-thenable": "error",
"unicorn/no-typeof-undefined": "error",
"unicorn/no-unreadable-array-destructuring": "error",
"unicorn/no-unnecessary-array-flat-depth": "error",
"unicorn/no-unnecessary-array-splice-count": "error",
"unicorn/no-unnecessary-slice-end": "error",
"unicorn/no-useless-error-capture-stack-trace": "error",
"unicorn/no-useless-promise-resolve-reject": "error",
"unicorn/no-zero-fractions": "error",
"unicorn/prefer-date-now": "error",
"unicorn/prefer-dom-node-text-content": "error",
"unicorn/prefer-keyboard-event-key": "error",
"unicorn/prefer-array-flat": "error",
"unicorn/prefer-array-some": "error",
"unicorn/prefer-math-min-max": "error",
"unicorn/prefer-node-protocol": "error",
@@ -139,8 +123,6 @@
"unicorn/prefer-prototype-methods": "error",
"unicorn/prefer-regexp-test": "error",
"unicorn/prefer-set-size": "error",
"unicorn/prefer-set-has": "error",
"unicorn/prefer-structured-clone": "error",
"unicorn/prefer-string-starts-ends-with": "error",
"unicorn/prefer-string-slice": "error",
"unicorn/require-array-join-separator": "error",
@@ -201,7 +183,6 @@
"docs/_layouts/",
"extensions/diffs/assets/viewer-runtime.js",
"extensions/diffs-language-pack/assets/viewer-runtime.js",
"extensions/canvas/src/host/a2ui/a2ui.bundle.js",
"node_modules/",
"patches/",
"pnpm-lock.yaml",
@@ -218,6 +199,13 @@
"**/node_modules/**"
],
"overrides": [
{
"files": ["src/security/**"],
"rules": {
"eslint/no-warning-comments": "off",
"oxc/no-map-spread": "off"
}
},
{
"files": [
"**/*.test.ts",

View File

@@ -78,7 +78,7 @@ Skills own workflows; root owns hard policy and routing.
- Gateway/plugin metadata is process-stable: installs, manifests, catalogs, generated paths, bundled metadata. Changes require restart or explicit owner reload/install/doctor flow.
- Runtime hot paths: no freshness polling (`stat`/`realpath`/JSON reread/hash). Reuse current snapshots, install records, discovery, lookup tables, root scopes, resolved paths.
- Process-local metadata caches ok when lifecycle-owned and bounded/single-slot. Freshness exceptions need named owner + tests.
- Inline comments: preserve reviewer context at the code site. Required for non-obvious cross-path/state invariants, lifecycle ordering, ownership boundaries, queue/dedupe symmetry, TTL/cache expiry, cleanup/release coupling, session/id adoption, fallback behavior, platform/dependency caps, deterministic ordering, compact encoded state, or intentional caller differences.
- Inline comments: preserve reviewer context at the code site. Use for cross-path/state invariants, platform/dependency caps, deterministic ordering, compact encoded state, lifecycle ordering, ownership boundaries, session/id adoption, queue-depth symmetry, fallbacks, or intentional caller differences.
- Comment shape: 1-3 short lines; state why the branch/helper exists, what contract it protects, and the bad outcome if removed. Cite nearby constants/helpers when useful. No syntax narration, PR/user-specific lore, or obvious mechanics.
- Gateway protocol changes: additive first; incompatible needs versioning/docs/client follow-through.
- Protocol version bumps: explicit owner confirmation only; never automatic/generated.
@@ -211,7 +211,6 @@ Skills own workflows; root owns hard policy and routing.
- Never commit real phone numbers, videos, credentials, live config.
- Secrets: channel/provider creds in `~/.openclaw/credentials/`; model auth profiles in `~/.openclaw/agents/<agentId>/agent/auth-profiles.json`.
- Dependency patches/overrides/vendor changes need explicit approval. `pnpm-workspace.yaml` patched dependencies use exact versions only.
- Release/package guards: no hard-coded retired-package denylists; use generic artifact/dependency checks or fix build source.
- Lockfiles/shrinkwrap are security surface: review `pnpm-lock.yaml`, `npm-shrinkwrap.json`, `package-lock.json`; root/plugin npm packages ship shrinkwrap, not package-lock.
- Carbon pins owner-only: do not change `@buape/carbon` unless Shadow (`@thewilloftheshadow`, verified by `gh`) asks.
- Releases/publish/version bumps need explicit approval. Use `$release-openclaw-maintainer`.
@@ -231,7 +230,6 @@ Skills own workflows; root owns hard policy and routing.
- Crabbox/WebVNC human demos: keep remote desktop visible/windowed; no fullscreen remote browser unless video/capture-style output.
- ClawSweeper ops: `$clawsweeper`. Deployed hook sessions may post one concise `#clawsweeper` note only when surprising/actionable/risky; if using message tool, reply exactly `NO_REPLY`.
- Generated-media completions wake the requester agent first. Requester visible-reply config decides final text vs message tool; direct media send is fallback/recovery only.
- `message_tool_only`: normal agent final visible reply = current-source `message(action=send)` only. No `NO_REPLY` prompt/contract; no message call = no source reply. Plugin-owned bound-thread reply = plugin return value; no message tool needed. Never auto-publish private final.
- Memory wiki prompt digest stays tiny; prefer `wiki_search` / `wiki_get`; verify contact data before use; source-class provenance for generated people facts.
- Rebrand/migration/config warnings: run `openclaw doctor`.
- Never edit `node_modules`.

View File

@@ -15,42 +15,27 @@ Docs: https://docs.openclaw.ai
### Changes
- Docs: add a dedicated Skill Workshop guide covering governed skill creation, reviewable proposals, CLI, Gateway, agent tool behavior, approval policy, support files, and recovery. Thanks @shakkernerd.
- Skills: let the `skill_workshop` agent tool apply, reject, and quarantine explicit proposals through the guarded review flow. Thanks @shakkernerd.
- Skills: let proposals carry approved support files under standard skill folders, with scanner, hash, and rollback safeguards. Thanks @shakkernerd.
- Skills: let pending proposals be revised in place with versioned, dated proposal frontmatter before approval. Thanks @shakkernerd.
- Skills: add Skill Workshop with pending proposals, CLI/Gateway review actions, rollback metadata, and the `skill_workshop` agent tool. Thanks @shakkernerd.
- Plugins: externalize Tokenjuice as the official `@openclaw/tokenjuice` plugin with npm and ClawHub publish metadata.
- Plugins: externalize the GitHub Copilot agent runtime as the official `@openclaw/copilot` plugin with npm and ClawHub publish metadata.
- iOS: add hosted push relay defaults, realtime Talk playback, and a guarded WebSocket ping path for more reliable mobile sessions. (#88096, #88105, #88231)
- Workboard: add orchestration primitives and agent coordination tools for multi-agent planning and run tracking. (#87469)
- Code mode: add internal namespaces for scoped agent/global sessions and exact namespace tool dispatch. (#88043)
- Control UI: add a Dreaming-tab agent selector and propagate the selected agent through Dreaming status, diary, and diary actions. (#78748) Thanks @stevenepalmer.
- Plugins: add a SecretRef provider integration manifest contract and extract shared LLM core packages for provider/plugin reuse. (#82326, #88117)
- Skills: add the core skills index and centralize skills runtime loading, status, filtering, and prompt formatting.
### Fixes
- Agents/Codex: keep public OpenAI API-key profiles from being treated as native Codex app-server auth while preserving persisted Codex OAuth sessions.
- Control UI: keep collapsed tool cards labeled with the tool name and action instead of generic output text. Thanks @shakkernerd.
- Agents/Codex: surface Skill Workshop guidance in Codex app-server prompts when `skill_workshop` is available. Thanks @shakkernerd.
- CLI: keep `plugins list --json` on the snapshot-only path so plugin sweeps avoid loading the full runtime status graph.
- Plugins: make PixVerse external-plugin ClawHub metadata explicit and keep it out of bundled dist builds.
- Cron: keep SQLite cron migrations compatible with legacy run-log tables, archived job stores, diagnostic cron names, and legacy one-shot delete-after-run behavior. (#88285)
- Providers: bound generated media downloads from OpenAI, Runway, xAI, MiniMax, BytePlus, DashScope-compatible, FAL, OpenRouter, Google, Vydra, and Comfy providers.
- Providers: cap GitHub Copilot OAuth request timeouts before creating abort signals.
- Cron: retry recurring jobs after transient model rate limits before waiting for the next scheduled slot.
- Agents/Codex: keep live session locks during cleanup, recover interrupted CLI tool transcripts, preserve Codex auth and compaction session identity, clear orphan tool state, cap app-server idle timers, and keep media completion delivery retryable. (#88129, #88136, #88141, #88162, #88182)
- Chat/UI: show Gateway chat failures as visible assistant messages in the Control UI instead of only setting an invisible error state.
- Channels: cap Telegram, Discord, WhatsApp, Signal, Feishu, Google Chat, Microsoft Teams, QQBot, Nostr, Zalo, Zalouser, and Nextcloud-style request/retry timers; preserve SMS approval reply routes; and retry WhatsApp QR login 408 timeouts. (#88183)
- Security/config parsing: reject unsafe OAuth/token lifetimes, retry-after delays, inbound timestamps, response body sizes, command timeout config, sandbox observer token TTLs, and gateway WebSocket calls after close.
- Providers/media: cap local service, model, usage, queue, generated media, TTS, music, workflow polling, and provider OAuth request timers across hosted and local providers.
- Release/CI/E2E: bound release candidate reads, beta smoke REST calls, changelog restore, kitchen-sink and bundled plugin readiness probes, secret-provider probes, Vitest routing, and mainline test flakes. (#88127, #88137, #88155, #88160)
- Release/CI/E2E: run the secret-provider integration proof through the repo pnpm runner so native macOS and Windows validation use the hydrated package-manager shim.
- Release/CI/E2E: run the Telegram desktop proof gateway through the repo pnpm runner so native macOS proof uses the hydrated package-manager shim.
- Docs/CI: run Mintlify anchor checks through the repo pnpm runner so docs link validation works when pnpm is only available through the hydrated package-manager shim.
- Agents: keep configured fallback model metadata typed so provider params, context-token caps, and media input limits do not break changed-gate typechecks.
- Agents: accept hidden `sessions_send` body aliases before validation while keeping the model-facing `message` schema canonical. (#88229) Thanks @zhangguiping-xydt.
- CI/Crabbox: keep default runner capacity spot-only and provider-neutral so OpenClaw remote validation does not silently fall back to on-demand leases or stale AWS region hints.
- CI/Crabbox: route Crabbox wrapper and Testbox workflow edits to their regression tests so changed-test gates do not silently run zero specs.
- CI/workflows: route workflow sanity helper edits to their guard tests and cover composite-action input interpolation checks.
@@ -59,26 +44,17 @@ Docs: https://docs.openclaw.ai
- CI/tooling: route shared script library edits through their owner tests so lock, process, safety, and scan helpers do not skip changed-test coverage.
- CI/tooling: skip expensive import-graph scans once a changed diff already requires broad fallback, keeping local changed-test planning fast while still collecting explicit owner tests.
- CI/tooling: route script edits through conventional owner tests when matching `test/scripts` or `src/scripts` coverage already exists.
- CI/tooling: honor option terminators in the memory FD repro script so follow-on arguments are not reparsed.
- Release/CI/E2E: assert plugin lifecycle runtime inspect output instead of only capturing it.
- Release/CI/E2E: make gateway-network prove the advertised health RPC and retry early WebSocket closes without burning full open timeouts.
- Release/CI/E2E: honor option terminators across release, Parallels smoke, plugin gauntlet, and extension-memory scripts.
- Release/CI/E2E: fail plugin gateway gauntlet QA chunks when the requested suite summary is missing or invalid.
- Performance: prebuild QA runtime probes with generated plugin assets but without CLI startup metadata.
- Performance: skip declaration bundling for runtime-only CLI startup and gateway watch build profiles.
- Performance: reuse prepared provider handles, strict tool schemas, gateway runtime metadata, session maintenance config, plugin metadata, bundled skill allowlists, package-local plugin artifacts, single-entry store writes, and validated/serialized session prompt blobs.
- Performance: reuse prepared provider handles, strict tool schemas, gateway runtime metadata, session maintenance config, plugin metadata, bundled skill allowlists, package-local plugin artifacts, and single-entry store writes.
## 2026.5.28
### Highlights
- Agent and Codex runtime recovery is steadier: subagents keep cwd/workspace separation, hook context stays prompt-local, session locks release on timeout abort while live OpenClaw locks survive cleanup, stale restart continuations are avoided, and Codex app-server/helper failures no longer tear down shared runtime state. (#87218, #86875, #87409, #87399, #87375, #88129)
- Channel delivery and session identity got safer across outbound plugin hooks, Matrix room ids, iMessage reactions/approvals, Slack final replies, Discord recovered tool warnings, runtime-config message actions, WhatsApp profile auth roots, Telegram polling, and Microsoft Teams service URL trust checks. (#73706, #75670, #87366, #87451, #87334, #84535, #82492, #83304, #87160)
- Mobile and chat surfaces got a broader refresh: the iOS Pro UI, hosted push relay default, realtime Talk tab playback, Gateway chat transport, onboarding, Talk permissions, WebChat reconnect delivery, and session picker behavior now preserve more state across reconnects and empty searches. (#87367, #87531, #87682, #88096, #88105) Thanks @ngutman and @BunsDev.
- Browser, channel, and automation inputs are stricter: Browser tool timeouts, viewport/tab indices, Gateway ports, cron retry handling, Discord component ids, schema array refs, Telegram callback pages, and channel progress callbacks now reject malformed values earlier and preserve the intended delivery context. (#82887)
- Provider, media, and document coverage expands with Claude Opus 4.8, Fal Krea image schemas, NVIDIA featured models, MiniMax streaming music responses, encrypted PDF extraction, voice model catalogs, GitHub Copilot agent runtime support, and a Codex Supervisor plugin path for delegated Codex workflows. (#87845, #87890, #80775, #84764, #87751, #87794)
- CLI, auth, doctor, and provider paths fail faster and recover more clearly: malformed numeric/version options are rejected, workspace dotenv provider credentials are ignored, heartbeat defaults, OAuth/token lifetimes, and local service startup requests are bounded, agent auth health labels are clearer, legacy `api_key` auth profiles migrate to canonical form, and restart guidance is actionable. (#87398, #86281, #87361, #88133, #83655, #87559, #88088, #85924) Thanks @vincentkoc and @giodl73-repo.
- Plugin and Gateway hot paths do less repeated work while preserving cache correctness for install records, config JSON parsing, tool search catalogs, session stores, manifest model rows, auto-enabled plugin config, browser tokens, viewer assets, and release-split external plugin packages. (#86699)
- Agent and Codex runtime recovery is steadier: subagents keep cwd/workspace separation, hook context stays prompt-local, session locks release on timeout abort, stale restart continuations are avoided, and Codex app-server/helper failures no longer tear down shared runtime state. (#87218, #86875, #87409, #87399, #87375)
- Channel delivery and session identity got safer across outbound plugin hooks, Matrix room ids, iMessage reactions/approvals, Slack final replies, Discord recovered tool warnings, and Microsoft Teams service URL trust checks. (#73706, #75670, #87366, #87451, #87334)
- Mobile and chat surfaces got a broader refresh: the iOS Pro UI, Gateway chat transport, onboarding, Talk permissions, WebChat reconnect delivery, and session picker behavior now preserve more state across reconnects and empty searches. (#87367, #87531, #87682)
- CLI, auth, doctor, and provider paths fail faster and recover more clearly: malformed numeric/version options are rejected, OAuth and local service startup requests are bounded, legacy `api_key` auth profiles migrate to canonical form, and restart guidance is actionable. (#87398, #86281, #87361)
- Plugin and Gateway hot paths do less repeated work while preserving cache correctness for install records, config JSON parsing, tool search catalogs, session stores, manifest model rows, auto-enabled plugin config, browser tokens, and viewer assets. (#86699)
- Release, QA, and E2E validation now bound more log, artifact, harness, and cross-OS waits so failing lanes produce proof instead of hanging or false-greening.
### Changes
@@ -86,41 +62,25 @@ Docs: https://docs.openclaw.ai
- Status: show active subagent details in status output.
- Diffs: split the default language pack and expand default Diffs language coverage while keeping the host floor aligned. (#87370, #87372) Thanks @RomneyDa.
- ClawHub: add plugin display names plus skill verification and trust surfaces. (#87354, #86699) Thanks @thewilloftheshadow and @Patrick-Erichsen.
- iOS: refresh the dev app with Pro Command, Chat, Agents, Settings, hosted push relay defaults, and realtime Talk playback wired to gateway sessions, diagnostics, chat, and realtime Talk. (#87367, #88096, #88105) Thanks @Solvely-Colin and @ngutman.
- Docs: clarify Codex computer-use setup, paste-token stdin auth setup, macOS gateway sleep troubleshooting, native Codex hook relay recovery, container model auth, install deployment cards, device-token admin gating, CLI setup flow compatibility, Notte cloud browser CDP setup, and backport targets. (#87313, #63050, #87685) Thanks @bdjben, @liaoandi, and @thewilloftheshadow.
- PDF/tools: use ClawPDF for PDF extraction, support encrypted PDF extraction, and surface MCP structured content in agent tool results. (#87670, #87751)
- Providers: add Claude Opus 4.8 support, Fal Krea image model schemas, NVIDIA featured model catalogs, MiniMax streaming music responses, and provider-backed voice model catalogs. (#87845, #87890, #80775, #84764, #87794) Thanks @eleqtrizit and @vincentkoc.
- Codex/GitHub: add the GitHub Copilot agent runtime and the Codex Supervisor plugin package.
- Plugins: externalize GitHub Copilot and Tokenjuice as official install-on-demand plugins with npm and ClawHub publish metadata.
- Workboard: add agent coordination tools for tracking and handing off active agent work.
- Discord: show commentary in progress drafts so live Discord runs expose useful in-progress context. (#85200)
- Plugin SDK: add a reply payload sending hook for plugins that need to deliver channel-owned replies and flatten package types for SDK declarations. (#82823, #87165) Thanks @piersonr and @RomneyDa.
- Policy: add policy comparison, ingress-channel conformance, and sandbox-posture conformance checks. (#85572, #85744, #86768)
- iOS: refresh the dev app with Pro Command, Chat, Agents, and Settings tabs wired to gateway sessions, diagnostics, chat, and realtime Talk. (#87367) Thanks @Solvely-Colin.
- Docs: clarify Codex computer-use setup, paste-token stdin auth setup, macOS gateway sleep troubleshooting, native Codex hook relay recovery, container model auth, install deployment cards, device-token admin gating, and backport targets. (#87313, #63050) Thanks @bdjben, @liaoandi, and @thewilloftheshadow.
- PDF/tools: use ClawPDF for PDF extraction and surface MCP structured content in agent tool results. (#87670)
### Fixes
- Agents: fall back to local config pruning when the optional `agents delete` Gateway probe cannot authenticate, so offline installs can still delete agents without removing shared workspaces.
- Tighten phone-control mutation authorization [AI]. (#87150) Thanks @pgondhi987.
- Clarify directive persistence authorization policy [AI]. (#86369) Thanks @pgondhi987.
- Agents/Codex: keep spawned agent cwd/workspace state separated, forward ACP spawn attachments, keep hook context prompt-local, release session locks on timeout abort and runtime teardown without deleting live OpenClaw-owned locks during cleanup, avoid session event queue self-wait, clean up exec abort listeners, stream assistant deltas incrementally, recover raw missing-thread compaction failures, preserve rotated compaction session identity, keep compaction-timeout snapshots continuable, preserve shared app-server state across startup or helper failures, keep native hook relay alive across restarts and prune stale bridge files, close native hook relay replacement races, keep Claude live tool progress visible for watchdog recovery, suppress abandoned requester completion handoff, route workspace memory through tools, resolve Codex runtime models first, report quarantined dynamic tools, format `skills` command output, bind node auto-review to prepared plans, retry Claude CLI transcript probes, and bound compaction/steering retries. (#87218, #86875, #86123, #88129, #87399, #87375, #72574, #87383, #87400, #83022, #87671, #87738, #87747, #87706, #87546, #87541, #81048) Thanks @mbelinky, @Alix-007, @luoyanglang, @yetval, @sjf, @joshavant, @benjamin1492, @c19354837, @fuller-stack-dev, @pfrederiksen, and @dodge1218.
- Codex Supervisor: keep real-home app-server MCP session listing on the loaded state path, bound stored history scans, and close WebSocket probes cleanly.
- Channels: thread canonical session keys into outbound hooks, preserve Matrix room-id case, keep fallback tool warnings mention-inert, retain delivered Slack final replies during late cleanup, continue iMessage polling after denied reactions, suppress duplicate native exec approvals, resolve Gateway message actions against the active runtime config, preserve Telegram SecretRef prompt config and polling keepalives, preserve WhatsApp profile auth roots, QR display, document filenames, and plugin hook config, suppress Discord recovered tool warnings, preserve the Discord voice outbound helper, cap Discord/Signal/Zalo channel request and container timeouts, and block untrusted Teams service URLs while keeping TeamsSDK patterns aligned. (#73706, #75670, #87366, #87451, #87465, #87334, #84535, #76262, #83304, #82492, #87581, #77114, #86426, #85529, #87160) Thanks @zeroaltitude, @lukeboyett, @jarvis-mns1, @xiaotian, @funmerlin, @joshavant, @eleqtrizit, @heyitsaamir, @amittell, @lidge-jun, @liorb-mountapps, @masatohoshino, @bladin, and @giodl73-repo.
- CLI/auth/doctor/providers: reject malformed numeric/timeout/subcommand-version inputs, ignore workspace dotenv provider credentials, wait for respawn child shutdown, bound heartbeat defaults plus Codex, GitHub Copilot, OpenAI, Anthropic, Google, Feishu, LM Studio, MiniMax, Xiaomi TTS, and local-provider OAuth/token/model requests, harden Codex auth probes, label auth health by agent, preserve explicit agentRuntime pins during Codex model migration, warm provider auth off the main thread, honor Codex response timeouts, stop migrating current Claude Haiku 4.5 profiles to Sonnet, bound local service startup, resolve GPT-5.5 without cached catalog, migrate legacy memory auto-provider config, rewrite non-canonical `api_key` auth profiles, and make doctor restart follow-ups actionable. (#87398, #86281, #87361, #88133, #83655, #87559, #87719, #88088, #85924, #84362) Thanks @Patrick-Erichsen, @samzong, @giodl73-repo, @alkor2000, @mmaps, @nxmxbbd, and @vincentkoc.
- Gateway/security/session state: expire browser tokens after auth rotation, scope assistant idempotency dedupe, drain probe client closes, avoid stale restart continuation reuse, preserve retry-after fallbacks and stale rate-limit cooldown probes, bound webchat image and artifact transcript scans, include seconds in inbound metadata timestamps, clear completed session active runs, clear stale chat stream buffers, and evict current plugin-state namespaces at row caps. (#87810, #87833, #75089) Thanks @joshavant and @litang9.
- Config/parsing/network: reject partial numeric parsing, parse provider/Discord retry headers and dates strictly, honor IPv6 and bare IPv6 `no_proxy` entries, preserve empty plugin allowlists, canonicalize secret target array indexes, and reject malformed media content lengths, inspected TCP ports, marketplace content lengths, cron epochs, sandbox stat fields, unsafe duration values, empty config path segments, noncanonical schema array refs, unsafe Telegram callback pages, and invalid Teams attachment-fetch DNS targets. (#87883) Thanks @zhangguiping-xydt.
- Browser/input hardening: reject invalid tab indexes, excessive viewport resizes, explicit zero CDP ports, malformed geolocation options, unsafe screenshot or permission-grant timeouts, loose response-body limits, invalid cookie expiries, and non-finite Browser tool delays/timeouts.
- Cron/automation: retry recurring jobs after transient model rate limits before waiting for the next scheduled slot, and preflight model fallbacks before skipping scheduled work. (#82887) Thanks @chen-zhang-cs-code.
- Auto-reply/directives: respect provider and relayed channel metadata during directive persistence so channel-originated decisions keep their intended context. (#87683)
- WhatsApp: resolve the auth directory from the active profile so profile-scoped WhatsApp installs do not drift to the wrong credential root. (#82492) Thanks @lidge-jun.
- Gateway/session state: clear completed session active runs, avoid cold-loading providers for MCP inventory, cache single-session child indexes, cap handshake timers, and bound preauth, auth-guard, media, transcript, readiness, and port options.
- Channels/replies: preserve channel-owned progress callbacks when verbose output is off, keep group-room progress suppression intact, prefer external session delivery context, escape Discord component id delimiters, force final TUI chat repaints, show Slack reasoning previews, and normalize Discord/Matrix/Mattermost channel numeric options. (#87476, #87423)
- Agents/tool args: harden smart-quoted argument repair for edit arrays and exact escaped arguments so model-produced tool calls recover without corrupting valid input. (#86611) Thanks @ferminquant.
- Providers/agents: preserve seeded Anthropic signatures, preserve signed thinking payloads, concatenate signature-delta chunks, preserve DeepSeek `reasoning_content` replay across tier suffixes, apply OpenRouter strict9 ids to Mistral routes, promote Ollama plain-text tool calls, load NVIDIA featured model catalogs, stream MiniMax music generation responses, and recover empty preflight compaction. (#87593, #87493, #80775, #84764) Thanks @Pluviobyte and @eleqtrizit.
- Media/images: skip CLI image cache refs when resolving generated images, allow trusted generated HTML attachments, and bound generated video downloads so stale refs and slow providers fail cleanly. (#87523, #87982)
- Agents/Codex: keep spawned agent cwd/workspace state separated, keep hook context prompt-local, release session locks on timeout abort, avoid session event queue self-wait, preserve shared app-server state across startup or helper failures, keep native hook relay alive across restarts, route workspace memory through tools, resolve Codex runtime models first, report quarantined dynamic tools, format `skills` command output, and bound compaction/steering retries. (#87218, #86875, #86123, #87399, #87375, #87383, #87400) Thanks @mbelinky, @Alix-007, @luoyanglang, @yetval, and @sjf.
- Codex Supervisor: keep real-home app-server MCP session listing on the loaded/state-DB path, bound stored history scans, and close WebSocket probes cleanly.
- Channels: thread canonical session keys into outbound hooks, preserve Matrix room-id case, keep fallback tool warnings mention-inert, retain delivered Slack final replies during late cleanup, continue iMessage polling after denied reactions, suppress duplicate native exec approvals, preserve Telegram SecretRef prompt config, suppress Discord recovered tool warnings, and block untrusted Teams service URLs. (#73706, #75670, #87366, #87451, #87334) Thanks @zeroaltitude, @lukeboyett, @xiaotian, and @eleqtrizit.
- CLI/auth/doctor/providers: reject malformed numeric/timeout/subcommand-version inputs, wait for respawn child shutdown, bound Codex and GitHub Copilot OAuth/token requests, warm provider auth off the main thread, honor Codex response timeouts, bound local service startup, resolve GPT-5.5 without cached catalog, migrate legacy memory auto-provider config, rewrite non-canonical `api_key` auth profiles, and make doctor restart follow-ups actionable. (#87398, #86281, #87361) Thanks @Patrick-Erichsen, @samzong, @giodl73-repo, and @alkor2000.
- Gateway/security/session state: expire browser tokens after auth rotation, scope assistant idempotency dedupe, drain probe client closes, avoid stale restart continuation reuse, preserve retry-after fallbacks, bound webchat image and artifact transcript scans, include seconds in inbound metadata timestamps, and evict current plugin-state namespaces at row caps.
- Config/parsing/network: reject partial numeric parsing, parse provider/Discord retry headers and dates strictly, honor IPv6 and bare IPv6 `no_proxy` entries, canonicalize secret target array indexes, and reject malformed media content lengths, inspected TCP ports, marketplace content lengths, cron epochs, and sandbox stat fields.
- Providers/agents: preserve seeded Anthropic signatures, concatenate signature-delta chunks, preserve DeepSeek `reasoning_content` replay across tier suffixes, apply OpenRouter strict9 ids to Mistral routes, promote Ollama plain-text tool calls, and recover empty preflight compaction. (#87593)
- File transfer: handle late tar stdin pipe errors after archive validation or unpacking has already settled.
- Performance: trust install-record caches between reloads, prefer native JSON parsing, reuse unchanged tool-search catalogs, reuse gateway session and plugin metadata paths, skip unchanged store serialization, patch single-entry session writes, add precomputed session patch writers, reduce store clone allocations, cache manifest model catalog rows and auto-enabled plugin config, avoid full session snapshots for entry reads, defer configured Slack full startup, prefer bundled plugin dist entries, and slim current metadata identity caches. (#87760)
- Docker/release/QA: package runtime workspace templates, stream cross-OS served artifacts, preserve sparse Crabbox run artifacts, isolate npm plugin installs per package, reject incompatible package plugin API installs, drop the leftover root Sharp dependency from package manifests after the Rastermill migration, bound OpenClaw instance logs, plugin gauntlet relay logs, MCP channel buffers, kitchen-sink scans, agent-turn assertions, QA-Lab credential broker calls, QA Matrix substrate requests, and release scenario logs, and keep release/google live guards current. (#87647, #87477) Thanks @rohitjavvadi and @vincentkoc.
- Release/CI: bound manual git fetches, ClawHub verifier responses, ClawHub owner metadata, dependency-guard error bodies, Parallels limits, startup/test/memory budget parsing, and diffs viewer build warnings so release lanes fail with useful proof instead of hanging. (#87839)
- Performance: trust install-record caches between reloads, prefer native JSON parsing, reuse unchanged tool-search catalogs, skip unchanged store serialization, add precomputed session patch writers, reduce store clone allocations, cache manifest model catalog rows and auto-enabled plugin config, and slim current metadata identity caches.
- Docker/release/QA: package runtime workspace templates, stream cross-OS served artifacts, preserve sparse Crabbox run artifacts, bound OpenClaw instance logs, plugin gauntlet relay logs, MCP channel buffers, kitchen-sink scans, agent-turn assertions, and release scenario logs, and keep release/google live guards current.
## 2026.5.27

View File

@@ -2,70 +2,6 @@
<rss xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0">
<channel>
<title>OpenClaw</title>
<item>
<title>2026.5.28</title>
<pubDate>Sat, 30 May 2026 21:21:09 +0000</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>2026052890</sparkle:version>
<sparkle:shortVersionString>2026.5.28</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.5.28</h2>
<h3>Highlights</h3>
<ul>
<li>Agent and Codex runtime recovery is steadier: subagents keep cwd/workspace separation, hook context stays prompt-local, session locks release on timeout abort while live OpenClaw locks survive cleanup, stale restart continuations are avoided, and Codex app-server/helper failures no longer tear down shared runtime state. (#87218, #86875, #87409, #87399, #87375, #88129)</li>
<li>Channel delivery and session identity got safer across outbound plugin hooks, Matrix room ids, iMessage reactions/approvals, Slack final replies, Discord recovered tool warnings, runtime-config message actions, WhatsApp profile auth roots, Telegram polling, and Microsoft Teams service URL trust checks. (#73706, #75670, #87366, #87451, #87334, #84535, #82492, #83304, #87160)</li>
<li>Mobile and chat surfaces got a broader refresh: the iOS Pro UI, hosted push relay default, realtime Talk tab playback, Gateway chat transport, onboarding, Talk permissions, WebChat reconnect delivery, and session picker behavior now preserve more state across reconnects and empty searches. (#87367, #87531, #87682, #88096, #88105) Thanks @ngutman.</li>
<li>Browser, channel, and automation inputs are stricter: Browser tool timeouts, viewport/tab indices, Gateway ports, cron retry handling, Discord component ids, schema array refs, Telegram callback pages, and channel progress callbacks now reject malformed values earlier and preserve the intended delivery context. (#82887)</li>
<li>Provider, media, and document coverage expands with Claude Opus 4.8, Fal Krea image schemas, NVIDIA featured models, MiniMax streaming music responses, encrypted PDF extraction, voice model catalogs, GitHub Copilot agent runtime support, and a Codex Supervisor plugin path for delegated Codex workflows. (#87845, #87890, #80775, #84764, #87751, #87794)</li>
<li>CLI, auth, doctor, and provider paths fail faster and recover more clearly: malformed numeric/version options are rejected, workspace dotenv provider credentials are ignored, heartbeat defaults, OAuth/token lifetimes, and local service startup requests are bounded, agent auth health labels are clearer, legacy <code>api_key</code> auth profiles migrate to canonical form, and restart guidance is actionable. (#87398, #86281, #87361, #88133, #83655, #87559, #88088, #85924) Thanks @vincentkoc and @giodl73-repo.</li>
<li>Plugin and Gateway hot paths do less repeated work while preserving cache correctness for install records, config JSON parsing, tool search catalogs, session stores, manifest model rows, auto-enabled plugin config, browser tokens, viewer assets, and release-split external plugin packages. (#86699)</li>
<li>Release, QA, and E2E validation now bound more log, artifact, harness, and cross-OS waits so failing lanes produce proof instead of hanging or false-greening.</li>
</ul>
<h3>Changes</h3>
<ul>
<li>Status: show active subagent details in status output.</li>
<li>Diffs: split the default language pack and expand default Diffs language coverage while keeping the host floor aligned. (#87370, #87372) Thanks @RomneyDa.</li>
<li>ClawHub: add plugin display names plus skill verification and trust surfaces. (#87354, #86699) Thanks @thewilloftheshadow and @Patrick-Erichsen.</li>
<li>iOS: refresh the dev app with Pro Command, Chat, Agents, Settings, hosted push relay defaults, and realtime Talk playback wired to gateway sessions, diagnostics, chat, and realtime Talk. (#87367, #88096, #88105) Thanks @Solvely-Colin and @ngutman.</li>
<li>Docs: clarify Codex computer-use setup, paste-token stdin auth setup, macOS gateway sleep troubleshooting, native Codex hook relay recovery, container model auth, install deployment cards, device-token admin gating, CLI setup flow compatibility, Notte cloud browser CDP setup, and backport targets. (#87313, #63050, #87685) Thanks @bdjben, @liaoandi, and @thewilloftheshadow.</li>
<li>PDF/tools: use ClawPDF for PDF extraction, support encrypted PDF extraction, and surface MCP structured content in agent tool results. (#87670, #87751)</li>
<li>Providers: add Claude Opus 4.8 support, Fal Krea image model schemas, NVIDIA featured model catalogs, MiniMax streaming music responses, and provider-backed voice model catalogs. (#87845, #87890, #80775, #84764, #87794) Thanks @eleqtrizit and @vincentkoc.</li>
<li>Codex/GitHub: add the GitHub Copilot agent runtime and the Codex Supervisor plugin package.</li>
<li>Plugins: externalize GitHub Copilot and Tokenjuice as official install-on-demand plugins with npm and ClawHub publish metadata.</li>
<li>Workboard: add agent coordination tools for tracking and handing off active agent work.</li>
<li>Discord: show commentary in progress drafts so live Discord runs expose useful in-progress context. (#85200)</li>
<li>Plugin SDK: add a reply payload sending hook for plugins that need to deliver channel-owned replies and flatten package types for SDK declarations. (#82823, #87165) Thanks @RomneyDa.</li>
<li>Policy: add policy comparison, ingress-channel conformance, and sandbox-posture conformance checks. (#85572, #85744, #86768)</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Agents: fall back to local config pruning when the optional <code>agents delete</code> Gateway probe cannot authenticate, so offline installs can still delete agents without removing shared workspaces.</li>
<li>Tighten phone-control mutation authorization [AI]. (#87150) Thanks @pgondhi987.</li>
<li>Clarify directive persistence authorization policy [AI]. (#86369) Thanks @pgondhi987.</li>
<li>Agents/Codex: keep spawned agent cwd/workspace state separated, forward ACP spawn attachments, keep hook context prompt-local, release session locks on timeout abort and runtime teardown without deleting live OpenClaw-owned locks during cleanup, avoid session event queue self-wait, clean up exec abort listeners, stream assistant deltas incrementally, recover raw missing-thread compaction failures, preserve rotated compaction session identity, keep compaction-timeout snapshots continuable, preserve shared app-server state across startup or helper failures, keep native hook relay alive across restarts and prune stale bridge files, close native hook relay replacement races, keep Claude live tool progress visible for watchdog recovery, suppress abandoned requester completion handoff, route workspace memory through tools, resolve Codex runtime models first, report quarantined dynamic tools, format <code>skills</code> command output, bind node auto-review to prepared plans, retry Claude CLI transcript probes, and bound compaction/steering retries. (#87218, #86875, #86123, #88129, #87399, #87375, #72574, #87383, #87400, #83022, #87671, #87738, #87747, #87706, #87546, #87541, #81048) Thanks @mbelinky, @Alix-007, @luoyanglang, @yetval, @sjf, @joshavant, and @benjamin1492.</li>
<li>Codex Supervisor: keep real-home app-server MCP session listing on the loaded state path, bound stored history scans, and close WebSocket probes cleanly.</li>
<li>Channels: thread canonical session keys into outbound hooks, preserve Matrix room-id case, keep fallback tool warnings mention-inert, retain delivered Slack final replies during late cleanup, continue iMessage polling after denied reactions, suppress duplicate native exec approvals, resolve Gateway message actions against the active runtime config, preserve Telegram SecretRef prompt config and polling keepalives, preserve WhatsApp profile auth roots, QR display, document filenames, and plugin hook config, suppress Discord recovered tool warnings, preserve the Discord voice outbound helper, cap Discord/Signal/Zalo channel request and container timeouts, and block untrusted Teams service URLs while keeping TeamsSDK patterns aligned. (#73706, #75670, #87366, #87451, #87465, #87334, #84535, #76262, #83304, #82492, #87581, #77114, #86426, #85529, #87160) Thanks @zeroaltitude, @lukeboyett, @xiaotian, @funmerlin, @joshavant, @eleqtrizit, @heyitsaamir, @amittell, @liorb-mountapps, @masatohoshino, @bladin, and @giodl73-repo.</li>
<li>CLI/auth/doctor/providers: reject malformed numeric/timeout/subcommand-version inputs, ignore workspace dotenv provider credentials, wait for respawn child shutdown, bound heartbeat defaults plus Codex, GitHub Copilot, OpenAI, Anthropic, Google, Feishu, LM Studio, MiniMax, Xiaomi TTS, and local-provider OAuth/token/model requests, harden Codex auth probes, label auth health by agent, preserve explicit agentRuntime pins during Codex model migration, warm provider auth off the main thread, honor Codex response timeouts, stop migrating current Claude Haiku 4.5 profiles to Sonnet, bound local service startup, resolve GPT-5.5 without cached catalog, migrate legacy memory auto-provider config, rewrite non-canonical <code>api_key</code> auth profiles, and make doctor restart follow-ups actionable. (#87398, #86281, #87361, #88133, #83655, #87559, #87719, #88088, #85924, #84362) Thanks @Patrick-Erichsen, @samzong, @giodl73-repo, @alkor2000, @mmaps, @nxmxbbd, and @vincentkoc.</li>
<li>Gateway/security/session state: expire browser tokens after auth rotation, scope assistant idempotency dedupe, drain probe client closes, avoid stale restart continuation reuse, preserve retry-after fallbacks and stale rate-limit cooldown probes, bound webchat image and artifact transcript scans, include seconds in inbound metadata timestamps, clear completed session active runs, clear stale chat stream buffers, and evict current plugin-state namespaces at row caps. (#87810, #87833, #75089) Thanks @joshavant and @litang9.</li>
<li>Config/parsing/network: reject partial numeric parsing, parse provider/Discord retry headers and dates strictly, honor IPv6 and bare IPv6 <code>no_proxy</code> entries, preserve empty plugin allowlists, canonicalize secret target array indexes, and reject malformed media content lengths, inspected TCP ports, marketplace content lengths, cron epochs, sandbox stat fields, unsafe duration values, empty config path segments, noncanonical schema array refs, unsafe Telegram callback pages, and invalid Teams attachment-fetch DNS targets. (#87883) Thanks @zhangguiping-xydt.</li>
<li>Browser/input hardening: reject invalid tab indexes, excessive viewport resizes, explicit zero CDP ports, malformed geolocation options, unsafe screenshot or permission-grant timeouts, loose response-body limits, invalid cookie expiries, and non-finite Browser tool delays/timeouts.</li>
<li>Cron/automation: retry recurring jobs after transient model rate limits before waiting for the next scheduled slot, and preflight model fallbacks before skipping scheduled work. (#82887)</li>
<li>Auto-reply/directives: respect provider and relayed channel metadata during directive persistence so channel-originated decisions keep their intended context. (#87683)</li>
<li>WhatsApp: resolve the auth directory from the active profile so profile-scoped WhatsApp installs do not drift to the wrong credential root. (#82492)</li>
<li>Gateway/session state: clear completed session active runs, avoid cold-loading providers for MCP inventory, cache single-session child indexes, cap handshake timers, and bound preauth, auth-guard, media, transcript, readiness, and port options.</li>
<li>Channels/replies: preserve channel-owned progress callbacks when verbose output is off, keep group-room progress suppression intact, prefer external session delivery context, escape Discord component id delimiters, force final TUI chat repaints, show Slack reasoning previews, and normalize Discord/Matrix/Mattermost channel numeric options. (#87476, #87423)</li>
<li>Agents/tool args: harden smart-quoted argument repair for edit arrays and exact escaped arguments so model-produced tool calls recover without corrupting valid input. (#86611)</li>
<li>Providers/agents: preserve seeded Anthropic signatures, preserve signed thinking payloads, concatenate signature-delta chunks, preserve DeepSeek <code>reasoning_content</code> replay across tier suffixes, apply OpenRouter strict9 ids to Mistral routes, promote Ollama plain-text tool calls, load NVIDIA featured model catalogs, stream MiniMax music generation responses, and recover empty preflight compaction. (#87593, #87493, #80775, #84764) Thanks @eleqtrizit.</li>
<li>Media/images: skip CLI image cache refs when resolving generated images, allow trusted generated HTML attachments, and bound generated video downloads so stale refs and slow providers fail cleanly. (#87523, #87982)</li>
<li>File transfer: handle late tar stdin pipe errors after archive validation or unpacking has already settled.</li>
<li>Performance: trust install-record caches between reloads, prefer native JSON parsing, reuse unchanged tool-search catalogs, reuse gateway session and plugin metadata paths, skip unchanged store serialization, patch single-entry session writes, add precomputed session patch writers, reduce store clone allocations, cache manifest model catalog rows and auto-enabled plugin config, avoid full session snapshots for entry reads, defer configured Slack full startup, prefer bundled plugin dist entries, and slim current metadata identity caches. (#87760)</li>
<li>Docker/release/QA: package runtime workspace templates, stream cross-OS served artifacts, preserve sparse Crabbox run artifacts, isolate npm plugin installs per package, reject incompatible package plugin API installs, drop the leftover root Sharp dependency from package manifests after the Rastermill migration, bound OpenClaw instance logs, plugin gauntlet relay logs, MCP channel buffers, kitchen-sink scans, agent-turn assertions, QA-Lab credential broker calls, QA Matrix substrate requests, and release scenario logs, and keep release/google live guards current. (#87647, #87477) Thanks @rohitjavvadi and @vincentkoc.</li>
<li>Release/CI: bound manual git fetches, ClawHub verifier responses, ClawHub owner metadata, dependency-guard error bodies, Parallels limits, startup/test/memory budget parsing, and diffs viewer build warnings so release lanes fail with useful proof instead of hanging. (#87839)</li>
</ul>
<p><a href="https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md">View full changelog</a></p>
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.5.28/OpenClaw-2026.5.28.zip" length="54750142" type="application/octet-stream" sparkle:edSignature="U4O55uMdPU+OqSx9QR1ApUJ8wg65wxTydzD7iyCn1GHtm1MBK9noEeiA/yoUKkqb/bx0hzi1gNhn+ye19RXnCA=="/>
</item>
<item>
<title>2026.5.27</title>
<pubDate>Thu, 28 May 2026 12:12:19 +0000</pubDate>
@@ -322,5 +258,284 @@
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.5.26/OpenClaw-2026.5.26.zip" length="54484748" type="application/octet-stream" sparkle:edSignature="y4WXG7JT8ktJ+K7YDgllY7u5Z9BSKR/SwGiwEh0gikOJ/SWqwcQd+z2tWa2zgwvCJKWsAUFwJs1ATor880SUBg=="/>
</item>
<item>
<title>2026.5.22</title>
<pubDate>Sun, 24 May 2026 01:41:27 +0000</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>2026052290</sparkle:version>
<sparkle:shortVersionString>2026.5.22</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.5.22</h2>
<h3>Changes</h3>
<ul>
<li>Gateway/perf: reuse process-stable channel catalog reads, avoid repeated bundled-channel boundary checks, and rotate gateway watch CPU profiles so benchmark runs do not accumulate unbounded artifacts.</li>
<li>Gateway/perf: reuse immutable plugin metadata snapshots across startup, config, model, channel, setup, and secret metadata readers so hot paths avoid repeated plugin file stats and manifest registry reloads.</li>
<li>Gateway/perf: lazy-load startup-idle plugin work, core gateway method handlers, and the embedded ACPX runtime so Gateway health and ready signals no longer wait on unused handler trees or ACPX probes.</li>
<li>Gateway/perf: cache plugin SDK public-surface alias maps and skip irrelevant macOS Linuxbrew PATH probes so Gateway startup avoids repeated filesystem walks and slow missing-directory stats.</li>
<li>Meeting Notes: add a source-only external meeting-notes plugin and SDK source-provider contract outside the core npm package, with auto-start capture config, manual transcript imports, read-only <code>openclaw meeting-notes</code> CLI access, and Discord voice as the first live source.</li>
<li>Docs/channels/config: add Signal <code>configPath</code>, Telegram wildcard topic defaults, local-time backup archive names, Termux home fallback, include-path validation, secret-scanner-safe placeholder guidance, Gemini CLI/Antigravity media guidance, and macOS VM auto-login guidance. Thanks @NorseGaud, @yudistiraashadi, @huangqian8, @VibhorGautam, @maweibin, @tianxingleo, @IgnacioPro, and @xzcxzcyy-claw.</li>
<li>Docs: clarify model-usage portability, Codex migration prerequisites, status bootstrap wording, thread-bound subagent limits, hook ownership, and config-preserving safety guidance. Thanks @aniruddhaadak80, @leno23, @TomDjerry, @matthewxmurphy, @vincentkoc, and @stablegenius49.</li>
<li>Docs: clarify README onboarding and Gateway startup paths, WhatsApp QR/408 recovery, cron output language prompts, skill advanced features, gateway upstream 403 troubleshooting, and plugin fallback override guidance. Thanks @deepujain, @Zacxxx, @Jah-yee, @neyric, @usimic, @Renu-Cybe, @BigUncle, and @SeashoreShi.</li>
<li>Docs: clarify context-pruning ratio bounds, local dashboard recovery, CLI env markers, remote onboarding token behavior, and Peekaboo Bridge permissions for subprocess agents. Thanks @ayesha-aziz123, @dishraters, @hougangdev, and @brandonlipman.</li>
<li>Docs: clarify browser CDP diagnostics, Plugin SDK allowlist imports, status-reaction timing defaults, queue steering behavior, limited-tool troubleshooting, cron HEARTBEAT handling, Telegram multi-agent groups, Bitwarden SecretRef setup, and EasyRunner deployments. Thanks @Quratulain-bilal, @mbelinky, @Mickey-, @vancece, @xenouzik, @posigit, @surlymochan, @janaka, and @choiking.</li>
<li>Crabbox/Testbox: run clean sparse-checkout Testbox syncs from a temporary full checkout and route remote changed gates through Corepack pnpm.</li>
<li>Docs: clarify IPv4-only Gateway BYOH binding, trusted-proxy scope clearing, Android pairing approval, macOS Accessibility grants, Zalo profile env vars, password-store SecretRef setup, and Chinese memory navigation. Thanks @itskai-dev, @gwh7078, @longstoryscott, @MoeJaberr, and @yuaiccc.</li>
<li>Docs: consolidate GLM under Z.AI, add the Upstash Box install guide and Gateway exposure runbook, clarify MEDIA directives, Copilot and Voyage setup, config path quoting, real behavior proof, and memory-file write guidance. Thanks @BobDu, @alitariksahin, @Jefsky, @musaabhasan, @OmerZeyveli, @leno23, @WuKongAI-CMU, @luoyanglang, and @majin1102.</li>
<li>Docs: clarify media provider credentials, Codex/OpenClaw code-mode boundaries, Slack and Telegram ack reactions, Feishu dynamic agents, secrets plaintext boundaries, memory guidance, and Chinese glossary terms. Thanks @nielskaspers, @cosmopolitan033, @drclaw-iq, @alexgduarte, @zccyman, @chengoak, and @cassthebandit.</li>
<li>Packaging: exclude documentation images and assets from the npm tarball, reducing published package size without affecting runtime docs search or CLI behavior. Thanks @SebTardif.</li>
<li>Media understanding: stop auto-probing Gemini CLI and use Antigravity CLI only as a lower-priority image/video fallback after configured provider APIs.</li>
<li>Agents/subagents: limit default sub-agent bootstrap context to <code>AGENTS.md</code> and <code>TOOLS.md</code>, keeping persona, identity, user, memory, heartbeat, and setup files out of delegated workers by default. (#85283) Thanks @100yenadmin.</li>
<li>Maintainer skills: exclude plugin SDK/API boundary work from <code>openclaw-landable-bug-sweep</code> so bugbash sweeps stay focused on small paper-cut fixes.</li>
<li>QA-Lab/diagnostics: extend the OpenTelemetry smoke harness to prove trace, metric, and log export, and add first-class Prometheus and observability smoke aliases.</li>
<li>Plugin SDK: add a generic channel-message poll sender so channel plugins can expose poll delivery without depending on channel-specific SDK facades.</li>
<li>Crabbox: keep the local wrapper's provider validation synced with the installed Crabbox binary while preserving supported aliases such as <code>docker</code> and <code>blacksmith</code>. (#85302) Thanks @hxy91819.</li>
<li>Maintainer skills: add <code>openclaw-landable-bug-sweep</code> for producing five small, reviewed, CI-green OpenClaw bugfix PRs from issue/PR sweeps.</li>
<li>Control UI/chat: add search and Load More pagination to the chat session picker, keeping initial session loads bounded while making older conversations reachable. (#85237) Thanks @amknight.</li>
<li>CLI/onboarding: start classic onboarding when bare <code>openclaw</code> runs before an authored config exists, while keeping configured installs on Crestodian. (#72343) Thanks @fuller-stack-dev.</li>
<li>Discord: allow configuring a bounded <code>agentComponents.ttlMs</code> callback registry lifetime for long-running component workflows, with per-account overrides and a 24-hour cap. (#84189) Thanks @100menotu001.</li>
<li>xAI/Grok: reuse xAI OAuth auth profiles for Grok <code>web_search</code>, thread active-agent auth through web search, add Grok model aliases, and let media providers declare default operation timeouts. (#85182) Thanks @fuller-stack-dev.</li>
<li>Plugin SDK: add row-level session workflow helpers and deprecate <code>loadSessionStore</code> so plugins can read and patch sessions without depending on the legacy whole-store shape. (#84693) Thanks @efpiva.</li>
<li>Gateway/plugins: reuse a compatible Gateway startup plugin registry during dispatch so safe plugin dispatches avoid redundant registry loading. (#84324) Thanks @ai-hpc.</li>
<li>Plugins/SDK: add a general <code>embeddingProviders</code> capability contract and registration API so embeddings can become a reusable provider surface outside memory-specific adapters.</li>
<li>Dependencies: refresh provider, plugin, UI, and tooling packages, update <code>protobufjs</code> to 8.4.0 to clear the current npm advisory, and carry the Claude ACP completion patch forward to <code>@agentclientprotocol/claude-agent-acp</code> 0.36.1.</li>
<li>Agents/tools: remove the old sender-owner tool gating path so configured tools stay visible for trusted sessions while command and channel-action auth still carry real sender identity.</li>
<li>QA-Lab: add curated mock JSONL replay fixtures and first-drift reporting for runtime-parity audits. (#80323, refs #80176) Thanks @100yenadmin.</li>
<li>QA-Lab: add a QA bus tool-trace visibility scenario for sanitized tool-call assertions.</li>
<li>QA-Lab: replace generic evidence framing in seeded scenario prompts with concrete observed QA behavior.</li>
<li>QA-Lab: list named scenario packs in the coverage report so personal-agent privacy coverage stays visible in audits.</li>
<li>QA-Lab: list live transport lane membership in the coverage report so real transport checks stay separate from seeded qa-channel scenarios.</li>
<li>Release/package: run package integrity checks before package acceptance lanes so public install/update validation fails before private QA assets can leak into the package.</li>
<li>QA-Lab: include the optional 100-turn runtime parity soak in release-soak artifacts so long-run Codex/Pi transcript drift stays visible outside the default gate. (#80395) Thanks @100yenadmin.</li>
<li>QA-Lab: add a live-only long-context progress watchdog scenario for Codex app-server timeout and stalled-run sentinels. (#80323) Thanks @100yenadmin.</li>
<li>QA-Lab: tag gateway restart recovery and streaming final-integrity scenarios as live-only runtime parity lanes. (#80323) Thanks @100yenadmin.</li>
<li>QA-Lab: add a personal-agent failure recovery scenario that checks honest partial status, retry boundaries, and local recovery artifacts. (#83872) Thanks @iFiras-Max1.</li>
<li>QA-Lab: include an opt-in <code>update.run</code> package self-upgrade sentinel for destructive latest-package recovery checks.</li>
<li>QA-Lab: add Codex plugin lifecycle and auth-profile fixture coverage for missing installs, pinned-version drift, first-turn install ordering, and doctor migration safety. (#80323, refs #80174) Thanks @100yenadmin.</li>
<li>Models/perf: pre-warm the provider auth-state map at gateway startup so <code>/models</code> and every model-listing call short-circuits the per-provider plugin / external-CLI discovery on the hot path. Per-call cost drops from ~20 s to ~5 ms (~4,100×); the one-time startup warm resets and re-warms after hot reloads. (#84816) Thanks @sjf.</li>
<li>Release/security: ship the root npm package and OpenClaw-owned npm plugins with generated shrinkwrap, support bundled plugin runtime dependencies for suitable plugin tarballs, and require review for lockfile/shrinkwrap changes so published installs use locked dependency graphs.</li>
<li>Tests/perf: isolate doctor core health check unit coverage from real skills/workspace discovery so <code>doctor-core-checks</code> no longer dominates unit perf while keeping one real skills-readiness smoke. (#84493) Thanks @frankekn.</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>WebChat: summarize internal message-tool source replies so tool cards no longer duplicate the visible reply body. (#84773) Thanks @jason-allen-oneal.</li>
<li>Gateway: preserve deferred lifecycle-error cleanup across later non-terminal events so provider timeouts can persist failed session state instead of leaving sessions stuck running. (#85256, fixes #63819) Thanks @samzong.</li>
<li>Agents/subagents: report tool-only child progress during timeout summaries instead of showing no visible output.</li>
<li>Telegram/ACP: preserve explicit <code>:topic:</code> conversation suffixes when inbound ACP targets do not carry a separate thread id.</li>
<li>Browser/proxy: bypass the managed proxy for the exact local managed Chrome CDP readiness and DevTools WebSocket endpoints, so <code>openclaw browser start</code> works when the operator proxy blocks loopback egress. (#83255) Thanks @lightcap.</li>
<li>Ollama: bypass the managed proxy for configured local embedding origins while keeping SSRF guardrails on unconfigured targets. Thanks @Kaspre.</li>
<li>OpenAI/images: route Codex API-key image generation through the native OpenAI Images API instead of the Codex OAuth streaming backend, avoiding 401s from valid API keys.</li>
<li>Agents/OpenAI completions: omit empty tool payload fields for proxy-like OpenAI-compatible endpoints so strict vLLM-style servers accept tool-free turns. (#85835) Thanks @rendrag-git.</li>
<li>Checks/Windows: route full <code>pnpm check</code> stage commands through the managed child runner so Windows avoids Node shell-argv deprecation warnings there too.</li>
<li>Checks/Windows: run managed child commands through explicit <code>cmd.exe</code> wrapping instead of Node shell mode with argv, avoiding Node 24 subprocess deprecation warnings during changed checks.</li>
<li>Gateway: omit internal stream-error placeholder entries from agent prompt history so failed assistant turns are not replayed as model-authored text. (#85652) Thanks @anyech.</li>
<li>Sessions: enforce the session write-lock max-hold policy during lock acquisition so long-held locks can be reclaimed before the stale-lock window. (#85764) Thanks @njuboy11.</li>
<li>Models: prune retired Groq, GitHub Copilot, OpenAI, xAI, and old Claude catalog entries, with doctor migration to upgrade existing configs to current provider refs.</li>
<li>Doctor/update: recognize junction-backed source checkouts as git installs by comparing canonical paths before showing package-manager update guidance. Fixes #82215. Thanks @igormf.</li>
<li>Channels: honor <code>/verbose on</code> for tool/progress summaries across direct chats, groups, channels, and forum topics while preserving quiet default behavior. (#85488) Thanks @kurplunkin.</li>
<li>CLI/skills: show an all-ready note with next-step commands when skill setup has no missing dependencies to install. (#85032) Thanks @aniruddhaadak80.</li>
<li>Microsoft Foundry: route DeepSeek V4 Pro and Flash models through the Foundry Responses API while keeping older DeepSeek models on their existing path. (#85549) Thanks @roslinmahmud.</li>
<li>Status/usage: show configured cost estimates for AWS SDK models in full usage output while keeping token-only usage replies cost-free. (#85619) Thanks @ItsOtherMauridian.</li>
<li>Agents/OpenAI Responses: retry non-visible reasoning-only turns for OpenAI Responses API families instead of treating them as empty failed turns. (#85603) Thanks @SebTardif.</li>
<li>Directive tags: preserve message and content-part object identity when display stripping makes no directive-tag changes. (#85682) Thanks @willamhou.</li>
<li>Telegram: send local <code>path</code>/<code>filePath</code> and structured attachment media from <code>sendMessage</code> actions instead of dropping them or sending text-only messages. (#85219) Thanks @keshavbotagent.</li>
<li>Sessions/status: show the estimated context budget when fresh provider usage is unavailable and clear stale estimates across session resets and compaction boundaries. (#84830) Thanks @giodl73-repo.</li>
<li>Gateway/config: pin relative <code>OPENCLAW_STATE_DIR</code> overrides to an absolute path at startup so later working-directory changes cannot retarget gateway state. (#52264) Thanks @PerfectPan.</li>
<li>Release/package: run npm release, prepublish, and postpublish verification through Windows-safe npm command shims so native Windows checks can execute <code>npm.cmd</code> instead of treating it as a binary.</li>
<li>Agents/harness: pass CLI runtime aliases through harness selection so provider-owned CLI aliases no longer get rejected before reaching the right runtime. (#85631) Thanks @potterdigital.</li>
<li>Secrets: show the irreversible apply warning after interactive <code>secrets configure</code> confirmation so confirmed migrations still get the final safety prompt. (#85638) Thanks @alkor2000.</li>
<li>Agents/CLI output: ignore cumulative Claude <code>stream-json</code> result usage when assistant usage events are present, preventing inflated cache-read accounting. (#85625) Thanks @zhouhe-xydt.</li>
<li>CLI: keep <code>waitForever()</code> alive by leaving its keep-alive interval ref'd so the public helper no longer exits immediately with Node's unsettled-await code. (#85694) Thanks @m1qaweb.</li>
<li>Agents/bootstrap: guard bootstrap name checks against missing file names so malformed bootstrap entries warn and truncate instead of crashing. Fixes #85523. (#85615) Thanks @zhouhe-xydt.</li>
<li>CLI/tasks: reject partially numeric <code>openclaw tasks audit --limit</code> values so audit limits must be real positive integers instead of accepting strings like <code>5abc</code>. (#84901) Thanks @jbetala7.</li>
<li>Status/diagnostics: bound deep Docker audit probes so <code>openclaw status --deep</code> reports slow container checks instead of hanging behind unbounded inspection. (#85476) Thanks @giodl73-repo.</li>
<li>Providers/Anthropic: migrate 1M context handling to GA-capable Claude 4.x models by sizing eligible models at 1M without the retired <code>context-1m-2025-08-07</code> beta, ignoring that retired beta in older configs, and preserving OAuth-required Anthropic beta headers. (#45613) Thanks @haoyu-haoyu.</li>
<li>Cron/Telegram: parse forum-topic delivery targets through the Telegram plugin instead of cron core, including <code>:topic:</code> and <code>:topicId</code> forms for announce delivery. Thanks @etticat.</li>
<li>Twitch: keep stale message-handler cleanup callbacks from removing newer handler registrations for the same account, preserving inbound message delivery after reconnects. Fixes #83888. (#85425) Thanks @alkor2000.</li>
<li>Memory/LanceDB: expose public memory artifacts through the active memory provider bridge so memory-wiki imports durable memory files, daily notes, dream reports, and event logs without depending on memory-core internals. Fixes #83604. (#85060) Thanks @brokemac79.</li>
<li>Crabbox: keep AWS hydration compatible with local Actions replay by inlining the hydrate workflow's Node/pnpm setup instead of invoking repo-local composite actions.</li>
<li>Agents/subagents: simplify native sub-agent completion handoff so children report their latest visible assistant result to the requester without using <code>message</code>, while keeping parent-owned message-tool delivery policy intact. Fixes #85070. (#85089) Thanks @brokemac79.</li>
<li>Docker setup: stop printing the Gateway bearer token in setup logs and printed follow-up commands.</li>
<li>Agents: let embedded compaction fallback retries proceed when PI-compatible candidates do not need agent harness plugin preparation.</li>
<li>Agents/tools: honor configured custom provider API keys when deciding whether media, image-generation, video-generation, music-generation, and PDF tools are available. (#85570)</li>
<li>StepFun: stop advertising stale generic API key auth choices so onboarding only offers runtime-backed Standard and Step Plan choices.</li>
<li>Diagnostics: keep OpenTelemetry log bodies behind explicit content capture and scrub scoped agent-session keys from OpenTelemetry and Prometheus labels while preserving bounded queue-lane prefixes.</li>
<li>Windows installer: fail Git checkout installs when <code>pnpm install</code> or <code>pnpm build</code> fails instead of writing a wrapper to a missing CLI build.</li>
<li>Sessions: surface previous-transcript archive failures during <code>/new</code> rotation so disk rename errors are logged instead of silently hiding stranded transcript files. Fixes #81984. (#85586, from #82081) Thanks @0xghost42.</li>
<li>TUI/agents: mirror internal-ui message-tool replies into final chat output so message-tool-only agents remain visible in <code>openclaw tui</code>. Fixes #85538. Thanks @danpolasek.</li>
<li>Agents: keep parallel OpenAI-compatible tool-call deltas in separate argument buffers so interleaved tool calls no longer corrupt streamed arguments. (#82263) Thanks @luna-system.</li>
<li>Memory/doctor: report missing or unusable QMD workspace directories as workspace failures instead of generic binary failures. (#63167) Thanks @sercada.</li>
<li>Debug proxy: record CONNECT client-socket errors and destroy the paired upstream socket so abrupt client disconnects no longer leak tunnel resources. (#82444) Thanks @SebTardif.</li>
<li>Diffs: continue hydrating later diff cards when one card fails so a single broken card no longer blanks the whole diff viewer. (#84775) Thanks @cosmopolitan033.</li>
<li>Mac app: use the native settings sidebar window chrome so the sidebar toggle stays on the left and content no longer clips under oversized titlebar padding.</li>
<li>QA-Lab/Codex: bundle auth/plugin fixture imports for flow scenarios and let terminal async media tools end Codex app-server turns without timing out. (#80397, refs #80323) Thanks @100yenadmin.</li>
<li>Gateway/agents: preserve fresh session overrides and metadata when stale cached agent-session entries race with store updates, so subagent model/provider overrides and routing policy survive concurrent writes. (#19328) Thanks @CodeReclaimers.</li>
<li>Control UI/chat: keep chat session search inline with the session selector so the header no longer shows a duplicate standalone search row.</li>
<li>Control UI/chat: collapse focused-mode header chrome and suppress hidden-header scroll updates so focus mode no longer jumps while scrolling. Thanks @amknight.</li>
<li>Codex app-server: restart the native app-server and retry once when server-side compaction times out, so preflight compaction stalls recover instead of failing every dispatch. (#85500)</li>
<li>Restore Control UI gateway token pairing [AI]. (#85459) Thanks @pgondhi987.</li>
<li>OpenAI video: honor configured provider request private-network opt-in for local/custom video endpoints so explicitly trusted mock and self-hosted providers are not blocked. Thanks @shakkernerd.</li>
<li>OpenAI video: send uploaded video edit requests to the documented <code>/videos/edits</code> endpoint with a <code>video</code> file instead of posting MP4 references to <code>/videos</code>. Thanks @shakkernerd.</li>
<li>Agents/channels: preserve message-tool delivery evidence through gateway agent completion handoffs so successful generated media sends are not followed by false failure messages. Thanks @shakkernerd.</li>
<li>CLI/update: repair managed npm plugin <code>openclaw</code> peer links during post-core convergence and reject stale or wrong-target peer links before restart. (#83794) Thanks @fuller-stack-dev.</li>
<li>CLI/agents: default new omitted-account bindings to all accounts when the channel has multiple configured accounts, and clarify account-scope docs. (#49769) Thanks @Gcaufy.</li>
<li>Codex app-server: let authorized <code>/codex</code> control commands such as <code>/codex detach</code> escape plugin-owned conversation bindings while keeping unknown or unauthorized slash text routed to the bound plugin. Fixes #85157. (#85188) Thanks @TurboTheTurtle.</li>
<li>Auto-reply/models: keep <code>/models</code> browse replies fast by sharing the bounded read-only catalog path with Gateway model listing. (#84735) Thanks @safrano9999.</li>
<li>Codex app-server: disable native Code Mode when the effective exec host is <code>node</code> and keep OpenClaw <code>exec</code>/<code>process</code> available, so <code>/exec host=node</code> routes shell commands through the selected node instead of the gateway. Fixes #85012. (#85090) Thanks @sahilsatralkar.</li>
<li>Agents: bound embedded auto-compaction session write-lock watchdogs to the compaction timeout instead of the full run timeout, so stuck compaction cannot hold the live session lock for the whole run window. (#84949) Thanks @luoyanglang.</li>
<li>Gateway/agents: return phase-aware <code>agent.wait</code> timeout attribution and only cool auth profiles on provider-started timeouts. Refs #65504. Thanks @100yenadmin.</li>
<li>Gateway: defer provider auth-state prewarm until after startup readiness so early gateway tool/session requests are not blocked by provider auth discovery. (#85272) Thanks @dutifulbob.</li>
<li>Gateway/models: coalesce provider auth-state rewarms after auth-profile failures and log event-loop delay for warm/rewarm work, so provider auth bursts no longer stack full auth sweeps behind channel replies.</li>
<li>Gateway/models: stop cancelled provider auth-state prewarms from continuing full provider sweeps, so reload and auth-failure bursts no longer keep startup busy.</li>
<li>Agents/Codex: show the first plan update as a transient chat status notice without counting it as final assistant content.</li>
<li>CLI/update: walk the macOS process ancestry and honor the inherited Gateway runtime PID before package updates stop the managed Gateway service, so nested in-band updater children can refuse instead of killing the LaunchAgent-supervised Gateway that owns them. Fixes #85120.</li>
<li>Gateway/LaunchAgent: wait for launchd reload bootout to finish and fall back to kickstart when bootstrap races, so reload handoff does not leave the service deregistered. Fixes #84630. (#84641) Thanks @NianJiuZst.</li>
<li>Gateway/LaunchAgent: treat a concurrent launchd bootstrap as a successful restart when the service is already loaded, avoiding false macOS Gateway restart failures. Fixes #84721. (#84722) Thanks @googlerest.</li>
<li>Gateway/service: include the active <code>openclaw</code> command bin directory in managed service PATH generation and doctor audit expectations for npm-global macOS installs. Fixes #84201. (#84475) Thanks @jbetala7.</li>
<li>Control UI/chat: disable the thinking selector for known non-reasoning models instead of showing duplicate Off choices. Fixes #84069. Thanks @DrippingMellow.</li>
<li>Memory: expand <code>~</code> in configured extra memory paths before resolving them, so home-relative folders are not treated as workspace-relative. Fixes #58026. Thanks @stadman.</li>
<li>Skills: treat <code>openclaw.os: macos</code> as Darwin when checking skill requirements, so macOS-only skills no longer report as missing on macOS hosts. Fixes #61338. Thanks @Jessecq1995.</li>
<li>Control UI/logs: strip ANSI escape sequences from displayed Gateway log messages so color codes no longer appear as raw text. Fixes #64399. Thanks @guguangxin-eng.</li>
<li>Docker: pre-create the workspace and auth-profile config mount points with <code>node</code> ownership so first-run named volumes do not start root-owned. Fixes #85076. Thanks @Noerr.</li>
<li>Telegram: pass configured markdown table mode through outbound markdown chunking so chunked sends render tables consistently. Fixes #85085. Thanks @ShuaiHui.</li>
<li>CLI/update: preserve managed Gateway service environment during package cutovers so macOS LaunchAgent repair/restart reads the pre-update service state instead of caller shell state. (#83026)</li>
<li>Agents/providers: honor per-model <code>api</code> and <code>baseUrl</code> overrides in custom provider auth hooks and transport selection. Fixes #80487. (#80488) Thanks @huveewomg.</li>
<li>Gateway/restart: eager-load the lifecycle runtime before in-place upgrade signal handling so package replacement does not deadlock restart imports. (#84890) Thanks @myps6415.</li>
<li>CLI/update: start managed Gateway update handoff helpers from a stable existing directory and tolerate deleted cwd/package roots during macOS LaunchAgent handoff. Fixes #83808. (#83875) Thanks @jason-allen-oneal.</li>
<li>Skills: watch each shared skill directory once across agent workspaces instead of once per agent, preventing file-descriptor exhaustion (<code>EMFILE</code>) that disposed bundle-mcp processes and stalled sessions on multi-agent gateways. Fixes #84968. (#85130) Thanks @openperf.</li>
<li>Release/security: keep generated npm shrinkwrap package versions inside the pnpm lock graph so published package locks cannot bypass pnpm dependency age and override policy.</li>
<li>Cron: honor <code>cron.retry.retryOn: ["network"]</code> for common network error codes such as <code>EAI_AGAIN</code>, <code>EHOSTUNREACH</code>, and <code>ENETUNREACH</code>.</li>
<li>Gateway chat: broadcast returned agent-run error payloads after an agent starts so ACP/WebChat clients receive terminal idle-timeout errors. Fixes #84945.</li>
<li>Gateway chat display: preserve OpenAI-compatible <code>prompt_tokens</code>, <code>completion_tokens</code>, and <code>total_tokens</code> usage fields in sanitized chat history so llama.cpp sessions keep context counts. Fixes #77992. Thanks @MarTT79.</li>
<li>Dashboard/CLI: allow macOS browser launching through <code>open</code> even when SSH environment variables are present, while preserving Linux SSH no-display protection. Fixes #67088. Thanks @theglove44.</li>
<li>Codex app-server: keep native web search observations out of mirrored chat transcripts while preserving tool progress telemetry. Fixes #85109. Thanks @ugitmebaby.</li>
<li>OpenCode Go: strip unsupported Kimi reasoning replay fields before provider requests so repeated <code>kimi-k2.6</code> turns do not fail schema validation. Fixes #83812. Thanks @Sleeck.</li>
<li>Browser/CDP: add a WSL2 portproxy self-loop hint when Chrome DevTools endpoints accept connections but return an empty HTTP reply. Fixes #59209. Thanks @Owlock.</li>
<li>Agents/OpenAI: preserve structured provider error code, type, and redacted body metadata on boundary-aware transport failures.</li>
<li>Doctor/Codex: point native Codex asset warnings at the canonical <code>openclaw migrate plan codex</code> preview command. Fixes #84948. Thanks @markoa.</li>
<li>CLI/models: make <code>capability model auth logout --agent</code> remove auth profiles from the selected non-default agent store. Fixes #85092. Thanks @islandpreneur007.</li>
<li>Gateway/models: reuse prepared provider auth metadata during model-listing auth checks so repeated lookups avoid broad plugin discovery while preserving synthetic local auth.</li>
<li>CLI/status: suppress systemd user-service setup hints when <code>openclaw status --deep</code> can already reach a running Gateway RPC service. Fixes #85094. Thanks @islandpreneur007.</li>
<li>CLI/devices: recover local approval when a same-device repair request replaces the request ID being approved.</li>
<li>CLI/agents: retry transient normal-close Gateway handshakes before falling back to embedded <code>openclaw agent</code> execution.</li>
<li>CLI/update: keep managed Gateway service stop/restart status lines out of <code>openclaw update --json</code> stdout so package-update automation can parse the JSON payload.</li>
<li>Plugins: resolve OpenClaw plugin SDK subpaths for native external plugin runtimes without mutating package installs or broadening process-wide module resolution.</li>
<li>Agents/OpenAI: preserve Responses and Chat Completions <code>reasoning_tokens</code> usage metadata without double-counting it in aggregate output tokens. (#85319)</li>
<li>Control UI/chat: convert pasted <code>data:image/...;base64,...</code> clipboard text into an image attachment instead of dumping the payload into the composer. Fixes #62604. Thanks @cpwilhelmi.</li>
<li>Providers/Gemini: strip fractional seconds from web-search time range filters so Gemini accepts freshness-bound search requests. (#85071) Thanks @Noerr.</li>
<li>OpenAI Codex: preserve image input support for sparse <code>openai-codex/gpt-5.5</code> catalog rows. (#85095) Thanks @sercada.</li>
<li>CLI/models: add a piped or pasted API-key path for OpenAI Codex auth and warn when API keys are pasted into token-mode auth. (#85533) Thanks @joshavant.</li>
<li>Telegram: dead-letter missing-harness isolated ingress failures so a poisoned spooled update no longer blocks later same-lane messages. Fixes #85470. (#85605) Thanks @joshavant.</li>
<li>Plugins/discovery: strip <code>-plugin</code> package suffixes when deriving plugin id hints so package names line up with manifest ids. (#85170) Thanks @JulyanXu.</li>
<li>Tlon: stop advertising a non-existent agent tool contract in the plugin manifest.</li>
<li>Telegram: preserve fenced code block languages through Markdown rendering so Telegram receives <code>language-*</code> code classes. (#85209) Thanks @leno23.</li>
<li>Windows installer: run npm and Corepack command shims from a Windows-local directory so installs launched from WSL2 UNC paths do not fail before OpenClaw is installed.</li>
<li>Windows updates: roll back git-backed updates to the previous checkout when dependency install, build, UI build, or doctor repair fails.</li>
<li>Windows installer: persist user-local portable Git on PATH and activate the repo-pinned pnpm version for git-backed installs and updates.</li>
<li>Windows installer: bootstrap a user-local portable Node.js when native Windows has no Node and no winget, Chocolatey, or Scoop, so first-run installs can continue on raw hosts.</li>
<li>Windows installer: extract the downloaded portable Node.js directory with native <code>tar</code> before falling back to .NET zip extraction, avoiding PowerShell 5.1 archive and path-length failures.</li>
<li>fix(integrations): enforce channel read target allowlists [AI]. (#84982) Thanks @pgondhi987.</li>
<li>Agents/heartbeat: route single-owner <code>session.dmScope=main</code> direct-message exec and cron event wakes back to the agent main session so async completions no longer strand context in orphan direct-DM queues. Fixes #71581. (#83743) Thanks @Kaspre.</li>
<li>Agents/code-mode: expose outer code-mode <code>exec</code> source through the <code>command</code> hook alias with <code>toolKind</code>/<code>toolInputKind</code> discriminators so exec-shaped policies can distinguish code-mode cells. (#83483) Thanks @Kaspre.</li>
<li>Agents/code mode: return structured timeout and runtime-unavailable error codes for known worker failures. Fixes #83389. (#83444) Thanks @Kaspre.</li>
<li>QA-Lab: isolate multi-scenario suite workers when scenarios need startup config patches, preventing message-routing config from leaking into unrelated scenarios.</li>
<li>QA-Lab: make the commitments heartbeat-target-none scenario request an immediate heartbeat instead of waiting for the next scheduled heartbeat.</li>
<li>Codex/Plugin SDK: deliver Codex-native subagent completions through a generic harness task runtime so harness-backed plugins can mirror durable task lifecycle and completion delivery without Codex-specific SDK imports. (#83445) Thanks @bryanpearson.</li>
<li>Gateway CLI: surface local post-challenge connect assembly failures immediately instead of waiting for the wrapper timeout. Fixes #68944. (#85253) Thanks @samzong.</li>
<li>Messages: strip unsupported web-search citation control markers from outbound replies before they reach WebChat or external channels. Fixes #85193. (#85204) Thanks @neeravmakwana.</li>
<li>Agents/exec: treat denied exec approvals as terminal instead of feeding them back into agent follow-up work, and recognize Chinese stop phrases in abort handling. Fixes #69386. (#85194) Thanks @samzong.</li>
<li>CLI/agents: abort accepted Gateway-backed <code>openclaw agent</code> runs on SIGINT/SIGTERM so cron and supervisor timeouts do not leave remote agent work alive. Fixes #71710. (#84381) Thanks @Kaspre.</li>
<li>Codex app-server: retry replay-safe stdio client-close turns once using structured failure metadata, while surfacing idle <code>turn/completed</code> timeouts instead of blindly replaying active shared-server turns. Thanks @VACInc.</li>
<li>Codex app-server: reject command overrides that embed Node or package-manager arguments and point users to <code>appServer.args</code>, so Windows startup avoids shell parsing failures. (#84417) Thanks @TurboTheTurtle.</li>
<li>Agents/Copilot: drop unsafe GitHub Copilot Responses reasoning replay items before send so Telegram direct sessions no longer fail on overlong replay IDs. Fixes #85197. (#85198) Thanks @galiniliev.</li>
<li>UI: add accessible tooltips to the topbar color-mode buttons so System, Light, and Dark choices are labeled on hover and focus. (#85227) Thanks @amknight.</li>
<li>fix: constrain Windows task script names [AI]. (#85064) Thanks @pgondhi987.</li>
<li>Control UI: keep the chat session picker from hiding older or cross-agent configured conversations while preserving the bounded configured-agent refresh. (#85211) Thanks @amknight.</li>
<li>Agents/Anthropic: preserve unsafe integer tool-call input values in streamed Anthropic tool-use JSON, preventing Discord-style IDs from being rounded before dispatch. Fixes #47229. (#83063) Thanks @leno23.</li>
<li>Agents/Codex: estimate tool-heavy prompt pressure at the LLM boundary before provider submission, so persistent sessions compact before overflowing context windows. (#85541) Thanks @fuller-stack-dev and @joshavant.</li>
<li>Agents/hooks: wait for local one-shot CLI and Codex <code>agent_end</code> plugin hooks before process cleanup so terminal observability flushes reliably. (#85007)</li>
<li>Providers/Google: preserve Gemini 3 cron <code>thinkingDefault: "low"</code> when stale catalog metadata says <code>reasoning:false</code>, so scheduled runs keep provider-supported thinking instead of downgrading to off. (#85185) Thanks @neeravmakwana.</li>
<li>CLI/agents: allow <code>openclaw agent --session-key</code> to target explicit session keys, including agent-scoped legacy keys. (#85121) Thanks @Kaspre.</li>
<li>Auto-reply/ACP: wait for same-channel block reply delivery before starting tool work, while still honoring ACP dispatch aborts so stopped turns do not wait on slow channel sends. (#83722) Thanks @IWhatsskill.</li>
<li>Codex/ACP: mark required child-run completions that only report progress, omit a final deliverable, or fail requester delivery as blocked while preserving real final reports. (#85110) Thanks @IWhatsskill.</li>
<li>Channels: treat bare abort messages such as <code>stop</code>, <code>abort</code>, and <code>wait</code> as immediate control commands in inbound debounce paths so stop requests are not delayed behind pending message coalescing. (#83348) Thanks @IWhatsskill.</li>
<li>Channels/message tool: resolve configured external channel plugins during in-agent channel selection, so <code>openclaw agent --local</code> message-tool sends no longer report an available channel as unavailable. (#85022) Thanks @Kaspre.</li>
<li>Agents/heartbeat: honor group/channel <code>message_tool</code> visible-reply policy and model-specific Codex runtime config for scheduled heartbeat runs, so failed internal tool output stays private. Fixes #85310. (#85357) Thanks @neeravmakwana.</li>
<li>Gateway/ACP: close child ACP sessions spawned via <code>sessions_spawn</code> when their parent session is reset or deleted, instead of leaving orphaned <code>claude-agent-acp</code> processes that accumulate and exhaust memory. Fixes #68916. (#85190) Thanks @openperf.</li>
<li>Codex app-server: block native execution paths when OpenClaw exec resolves to a node host while preserving the first-party CLI node binding path. Fixes #85012. (#85534) Thanks @joshavant.</li>
<li>Diagnostics: bound cleanup timeout detail logs, emit drop summaries when async diagnostic bursts exceed the queue cap, and surface async queue drops through diagnostic telemetry.</li>
<li>Agents/subagents: surface blocked child-run completions as errors instead of successful subagent finishes. (#80886) Thanks @TurboTheTurtle.</li>
<li>Context engines: fail closed with a descriptive error when the selected agent runtime cannot satisfy declared context-engine host requirements.</li>
<li>Agents/Pi: treat accepted embedded <code>sessions_spawn</code> child-session handoffs as terminal progress so parent turns no longer report false non-deliverable failures. (#85054) Thanks @samzong.</li>
<li>CLI/models: resolve <code>openclaw models set</code> aliases from the runtime config while keeping authored aliases ahead of runtime-only defaults. (#83262) Thanks @IWhatsskill.</li>
<li>Doctor: show personal Codex CLI asset notices as info instead of warnings. Fixes #84859.</li>
<li>WhatsApp: update Baileys to <code>7.0.0-rc13</code> and drop the obsolete logger type patch.</li>
<li>CLI/update: pre-pack GitHub/git package update targets before the staged npm install, restoring <code>openclaw update --tag main</code> for one-off package updates. (#81296) Thanks @fuller-stack-dev.</li>
<li>Gateway: mirror successful same-source message-tool sends into session transcripts so delivered replies stay in later history/context. (#84837) Thanks @iFiras-Max1.</li>
<li>Media generation: keep image, music, and video completion delivery from duplicating or losing task ownership when generated media finishes through active session replies. (#84006) Thanks @fuller-stack-dev.</li>
<li>Infra/json: retry transient <code>File changed during read</code> races while loading JSON state so config and state reads recover instead of failing the turn. (#84285)</li>
<li>Plugins/providers: fail closed for workspace provider plugins during setup-mode discovery unless explicitly trusted, preventing untrusted workspace plugin code from running during provider setup. (#81069) Thanks @mmaps.</li>
<li>Providers/Ollama: resolve configured Ollama Cloud <code>OLLAMA_API_KEY</code> markers to the real discovery key so cloud provider entries keep authenticated model catalog access. (#85037)</li>
<li>Discord: keep persistent component registry fallback warnings actionable by forwarding structured error and cause metadata through the runtime logger. Fixes #84185. (#84190) Thanks @100menotu001.</li>
<li>Gateway/sessions: preserve compatible session auth profile overrides when switching models within the same provider, including provider-auth aliases. Fixes #81837. (#81886) Thanks @TurboTheTurtle.</li>
<li>Gateway/status: surface inbound delivery telemetry counters and transport-liveness warnings in <code>openclaw status --all</code>. Fixes #49577. (#72724)</li>
<li>Docker: prune package-excluded plugin source workspaces and dependency closures so runtime images do not keep packages for plugins that were not opted in.</li>
<li>Providers/Ollama: treat Docker/OrbStack host aliases as local Ollama endpoints so <code>ollama-local</code> marker auth works when OpenClaw runs inside a VM/container and Ollama runs on the host. Fixes #84875.</li>
<li>QA-Lab: keep explicitly searchable/deferred OpenClaw dynamic tool rows report-only by default so tool-coverage gates do not treat mock discovery gaps as hard product failures. (#80319) Thanks @100yenadmin.</li>
<li>Agents/config: keep non-Google provider model refs from being rewritten by Google Gemini preview-id normalization. (#84762) Thanks @zhangguiping-xydt.</li>
<li>Installer: require a real controlling terminal before launching onboarding so headless <code>curl | bash</code> installs finish cleanly after installing the CLI.</li>
<li>Agents/Codex: promote a completed final assistant response when a prompt timeout races Codex app-server completion instead of returning an empty timeout envelope. Refs #84516.</li>
<li>Codex app-server: keep interrupted turn statuses from being treated as OpenClaw aborts by themselves, so tool-only turns remain eligible for no-visible-answer recovery. Fixes #84492.</li>
<li>Agents: cap heartbeat model bleed context hints by the stored session window when runtime model metadata is unavailable, so overflow recovery advice does not suggest a larger window than the active session actually has.</li>
<li>Control UI/Web Push: use <code>https://openclaw.ai</code> as the generated default VAPID subject instead of the old localhost mailbox so iOS PWA push setup uses an Apple-acceptable subject when <code>OPENCLAW_VAPID_SUBJECT</code> is unset. Fixes #83134. (#83317) Thanks @IWhatsskill.</li>
<li>Control UI: distinguish inherited thinking-off settings from explicit Off selections so the thinking selector no longer shows two identical Off rows. (#85223) Thanks @amknight.</li>
<li>Agents/Pi: keep embedded session transcript writes from tripping false takeover detection after packaged npm onboarding agent turns.</li>
<li>Codex/TUI: surface Codex-native post-turn compaction failures instead of continuing uncompacted, and keep successful native compaction serialized before local idle/next-turn handling. Fixes #84305. (#85160) Thanks @joshavant.</li>
<li>Memory/search: stop recall tracking from writing dreaming side-effect artifacts when <code>dreaming.enabled=false</code>, while preserving normal search results. Fixes #84436. (#84444) Thanks @NianJiuZst.</li>
<li>Diffs: render viewer toolbar icons from a closed icon-name map instead of HTML strings, removing the toolbar icon XSS sink. (#83955) Thanks @tanshanshan.</li>
<li>QA: keep <code>pnpm qa:e2e</code> self-check runs inside the private QA runtime envelope even when inherited shell env disables bundled plugins.</li>
<li>fix(config): validate browser sandbox bind sources [AI]. (#84799) Thanks @pgondhi987.</li>
<li>doctor: constrain legacy plugin cleanup paths [AI]. (#84801) Thanks @pgondhi987.</li>
<li>Update/doctor: prune stale local bundled plugin install records that point at old compiled bundled output so current bundled plugin schemas win after upgrade. (#84863) Thanks @fuller-stack-dev.</li>
<li>Providers/Ollama: preserve native Ollama tool-call IDs across assistant replay so Gemini over Ollama Cloud can keep its hidden function-call thought-signature handle.</li>
<li>Discord: keep session recovery and <code>/stop</code> abort ownership on the source dispatch lane while bound ACP turns continue routing to their target session, so stalled pre-run work and late replies are cleared instead of leaking after stop. Fixes #84477. (#85100) Thanks @joshavant.</li>
<li>Codex app-server: mark missing turn completion after observed execution as replay-unsafe and release the session so follow-up turns can run. Fixes #84076. (#85107) Thanks @joshavant.</li>
<li>Codex app-server: give visible <code>message</code> dynamic tool sends a longer timeout budget so slow channel delivery can return its own result or error instead of hitting the 30-second Codex wrapper. (#85216) Thanks @amknight.</li>
<li>Codex app-server: add a dedicated post-tool raw assistant completion idle timeout config so trusted heavy turns can wait longer after tool handoff without weakening final assistant release.</li>
<li>Matrix: keep explicitly configured two-person rooms on the room route before stale <code>m.direct</code> or strict two-member DM fallback can bypass mention gating. Fixes #85017. (#85137) Thanks @joshavant.</li>
<li>Agents/subagents: require explicit subagent allowlist targets to be configured agents so stale deleted-agent ids are omitted from <code>agents_list</code> and rejected by <code>sessions_spawn</code>. Fixes #84811. (#85154) Thanks @joshavant.</li>
<li>PDF tool: time out idle remote PDF body reads after 120 seconds so stalled remote documents return an error instead of wedging the session. Fixes #68649. (#84768) Thanks @luoyanglang.</li>
<li>Diagnostics/OpenTelemetry plugin: suppress handled OTLP exporter promise rejections so collector shutdowns no longer crash the Gateway. (#81085) Thanks @luoyanglang.</li>
<li>Agents/exec: omit raw command text and env values from denied exec failure logs while keeping safe correlation metadata. Fixes #85049. (#85140) Thanks @joshavant.</li>
<li>Media/audio: skip empty structured sherpa-onnx transcripts instead of treating the raw JSON payload as spoken text. (#84667) Thanks @TurboTheTurtle.</li>
<li>Agents/exec: preserve inherited XDG base-directory environment values for subprocesses while still rejecting agent-supplied XDG overrides. Fixes #84854. (#85139) Thanks @joshavant.</li>
<li>Node/Linux: keep <code>OPENCLAW_GATEWAY_TOKEN</code> out of generated systemd unit files by writing node service token values to a node-specific env file. (#84408)</li>
<li>Memory-core/dreaming: reuse stable narrative subagent session keys per workspace and phase while keeping per-run idempotency and bounded cleanup, so stale <code>dreaming-narrative-*</code> sessions do not accumulate. Fixes #68252, #69187, and #70402. (#70464) Thanks @chiyouYCH.</li>
<li>Trajectory/support: tolerate partial skill snapshot entries when building support metadata so rejected skill path scans no longer abort trajectory capture. (#71185) Thanks @lukeboyett.</li>
<li>TUI: coalesce repeated idle Esc abort notices into a single <code>no active run xN</code> system row instead of appending duplicate rows.</li>
<li>Telegram: honor <code>channels.telegram.pollingStallThresholdMs</code> in the default isolated polling path, restarting silent workers instead of leaving inbound updates wedged. Fixes #83950. (#84861) Thanks @joshavant.</li>
<li>Telegram: dedupe replayed message dispatches by Telegram chat/message identity so isolated-ingress replays do not trigger duplicate model dispatches. Fixes #84886. (#85208) Thanks @joshavant.</li>
<li>Slack: suppress reasoning payloads before reply delivery and dispatch accounting, so Slack monitor, slash-command, fallback, and direct reply paths do not leak model reasoning. Fixes #84319. (#84322) Thanks @ffluk3 and @joshavant.</li>
<li>Slack: deliver native plugin approval prompts and updates when Slack native approvals are enabled, while keeping plugin approval authorization separate from exec approvers.</li>
<li>Slack: keep native plugin approval prompts in the originating app conversation thread when the live Slack turn source is a <code>D...</code> conversation.</li>
<li>Agents/Pi: disable the embedded pi-coding-agent runtime auto-retry so OpenClaw's own retry and failover loop does not replay failed tool calls through a nested SDK retry. Fixes #73781. (#74434) Thanks @yelog.</li>
<li>CLI/perf: keep <code>setup --help</code>, <code>onboard --help</code>, and <code>configure --help</code> out of the full wizard runtime while preserving the existing help output. (#84488) Thanks @frankekn.</li>
<li>CLI/perf: keep <code>agents --help</code> out of agents action/runtime imports so help, completion, and command discovery paths avoid loading the full agents runtime. (#84483) Thanks @frankekn.</li>
<li>CLI/perf: keep <code>secrets --help</code> and <code>nodes --help</code> on the precomputed help path so parent help avoids loading action-heavy command runtime modules. (#84818) Thanks @frankekn.</li>
<li>CLI/perf: serve <code>doctor</code>, <code>gateway</code>, <code>models</code>, and <code>plugins</code> parent help from startup metadata so common subcommand help avoids full CLI program construction. (#84786) Thanks @frankekn.</li>
<li>Codex/Lossless: keep context-engine history on the canonical run session when Telegram DMs use per-peer runtime policy keys. Fixes #84936. (#84954) Thanks @neeravmakwana.</li>
<li>Codex: keep heartbeat response tool schemas durable without exposing dynamic tools disabled by turn policy, so heartbeat wakeups can reuse threads while scoped tool allowlists stay enforced. (#84681) Thanks @jalehman.</li>
<li>Auth/OAuth: skip the refresh adapter when a stored OAuth credential has no refresh token so agent turns fail fast on missing-key instead of waiting on the 120s refresh timeout. Thanks @romneyda.</li>
<li>Auth/Codex: load legacy OAuth sidecar credentials in the embedded runner's secrets-runtime auth loaders so Telegram replies, cron-triggered turns, and other isolated sub-agent lanes can reach the existing #83312 refresh-and-rewrite migration instead of failing with <code>No API key found for provider "openai-codex"</code> until the user runs <code>openclaw doctor</code>. Thanks @Totalsolutionsync and @romneyda.</li>
<li>Codex/failover: classify <code>deactivated_workspace</code> as a permanent auth failure so configured fallback models can advance when a Codex workspace is deactivated. (#55893) Thanks @litang9.</li>
<li>Exec: keep configured <code>tools.exec.pathPrepend</code> entries ahead of user shell startup PATH changes on POSIX gateway runs. (#81403) Thanks @medns.</li>
<li>Gateway/sessions: allow shared-secret bearer callers to read and stream session history without an explicit scope header. (#81815) Thanks @medns.</li>
<li>Agents/embedded runner: classify HTML auth provider responses as <code>auth_html</code> and return a re-authentication hint instead of the CDN-blocked copy that <code>upstream_html</code> returns. Cloudflare Access login pages, nginx basic-auth challenges, and gateway login walls all produce HTML auth bodies that were previously misdiagnosed as transient CDN blocks. (#79900) Thanks @martingarramon.</li>
<li>TUI/streaming watchdog: dismiss the <code>This response is taking longer than expected</code> notice as soon as a chat event for the same run arrives, so the message no longer sits next to the recovered response when the run was only briefly silent. Refs #67052, #69081 (closed), prior attempt #69026. Thanks @jpruit20 and @romneyda.</li>
<li>Agents/Pi: tolerate OpenClaw-owned transcript writes while embedded prompts are released for model I/O, keeping long-running Feishu, Slack, Telegram, and cron turns from failing with false session-takeover errors. Fixes #84059. (#84250) Thanks @tianxiaochannel-oss88.</li>
</ul>
<p><a href="https://github.com/openclaw/openclaw/blob/main/CHANGELOG.md">View full changelog</a></p>
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.5.22/OpenClaw-2026.5.22.zip" length="54409357" type="application/octet-stream" sparkle:edSignature="am1mwLOmUHor9QuQWtxSsKoBOCySUBo4fB+0Qdcrz0E3wf6ESIMTfOC0k+dKJSh9gtLZw5jzpWVqTBzEdU36Aw=="/>
</item>
</channel>
</rss>

View File

@@ -2871,7 +2871,7 @@ fun providerDisplayName(provider: String): String =
when (provider.trim().lowercase()) {
"openai" -> "OpenAI"
"openrouter" -> "OpenRouter"
"codex" -> "Codex"
"openai-codex", "codex" -> "Codex"
"ollama", "ollama-local" -> "Ollama Local"
else ->
provider

View File

@@ -11,6 +11,10 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
// ---------------------------------------------------------------------------
// MobileColors semantic color tokens with light + dark variants
// ---------------------------------------------------------------------------
internal data class MobileColors(
val surface: Color,
val surfaceStrong: Color,
@@ -104,6 +108,9 @@ internal object MobileColorsAccessor {
@Composable get() = LocalMobileColors.current
}
// ---------------------------------------------------------------------------
// Backward-compatible top-level accessors (composable getters)
// ---------------------------------------------------------------------------
// These allow existing call sites to keep using `mobileSurface`, `mobileText`, etc.
// without converting every file at once. Each resolves to the themed value.
@@ -142,6 +149,10 @@ internal val mobileBackgroundGradient: Brush
)
}
// ---------------------------------------------------------------------------
// Typography tokens (theme-independent)
// ---------------------------------------------------------------------------
internal val mobileFontFamily =
FontFamily(
Font(resId = R.font.manrope_400_regular, weight = FontWeight.Normal),

View File

@@ -270,7 +270,7 @@ private fun providerPriority(provider: String): Int =
"google" -> 2
"openrouter" -> 3
"ollama", "ollama-local" -> 4
"codex" -> 5
"codex", "openai-codex" -> 5
else -> 100
}

View File

@@ -5,8 +5,6 @@
Maintenance update for the current OpenClaw release.
- Added hosted push relay defaults, realtime Talk playback, and safer WebSocket ping handling for mobile sessions.
- Updated App Store screenshots to cover Gateway pairing, Command, Chat, Talk, Agent, and Settings flows.
- Highlighted realtime Talk relay, Gateway connection status, node capabilities, push wake, and privacy controls.
## 2026.5.28 - 2026-05-28

View File

@@ -29,14 +29,6 @@ def clear_empty_env_var(key)
ENV.delete(key) unless env_present?(ENV[key])
end
def screenshot_upload_requested?
ENV["DELIVER_SCREENSHOTS"] == "1"
end
def screenshot_paths
Dir[File.join(__dir__, "screenshots", "**", "*.png")]
end
def maybe_decode_hex_keychain_secret(value)
return value unless env_present?(value)
@@ -322,7 +314,6 @@ platform :ios do
desc "Upload App Store metadata (and optionally screenshots)"
lane :metadata do
sync_ios_versioning!
version_metadata = read_ios_version_metadata
api_key = asc_api_key
clear_empty_env_var("APP_STORE_CONNECT_API_KEY_PATH")
app_identifier = ENV["ASC_APP_IDENTIFIER"]
@@ -330,21 +321,11 @@ platform :ios do
app_identifier = nil unless env_present?(app_identifier)
app_id = nil unless env_present?(app_id)
if screenshot_upload_requested? && screenshot_paths.empty?
UI.user_error!("DELIVER_SCREENSHOTS=1 but no PNG screenshots were found under apps/ios/fastlane/screenshots.")
end
deliver_options = {
api_key: api_key,
force: true,
app_version: version_metadata[:short_version],
copyright: "2026 OpenClaw",
primary_category: "PRODUCTIVITY",
secondary_category: "UTILITIES",
skip_screenshots: !screenshot_upload_requested?,
skip_screenshots: ENV["DELIVER_SCREENSHOTS"] != "1",
skip_metadata: ENV["DELIVER_METADATA"] != "1",
skip_binary_upload: true,
overwrite_screenshots: screenshot_upload_requested?,
run_precheck_before_submit: false
}
deliver_options[:app_identifier] = app_identifier if app_identifier

View File

@@ -1,19 +1,18 @@
OpenClaw is a personal AI assistant you run on your own devices.
Pair this iPhone app with your OpenClaw Gateway to use your phone as a secure node for chat, voice, approvals, sharing, and device-aware automation.
Pair this iPhone app with your OpenClaw Gateway to connect your phone as a secure node for voice, camera, and device automation.
What you can do:
- Pair with your private OpenClaw Gateway by QR code or setup code
- Chat with your assistant from iPhone
- Use realtime Talk mode and push-to-talk
- Review Gateway action approvals from your phone
- Use voice wake and push-to-talk
- Capture photos and short clips on request
- Record screen snippets for troubleshooting and workflows
- Share text, links, and media directly from iOS into OpenClaw
- Enable device capabilities such as camera, screen, location, photos, contacts, calendar, and reminders when you choose
- Receive push wakes and node status updates for connected workflows
- Run location-aware and device-aware automations
OpenClaw is local-first: you control your gateway, keys, configuration, and permissions. Device access is managed by iOS permissions and can be enabled only for the capabilities you want to use.
OpenClaw is local-first: you control your gateway, keys, and configuration.
Getting started:
1) Set up your OpenClaw Gateway
2) Open the iOS app and pair with your gateway
3) Start using chat, Talk mode, approvals, and automations from your phone
3) Start using commands and automations from your phone

View File

@@ -1 +1 @@
openclaw,ai assistant,local ai,iphone ai,voice assistant,automation,gateway,chat,agent
openclaw,ai assistant,local ai,voice assistant,automation,gateway,chat,agent,node

View File

@@ -1 +1 @@
Pair your iPhone with your OpenClaw Gateway for chat, realtime voice, approvals, device capabilities, and private automation.
Run OpenClaw from your iPhone: pair with your own gateway, trigger automations, and use voice, camera, and share actions.

View File

@@ -1,5 +1,3 @@
Maintenance update for the current OpenClaw release.
- Added hosted push relay defaults, realtime Talk playback, and safer WebSocket ping handling for mobile sessions.
- Updated App Store screenshots to cover Gateway pairing, Command, Chat, Talk, Agent, and Settings flows.
- Highlighted realtime Talk relay, Gateway connection status, node capabilities, push wake, and privacy controls.

View File

@@ -97,7 +97,7 @@ struct MenuSessionsInjectorTests {
plan: "Pro",
error: nil),
GatewayUsageProvider(
provider: "openai",
provider: "openai-codex",
displayName: "Codex",
windows: [GatewayUsageWindow(label: "day", usedPercent: 3, resetAt: nil)],
plan: nil,

View File

@@ -13,10 +13,6 @@ let package = Package(
.library(name: "OpenClawKit", targets: ["OpenClawKit"]),
.library(name: "OpenClawChatUI", targets: ["OpenClawChatUI"]),
],
traits: [
.trait(name: "Talk", description: "ElevenLabs cloud TTS / talk support"),
.default(enabledTraits: ["Talk"]),
],
dependencies: [
.package(url: "https://github.com/steipete/ElevenLabsKit", exact: "0.1.1"),
.package(url: "https://github.com/gonzalezreal/textual", exact: "0.3.1"),
@@ -32,7 +28,7 @@ let package = Package(
name: "OpenClawKit",
dependencies: [
"OpenClawProtocol",
.product(name: "ElevenLabsKit", package: "ElevenLabsKit", condition: .when(traits: ["Talk"])),
.product(name: "ElevenLabsKit", package: "ElevenLabsKit"),
],
path: "Sources/OpenClawKit",
resources: [

View File

@@ -1,4 +1,3 @@
#if Talk
import Foundation
@MainActor
@@ -15,4 +14,3 @@ public protocol PCMStreamingAudioPlaying {
extension StreamingAudioPlayer: StreamingAudioPlaying {}
extension PCMStreamingAudioPlayer: PCMStreamingAudioPlaying {}
#endif

View File

@@ -1,4 +1,3 @@
#if Talk
@_exported import ElevenLabsKit
public typealias ElevenLabsVoice = ElevenLabsKit.ElevenLabsVoice
@@ -8,4 +7,3 @@ public typealias TalkTTSValidation = ElevenLabsKit.TalkTTSValidation
public typealias StreamingAudioPlayer = ElevenLabsKit.StreamingAudioPlayer
public typealias PCMStreamingAudioPlayer = ElevenLabsKit.PCMStreamingAudioPlayer
public typealias StreamingPlaybackResult = ElevenLabsKit.StreamingPlaybackResult
#endif

View File

@@ -389,15 +389,6 @@
"plan.0.step"
]
},
"skill_workshop": {
"emoji": "🧰",
"title": "Skill Workshop",
"detailKeys": [
"action",
"name",
"proposal_id"
]
},
"gateway": {
"emoji": "🔌",
"title": "Gateway",

View File

@@ -5276,334 +5276,6 @@ public struct SkillsDetailResult: Codable, Sendable {
}
}
public struct SkillsProposalsListParams: Codable, Sendable {
public let agentid: String?
public init(
agentid: String? = nil)
{
self.agentid = agentid
}
private enum CodingKeys: String, CodingKey {
case agentid = "agentId"
}
}
public struct SkillsProposalsListResult: Codable, Sendable {
public let schema: String
public let updatedat: String
public let proposals: [[String: AnyCodable]]
public init(
schema: String,
updatedat: String,
proposals: [[String: AnyCodable]])
{
self.schema = schema
self.updatedat = updatedat
self.proposals = proposals
}
private enum CodingKeys: String, CodingKey {
case schema
case updatedat = "updatedAt"
case proposals
}
}
public struct SkillsProposalInspectParams: Codable, Sendable {
public let agentid: String?
public let proposalid: String
public init(
agentid: String? = nil,
proposalid: String)
{
self.agentid = agentid
self.proposalid = proposalid
}
private enum CodingKeys: String, CodingKey {
case agentid = "agentId"
case proposalid = "proposalId"
}
}
public struct SkillsProposalInspectResult: Codable, Sendable {
public let record: SkillsProposalRecordResult
public let content: String
public let supportfiles: [[String: AnyCodable]]?
public init(
record: SkillsProposalRecordResult,
content: String,
supportfiles: [[String: AnyCodable]]?)
{
self.record = record
self.content = content
self.supportfiles = supportfiles
}
private enum CodingKeys: String, CodingKey {
case record
case content
case supportfiles = "supportFiles"
}
}
public struct SkillsProposalCreateParams: Codable, Sendable {
public let agentid: String?
public let name: String
public let description: String
public let content: String
public let supportfiles: [[String: AnyCodable]]?
public let goal: String?
public let evidence: String?
public init(
agentid: String? = nil,
name: String,
description: String,
content: String,
supportfiles: [[String: AnyCodable]]?,
goal: String?,
evidence: String?)
{
self.agentid = agentid
self.name = name
self.description = description
self.content = content
self.supportfiles = supportfiles
self.goal = goal
self.evidence = evidence
}
private enum CodingKeys: String, CodingKey {
case agentid = "agentId"
case name
case description
case content
case supportfiles = "supportFiles"
case goal
case evidence
}
}
public struct SkillsProposalUpdateParams: Codable, Sendable {
public let agentid: String?
public let skillname: String
public let description: String?
public let content: String
public let supportfiles: [[String: AnyCodable]]?
public let goal: String?
public let evidence: String?
public init(
agentid: String? = nil,
skillname: String,
description: String?,
content: String,
supportfiles: [[String: AnyCodable]]?,
goal: String?,
evidence: String?)
{
self.agentid = agentid
self.skillname = skillname
self.description = description
self.content = content
self.supportfiles = supportfiles
self.goal = goal
self.evidence = evidence
}
private enum CodingKeys: String, CodingKey {
case agentid = "agentId"
case skillname = "skillName"
case description
case content
case supportfiles = "supportFiles"
case goal
case evidence
}
}
public struct SkillsProposalReviseParams: Codable, Sendable {
public let agentid: String?
public let proposalid: String
public let content: String
public let supportfiles: [[String: AnyCodable]]?
public let description: String?
public let goal: String?
public let evidence: String?
public init(
agentid: String? = nil,
proposalid: String,
content: String,
supportfiles: [[String: AnyCodable]]?,
description: String?,
goal: String?,
evidence: String?)
{
self.agentid = agentid
self.proposalid = proposalid
self.content = content
self.supportfiles = supportfiles
self.description = description
self.goal = goal
self.evidence = evidence
}
private enum CodingKeys: String, CodingKey {
case agentid = "agentId"
case proposalid = "proposalId"
case content
case supportfiles = "supportFiles"
case description
case goal
case evidence
}
}
public struct SkillsProposalActionParams: Codable, Sendable {
public let agentid: String?
public let proposalid: String
public let reason: String?
public init(
agentid: String? = nil,
proposalid: String,
reason: String?)
{
self.agentid = agentid
self.proposalid = proposalid
self.reason = reason
}
private enum CodingKeys: String, CodingKey {
case agentid = "agentId"
case proposalid = "proposalId"
case reason
}
}
public struct SkillsProposalApplyResult: Codable, Sendable {
public let record: SkillsProposalRecordResult
public let targetskillfile: String
public init(
record: SkillsProposalRecordResult,
targetskillfile: String)
{
self.record = record
self.targetskillfile = targetskillfile
}
private enum CodingKeys: String, CodingKey {
case record
case targetskillfile = "targetSkillFile"
}
}
public struct SkillsProposalRecordResult: Codable, Sendable {
public let schema: String
public let id: String
public let kind: AnyCodable
public let status: AnyCodable
public let title: String
public let description: String
public let createdat: String
public let updatedat: String
public let createdby: AnyCodable
public let proposedversion: String
public let draftfile: String
public let drafthash: String
public let supportfiles: [[String: AnyCodable]]?
public let target: [String: AnyCodable]
public let scan: [String: AnyCodable]
public let goal: String?
public let evidence: String?
public let appliedat: String?
public let rejectedat: String?
public let quarantinedat: String?
public let staleat: String?
public let statusreason: String?
public init(
schema: String,
id: String,
kind: AnyCodable,
status: AnyCodable,
title: String,
description: String,
createdat: String,
updatedat: String,
createdby: AnyCodable,
proposedversion: String,
draftfile: String,
drafthash: String,
supportfiles: [[String: AnyCodable]]?,
target: [String: AnyCodable],
scan: [String: AnyCodable],
goal: String?,
evidence: String?,
appliedat: String?,
rejectedat: String?,
quarantinedat: String?,
staleat: String?,
statusreason: String?)
{
self.schema = schema
self.id = id
self.kind = kind
self.status = status
self.title = title
self.description = description
self.createdat = createdat
self.updatedat = updatedat
self.createdby = createdby
self.proposedversion = proposedversion
self.draftfile = draftfile
self.drafthash = drafthash
self.supportfiles = supportfiles
self.target = target
self.scan = scan
self.goal = goal
self.evidence = evidence
self.appliedat = appliedat
self.rejectedat = rejectedat
self.quarantinedat = quarantinedat
self.staleat = staleat
self.statusreason = statusreason
}
private enum CodingKeys: String, CodingKey {
case schema
case id
case kind
case status
case title
case description
case createdat = "createdAt"
case updatedat = "updatedAt"
case createdby = "createdBy"
case proposedversion = "proposedVersion"
case draftfile = "draftFile"
case drafthash = "draftHash"
case supportfiles = "supportFiles"
case target
case scan
case goal
case evidence
case appliedat = "appliedAt"
case rejectedat = "rejectedAt"
case quarantinedat = "quarantinedAt"
case staleat = "staleAt"
case statusreason = "statusReason"
}
}
public struct SkillsSecurityVerdictsParams: Codable, Sendable {
public let agentid: String?
@@ -6880,54 +6552,6 @@ public struct ChatHistoryParams: Codable, Sendable {
}
}
public struct ChatMessageGetParams: Codable, Sendable {
public let sessionkey: String
public let agentid: String?
public let messageid: String
public let maxchars: Int?
public init(
sessionkey: String,
agentid: String? = nil,
messageid: String,
maxchars: Int?)
{
self.sessionkey = sessionkey
self.agentid = agentid
self.messageid = messageid
self.maxchars = maxchars
}
private enum CodingKeys: String, CodingKey {
case sessionkey = "sessionKey"
case agentid = "agentId"
case messageid = "messageId"
case maxchars = "maxChars"
}
}
public struct ChatMessageGetResult: Codable, Sendable {
public let ok: Bool
public let message: AnyCodable?
public let unavailablereason: AnyCodable?
public init(
ok: Bool,
message: AnyCodable?,
unavailablereason: AnyCodable?)
{
self.ok = ok
self.message = message
self.unavailablereason = unavailablereason
}
private enum CodingKeys: String, CodingKey {
case ok
case message
case unavailablereason = "unavailableReason"
}
}
public struct ChatSendParams: Codable, Sendable {
public let sessionkey: String
public let agentid: String?

View File

@@ -2192,7 +2192,7 @@ extension TestChatTransportState {
path: nil,
count: 1,
defaults: OpenClawChatSessionsDefaults(
modelProvider: "openai",
modelProvider: "openai-codex",
model: "gpt-5.5",
contextTokens: nil,
thinkingLevels: [

View File

@@ -1,4 +1,3 @@
#if Talk
import XCTest
@testable import OpenClawKit
@@ -18,4 +17,3 @@ final class ElevenLabsTTSValidationTests: XCTestCase {
XCTAssertNil(ElevenLabsTTSClient.validatedNormalize("maybe"))
}
}
#endif

View File

@@ -144,7 +144,6 @@ const config = {
entry: rootEntries,
ignoreDependencies: [
"@openclaw/*",
"file-type",
"playwright-core",
"sqlite-vec",
"tree-sitter-bash",
@@ -185,14 +184,6 @@ const config = {
entry: ["src/*.ts!"],
project: ["src/**/*.ts!"],
},
"packages/media-core": {
entry: ["src/*.ts!"],
project: ["src/**/*.ts!"],
},
"packages/acp-core": {
entry: ["src/*.ts!"],
project: ["src/**/*.ts!"],
},
"packages/terminal-core": {
entry: ["src/*.ts!"],
project: ["src/**/*.ts!"],

View File

@@ -1,4 +1,4 @@
f4a00ada9d154a4d3a54e109aa6e9f73f22b09d7df9ab6745e87f88724eec06b config-baseline.json
5ee177382cf32c2816dca0a4e67cd6c01df1045d600b21a6e9c11639ddb10ce8 config-baseline.core.json
0e654bad3f1ef9100f76e512c4453c1f26b6bc1f5ee121ce505d0624a1dad4cd config-baseline.channel.json
e6a1d6f51f0d9c04bd92d51deebfaca8c7917dd28d7998d225c0074e0a095348 config-baseline.plugin.json
289c1bae4b9574d219fe61931be6b3ce42d4efb37d0a2edc570a521016394db5 config-baseline.json
5bcb22d1506d82e59caa3bbc97931213299e3a2c0d45dbc549386b254661094a config-baseline.core.json
a9102c0611b8170fac37853cc31771810f31757a9e3b2c6796bbd9625f9b9206 config-baseline.channel.json
0a8e088f8dc7b12341075ce019281d5fe45827ae802f60c71a490022ba5867cf config-baseline.plugin.json

View File

@@ -1,2 +1,2 @@
8b0cb667fc676d9cf9e47ec8b3889aaa1cd75d493cc78428844931ca0ac415ff plugin-sdk-api-baseline.json
b97fddcfae489bb4496e5cba26de388e4fe7eb52584d6a6b8e9cb4e539b258c5 plugin-sdk-api-baseline.jsonl
cf29066e9465cb5ac1387d1d482d0939b9176220ecc69964da9af1a471939269 plugin-sdk-api-baseline.json
ab43993cf713a96b191c55cf89bb215c18ecdc2d8edf50f31369ce3b162c56e3 plugin-sdk-api-baseline.jsonl

View File

@@ -40,9 +40,11 @@ Cron is the Gateway's built-in scheduler. It persists jobs, wakes the agent at t
## How cron works
- Cron runs **inside the Gateway** process (not inside the model).
- Job definitions, runtime state, and run history persist in OpenClaw's shared SQLite state database so restarts do not lose schedules.
- On upgrade, legacy `~/.openclaw/cron/jobs.json`, `jobs-state.json`, and `runs/*.jsonl` files are imported once and renamed with a `.migrated` suffix. Malformed job rows are skipped from runtime and copied to `jobs-quarantine.json` for later repair or review.
- `cron.store` still names the logical cron store key and legacy import path. After import, editing that JSON file no longer changes active cron jobs; use `openclaw cron add|edit|remove` or the Gateway cron RPC methods instead.
- Job definitions persist at `~/.openclaw/cron/jobs.json` so restarts do not lose schedules.
- Runtime execution state persists next to it in `~/.openclaw/cron/jobs-state.json`. If you track cron definitions in git, track `jobs.json` and gitignore `jobs-state.json`.
- If `jobs.json` contains malformed rows, the Gateway keeps valid jobs running, removes the malformed rows from the active store, and saves the raw rows beside it in `jobs-quarantine.json` for later repair or review.
- After the split, older OpenClaw versions can read `jobs.json` but may treat jobs as fresh because runtime fields now live in `jobs-state.json`.
- When `jobs.json` is edited while the Gateway is running or stopped, OpenClaw compares the changed schedule fields with pending runtime slot metadata and clears stale `nextRunAtMs` values. Pure formatting or key-order-only rewrites preserve the pending slot.
- All cron executions create [background task](/automation/tasks) records.
- On Gateway startup, overdue isolated agent-turn jobs are rescheduled out of the channel-connect window instead of replaying immediately, so Discord/Telegram startup and native-command setup stay responsive after restarts.
- One-shot jobs (`--at`) auto-delete after success by default.
@@ -460,7 +462,9 @@ Model override note:
`maxConcurrentRuns` limits both scheduled cron dispatch and isolated agent-turn execution, and defaults to 8. Isolated cron agent turns use the queue's dedicated `cron-nested` execution lane internally, so raising this value lets independent cron LLM runs progress in parallel instead of only starting their outer cron wrappers. The shared non-cron `nested` lane is not widened by this setting.
`cron.store` is a logical store key and legacy import path. Existing stores are imported into SQLite on first load and archived; future cron changes should go through the CLI or Gateway API.
The runtime state sidecar is derived from `cron.store`: a `.json` store such as `~/clawd/cron/jobs.json` uses `~/clawd/cron/jobs-state.json`, while a store path without a `.json` suffix appends `-state.json`.
If you hand-edit `jobs.json`, leave `jobs-state.json` out of source control. OpenClaw uses that sidecar for pending slots, active markers, last-run metadata, and the schedule identity that tells the scheduler when an externally edited job needs a fresh `nextRunAtMs`.
Disable cron: `cron.enabled: false` or `OPENCLAW_SKIP_CRON=1`.
@@ -472,7 +476,7 @@ Disable cron: `cron.enabled: false` or `OPENCLAW_SKIP_CRON=1`.
</Accordion>
<Accordion title="Maintenance">
`cron.sessionRetention` (default `24h`) prunes isolated run-session entries. `cron.runLog.keepLines` limits retained SQLite run-history rows per job; `maxBytes` is retained for config compatibility with older file-backed run logs.
`cron.sessionRetention` (default `24h`) prunes isolated run-session entries. `cron.runLog.maxBytes` / `cron.runLog.keepLines` auto-prune run-log files.
</Accordion>
</AccordionGroup>

View File

@@ -346,7 +346,7 @@ A sweeper runs every **60 seconds** and handles four things:
</Accordion>
<Accordion title="Tasks and cron">
Cron job definitions, runtime execution state, and run history live in OpenClaw's shared SQLite state database. **Every** cron execution creates a task record - both main-session and isolated. Main-session cron tasks default to `silent` notify policy so they track without generating notifications.
A cron job **definition** lives in `~/.openclaw/cron/jobs.json`; runtime execution state lives beside it in `~/.openclaw/cron/jobs-state.json`. **Every** cron execution creates a task record - both main-session and isolated. Main-session cron tasks default to `silent` notify policy so they track without generating notifications.
See [Cron Jobs](/automation/cron-jobs).

View File

@@ -2,7 +2,6 @@
summary: "Group chat behavior across surfaces (Discord/iMessage/Matrix/Microsoft Teams/Signal/Slack/Telegram/WhatsApp/Zalo)"
read_when:
- Changing group chat behavior or mention gating
- Scoping mentionPatterns to specific group conversations
title: "Groups"
sidebarTitle: "Groups"
---
@@ -48,17 +47,13 @@ For normal group/channel requests, OpenClaw defaults to `messages.groupChat.visi
Use `messages.groupChat.visibleReplies: "message_tool"` when a shared room should let the agent decide when to speak by calling `message(action=send)`. This works best for group rooms backed by latest-generation, tool-reliable models such as GPT 5.5. If the model misses that tool and returns substantive final text, OpenClaw keeps that final text private instead of posting it to the room.
Use `"automatic"` for weaker models or runtimes that do not reliably understand tool-only delivery. In automatic mode, the agent's final assistant text is the visible source reply path, so a model that cannot consistently call `message(action=send)` can still answer normally.
If the message tool is unavailable under the active tool policy, OpenClaw falls
back to automatic visible replies instead of silently suppressing the response.
`openclaw doctor` warns about this mismatch.
For direct chats and any other source event, use `messages.visibleReplies: "message_tool"` to apply the same tool-only visible-reply behavior globally. Internal WebChat direct turns default to automatic final-reply delivery so Pi and Codex receive the same visible-reply contract. Set `messages.visibleReplies: "message_tool"` to intentionally require `message(action=send)` for visible output. `messages.groupChat.visibleReplies` remains the more specific override for group/channel rooms.
This replaces the old pattern of forcing the model to answer `NO_REPLY` for most lurk-mode turns. In tool-only mode, the prompt does not define a `NO_REPLY` contract. Doing nothing visible simply means not calling the message tool.
Plugin-owned conversation bindings are the exception. Once a plugin binds a thread and claims the inbound turn, the plugin's returned reply is the visible binding response; it does not need `message(action=send)`. That reply is plugin runtime output, not private model final text.
This replaces the old pattern of forcing the model to answer `NO_REPLY` for most lurk-mode turns. In tool-only mode, doing nothing visible simply means not calling the message tool.
Typing indicators are still sent for direct group requests. Ambient always-on room events, when enabled, stay strict and quiet unless the agent calls the message tool.
@@ -363,91 +358,10 @@ Replying to a bot message counts as an implicit mention when the channel support
}
```
## Scope configured mention patterns
Configured `mentionPatterns` are regex fallback triggers. Use them when the
platform does not expose a native bot mention, or when you want plain text such
as `openclaw:` to count as a mention. Native platform mentions are separate:
when Discord, Slack, Telegram, Matrix, or another channel can prove the message
explicitly mentioned the bot, that native mention still triggers even if
configured regex patterns are denied.
By default, configured mention patterns apply everywhere that channel passes
provider and conversation facts into mention detection. To keep broad patterns
from waking the agent in every group, scope them per channel with
`channels.<channel>.mentionPatterns`.
Use `mode: "deny"` when regex mention patterns should be off by default for a
channel, then opt in specific rooms with `allowIn`:
```json5
{
messages: {
groupChat: {
mentionPatterns: ["\\bopenclaw\\b", "\\bops bot\\b"],
},
},
channels: {
slack: {
mentionPatterns: {
mode: "deny",
allowIn: ["C0123OPS"],
},
},
},
}
```
Use the default `mode: "allow"` (or omit `mode`) when regex mention patterns
should apply broadly, then turn them off in noisy rooms with `denyIn`:
```json5
{
messages: {
groupChat: {
mentionPatterns: ["\\bopenclaw\\b"],
},
},
channels: {
telegram: {
mentionPatterns: {
denyIn: ["-1001234567890", "-1001234567890:topic:42"],
},
},
},
}
```
Policy resolution:
| Field | Effect |
| --------------- | --------------------------------------------------------------------------------------------------------------------- |
| `mode: "allow"` | Regex mention patterns are enabled unless the conversation ID is in `denyIn`. This is the default. |
| `mode: "deny"` | Regex mention patterns are disabled unless the conversation ID is in `allowIn`. |
| `allowIn` | Conversation IDs where regex mention patterns are enabled in deny mode. |
| `denyIn` | Conversation IDs where regex mention patterns are disabled. `denyIn` wins over `allowIn` if both include the same ID. |
Supported scoped regex policy today:
| Channel | IDs used in `allowIn` / `denyIn` |
| -------- | ------------------------------------------------------------ |
| Discord | Discord channel IDs. |
| Matrix | Matrix room IDs. |
| Slack | Slack channel IDs. |
| Telegram | Group chat IDs, or `chatId:topic:threadId` for forum topics. |
| WhatsApp | WhatsApp conversation IDs such as `123@g.us`. |
Account-level channel configs can set the same policy under
`channels.<channel>.accounts.<accountId>.mentionPatterns` when that channel
supports multiple accounts. Account policy takes precedence over the top-level
channel policy for that account.
<AccordionGroup>
<Accordion title="Mention gating notes">
- `mentionPatterns` are case-insensitive safe regex patterns; invalid patterns and unsafe nested-repetition forms are ignored.
- Surfaces that provide explicit mentions still pass; configured regex patterns are a fallback.
- `channels.<channel>.mentionPatterns.mode: "deny"` disables configured mention patterns by default for that channel; opt selected conversations back in with `allowIn`.
- `channels.<channel>.mentionPatterns.denyIn` disables configured mention patterns for specific conversation IDs while native platform @mentions still pass.
- Surfaces that provide explicit mentions still pass; patterns are a fallback.
- Per-agent override: `agents.list[].groupChat.mentionPatterns` (useful when multiple agents share a group).
- Mention gating is only enforced when mention detection is possible (native mentions or `mentionPatterns` are configured).
- Allowlisting a group or sender does not disable mention gating; set that group's `requireMention` to `false` when all messages should trigger.

View File

@@ -41,7 +41,6 @@ Text is supported everywhere; media and reactions vary by channel.
- [QQ Bot](/channels/qqbot) - QQ Bot API; private chat, group chat, and rich media (bundled plugin).
- [Signal](/channels/signal) - signal-cli; privacy-focused.
- [Slack](/channels/slack) - Bolt SDK; workspace apps.
- [SMS](/channels/sms) - Twilio-backed SMS through the Gateway webhook (bundled plugin).
- [Synology Chat](/channels/synology-chat) - Synology NAS Chat via outgoing+incoming webhooks (bundled plugin).
- [Telegram](/channels/telegram) - Bot API via grammY; supports groups.
- [Tlon](/channels/tlon) - Urbit-based messenger (bundled plugin).

View File

@@ -915,10 +915,9 @@ Uploaded files are stored in a `/OpenClawShared/` folder in the configured Share
OpenClaw sends Teams polls as Adaptive Cards (there is no native Teams poll API).
- CLI: `openclaw message poll --channel msteams --target conversation:<id> ...`
- Votes are recorded by the gateway in OpenClaw plugin-state SQLite under `state/openclaw.sqlite`.
- Existing `msteams-polls.json` files are imported once when the MSTeams plugin starts.
- Votes are recorded by the gateway in `~/.openclaw/msteams-polls.json`.
- The gateway must stay online to record votes.
- Polls do not auto-post result summaries yet, and there is no supported poll-results CLI yet.
- Polls do not auto-post result summaries yet (inspect the store file if needed).
## Presentation cards

View File

@@ -1,380 +0,0 @@
---
summary: "Twilio SMS channel setup, access controls, and webhook configuration"
read_when:
- You want to connect OpenClaw to SMS through Twilio
- You need SMS webhook or allowlist setup
title: "SMS"
---
OpenClaw can receive and send SMS through a Twilio phone number or Messaging Service. The Gateway registers an inbound webhook route, validates Twilio request signatures by default, and sends replies back through Twilio's Messages API.
<CardGroup cols={3}>
<Card title="Pairing" icon="link" href="/channels/pairing">
Default DM policy for SMS is pairing.
</Card>
<Card title="Gateway security" icon="shield" href="/gateway/security">
Review webhook exposure and sender access controls.
</Card>
<Card title="Channel troubleshooting" icon="wrench" href="/channels/troubleshooting">
Cross-channel diagnostics and repair playbooks.
</Card>
</CardGroup>
## Before you begin
You need:
- A Twilio account with an SMS-capable phone number, or a Twilio Messaging Service.
- The Twilio Account SID and Auth Token.
- A public HTTPS URL that reaches your OpenClaw Gateway.
- A sender policy choice: `pairing` for private use, `allowlist` for preapproved phone numbers, or `open` only for intentionally public SMS access.
Use one Twilio number for both SMS and Voice Call if the number has both capabilities. Configure the SMS webhook and Voice webhook separately in Twilio; this page only covers the SMS webhook.
## Quick Setup
<Steps>
<Step title="Create or choose a Twilio sender">
In Twilio, open **Phone Numbers > Manage > Active numbers** and choose an SMS-capable number. Save:
- Account SID, for example `ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
- Auth Token
- Sender phone number, for example `+15551234567`
If you use a Messaging Service instead of a fixed sender number, save the Messaging Service SID, for example `MGxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`.
</Step>
<Step title="Configure the SMS channel">
Save this as `sms.patch.json5` and change the placeholders:
```json5
{
channels: {
sms: {
enabled: true,
accountSid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authToken: "twilio-auth-token",
fromNumber: "+15551234567",
publicWebhookUrl: "https://gateway.example.com/webhooks/sms",
dmPolicy: "pairing",
},
},
}
```
Apply it:
```bash
openclaw config patch --file ./sms.patch.json5 --dry-run
openclaw config patch --file ./sms.patch.json5
```
</Step>
<Step title="Point Twilio at the Gateway webhook">
In the Twilio phone number settings, open **Messaging** and set **A message comes in** to:
```text
https://gateway.example.com/webhooks/sms
```
Use HTTP `POST`. The default local path is `/webhooks/sms`; change `channels.sms.webhookPath` if you need a different route.
</Step>
<Step title="Expose the exact SMS webhook path">
Your public URL must route the SMS path to the Gateway process. If you use Tailscale Funnel for local testing, expose `/webhooks/sms` explicitly:
```bash
tailscale funnel --bg --set-path /webhooks/sms http://127.0.0.1:<gateway-port>/webhooks/sms
tailscale funnel status
```
Voice Call and SMS use separate webhook paths. If the same Twilio number handles both, keep both routes configured in Twilio and in your tunnel.
</Step>
<Step title="Start the Gateway and approve first sender">
```bash
openclaw gateway
```
Send a text message to the Twilio number. The first message creates a pairing request. Approve it:
```bash
openclaw pairing list sms
openclaw pairing approve sms <CODE>
```
Pairing codes expire after 1 hour.
</Step>
</Steps>
## Configuration Examples
### Config file
Use config-file setup when you want the channel definition to travel with the Gateway config:
```json5
{
channels: {
sms: {
enabled: true,
accountSid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authToken: "twilio-auth-token",
fromNumber: "+15551234567",
publicWebhookUrl: "https://gateway.example.com/webhooks/sms",
dmPolicy: "pairing",
},
},
}
```
### Environment variables
Use env setup for single-account deployments where secrets come from the host environment:
```bash
export TWILIO_ACCOUNT_SID="ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export TWILIO_AUTH_TOKEN="<twilio-auth-token>"
export TWILIO_PHONE_NUMBER="+15551234567"
export SMS_PUBLIC_WEBHOOK_URL="https://gateway.example.com/webhooks/sms"
```
Then enable the channel in config:
```json5
{
channels: {
sms: {
enabled: true,
dmPolicy: "pairing",
},
},
}
```
`TWILIO_SMS_FROM` is accepted as an alias for `TWILIO_PHONE_NUMBER`. Use `TWILIO_MESSAGING_SERVICE_SID` instead of a phone-number sender when Twilio should choose the sender from a Messaging Service.
### SecretRef auth token
`authToken` can be a SecretRef. Use this when the Gateway should resolve the Twilio Auth Token from the OpenClaw secrets runtime instead of storing plaintext config:
```json5
{
channels: {
sms: {
enabled: true,
accountSid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authToken: { source: "env", provider: "default", id: "TWILIO_AUTH_TOKEN" },
fromNumber: "+15551234567",
publicWebhookUrl: "https://gateway.example.com/webhooks/sms",
dmPolicy: "pairing",
},
},
}
```
The referenced environment variable or secret provider must be visible to the Gateway runtime. Restart managed Gateway processes after changing host environment variables.
### Allowlist-only private number
Use `allowlist` when only known phone numbers should be able to talk to the agent:
```json5
{
channels: {
sms: {
enabled: true,
accountSid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authToken: "twilio-auth-token",
fromNumber: "+15551234567",
publicWebhookUrl: "https://gateway.example.com/webhooks/sms",
dmPolicy: "allowlist",
allowFrom: ["+15557654321"],
},
},
}
```
### Messaging Service sender
Use `messagingServiceSid` instead of `fromNumber` when Twilio should choose the sender through a Messaging Service:
```json5
{
channels: {
sms: {
enabled: true,
accountSid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authToken: "twilio-auth-token",
messagingServiceSid: "MGxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
publicWebhookUrl: "https://gateway.example.com/webhooks/sms",
dmPolicy: "pairing",
},
},
}
```
If both `fromNumber` and `messagingServiceSid` are present after config and env resolution, `fromNumber` is used.
### Default outbound target
Set `defaultTo` when automation or agent-initiated delivery should have a default destination if a send flow omits an explicit target:
```json5
{
channels: {
sms: {
enabled: true,
accountSid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authToken: "twilio-auth-token",
fromNumber: "+15551234567",
defaultTo: "+15557654321",
publicWebhookUrl: "https://gateway.example.com/webhooks/sms",
},
},
}
```
## Access control
`channels.sms.dmPolicy` controls direct SMS access:
- `pairing` (default)
- `allowlist` (requires at least one sender in `allowFrom`)
- `open` (requires `allowFrom` to include `"*"`)
- `disabled`
`allowFrom` entries should be E.164 phone numbers such as `+15551234567`. `sms:` prefixes are accepted and normalized. For a private assistant, prefer `dmPolicy: "allowlist"` with explicit phone numbers.
## Sending SMS
Outbound SMS targets use the `sms:` service prefix with the SMS channel selected:
```bash
openclaw message send --channel sms --target sms:+15551234567 --message "hello"
```
When channel selection is implicit, `twilio-sms:+15551234567` selects this channel without taking over the existing channel-owned `sms:` service prefix used by iMessage.
```bash
openclaw message send --target twilio-sms:+15551234567 --message "hello"
```
The CLI requires an explicit `--target`. `defaultTo` is for automation and agent-initiated delivery paths where the target can be resolved from channel config.
Agent replies from inbound SMS conversations automatically go back to the sender through the configured Twilio sender.
SMS output is plain text. OpenClaw strips markdown, flattens fenced code blocks, preserves readable links, and chunks long replies before sending them through Twilio.
## Verify Setup
After the Gateway starts:
1. Confirm the Gateway log shows the SMS webhook route.
2. Run a Twilio-side probe:
```bash
openclaw channels capabilities --channel sms
openclaw channels status --channel sms --probe --json
```
3. Send an SMS to the Twilio number from your phone.
4. Run `openclaw pairing list sms`.
5. Approve the pairing code with `openclaw pairing approve sms <CODE>`.
6. Send another SMS and confirm the agent replies.
For outbound-only testing, use:
```bash
openclaw message send --channel sms --target sms:+15557654321 --message "OpenClaw SMS test"
```
### End-to-end test from macOS iMessage/SMS
On a Mac that can send carrier SMS through Messages, you can use `imsg` to drive the sender side without touching your phone:
```bash
imsg send --to "+15551234567" --service sms --text "OpenClaw SMS E2E $(date -u +%Y%m%dT%H%M%SZ)" --json
openclaw pairing list sms
openclaw pairing approve sms <CODE>
imsg send --to "+15551234567" --service sms --text "reply exactly SMS pong" --json
```
The first message should create a pairing request. The second message should receive the agent reply through Twilio.
## Webhook security
By default, OpenClaw validates `X-Twilio-Signature` using `publicWebhookUrl` and `authToken`. Keep `publicWebhookUrl` byte-for-byte aligned with the URL configured in Twilio, including scheme, host, path, and query string.
For local tunnel testing only, you can set:
```json5
{
channels: {
sms: {
dangerouslyDisableSignatureValidation: true,
},
},
}
```
Do not use disabled signature validation on a public Gateway.
## Multi-account config
Use `accounts` when you operate more than one Twilio number:
```json5
{
channels: {
sms: {
accounts: {
support: {
enabled: true,
accountSid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
authToken: "twilio-auth-token",
fromNumber: "+15551234567",
publicWebhookUrl: "https://gateway.example.com/webhooks/sms/support",
webhookPath: "/webhooks/sms/support",
dmPolicy: "allowlist",
allowFrom: ["+15557654321"],
},
},
},
},
}
```
Each account should use a distinct `webhookPath`.
## Troubleshooting
### Twilio returns 403 or OpenClaw rejects the webhook
Check that `publicWebhookUrl` exactly matches the URL configured in Twilio, including scheme, host, path, and query string. Twilio signs the public URL string, so proxy rewrites and alternate hostnames can break signature validation.
### No pairing request appears
Check the Twilio number's **Messaging** webhook URL and method. It must point to the SMS webhook URL and use `POST`. Also confirm the Gateway is reachable from the public internet or through your tunnel.
If the Twilio message log shows error `11200`, Twilio accepted the inbound SMS but could not reach your webhook. Check:
- Twilio **Messaging > A message comes in** points at `publicWebhookUrl`.
- The method is `POST`.
- The tunnel or reverse proxy exposes the exact `webhookPath`; for Tailscale Funnel, run `tailscale funnel status` and confirm `/webhooks/sms` is listed.
- `publicWebhookUrl` uses the same scheme, host, path, and query string Twilio sends, so signature validation can reproduce the signed URL.
### Outbound sends fail
Confirm `accountSid`, `authToken`, and either `fromNumber` or `messagingServiceSid` are resolved. If you use a trial Twilio account, the destination number may need to be verified in Twilio before outbound SMS will send.
### Messages arrive but the agent does not answer
Check `dmPolicy` and `allowFrom`. With the default `pairing` policy, the sender must be approved before normal agent turns are processed.

View File

@@ -587,7 +587,7 @@ curl "https://api.telegram.org/bot<bot_token>/getUpdates"
- `sendMessage` (`to`, `content`, optional `mediaUrl`, `replyToMessageId`, `messageThreadId`)
- `react` (`chatId`, `messageId`, `emoji`)
- `deleteMessage` (`chatId`, `messageId`)
- `editMessage` (`chatId`, `messageId`, `content` or `caption`, optional `presentation` inline buttons; button-only edits update reply markup)
- `editMessage` (`chatId`, `messageId`, `content`)
- `createForumTopic` (`chatId`, `name`, optional `iconColor`, `iconCustomEmojiId`)
Channel message actions expose ergonomic aliases (`send`, `react`, `delete`, `edit`, `sticker`, `sticker-search`, `topic-create`).

View File

@@ -566,13 +566,6 @@ The repo wrapper refuses a stale Crabbox binary that does not advertise `blacksm
node scripts/crabbox-wrapper.mjs run --provider blacksmith-testbox --timing-json --shell -- "pnpm test <path-or-filter>"
```
Blacksmith-backed runs require Crabbox 0.22.0 or newer so the wrapper gets the current Testbox sync, queue, and cleanup behavior. When using the sibling checkout, rebuild the ignored local binary before timing or proof work:
```bash
version="$(git -C ../crabbox describe --tags --always --dirty | sed 's/^v//')" \
&& go build -C ../crabbox -trimpath -ldflags "-s -w -X github.com/openclaw/crabbox/internal/cli.version=${version}" -o bin/crabbox ./cmd/crabbox
```
Changed gate:
```bash

View File

@@ -205,7 +205,6 @@ File + dialog helpers:
```bash
openclaw browser upload /tmp/openclaw/uploads/file.pdf --ref <ref>
openclaw browser upload media://inbound/file.pdf --ref <ref>
openclaw browser waitfordownload
openclaw browser download <ref> report.pdf
openclaw browser dialog --accept
@@ -216,10 +215,6 @@ Managed Chrome profiles save ordinary click-triggered downloads into the OpenCla
downloads directory (`/tmp/openclaw/downloads` by default, or the configured temp
root). Use `waitfordownload` or `download` when the agent needs to wait for a
specific file and return its path; those explicit waiters own the next download.
Uploads accept files from the OpenClaw temp uploads root and OpenClaw-managed
inbound media, including `media://inbound/<id>` and sandbox-relative
`media/inbound/<id>` references. Nested media refs, traversal, and arbitrary
local paths remain rejected.
When an action opens a modal dialog, the action response returns
`blockedByDialog` with `browserState.dialogs.pending`; pass `--dialog-id` to
answer it directly. Dialogs handled outside OpenClaw appear under

View File

@@ -118,7 +118,7 @@ Skipped runs are tracked separately from execution errors. They do not affect re
For isolated jobs that target a local configured model provider, cron runs a lightweight provider preflight before starting the agent turn. Loopback, private-network, and `.local` `api: "ollama"` providers are probed at `/api/tags`; local OpenAI-compatible providers such as vLLM, SGLang, and LM Studio are probed at `/models`. If the endpoint is unreachable, the run is recorded as `skipped` and retried on a later schedule; matching dead endpoints are cached for 5 minutes to avoid many jobs hammering the same local server.
Note: cron jobs, pending runtime state, and run history live in the shared SQLite state database. Legacy `jobs.json`, `jobs-state.json`, and `runs/*.jsonl` files are imported once and renamed with a `.migrated` suffix. After import, edit schedules with `openclaw cron add|edit|remove` instead of editing JSON files.
Note: cron job definitions live in `jobs.json`, while pending runtime state lives in `jobs-state.json`. If `jobs.json` is edited externally, the Gateway reloads changed schedules and clears stale pending slots; formatting-only rewrites do not clear the pending slot. Malformed job rows are removed from active `jobs.json` at load time after their raw contents are copied to `jobs-quarantine.json`.
### Manual runs
@@ -199,12 +199,12 @@ Cron does not classify final-output prose or approval-looking refusal phrases as
Retention and pruning are controlled in config:
- `cron.sessionRetention` (default `24h`) prunes completed isolated run sessions.
- `cron.runLog.keepLines` prunes retained SQLite run-history rows per job. `cron.runLog.maxBytes` remains accepted for compatibility with older file-backed run logs.
- `cron.runLog.maxBytes` and `cron.runLog.keepLines` prune `~/.openclaw/cron/runs/<jobId>.jsonl`.
## Migrating older jobs
<Note>
If you have cron jobs from before the current delivery and store format, run `openclaw doctor --fix`. Doctor normalizes legacy cron fields (`jobId`, `schedule.cron`, top-level delivery fields including legacy `threadId`, payload `provider` delivery aliases) and migrates `notify: true` webhook fallback jobs from `cron.webhook` to explicit webhook delivery. Jobs that already announce to a chat keep that delivery and get a completion webhook destination.
If you have cron jobs from before the current delivery and store format, run `openclaw doctor --fix`. Doctor normalizes legacy cron fields (`jobId`, `schedule.cron`, top-level delivery fields including legacy `threadId`, payload `provider` delivery aliases) and migrates simple `notify: true` webhook fallback jobs to explicit webhook delivery when `cron.webhook` is configured.
</Note>
## Common edits

View File

@@ -35,7 +35,7 @@ Use the setup commands by intent:
| Pairing and channels | [`pairing`](/cli/pairing) · [`qr`](/cli/qr) · [`channels`](/cli/channels) |
| Security and plugins | [`security`](/cli/security) · [`secrets`](/cli/secrets) · [`skills`](/cli/skills) · [`plugins`](/cli/plugins) · [`proxy`](/cli/proxy) |
| Legacy aliases | [`daemon`](/cli/daemon) (gateway service) · [`clawbot`](/cli/clawbot) (namespace) |
| Plugins (optional) | [`path`](/cli/path) · [`policy`](/cli/policy) · [`voicecall`](/cli/voicecall) · [`workboard`](/cli/workboard) (if installed) |
| Plugins (optional) | [`path`](/cli/path) · [`policy`](/cli/policy) · [`voicecall`](/cli/voicecall) (if installed) |
## Global flags
@@ -124,11 +124,6 @@ openclaw [--dev] [--profile <name>] <command>
disable
doctor
marketplace list
workboard
list
create
show
dispatch
memory
status
index
@@ -373,8 +368,7 @@ openclaw [--dev] [--profile <name>] <command>
terminal (alias: tui --local)
```
Plugins can add additional top-level commands, such as
[`openclaw workboard`](/cli/workboard) or `openclaw voicecall`.
Plugins can add additional top-level commands (for example `openclaw voicecall`).
</Accordion>

View File

@@ -11,32 +11,15 @@ sidebarTitle: "MCP"
`openclaw mcp` has two jobs:
- run OpenClaw as an MCP server with `openclaw mcp serve`
- manage OpenClaw-owned outbound MCP server definitions with `list`, `show`, `status`, `doctor`, `probe`, `add`, `set`, `configure`, `tools`, `login`, `logout`, `reload`, and `unset`
- manage OpenClaw-owned outbound MCP server definitions with `list`, `show`, `set`, and `unset`
In other words:
- `serve` is OpenClaw acting as an MCP server
- the other subcommands are OpenClaw acting as an MCP client-side registry for MCP servers its runtimes may consume later
- `list` / `show` / `set` / `unset` is OpenClaw acting as an MCP client-side registry for other MCP servers its runtimes may consume later
Use [`openclaw acp`](/cli/acp) when OpenClaw should host a coding harness session itself and route that runtime through ACP.
## Choose the right MCP path
OpenClaw has several MCP surfaces. Pick the one that matches who owns the agent runtime and who owns the tools.
| Goal | Use | Why |
| ------------------------------------------------------------------- | -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| Let an external MCP client read/send OpenClaw channel conversations | `openclaw mcp serve` | OpenClaw is the MCP server and exposes Gateway-backed conversations over stdio. |
| Save third-party MCP servers for OpenClaw-managed agent runs | `openclaw mcp add`, `set`, `configure`, `tools`, `login` | OpenClaw is the MCP client-side registry and later projects those servers into eligible runtimes. |
| Check a saved server without running an agent turn | `openclaw mcp status`, `doctor`, `probe` | `status` and `doctor` inspect config; `probe` opens a live MCP connection and lists capabilities. |
| Edit MCP config from a browser | Control UI `/mcp` | The page shows inventory, enablement, OAuth/filter summaries, command hints, and a scoped `mcp` editor. |
| Give Codex app-server a scoped native MCP server | `mcp.servers.<name>.codex` | The `codex` block only affects Codex app-server thread projection and is stripped before native config handoff. |
| Run ACP-hosted harness sessions | [`openclaw acp`](/cli/acp) and [ACP Agents](/tools/acp-agents-setup) | ACP bridge mode does not accept per-session MCP server injection; configure gateway/plugin bridges instead. |
<Tip>
If you are not sure which path you need, start with `openclaw mcp status --verbose`. It shows what OpenClaw has saved without starting any MCP servers.
</Tip>
## OpenClaw as an MCP server
This is the `openclaw mcp serve` path.
@@ -365,8 +348,7 @@ For broader testing context, see [Testing](/help/testing).
## OpenClaw as an MCP client registry
This is the `openclaw mcp list`, `show`, `status`, `doctor`, `probe`, `add`, `set`,
`configure`, `tools`, `login`, `logout`, `reload`, and `unset` path.
This is the `openclaw mcp list`, `show`, `set`, and `unset` path.
These commands do not expose OpenClaw over MCP. They manage OpenClaw-owned MCP server definitions under `mcp.servers` in OpenClaw config.
@@ -375,23 +357,10 @@ Those saved definitions are for runtimes that OpenClaw launches or configures la
<AccordionGroup>
<Accordion title="Important behavior">
- these commands only read or write OpenClaw config
- `status`, `list`, `show`, `doctor` without `--probe`, `set`, `configure`, `tools`, `logout`, `reload`, and `unset` do not connect to the target MCP server
- `login` performs the MCP OAuth network flow for the configured HTTP server and saves the resulting local credentials
- `status --verbose` prints resolved transport, auth, timeout, filter, and parallel-tool-call hints without connecting
- `doctor` checks saved definitions for local setup problems such as missing stdio commands, invalid working directories, missing TLS files, disabled servers, literal sensitive header/env values, and incomplete OAuth authorization
- `doctor --probe` adds the same live connection proof as `probe` after static checks pass
- `probe` connects to the selected server or all configured servers, lists tools, and reports capabilities/diagnostics
- `add` builds a definition from flags and probes before saving unless `--no-probe` is set or OAuth authorization is needed first
- they do not connect to the target MCP server
- they do not validate whether the command, URL, or remote transport is reachable right now
- runtime adapters decide which transport shapes they actually support at execution time
- `enabled: false` keeps a server saved but excludes it from embedded runtime discovery
- `timeout` and `connectTimeout` set per-server request and connection timeouts in seconds
- `supportsParallelToolCalls: true` marks servers that adapters can call concurrently
- HTTP servers can use static headers, OAuth login, TLS verification control, and mTLS certificate/key paths
- embedded OpenClaw exposes configured MCP tools in normal `coding` and `messaging` tool profiles; `minimal` still hides them, and `tools.deny: ["bundle-mcp"]` disables them explicitly
- per-server `toolFilter.include` and `toolFilter.exclude` filter discovered MCP tools before they become OpenClaw tools
- servers that advertise resources or prompts also expose utility tools for listing/reading resources and listing/fetching prompts; those generated utility names (`resources_list`, `resources_read`, `prompts_list`, `prompts_get`) use the same include/exclude filter
- dynamic MCP tool-list changes invalidate the cached catalog for that session; the next discovery/use refreshes from the server
- repeated MCP tool request/protocol failures pause that server briefly so one broken server does not consume the whole turn
- session-scoped bundled MCP runtimes are reaped after `mcp.sessionIdleTtlMs` milliseconds of idle time (default 10 minutes; set `0` to disable) and one-shot embedded runs clean them up at run end
</Accordion>
@@ -418,32 +387,14 @@ Commands:
- `openclaw mcp list`
- `openclaw mcp show [name]`
- `openclaw mcp status [--verbose]`
- `openclaw mcp doctor [name] [--probe]`
- `openclaw mcp probe [name]`
- `openclaw mcp add <name> [flags]`
- `openclaw mcp set <name> <json>`
- `openclaw mcp configure <name> [flags]`
- `openclaw mcp tools <name> [--include csv] [--exclude csv] [--clear]`
- `openclaw mcp login <name> [--code code]`
- `openclaw mcp logout <name>`
- `openclaw mcp reload`
- `openclaw mcp unset <name>`
Notes:
- `list` sorts server names.
- `show` without a name prints the full configured MCP server object.
- `status` classifies configured transports without connecting. `--verbose` includes resolved launch, timeout, OAuth, filter, and parallel-call details.
- `doctor` performs static checks without connecting. Add `--probe` when the command should also verify that enabled servers connect.
- `probe` connects and reports tool counts, resources/prompts support, list-change support, and diagnostics.
- `add` accepts stdio flags such as `--command`, `--arg`, `--env`, and `--cwd`, or HTTP flags such as `--url`, `--transport`, `--header`, `--auth oauth`, TLS, timeout, and tool-selection flags.
- `set` expects one JSON object value on the command line.
- `configure` updates enablement, tool filters, timeouts, OAuth, TLS, and parallel-tool-call hints without replacing the whole server definition.
- `tools` updates per-server tool filters. Include/exclude entries are MCP tool names and simple `*` globs.
- `login` runs the OAuth flow for HTTP servers configured with `auth: "oauth"`. The first run prints an authorization URL; rerun with `--code` after approval.
- `logout` clears stored OAuth credentials for the named server without removing the saved server definition.
- `reload` disposes cached in-process MCP runtimes. Gateway or agent processes in another process still need their own reload or restart path.
- Use `transport: "streamable-http"` for Streamable HTTP MCP servers. `openclaw mcp set` also normalizes CLI-native `type: "http"` to the same canonical config shape for compatibility.
- `unset` fails if the named server does not exist.
@@ -452,180 +403,11 @@ Examples:
```bash
openclaw mcp list
openclaw mcp show context7 --json
openclaw mcp status --verbose
openclaw mcp doctor --probe
openclaw mcp probe context7 --json
openclaw mcp add memory --command npx --arg -y --arg @modelcontextprotocol/server-memory
openclaw mcp set context7 '{"command":"uvx","args":["context7-mcp"]}'
openclaw mcp tools context7 --include 'resolve-library-id,get-library-docs'
openclaw mcp set docs '{"url":"https://mcp.example.com","transport":"streamable-http"}'
openclaw mcp configure docs --timeout 20 --connect-timeout 5 --include 'search,read_*'
openclaw mcp configure docs --auth oauth --oauth-scope 'docs.read'
openclaw mcp login docs
openclaw mcp logout docs
openclaw mcp unset context7
```
### Common server recipes
These examples save server definitions only. Run `openclaw mcp doctor --probe` afterward to prove that the server starts and exposes tools.
<Tabs>
<Tab title="Filesystem">
```bash
openclaw mcp add files \
--command npx \
--arg -y \
--arg @modelcontextprotocol/server-filesystem \
--arg "$HOME/Documents" \
--include 'read_file,list_directory,search_files'
openclaw mcp doctor files --probe
```
Scope filesystem servers to the smallest directory tree that the agent should read or edit.
</Tab>
<Tab title="Memory">
```bash
openclaw mcp add memory \
--command npx \
--arg -y \
--arg @modelcontextprotocol/server-memory
openclaw mcp probe memory --json
```
Use a tool filter if the server exposes write tools that should not be available to normal agents.
</Tab>
<Tab title="Local script">
```bash
openclaw mcp add local-tools \
--command node \
--arg ./dist/mcp-server.js \
--cwd /srv/openclaw-tools \
--env API_BASE=https://internal.example
openclaw mcp status --verbose
```
`doctor` checks that `cwd` exists and that the command resolves from the configured environment.
</Tab>
<Tab title="Remote HTTP">
```bash
openclaw mcp add docs \
--url https://mcp.example.com/mcp \
--transport streamable-http \
--auth oauth \
--oauth-scope docs.read \
--timeout 20 \
--connect-timeout 5 \
--include 'search,read_*'
openclaw mcp doctor docs --probe
```
Use OAuth when the remote server supports it. If the server requires static headers, avoid committing literal bearer tokens.
</Tab>
<Tab title="Desktop/CUA">
```bash
openclaw mcp set cua-driver '{"command":"cua-driver","args":["mcp"]}'
openclaw mcp tools cua-driver --include 'list_apps,observe,click,type'
openclaw mcp doctor cua-driver --probe
```
Direct desktop-control servers inherit the permissions of the process they launch. Use narrow tool filters and OS-level permission prompts.
</Tab>
</Tabs>
### JSON output shapes
Use `--json` for scripts and dashboards. Field sets can grow over time, so consumers should ignore unknown keys.
<AccordionGroup>
<Accordion title="status --json">
```json
{
"path": "/home/user/.openclaw/openclaw.json",
"servers": [
{
"name": "docs",
"configured": true,
"enabled": true,
"ok": true,
"transport": "streamable-http",
"launch": "streamable-http https://mcp.example.com/mcp",
"auth": "oauth",
"authStatus": {
"hasTokens": true,
"hasClientInformation": true,
"hasCodeVerifier": false,
"hasDiscoveryState": true,
"hasLastAuthorizationUrl": false
},
"requestTimeoutMs": 20000,
"connectionTimeoutMs": 5000,
"toolFilter": {
"include": ["search", "read_*"],
"exclude": []
},
"supportsParallelToolCalls": true
}
]
}
```
</Accordion>
<Accordion title="doctor --json">
```json
{
"ok": false,
"path": "/home/user/.openclaw/openclaw.json",
"servers": [
{
"name": "docs",
"ok": false,
"issues": [
{
"level": "error",
"message": "OAuth credentials are not authorized; run openclaw mcp login docs"
}
]
}
]
}
```
`doctor --json` exits nonzero when any enabled checked server has an error. Warnings are reported but do not make the command fail by themselves.
</Accordion>
<Accordion title="probe --json">
```json
{
"path": "/home/user/.openclaw/openclaw.json",
"generatedAt": "2026-05-31T09:00:00.000Z",
"servers": {
"docs": {
"launch": "streamable-http https://mcp.example.com/mcp",
"tools": 2,
"resources": true,
"prompts": false,
"listChanged": {
"tools": true,
"resources": false,
"prompts": false
}
}
},
"tools": ["docs__read_page", "docs__search"],
"diagnostics": []
}
```
`probe` opens a live MCP client session. Use it for reachability and capability proof, not for static config audits.
</Accordion>
</AccordionGroup>
Example config shape:
```json
@@ -638,21 +420,7 @@ Example config shape:
},
"docs": {
"url": "https://mcp.example.com",
"transport": "streamable-http",
"timeout": 20,
"connectTimeout": 5,
"supportsParallelToolCalls": true,
"auth": "oauth",
"oauth": {
"scope": "docs.read"
},
"sslVerify": true,
"clientCert": "/path/to/client.crt",
"clientKey": "/path/to/client.key",
"toolFilter": {
"include": ["search_*"],
"exclude": ["admin_*"]
}
"transport": "streamable-http"
}
}
}
@@ -682,17 +450,11 @@ If your MCP server genuinely needs one of the blocked variables, set it on the g
Connects to a remote MCP server over HTTP Server-Sent Events.
| Field | Description |
| ------------------------------ | ---------------------------------------------------------------- |
| `url` | HTTP or HTTPS URL of the remote server (required) |
| `headers` | Optional key-value map of HTTP headers (for example auth tokens) |
| `connectionTimeoutMs` | Per-server connection timeout in ms (optional) |
| `connectTimeout` | Per-server connection timeout in seconds (optional) |
| `timeout` / `requestTimeoutMs` | Per-server MCP request timeout in seconds or ms |
| `auth: "oauth"` | Use MCP OAuth token storage and `openclaw mcp login` |
| `sslVerify` | Set false only for explicitly trusted private HTTPS endpoints |
| `clientCert` / `clientKey` | mTLS client certificate and key paths |
| `supportsParallelToolCalls` | Hint that concurrent calls are safe for this server |
| Field | Description |
| --------------------- | ---------------------------------------------------------------- |
| `url` | HTTP or HTTPS URL of the remote server (required) |
| `headers` | Optional key-value map of HTTP headers (for example auth tokens) |
| `connectionTimeoutMs` | Per-server connection timeout in ms (optional) |
Example:
@@ -702,8 +464,6 @@ Example:
"servers": {
"remote-tools": {
"url": "https://mcp.example.com",
"auth": "oauth",
"timeout": 20,
"headers": {
"Authorization": "Bearer <token>"
}
@@ -713,76 +473,18 @@ Example:
}
```
Sensitive values in `url` (userinfo) and `headers` are redacted in logs and status output. `openclaw mcp doctor` warns when sensitive-looking `headers` or `env` entries contain literal values, so operators can move those values out of committed config.
### OAuth workflow
OAuth is for HTTP MCP servers that advertise the MCP OAuth flow. Static `Authorization` headers are ignored for a server while `auth: "oauth"` is enabled.
<Steps>
<Step title="Save the server">
Add or update the server with `auth: "oauth"` and any optional OAuth metadata.
```bash
openclaw mcp set docs '{"url":"https://mcp.example.com/mcp","transport":"streamable-http","auth":"oauth","oauth":{"scope":"docs.read"}}'
```
</Step>
<Step title="Start login">
Run login to create the authorization request.
```bash
openclaw mcp login docs
```
OpenClaw prints the authorization URL and stores temporary OAuth verifier state under the OpenClaw state directory.
</Step>
<Step title="Finish with the code">
After approving in the browser, pass the returned code back to OpenClaw.
```bash
openclaw mcp login docs --code abc123
```
</Step>
<Step title="Check authorization">
Use status or doctor to confirm that tokens are present.
```bash
openclaw mcp status --verbose
openclaw mcp doctor docs --probe
```
</Step>
<Step title="Clear credentials">
Logout removes stored OAuth credentials but keeps the saved server definition.
```bash
openclaw mcp logout docs
```
</Step>
</Steps>
If the provider rotates tokens or the authorization state gets stuck, run `openclaw mcp logout <name>`, then repeat `login`. `logout` can clear credentials for a saved HTTP server even after `auth: "oauth"` has been removed from config, as long as the server name and URL still identify the credential store entry.
Sensitive values in `url` (userinfo) and `headers` are redacted in logs and status output.
### Streamable HTTP transport
`streamable-http` is an additional transport option alongside `sse` and `stdio`. It uses HTTP streaming for bidirectional communication with remote MCP servers.
| Field | Description |
| ------------------------------ | -------------------------------------------------------------------------------------- |
| `url` | HTTP or HTTPS URL of the remote server (required) |
| `transport` | Set to `"streamable-http"` to select this transport; when omitted, OpenClaw uses `sse` |
| `headers` | Optional key-value map of HTTP headers (for example auth tokens) |
| `connectionTimeoutMs` | Per-server connection timeout in ms (optional) |
| `connectTimeout` | Per-server connection timeout in seconds (optional) |
| `timeout` / `requestTimeoutMs` | Per-server MCP request timeout in seconds or ms |
| `auth: "oauth"` | Use MCP OAuth token storage and `openclaw mcp login` |
| `sslVerify` | Set false only for explicitly trusted private HTTPS endpoints |
| `clientCert` / `clientKey` | mTLS client certificate and key paths |
| `supportsParallelToolCalls` | Hint that concurrent calls are safe for this server |
| Field | Description |
| --------------------- | -------------------------------------------------------------------------------------- |
| `url` | HTTP or HTTPS URL of the remote server (required) |
| `transport` | Set to `"streamable-http"` to select this transport; when omitted, OpenClaw uses `sse` |
| `headers` | Optional key-value map of HTTP headers (for example auth tokens) |
| `connectionTimeoutMs` | Per-server connection timeout in ms (optional) |
OpenClaw config uses `transport: "streamable-http"` as the canonical spelling. CLI-native MCP `type: "http"` values are accepted when saved through `openclaw mcp set` and repaired by `openclaw doctor --fix` in existing config, but `transport` is what embedded OpenClaw consumes directly.
@@ -795,8 +497,7 @@ Example:
"streaming-tools": {
"url": "https://mcp.example.com/stream",
"transport": "streamable-http",
"connectTimeout": 10,
"timeout": 30,
"connectionTimeoutMs": 10000,
"headers": {
"Authorization": "Bearer <token>"
}
@@ -807,32 +508,9 @@ Example:
```
<Note>
Registry commands do not start the channel bridge. Only `probe` and `doctor --probe` open a live MCP client session to prove the target server is reachable.
These commands manage saved config only. They do not start the channel bridge, open a live MCP client session, or prove the target server is reachable.
</Note>
## Control UI
The browser Control UI includes a dedicated MCP settings page at `/mcp`. It shows configured server counts, enabled/OAuth/filter summaries, per-server transport rows, enable/disable controls, common CLI commands, and a scoped editor for the `mcp` config section.
Use the page for operator edits and quick inventory. Use `openclaw mcp doctor --probe` or `openclaw mcp probe` when you need live server proof.
Operator workflow:
1. Open the Control UI and choose **MCP**.
2. Review the summary cards for total, enabled, OAuth, and filtered servers.
3. Use each server row for transport, auth, filter, timeout, and command hints.
4. Toggle enablement when you want to keep a definition but exclude it from runtime discovery.
5. Edit the scoped `mcp` config section for structural changes such as new servers, headers, TLS, OAuth metadata, or tool filters.
6. Choose **Save** to persist config only, or **Save & Publish** to apply through the Gateway config path.
7. Run `openclaw mcp doctor --probe` when you need live proof that the edited server starts and lists tools.
Notes:
- command snippets quote server names so unusual names remain copyable in a shell
- displayed URL-like values are redacted before rendering when they contain embedded credentials
- the page does not start MCP transports by itself
- active runtimes may need `openclaw mcp reload`, Gateway config publish, or process restart depending on which process owns the MCP clients
## Current limits
This page documents the bridge as shipped today.

View File

@@ -218,10 +218,6 @@ Target-side auth-required installs are reported on the affected plugin item with
Their explicit config entries are written disabled until you reauthorize and
enable them. Other install failures are item-scoped `error` results.
The native Codex plugin config also accepts first-party `openai-bundled` and
`openai-primary-runtime` marketplace identities, but migration does not
auto-discover or install them from source state.
If Codex app-server plugin inventory is unavailable during planning, migration
falls back to cached bundle advisory items instead of failing the whole
migration.
@@ -240,7 +236,7 @@ The bundled Hermes provider detects state at `~/.hermes` by default. Use `--from
- Memory config defaults for OpenClaw file memory, plus archive or manual-review items for external memory providers such as Honcho.
- Skills that include a `SKILL.md` file under `skills/<name>/`.
- Per-skill config values from `skills.config`.
- OpenCode OpenAI OAuth credentials from OpenCode `auth.json` when interactive credential migration is accepted, or when `--include-secrets` is set. Hermes `auth.json` OAuth entries are legacy state reported for manual OpenAI reauth or doctor repair.
- Supported OAuth credentials from Hermes `auth.json` and OpenCode OpenAI OAuth credentials from OpenCode `auth.json` when interactive credential migration is accepted, or when `--include-secrets` is set.
- Supported API keys and tokens from Hermes `.env` and OpenCode `auth.json` when interactive credential migration is accepted, or when `--include-secrets` is set.
### Supported `.env` keys

View File

@@ -193,7 +193,7 @@ specific configured agent store. The parent `--agent` flag is honored by
For OpenAI models, `--provider openai` defaults to ChatGPT/Codex account login.
Use `--method api-key` only when you want to add an OpenAI API-key profile,
usually as a backup for Codex subscription limits. Run `openclaw doctor --fix`
to migrate older legacy OpenAI Codex prefix auth/profile state to `openai`.
to migrate older `openai-codex` auth/profile state to `openai`.
Examples:

View File

@@ -326,8 +326,6 @@ Use `--link` to avoid copying a local directory (adds to `plugins.load.paths`):
openclaw plugins install -l ./my-plugin
```
Standalone plugin files must be listed in `plugins.load.paths` rather than placed directly in `~/.openclaw/extensions` or `<workspace>/.openclaw/extensions`. Those auto-discovered roots load plugin package or bundle directories, while top-level script files are treated as local helpers and skipped.
<Note>
`--force` is not supported with `--link` because linked installs reuse the source path instead of copying over a managed install target.

View File

@@ -47,20 +47,6 @@ Scope selection:
- `--store <path>`: explicit store path (cannot be combined with `--agent` or `--all-agents`)
- `--limit <n|all>`: max rows to output (default `100`; `all` restores full output)
Tail human-readable trajectory progress for stored sessions:
```bash
openclaw sessions tail
openclaw sessions tail --follow
openclaw sessions tail --session-key "agent:main:telegram:direct:123" --tail 25
openclaw sessions --agent work tail --follow
openclaw sessions --all-agents tail --follow
```
`openclaw sessions tail` renders recent trajectory JSONL events as compact progress lines. Without `--session-key`, it tails running sessions first, then the latest stored session. `--tail <count>` controls how many existing events print before follow mode; the default is `80`, and `0` starts at the current end. `--follow` keeps watching the selected trajectory files, including relocated files referenced by `<session>.trajectory-path.json`.
The progress view is intentionally conservative: prompt text, tool arguments, and tool result bodies are not printed. Tool calls show the tool name with `{...redacted...}`; tool results show status such as `ok`, `error`, or `done`; model completion lines show provider/model and terminal status.
Export a trajectory bundle for a stored session:
```bash
@@ -118,7 +104,7 @@ openclaw sessions cleanup --json
`openclaw sessions cleanup` uses `session.maintenance` settings from config:
- Scope note: `openclaw sessions cleanup` maintains session stores, transcripts, and trajectory sidecars. It does not prune cron run history, which is managed by `cron.runLog.keepLines` in [Cron configuration](/automation/cron-jobs#configuration) and explained in [Cron maintenance](/automation/cron-jobs#maintenance).
- Scope note: `openclaw sessions cleanup` maintains session stores, transcripts, and trajectory sidecars. It does not prune cron run logs (`cron/runs/<jobId>.jsonl`), which are managed by `cron.runLog.maxBytes` and `cron.runLog.keepLines` in [Cron configuration](/automation/cron-jobs#configuration) and explained in [Cron maintenance](/automation/cron-jobs#maintenance).
- Cleanup also prunes unreferenced primary transcripts, compaction checkpoints, and trajectory sidecars older than `session.maintenance.pruneAfter`; files still referenced by `sessions.json` are preserved.
- `--dry-run`: preview how many entries would be pruned/capped without writing.

View File

@@ -1,5 +1,5 @@
---
summary: "CLI reference for `openclaw skills` (search/install/update/verify/list/info/check/workshop)"
summary: "CLI reference for `openclaw skills` (search/install/update/verify/list/info/check)"
read_when:
- You want to see which skills are available and ready to run
- You want to search ClawHub or install skills from ClawHub, Git, or local directories
@@ -16,7 +16,6 @@ directories, verify ClawHub skills, and update ClawHub-tracked installs.
Related:
- Skills system: [Skills](/tools/skills)
- Skill Workshop: [Skill Workshop](/tools/skill-workshop)
- Skills config: [Skills config](/tools/skills-config)
- ClawHub installs: [ClawHub](/clawhub/cli)
@@ -54,14 +53,6 @@ openclaw skills info <name> --agent <id>
openclaw skills check
openclaw skills check --agent <id>
openclaw skills check --json
openclaw skills workshop propose-create --name "qa-check" --description "QA checklist" --proposal ./PROPOSAL.md
openclaw skills workshop propose-update qa-check --proposal ./PROPOSAL.md
openclaw skills workshop list
openclaw skills workshop inspect <proposal-id>
openclaw skills workshop revise <proposal-id> --proposal ./PROPOSAL.md
openclaw skills workshop apply <proposal-id>
openclaw skills workshop reject <proposal-id> --reason "Not reusable"
openclaw skills workshop quarantine <proposal-id> --reason "Needs security review"
```
`search`, `update`, and `verify` use ClawHub directly. `install <slug>` installs
@@ -125,31 +116,6 @@ Notes:
`--json`, that means the machine-readable payload stays on stdout for pipes
and scripts.
## Skill Workshop
`openclaw skills workshop` manages pending skill proposals in the selected
workspace. Proposals are not active skills until applied. For proposal storage,
support-file safeguards, Gateway methods, and approval policy, see
[Skill Workshop](/tools/skill-workshop).
```bash
openclaw skills workshop propose-create \
--name "qa-check" \
--description "Repeatable QA checklist" \
--proposal ./PROPOSAL.md
openclaw skills workshop propose-create \
--name "qa-check" \
--description "Repeatable QA checklist" \
--proposal-dir ./qa-check-proposal
openclaw skills workshop propose-update qa-check --proposal ./PROPOSAL.md
openclaw skills workshop list
openclaw skills workshop inspect <proposal-id>
openclaw skills workshop revise <proposal-id> --proposal ./PROPOSAL.md
openclaw skills workshop apply <proposal-id>
openclaw skills workshop reject <proposal-id> --reason "Duplicate"
openclaw skills workshop quarantine <proposal-id> --reason "Needs security review"
```
## Related
- [CLI reference](/cli)

View File

@@ -1,221 +0,0 @@
---
summary: "CLI reference for `openclaw workboard` cards, dispatch, and worker runs"
read_when:
- You want to inspect or create Workboard cards from the terminal
- You want to dispatch Workboard worker runs from the CLI
- You are debugging Workboard CLI or slash command behavior
title: "Workboard CLI"
---
`openclaw workboard` is the terminal surface for the bundled
[Workboard plugin](/plugins/workboard). It lets an operator list cards, create a
card, inspect one card, and ask the running Gateway to dispatch ready work into
subagent worker runs.
Enable the plugin before using the command:
```bash
openclaw plugins enable workboard
openclaw gateway restart
```
## Usage
```bash
openclaw workboard list [--board <id>] [--status <status>] [--json]
openclaw workboard create <title...> [--notes <text>] [--status <status>] [--priority <priority>] [--agent <id>] [--board <id>] [--labels <items>] [--json]
openclaw workboard show <id> [--json]
openclaw workboard dispatch [--url <url>] [--token <token>] [--timeout <ms>] [--json]
```
The command reads and writes the same plugin-owned SQLite database used by the
dashboard and Workboard agent tools. Card ids can be passed by full id or by an
unambiguous prefix when a command accepts a card id.
## `list`
```bash
openclaw workboard list
openclaw workboard list --board default --status ready
openclaw workboard list --json
```
Text output is compact:
```text
7f4a2c10 ready high default agent-a Fix stale worker heartbeat
```
Columns are id prefix, status, priority, board id, optional agent id, and title.
Flags:
| Flag | Purpose |
| ------------------- | ---------------------------------------- |
| `--board <id>` | Limit results to one board namespace |
| `--status <status>` | Limit results to one Workboard status |
| `--json` | Print the full card list as machine JSON |
## `create`
```bash
openclaw workboard create "Fix stale worker heartbeat" --priority high --labels bug,workboard
openclaw workboard create "Write Workboard docs" --status ready --agent docs-agent --board docs --notes "Cover CLI, slash command, dispatch, and SQLite state."
```
Flags:
| Flag | Purpose |
| ----------------------- | --------------------------------------- |
| `--notes <text>` | Initial card notes |
| `--status <status>` | Initial status, default `todo` |
| `--priority <priority>` | Priority, default `normal` |
| `--agent <id>` | Assign the card to an agent or owner id |
| `--board <id>` | Store the card on a board namespace |
| `--labels <items>` | Comma-separated labels |
| `--json` | Print the created card as machine JSON |
`create` writes directly to Workboard SQLite state. The card is immediately
visible in the Control UI Workboard tab and to Workboard tools.
## `show`
```bash
openclaw workboard show 7f4a2c10
openclaw workboard show 7f4a2c10 --json
```
Text output prints the compact card line and notes. JSON output returns the full
card record, including execution metadata, attempts, comments, links, proof,
artifacts, worker logs, protocol state, diagnostics, and automation metadata.
## `dispatch`
```bash
openclaw workboard dispatch
openclaw workboard dispatch --json
openclaw workboard dispatch --url http://127.0.0.1:18789 --token "$OPENCLAW_GATEWAY_TOKEN"
```
`dispatch` first calls the running Gateway RPC method
`workboard.cards.dispatch`. That path uses the same subagent runtime as the
dashboard dispatch action, so ready cards can become real worker sessions.
The dispatch loop:
1. Promotes dependency-ready children to `ready`.
2. Blocks expired claims or timed-out worker runs.
3. Records dispatch metadata on ready cards.
4. Selects a small batch of unclaimed ready cards.
5. Claims each selected card for the dispatcher or assigned agent.
6. Starts a subagent worker run with bounded card context and the card claim
token.
7. Stores the worker run id, session key, execution status, and worker log on
the card.
Selection is intentionally conservative. One dispatch starts at most three
workers by default, skips archived or already-claimed cards, and starts only one
card per owner or agent in a single pass. Cards already owned by active running
or review work are left for a later dispatch.
If worker start fails after a card is claimed, Workboard blocks that card,
clears the claim, and records the failure in card execution and worker-log
metadata. This keeps failed starts visible instead of silently returning the
card to the queue.
If no explicit Gateway target is provided and the local Gateway is unavailable
or does not expose the Workboard dispatch method yet, the CLI falls back to
data-only dispatch against local Workboard state. Data-only dispatch can still
promote dependencies, clean stale claims, and block timed-out runs, but it does
not start workers. Auth, permission, validation failures, and failures for an
explicit `--url` or `--token` target are reported directly.
Text output reports worker starts:
```text
dispatch complete: started=2 failures=0
```
Fallback output is explicit:
```text
gateway unavailable; data dispatch only: promoted=1 blocked=0
```
JSON output includes the dispatch result. Gateway-backed dispatch can include
`started` and `startFailures`; data-only fallback includes
`gatewayUnavailable: true`. Claim tokens are redacted from card JSON output.
## Slash Command Parity
Command-capable channels can use the matching slash command:
```text
/workboard list
/workboard show 7f4a2c10
/workboard create Fix stale worker heartbeat
/workboard dispatch
```
Slash command dispatch also uses the Gateway subagent runtime, so it follows the
same claim, worker-start, and failure behavior as the dashboard and CLI Gateway
path.
`/workboard list` and `/workboard show` are read commands for authorized command
senders. `/workboard create` and `/workboard dispatch` mutate board state and
require owner status on chat surfaces or a Gateway client with `operator.write`
or `operator.admin`.
## Permissions
The CLI dispatch path calls Gateway RPC with `operator.read` and
`operator.write` scopes. A read-only Gateway token can inspect Workboard data
through read methods, but it cannot create cards or dispatch workers.
Local `list`, `create`, and `show` commands operate on the local OpenClaw state
directory used by the current profile. Use `--dev` or `--profile <name>` on the
top-level `openclaw` command when you need a different state root.
## Troubleshooting
### No Cards Appear
Confirm the plugin is enabled for the same profile and state root:
```bash
openclaw plugins inspect workboard --runtime --json
```
If the dashboard shows cards but the CLI does not, check that both commands use
the same `--dev` or `--profile` setting.
### Dispatch Says Data-Only
Start or restart the Gateway:
```bash
openclaw gateway restart
openclaw gateway status --deep
```
Then retry `openclaw workboard dispatch`. Data-only fallback is useful for local
state cleanup, but worker runs need a live Gateway.
### Dispatch Starts Nothing
Check for at least one `ready` card without an active claim:
```bash
openclaw workboard list --status ready
```
Cards can also be skipped when the same owner already has running or review
work. Move completed work to `done`, release stale claims through the Workboard
tools, or run dispatch again after the active worker finishes.
## Related
- [Workboard plugin](/plugins/workboard)
- [CLI reference](/cli)
- [Slash commands](/tools/slash-commands)
- [Control UI](/web/control-ui)

View File

@@ -58,7 +58,7 @@ Most confusion comes from several different surfaces sharing the Codex name:
Those surfaces are intentionally independent. Enabling the `codex` plugin makes
the native app-server features available; `openclaw doctor --fix` owns legacy
legacy Codex route repair and stale session pin cleanup. Selecting
`openai-codex/*` route repair and stale session pin cleanup. Selecting
`openai/*` for an agent model now means "run this through Codex" unless a
non-agent OpenAI API surface is being used.
@@ -97,7 +97,7 @@ This is the agent-facing decision tree:
as `openai/<model>` and set provider/model runtime policy to
`agentRuntime.id: "openclaw"`. A selected `openai` OAuth profile is routed
internally through OpenClaw's Codex-auth transport.
4. If legacy config still contains **legacy Codex model refs**, repair it to
4. If legacy config still contains **`openai-codex/*` model refs**, repair it to
`openai/<model>` with `openclaw doctor --fix`; doctor keeps the Codex auth
route by adding provider/model-scoped `agentRuntime.id: "codex"` where the
old model ref implied it.
@@ -202,7 +202,7 @@ keeping the public model ref as `openai/*`. Stale OpenAI runtime session pins ar
ignored by runtime selection and can be cleaned with `openclaw doctor --fix`.
If `openclaw doctor` warns that the `codex` plugin is enabled while
legacy Codex model refs remain in config, treat that as legacy route state. Run
`openai-codex/*` remains in config, treat that as legacy route state. Run
`openclaw doctor --fix` to rewrite it to `openai/*` with the Codex runtime.
## GitHub Copilot agent runtime

View File

@@ -127,7 +127,7 @@ See [Sandboxing](/gateway/sandboxing) and [Multi-Agent Sandbox & Tools](/tools/m
Configure logging before the delegate handles any real data:
- Cron run history: OpenClaw shared SQLite state database
- Cron run history: `~/.openclaw/cron/runs/<jobId>.jsonl`
- Session transcripts: `~/.openclaw/agents/delegate/sessions`
- Identity provider audit logs (Exchange, Google Workspace)

View File

@@ -119,14 +119,6 @@ stays separate from `MEMORY.md` and that the agent does not claim the candidate
was promoted. It does not add production shadow-trial behavior or change the
deep-phase promotion engine.
The `memory-core` shadow-trial runner keeps that same report-only contract for
code paths that need a stable artifact. It accepts the candidate, trial prompt,
baseline outcome, candidate outcome, verdict, reason, risk flags, and evidence
references, then writes a report with `promotion action: report-only`. Helpful
verdicts map to a `promote` recommendation, neutral verdicts map to `defer`, and
harmful verdicts map to `reject`; none of those recommendations writes to
`MEMORY.md` or applies deep-phase promotion.
## Scheduling
When enabled, `memory-core` auto-manages one cron job for a full dreaming sweep. Each sweep runs phases in order: light → REM → deep.

View File

@@ -30,7 +30,7 @@ Reference for **LLM/model providers** (not chat channels like WhatsApp/Telegram)
OpenAI-family routes are prefix-specific:
- `openai/<model>` uses the native Codex app-server harness for agent turns by default. This is the usual ChatGPT/Codex subscription setup.
- legacy Codex model refs are legacy config that doctor rewrites to `openai/<model>`.
- `openai-codex/<model>` is legacy config that doctor rewrites to `openai/<model>`.
- `openai/<model>` plus provider/model `agentRuntime.id: "openclaw"` uses OpenClaw's built-in runtime for explicit API-key or compatibility routes.
See [OpenAI](/providers/openai) and [Codex harness](/plugins/codex-harness). If the provider/runtime split is confusing, read [Agent runtimes](/concepts/agent-runtimes) first.
@@ -149,7 +149,7 @@ Anthropic staff told us OpenClaw-style Claude CLI usage is allowed again, so Ope
- Policy note: OpenAI Codex OAuth is explicitly supported for external tools/workflows like OpenClaw.
- For the common subscription plus native Codex runtime route, sign in with `openai` auth and configure `openai/gpt-5.5`; OpenAI agent turns select Codex by default.
- Use provider/model `agentRuntime.id: "openclaw"` only when you want the built-in OpenClaw route; otherwise keep `openai/gpt-5.5` on the default Codex harness.
- legacy Codex GPT refs are legacy state, not a live provider route. Use `openai/gpt-5.5` on the native Codex runtime for new agent config, and run `openclaw doctor --fix` to migrate old legacy Codex model refs to canonical `openai/*` refs.
- `openai-codex/gpt-*` refs remain a legacy OpenAI Codex route. Prefer `openai/gpt-5.5` on the native Codex runtime for new agent config, and run `openclaw doctor --fix` when you want to migrate old `openai-codex/*` refs to canonical `openai/*` refs.
```json5
{

View File

@@ -54,16 +54,16 @@ Legend:
### Media delivery with block streaming
Streaming media must use structured payload fields such as `mediaUrl` or
`mediaUrls`; streamed text is not parsed as an attachment command. When block
streaming sends media early, OpenClaw remembers that delivery for the turn. If
the final assistant payload repeats the same media URL, the final delivery
strips the duplicate media instead of sending the attachment again.
`MEDIA:` directives are normal delivery metadata. When block streaming sends a
media block early, OpenClaw remembers that delivery for the turn. If the final
assistant payload repeats the same media URL, the final delivery strips the
duplicate media instead of sending the attachment again.
Exact duplicate final payloads are suppressed. If the final payload adds
distinct text around media that was already streamed, OpenClaw still sends the
new text while keeping the media single-delivery. This prevents duplicate voice
notes or files on channels such as Telegram.
notes or files on channels such as Telegram when an agent emits `MEDIA:` during
streaming and the provider also includes it in the completed reply.
## Chunking algorithm (low/high bounds)

View File

@@ -1235,6 +1235,7 @@
"plugins/memory-wiki",
"plugins/memory-lancedb",
"plugins/oc-path",
"plugins/skill-workshop",
"plugins/zalouser"
]
},
@@ -1255,7 +1256,6 @@
"group": "Skills",
"pages": [
"tools/skills",
"tools/skill-workshop",
"tools/creating-skills",
"tools/skills-config",
"tools/slash-commands",
@@ -1281,7 +1281,6 @@
"tools/code-execution",
"tools/diffs",
"tools/elevated",
"tools/permission-modes",
"tools/exec-approvals",
"tools/exec-approvals-advanced",
"tools/exec",
@@ -1701,13 +1700,7 @@
},
{
"group": "Plugins and skills",
"pages": [
"cli/plugins",
"cli/path",
"cli/policy",
"cli/skills",
"cli/workboard"
]
"pages": ["cli/plugins", "cli/path", "cli/policy", "cli/skills"]
},
{
"group": "Interfaces",

View File

@@ -790,17 +790,21 @@ Group messages default to **require mention** (metadata mention or safe regex pa
Visible replies are controlled separately. Normal group, channel, and internal WebChat direct requests default to automatic final delivery: final assistant text posts through the legacy visible reply path. Opt into `messages.visibleReplies: "message_tool"` or `messages.groupChat.visibleReplies: "message_tool"` when visible output should only post after the agent calls `message(action=send)`. If the model returns final text without calling the message tool in an opted-in tool-only mode, that final text stays private and the gateway verbose log records suppressed payload metadata.
Tool-only visible replies require a model/runtime that reliably calls tools, and are recommended for shared ambient rooms on latest-generation models such as GPT 5.5. Some weaker models can answer final text but fail to understand that source-visible output must be sent with `message(action=send)`. For those models, use `"automatic"` so the final assistant turn is the visible reply path. If the session log shows assistant text with `didSendViaMessagingTool: false`, the model produced private final text instead of calling the message tool. Switch to a stronger tool-calling model for that channel, inspect the gateway verbose log for the suppressed payload summary, or set `messages.groupChat.visibleReplies: "automatic"` to use visible final replies for every group/channel request.
Tool-only visible replies require a model/runtime that reliably calls tools, and are recommended for shared ambient rooms on latest-generation models such as GPT 5.5. If
the session log shows assistant text with `didSendViaMessagingTool: false`, the
model produced private final text instead of calling the message tool. Switch
to a stronger tool-calling model for that channel, inspect the gateway verbose
log for the suppressed payload summary, or set
`messages.groupChat.visibleReplies: "automatic"` to use visible final replies
for every group/channel request.
If the message tool is unavailable under the active tool policy, OpenClaw falls back to automatic visible replies instead of silently suppressing the response. `openclaw doctor` warns about this mismatch.
This rule applies to normal agent final text. Plugin-owned conversation bindings use the owning plugin's returned reply as the visible response for claimed bound-thread turns; the plugin does not need to call `message(action=send)` for those binding replies.
**Troubleshooting: group @mention triggers typing then silence (no error)**
Symptom: a group/channel @mention shows the typing indicator and the gateway log reports `dispatch complete (queuedFinal=false, replies=0)`, but no message lands in the room. DMs to the same agent reply normally.
Cause: the group/channel visible-reply mode resolves to `"message_tool"`, so OpenClaw runs the turn but suppresses the final assistant text unless the agent calls `message(action=send)`. There is no `NO_REPLY` contract in this mode; no message-tool call means no source reply. There is no error because suppression is the configured behavior. Normal group and channel turns default to `"automatic"`, so this symptom only appears when `messages.groupChat.visibleReplies` (or global `messages.visibleReplies`) is explicitly set to `"message_tool"`. Harness `defaultVisibleReplies` does not apply here — the group/channel resolver ignores it; it only affects direct/source chats (the Codex harness suppresses direct-chat finals that way).
Cause: the group/channel visible-reply mode resolves to `"message_tool"`, so OpenClaw runs the turn but suppresses the final assistant text unless the agent calls `message(action=send)`. There is no error because suppression is the configured behavior. Normal group and channel turns default to `"automatic"`, so this symptom only appears when `messages.groupChat.visibleReplies` (or global `messages.visibleReplies`) is explicitly set to `"message_tool"`. Harness `defaultVisibleReplies` does not apply here — the group/channel resolver ignores it; it only affects direct/source chats (the Codex harness suppresses direct-chat finals that way).
Fix: either pick a stronger tool-calling model, remove the explicit `"message_tool"` override to fall back to the `"automatic"` default, or set `messages.groupChat.visibleReplies: "automatic"` to force visible replies for every group/channel request. The gateway hot-reloads `messages` config after the file is saved; only restart the gateway when file watching or config reload is disabled in the deployment.

View File

@@ -106,23 +106,9 @@ target server during config edits.
remote: {
url: "https://example.com/mcp",
transport: "streamable-http", // streamable-http | sse
timeout: 20,
connectTimeout: 5,
supportsParallelToolCalls: true,
headers: {
Authorization: "Bearer ${MCP_REMOTE_TOKEN}",
},
auth: "oauth",
oauth: {
scope: "docs.read",
},
sslVerify: true,
clientCert: "/path/to/client.crt",
clientKey: "/path/to/client.key",
toolFilter: {
include: ["search_*"],
exclude: ["admin_*"],
},
// Optional Codex app-server projection controls.
codex: {
agents: ["main"],
@@ -139,26 +125,6 @@ target server during config edits.
Remote entries use `transport: "streamable-http"` or `transport: "sse"`;
`type: "http"` is a CLI-native alias that `openclaw mcp set` and
`openclaw doctor --fix` normalize into the canonical `transport` field.
- `mcp.servers.<name>.enabled`: set `false` to keep a saved server definition
while excluding it from embedded OpenClaw MCP discovery and tool projection.
- `mcp.servers.<name>.timeout` / `requestTimeoutMs`: per-server MCP request
timeout in seconds or milliseconds.
- `mcp.servers.<name>.connectTimeout` / `connectionTimeoutMs`: per-server
connection timeout in seconds or milliseconds.
- `mcp.servers.<name>.supportsParallelToolCalls`: optional concurrency hint for
adapters that can choose whether to issue parallel MCP tool calls.
- `mcp.servers.<name>.auth`: set `"oauth"` for HTTP MCP servers that require
OAuth. Run `openclaw mcp login <name>` to store tokens under OpenClaw state.
- `mcp.servers.<name>.oauth`: optional OAuth scope, redirect URL, and client
metadata URL overrides.
- `mcp.servers.<name>.sslVerify`, `clientCert`, `clientKey`: HTTP TLS controls
for private endpoints and mutual TLS.
- `mcp.servers.<name>.toolFilter`: optional per-server tool selection. `include`
limits the discovered MCP tools to matching names; `exclude` hides matching
names. Entries are exact MCP tool names or simple `*` globs. Servers with
resources or prompts also generate utility tool names (`resources_list`,
`resources_read`, `prompts_list`, `prompts_get`), and those names use the
same filter.
- `mcp.servers.<name>.codex`: optional Codex app-server projection controls.
This block is OpenClaw metadata for Codex app-server threads only; it does not
affect ACP sessions, generic Codex harness config, or other runtime adapters.
@@ -176,11 +142,6 @@ target server during config edits.
- Changes under `mcp.*` hot-apply by disposing cached session MCP runtimes.
The next tool discovery/use recreates them from the new config, so removed
`mcp.servers` entries are reaped immediately instead of waiting for idle TTL.
- Runtime discovery also honors MCP tool-list change notifications by dropping
the cached catalog for that session. Servers that advertise resources or
prompts get utility tools for listing/reading resources and listing/fetching
prompts. Repeated tool-call failures pause the affected server briefly before
another call is attempted.
See [MCP](/cli/mcp#openclaw-as-an-mcp-client-registry) and
[CLI backends](/gateway/cli-backends#bundle-mcp-overlays) for runtime behavior.
@@ -253,8 +214,7 @@ See [MCP](/cli/mcp#openclaw-as-an-mcp-client-registry) and
}
```
- Loaded from package or bundle directories under `~/.openclaw/extensions` and `<workspace>/.openclaw/extensions`, plus files or directories listed in `plugins.load.paths`.
- Put standalone plugin files in `plugins.load.paths`; auto-discovered extension roots ignore top-level `.js`, `.mjs`, and `.ts` files so helper scripts in those roots do not block startup.
- Loaded from `~/.openclaw/extensions`, `<workspace>/.openclaw/extensions`, plus `plugins.load.paths`.
- Discovery accepts native OpenClaw plugins plus compatible Codex bundles and Claude bundles, including manifestless Claude default-layout bundles.
- **Config changes require a gateway restart.**
- `allow`: optional allowlist (only listed plugins load). `deny` wins.
@@ -316,8 +276,7 @@ conversation bindings, or any non-Codex harness.
migrated plugin entry when global `codexPlugins.enabled` is also true.
Default: `true` for explicit entries.
- `plugins.entries.codex.config.codexPlugins.plugins.<key>.marketplaceName`:
stable marketplace identity. V1 supports `"openai-curated"`,
`"openai-bundled"`, and `"openai-primary-runtime"`.
stable marketplace identity. V1 only supports `"openai-curated"`.
- `plugins.entries.codex.config.codexPlugins.plugins.<key>.pluginName`: stable
Codex plugin identity from migration, for example `"google-calendar"`.
- `plugins.entries.codex.config.codexPlugins.plugins.<key>.allow_destructive_actions`:
@@ -1290,10 +1249,10 @@ Current builds no longer include the TCP bridge. Nodes connect over the Gateway
```
- `sessionRetention`: how long to keep completed isolated cron run sessions before pruning from `sessions.json`. Also controls cleanup of archived deleted cron transcripts. Default: `24h`; set `false` to disable.
- `runLog.maxBytes`: accepted for compatibility with older file-backed cron run logs. Default: `2_000_000` bytes.
- `runLog.keepLines`: newest SQLite run-history rows retained per job. Default: `2000`.
- `runLog.maxBytes`: max size per run log file (`cron/runs/<jobId>.jsonl`) before pruning. Default: `2_000_000` bytes.
- `runLog.keepLines`: newest lines retained when run-log pruning is triggered. Default: `2000`.
- `webhookToken`: bearer token used for cron webhook POST delivery (`delivery.mode = "webhook"`), if omitted no auth header is sent.
- `webhook`: deprecated legacy fallback webhook URL (http/https) used by `openclaw doctor --fix` to migrate stored jobs that still have `notify: true`; runtime delivery uses per-job `delivery.mode="webhook"` plus `delivery.to`, or `delivery.completionDestination` when preserving announce delivery.
- `webhook`: deprecated legacy fallback webhook URL (http/https) used only for stored jobs that still have `notify: true`.
### `cron.retry`

View File

@@ -431,7 +431,7 @@ candidate contains redacted secret placeholders such as `***`.
```
- `sessionRetention`: prune completed isolated run sessions from `sessions.json` (default `24h`; set `false` to disable).
- `runLog`: prune retained cron run-history rows per job. `maxBytes` remains accepted for older file-backed run logs.
- `runLog`: prune `cron/runs/<jobId>.jsonl` by size and retained lines.
- See [Cron jobs](/automation/cron-jobs) for feature overview and CLI examples.
</Accordion>

View File

@@ -148,7 +148,7 @@ must be paired with `--lint`; regular doctor and repair runs reject them.
- Plugin/tool allowlist warnings when `plugins.allow` is restrictive but tool policy still asks for wildcard or plugin-owned tools.
- Legacy on-disk state migration (sessions/agent dir/WhatsApp auth).
- Legacy plugin manifest contract key migration (`speechProviders`, `realtimeTranscriptionProviders`, `realtimeVoiceProviders`, `mediaUnderstandingProviders`, `imageGenerationProviders`, `videoGenerationProviders`, `webFetchProviders`, `webSearchProviders` → `contracts`).
- Legacy cron store migration (`jobId`, `schedule.cron`, top-level delivery/payload fields, payload `provider`, `notify: true` webhook fallback jobs).
- Legacy cron store migration (`jobId`, `schedule.cron`, top-level delivery/payload fields, payload `provider`, simple `notify: true` webhook fallback jobs).
- Legacy whole-agent runtime-policy cleanup; provider/model runtime policy is the active route selector.
- Stale plugin config cleanup when plugins are enabled; when `plugins.enabled=false`, stale plugin references are treated as inert containment config and are preserved.
@@ -372,11 +372,11 @@ That stages grounded durable candidates into the short-term dreaming store while
- top-level payload fields (`message`, `model`, `thinking`, ...) → `payload`
- top-level delivery fields (`deliver`, `channel`, `to`, `provider`, ...) → `delivery`
- payload `provider` delivery aliases → explicit `delivery.channel`
- legacy `notify: true` webhook fallback jobs → explicit webhook delivery from `cron.webhook`; announce jobs keep their chat delivery and get `delivery.completionDestination`
- simple legacy `notify: true` webhook fallback jobs → explicit `delivery.mode="webhook"` with `delivery.to=cron.webhook`
The Gateway also sanitizes malformed cron rows at load time so valid jobs keep running. Raw malformed rows are copied to `jobs-quarantine.json` next to the active store before they are removed from `jobs.json`; doctor reports quarantined rows so you can review or repair them manually.
Doctor and Gateway startup use the same `notify: true` migration before the scheduler runs. If `cron.webhook` is missing, doctor warns and leaves the legacy notify marker for manual repair.
Doctor only auto-migrates `notify: true` jobs when it can do so without changing behavior. If a job combines legacy notify fallback with an existing non-webhook delivery mode, doctor warns and leaves that job for manual review.
On Linux, doctor also warns when the user's crontab still invokes legacy `~/.openclaw/bin/ensure-whatsapp.sh`. That host-local script is not maintained by current OpenClaw and can write false `Gateway inactive` messages to `~/.openclaw/logs/whatsapp-health.log` when cron cannot reach the systemd user bus. Remove the stale crontab entry with `crontab -e`; use `openclaw channels status --probe`, `openclaw doctor`, and `openclaw gateway status` for current health checks.
@@ -414,7 +414,7 @@ That stages grounded durable candidates into the short-term dreaming store while
- short cooldowns (rate limits/timeouts/auth failures)
- longer disables (billing/credit failures)
Legacy Codex OAuth profiles whose tokens live in macOS Keychain (older onboarding before the file-based sidecar layout) are repaired only by doctor. Run `openclaw doctor --fix` once from an interactive terminal to migrate Keychain-backed legacy tokens inline into `auth-profiles.json`; after that, embedded turns (Telegram, cron, sub-agent dispatch) resolve them as canonical OpenAI OAuth profiles.
Legacy Codex OAuth profiles whose tokens live in macOS Keychain (older onboarding before the file-based sidecar layout) are not picked up by the embedded runtime path — that path runs with `allowKeychainPrompt: false` and cannot trigger a Keychain prompt. Affected users will see a one-shot `log.warn` from the legacy sidecar loader naming `openclaw doctor --fix` and macOS Keychain (instead of the credential silently falling through to a downstream `No API key found for provider "openai-codex"`). Run `openclaw doctor --fix` once from an interactive terminal to migrate Keychain-backed legacy tokens inline into `auth-profiles.json`; after that, embedded turns (Telegram, cron, sub-agent dispatch) resolve them like any other inline OAuth profile.
</Accordion>
<Accordion title="6. Hooks model validation">

View File

@@ -222,9 +222,8 @@ Set `stream: true` to receive Server-Sent Events (SSE):
- `frequency_penalty`: number; best-effort frequency penalty forwarded to the upstream provider via the agent stream-param channel. Validated range: -2.0 to 2.0. Returns `400 invalid_request_error` for out-of-range values.
- `presence_penalty`: number; best-effort presence penalty forwarded to the upstream provider via the agent stream-param channel. Validated range: -2.0 to 2.0. Returns `400 invalid_request_error` for out-of-range values.
- `seed`: number (integer); best-effort seed forwarded to the upstream provider via the agent stream-param channel. Returns `400 invalid_request_error` for non-integer values.
- `stop`: string or array of up to 4 strings; best-effort stop sequences forwarded to the upstream provider via the agent stream-param channel. Returns `400 invalid_request_error` for more than 4 sequences or non-string/empty entries.
When either token-cap field is set, the value is forwarded to the upstream provider via the agent stream-param channel. The actual wire field name sent to the upstream provider is chosen by the provider transport: `max_completion_tokens` for OpenAI-family endpoints, and `max_tokens` for providers that only accept the legacy name (such as Mistral and Chutes). Sampling fields (`temperature`, `top_p`, `frequency_penalty`, `presence_penalty`, `seed`) follow the same stream-param channel; the ChatGPT-based Codex Responses backend strips them server-side since it uses fixed sampling. `stop` also rides the stream-param channel and maps to the transport's stop field (`stop` for Chat Completions backends, `stop_sequences` for Anthropic); the OpenAI Responses API has no stop parameter, so `stop` is not applied on Responses-backed models.
When either token-cap field is set, the value is forwarded to the upstream provider via the agent stream-param channel. The actual wire field name sent to the upstream provider is chosen by the provider transport: `max_completion_tokens` for OpenAI-family endpoints, and `max_tokens` for providers that only accept the legacy name (such as Mistral and Chutes). Sampling fields (`temperature`, `top_p`, `frequency_penalty`, `presence_penalty`, `seed`) follow the same stream-param channel; the ChatGPT-based Codex Responses backend strips them server-side since it uses fixed sampling.
### Unsupported variants

View File

@@ -348,8 +348,7 @@ enumeration of `src/gateway/server-methods/*.ts`.
- `usage.status` returns provider usage windows/remaining quota summaries.
- `usage.cost` returns aggregated cost usage summaries for a date range.
Pass `agentId` for one agent, or `agentScope: "all"` to aggregate configured agents.
- `doctor.memory.status` returns vector-memory / cached embedding readiness for the active default agent workspace. Pass `{ "probe": true }` or `{ "deep": true }` only when the caller explicitly wants a live embedding provider ping. Dreaming-aware clients may also pass `{ "agentId": "agent-id" }` to scope Dreaming store stats to a selected agent workspace; omitting `agentId` keeps the default-agent fallback and aggregates configured Dreaming workspaces.
- `doctor.memory.dreamDiary`, `doctor.memory.backfillDreamDiary`, `doctor.memory.resetDreamDiary`, `doctor.memory.resetGroundedShortTerm`, `doctor.memory.repairDreamingArtifacts`, and `doctor.memory.dedupeDreamDiary` accept optional `{ "agentId": "agent-id" }` params for selected-agent Dreaming views/actions. When `agentId` is omitted, they operate on the configured default agent workspace.
- `doctor.memory.status` returns vector-memory / cached embedding readiness for the active default agent workspace. Pass `{ "probe": true }` or `{ "deep": true }` only when the caller explicitly wants a live embedding provider ping.
- `doctor.memory.remHarness` returns a bounded, read-only REM harness preview for remote control-plane clients. It can include workspace paths, memory snippets, rendered grounded markdown, and deep promotion candidates, so callers need `operator.read`.
- `sessions.usage` returns per-session usage summaries. Pass `agentId` for one
agent, or `agentScope: "all"` to list configured agents together.
@@ -442,7 +441,6 @@ enumeration of `src/gateway/server-methods/*.ts`.
- `sessions.reset`, `sessions.delete`, and `sessions.compact` perform session maintenance.
- `sessions.get` returns the full stored session row.
- Chat execution still uses `chat.history`, `chat.send`, `chat.abort`, and `chat.inject`. `chat.history` is display-normalized for UI clients: inline directive tags are stripped from visible text, plain-text tool-call XML payloads (including `<tool_call>...</tool_call>`, `<function_call>...</function_call>`, `<tool_calls>...</tool_calls>`, `<function_calls>...</function_calls>`, and truncated tool-call blocks) and leaked ASCII/full-width model control tokens are stripped, pure silent-token assistant rows such as exact `NO_REPLY` / `no_reply` are omitted, and oversized rows can be replaced with placeholders.
- `chat.message.get` is the additive bounded full-message reader for a single visible transcript entry. Clients pass `sessionKey`, optional `agentId` when the session selection is agent-scoped, plus a transcript `messageId` previously surfaced through `chat.history`, and the Gateway returns the same display-normalized projection without the lightweight history truncation cap when the stored entry is still available and not oversized.
</Accordion>

View File

@@ -596,28 +596,28 @@ and troubleshooting see the main [FAQ](/help/faq).
<Accordion title="How does Codex auth work?">
OpenClaw supports **OpenAI Code (Codex)** via OAuth (ChatGPT sign-in). Use
`openai/gpt-5.5` for the common setup: ChatGPT/Codex subscription auth plus
native Codex app-server execution. Legacy Codex GPT refs are
native Codex app-server execution. `openai-codex/gpt-*` model refs are
legacy config repaired by `openclaw doctor --fix`. Direct OpenAI API-key
access remains available for non-agent OpenAI API surfaces and for agent
models through an ordered `openai` API-key profile.
See [Model providers](/concepts/model-providers) and [Onboarding (CLI)](/start/wizard).
</Accordion>
<Accordion title="Why does OpenClaw still mention legacy OpenAI Codex prefix?">
<Accordion title="Why does OpenClaw still mention openai-codex?">
`openai` is the provider and auth-profile id for both OpenAI API keys and
ChatGPT/Codex OAuth. You may still see legacy OpenAI Codex prefix in legacy config and
ChatGPT/Codex OAuth. You may still see `openai-codex` in legacy config and
migration warnings.
Older configs also used it as a model prefix:
- `openai/gpt-5.5` = ChatGPT/Codex subscription auth with native Codex runtime for agent turns
- legacy Codex GPT-5.5 ref = legacy model route repaired by `openclaw doctor --fix`
- `openai-codex/gpt-5.5` = legacy model route repaired by `openclaw doctor --fix`
- `openai/gpt-5.5` plus an ordered `openai` API-key profile = API-key auth for an OpenAI agent model
- legacy Codex auth profile ids = legacy auth profile id migrated by `openclaw doctor --fix`
- `openai-codex:...` = legacy auth profile id migrated by `openclaw doctor --fix`
If you want the direct OpenAI Platform billing/limit path, set
`OPENAI_API_KEY`. If you want ChatGPT/Codex subscription auth, sign in with
`openclaw models auth login --provider openai`. Keep the model ref as
`openai/gpt-5.5`; legacy Codex model refs are legacy config that
`openai/gpt-5.5`; `openai-codex/*` model refs are legacy config that
`openclaw doctor --fix` rewrites.
</Accordion>

View File

@@ -1737,7 +1737,7 @@ lives on the [Models FAQ](/help/faq-models).
<AccordionGroup>
<Accordion title="My skill generated an image/PDF, but nothing was sent">
Outbound attachments from the agent must use structured media fields such as `media`, `mediaUrl`, `path`, or `filePath`. See [OpenClaw assistant setup](/start/openclaw) and [Agent send](/tools/agent-send).
Outbound attachments from the agent must include a `MEDIA:<path-or-url>` line (on its own line). See [OpenClaw assistant setup](/start/openclaw) and [Agent send](/tools/agent-send).
CLI sending:
@@ -1750,7 +1750,7 @@ lives on the [Models FAQ](/help/faq-models).
- The target channel supports outbound media and isn't blocked by allowlists.
- The file is within the provider's size limits (images are resized to max 2048px).
- `tools.fs.workspaceOnly=true` keeps local-path sends limited to workspace, temp/media-store, and sandbox-validated files.
- `tools.fs.workspaceOnly=false` lets structured local media sends use host-local files the agent can already read, but only for media plus safe document types (images, audio, video, PDF, and Office docs). Plain text and secret-like files are still blocked.
- `tools.fs.workspaceOnly=false` lets `MEDIA:` send host-local files the agent can already read, but only for media plus safe document types (images, audio, video, PDF, and Office docs). Plain text and secret-like files are still blocked.
See [Images](/nodes/images).

View File

@@ -296,8 +296,8 @@ replacement. Gateway startup does not generate bundled-plugin dependency trees.
For full persistence details on VM deployments, see
[Docker VM Runtime - What persists where](/install/docker-vm-runtime#what-persists-where).
**Disk growth hotspots:** watch `media/`, session JSONL files, the shared
SQLite state database, installed plugin package roots, and rolling file logs
**Disk growth hotspots:** watch `media/`, session JSONL files,
`cron/runs/*.jsonl`, installed plugin package roots, and rolling file logs
under `/tmp/openclaw/`.
### Shell helpers (optional)

View File

@@ -66,7 +66,7 @@ Imports require a fresh OpenClaw setup. If you already have local OpenClaw state
Skills with a `SKILL.md` file under `skills/<name>/` are copied, along with per-skill config values from `skills.config`.
</Accordion>
<Accordion title="Auth credentials">
Interactive `openclaw migrate` asks before importing auth credentials, with yes selected by default. Accepted imports include OpenCode OpenAI OAuth credentials from OpenCode `auth.json`, OpenCode and GitHub Copilot entries from OpenCode `auth.json`, and the [supported `.env` keys](/cli/migrate#supported-env-keys). Hermes `auth.json` OAuth entries are legacy state and are surfaced as manual reauth/doctor work instead of imported into live auth. Use `--include-secrets` for non-interactive `openclaw migrate` credential import, `--no-auth-credentials` to skip it, or onboarding `--import-secrets` when importing from the onboarding wizard.
Interactive `openclaw migrate` asks before importing auth credentials, with yes selected by default. Accepted imports include supported OAuth credentials from Hermes `auth.json`, OpenCode OpenAI OAuth credentials from OpenCode `auth.json`, OpenCode and GitHub Copilot entries from OpenCode `auth.json`, and the [supported `.env` keys](/cli/migrate#supported-env-keys). Use `--include-secrets` for non-interactive `openclaw migrate` credential import, `--no-auth-credentials` to skip it, or onboarding `--import-secrets` when importing from the onboarding wizard.
</Accordion>
</AccordionGroup>
@@ -137,7 +137,7 @@ If a conflict surfaces mid-apply (for example, an unexpected race on a config fi
Interactive `openclaw migrate` asks whether to import detected auth credentials, with yes selected by default.
- Accepting the prompt imports OpenCode OpenAI OAuth credentials from OpenCode `auth.json`, OpenCode and GitHub Copilot entries from OpenCode `auth.json`, and the [supported `.env` keys](/cli/migrate#supported-env-keys). Hermes `auth.json` OAuth entries are reported for manual OpenAI reauth or doctor repair.
- Accepting the prompt imports supported OAuth credentials from Hermes `auth.json`, OpenCode OpenAI OAuth credentials from OpenCode `auth.json`, OpenCode and GitHub Copilot entries from OpenCode `auth.json`, and the [supported `.env` keys](/cli/migrate#supported-env-keys).
- Use `--no-auth-credentials` or choose no at the prompt to import non-secret state only.
- Use `--include-secrets` when running unattended with `--yes`.
- Use onboarding `--import-secrets` when importing credentials from the onboarding wizard.

View File

@@ -59,9 +59,9 @@ All camera access is gated behind **user-controlled settings**.
Like `canvas.*`, the iOS node only allows `camera.*` commands in the **foreground**. Background invocations return `NODE_BACKGROUND_UNAVAILABLE`.
### CLI helper
### CLI helper (temp files + MEDIA)
The easiest way to get media files is via the CLI helper, which writes decoded media to a temp file and prints the saved path.
The easiest way to get attachments is via the CLI helper, which writes decoded media to a temp file and prints `MEDIA:<path>`.
Examples:
@@ -126,12 +126,12 @@ Examples:
```bash
openclaw nodes camera list --node <id> # list camera ids
openclaw nodes camera snap --node <id> # prints saved path
openclaw nodes camera snap --node <id> # prints MEDIA:<path>
openclaw nodes camera snap --node <id> --max-width 1280
openclaw nodes camera snap --node <id> --delay-ms 2000
openclaw nodes camera snap --node <id> --device-id <id>
openclaw nodes camera clip --node <id> --duration 10s # prints saved path
openclaw nodes camera clip --node <id> --duration-ms 3000 # prints saved path (legacy flag)
openclaw nodes camera clip --node <id> --duration 10s # prints MEDIA:<path>
openclaw nodes camera clip --node <id> --duration-ms 3000 # prints MEDIA:<path> (legacy flag)
openclaw nodes camera clip --node <id> --device-id <id>
openclaw nodes camera clip --node <id> --no-audio
```
@@ -152,7 +152,7 @@ Notes:
For _screen_ video (not camera), use the macOS companion:
```bash
openclaw nodes screen record --node <id> --duration 10s --fps 15 # prints saved path
openclaw nodes screen record --node <id> --duration 10s --fps 15 # prints MEDIA:<path>
```
Notes:

View File

@@ -218,7 +218,7 @@ and approve the new request so the gateway stores the updated command snapshot.
If the node is showing the Canvas (WebView), `canvas.snapshot` returns `{ format, base64 }`.
CLI helper (writes to a temp file and prints the saved path):
CLI helper (writes to a temp file and prints `MEDIA:<path>`):
```bash
openclaw nodes canvas snapshot --node <idOrNameOrIp> --format png

View File

@@ -7,7 +7,7 @@ read_when:
title: "iOS app"
---
Availability: iPhone app builds are distributed through Apple channels when enabled for a release. Local development builds can also run from source.
Availability: internal preview. The iOS app is not publicly distributed yet.
## What it does

View File

@@ -38,14 +38,14 @@ All Codex harness settings live under `plugins.entries.codex.config`.
Supported top-level fields:
| Field | Default | Meaning |
| -------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
| `discovery` | enabled | Model discovery settings for Codex app-server `model/list`. |
| `appServer` | managed stdio app-server | Transport, command, auth, approval, sandbox, and timeout settings. |
| `codexDynamicToolsLoading` | `"searchable"` | Use `"direct"` to put OpenClaw dynamic tools directly in the initial Codex tool context. |
| `codexDynamicToolsExclude` | `[]` | Additional OpenClaw dynamic tool names to omit from Codex app-server turns. |
| `codexPlugins` | disabled | Native Codex plugin/app support for configured first-party Codex plugins. See [Native Codex plugins](/plugins/codex-native-plugins). |
| `computerUse` | disabled | Codex Computer Use setup. See [Codex Computer Use](/plugins/codex-computer-use). |
| Field | Default | Meaning |
| -------------------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `discovery` | enabled | Model discovery settings for Codex app-server `model/list`. |
| `appServer` | managed stdio app-server | Transport, command, auth, approval, sandbox, and timeout settings. |
| `codexDynamicToolsLoading` | `"searchable"` | Use `"direct"` to put OpenClaw dynamic tools directly in the initial Codex tool context. |
| `codexDynamicToolsExclude` | `[]` | Additional OpenClaw dynamic tool names to omit from Codex app-server turns. |
| `codexPlugins` | disabled | Native Codex plugin/app support for migrated source-installed curated plugins. See [Native Codex plugins](/plugins/codex-native-plugins). |
| `computerUse` | disabled | Codex Computer Use setup. See [Codex Computer Use](/plugins/codex-computer-use). |
## App-server transport
@@ -85,25 +85,25 @@ For an already-running app-server, use WebSocket transport:
Supported `appServer` fields:
| Field | Default | Meaning |
| --------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `transport` | `"stdio"` | `"stdio"` spawns Codex; `"websocket"` connects to `url`. |
| `command` | managed Codex binary | Executable for stdio transport. Leave unset to use the managed binary. |
| `args` | `["app-server", "--listen", "stdio://"]` | Arguments for stdio transport. |
| `url` | unset | WebSocket app-server URL. |
| `authToken` | unset | Bearer token for WebSocket transport. |
| `headers` | `{}` | Extra WebSocket headers. |
| `clearEnv` | `[]` | Extra environment variable names removed from the spawned stdio app-server process after OpenClaw builds its inherited environment. |
| `requestTimeoutMs` | `60000` | Timeout for app-server control-plane calls. |
| `turnCompletionIdleTimeoutMs` | `60000` | Quiet window after Codex accepts a turn or after a turn-scoped app-server request while OpenClaw waits for `turn/completed`. |
| `postToolRawAssistantCompletionIdleTimeoutMs` | `300000` | Completion-idle and progress guard used after a tool handoff, native tool completion, or post-tool raw assistant progress while OpenClaw waits for `turn/completed`. Use this for trusted or heavy workloads where post-tool synthesis can legitimately stay quiet longer than the final assistant release budget. |
| `mode` | `"yolo"` unless local Codex requirements disallow YOLO | Preset for YOLO or guardian-reviewed execution. |
| `approvalPolicy` | `"never"` or an allowed guardian approval policy | Native Codex approval policy sent to thread start, resume, and turn. |
| `sandbox` | `"danger-full-access"` or an allowed guardian sandbox | Native Codex sandbox mode sent to thread start and resume. Active OpenClaw sandboxes narrow `danger-full-access` turns to Codex `workspace-write`; the turn network flag follows OpenClaw sandbox egress. |
| `approvalsReviewer` | `"user"` or an allowed guardian reviewer | Use `"auto_review"` to let Codex review native approval prompts when allowed. |
| `defaultWorkspaceDir` | current process directory | Workspace used by `/codex bind` when `--cwd` is omitted. |
| `serviceTier` | unset | Optional Codex app-server service tier. `"priority"` enables fast-mode routing, `"flex"` requests flex processing, and `null` clears the override. Legacy `"fast"` is accepted as `"priority"`. |
| `experimental.sandboxExecServer` | `false` | Preview opt-in that registers an OpenClaw sandbox-backed Codex environment with Codex app-server 0.132.0 or newer so native Codex execution can run inside the active OpenClaw sandbox. |
| Field | Default | Meaning |
| --------------------------------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transport` | `"stdio"` | `"stdio"` spawns Codex; `"websocket"` connects to `url`. |
| `command` | managed Codex binary | Executable for stdio transport. Leave unset to use the managed binary. |
| `args` | `["app-server", "--listen", "stdio://"]` | Arguments for stdio transport. |
| `url` | unset | WebSocket app-server URL. |
| `authToken` | unset | Bearer token for WebSocket transport. |
| `headers` | `{}` | Extra WebSocket headers. |
| `clearEnv` | `[]` | Extra environment variable names removed from the spawned stdio app-server process after OpenClaw builds its inherited environment. |
| `requestTimeoutMs` | `60000` | Timeout for app-server control-plane calls. |
| `turnCompletionIdleTimeoutMs` | `60000` | Quiet window after Codex accepts a turn or after a turn-scoped app-server request while OpenClaw waits for `turn/completed`. |
| `postToolRawAssistantCompletionIdleTimeoutMs` | `300000` | Completion-idle guard used after a tool handoff when Codex emits raw assistant completion or progress but does not send `turn/completed`. Use this for trusted or heavy workloads where post-tool synthesis can legitimately stay quiet longer than the final assistant release budget. |
| `mode` | `"yolo"` unless local Codex requirements disallow YOLO | Preset for YOLO or guardian-reviewed execution. |
| `approvalPolicy` | `"never"` or an allowed guardian approval policy | Native Codex approval policy sent to thread start, resume, and turn. |
| `sandbox` | `"danger-full-access"` or an allowed guardian sandbox | Native Codex sandbox mode sent to thread start and resume. Active OpenClaw sandboxes narrow `danger-full-access` turns to Codex `workspace-write`; the turn network flag follows OpenClaw sandbox egress. |
| `approvalsReviewer` | `"user"` or an allowed guardian reviewer | Use `"auto_review"` to let Codex review native approval prompts when allowed. |
| `defaultWorkspaceDir` | current process directory | Workspace used by `/codex bind` when `--cwd` is omitted. |
| `serviceTier` | unset | Optional Codex app-server service tier. `"priority"` enables fast-mode routing, `"flex"` requests flex processing, and `null` clears the override. Legacy `"fast"` is accepted as `"priority"`. |
| `experimental.sandboxExecServer` | `false` | Preview opt-in that registers an OpenClaw sandbox-backed Codex environment with Codex app-server 0.132.0 or newer so native Codex execution can run inside the active OpenClaw sandbox. |
The plugin blocks older or unversioned app-server handshakes. Codex app-server
must report stable version `0.125.0` or newer.
@@ -329,29 +329,23 @@ OpenClaw session lane so follow-up chat messages are not queued behind a stale
native turn.
Most non-terminal notifications for the same turn disarm that short watchdog
because Codex has proven the turn is still alive. Tool handoffs use a longer
post-tool idle budget: after OpenClaw returns an `item/tool/call` response, after
native tool items such as `commandExecution` complete, after raw
`custom_tool_call_output` completions, and after post-tool raw assistant
progress. The guard uses `appServer.postToolRawAssistantCompletionIdleTimeoutMs`
when configured and defaults to five minutes otherwise. That same post-tool
budget also extends the progress watchdog for the silent synthesis window before
Codex emits the next current-turn event. Reasoning completions, commentary
`agentMessage` completions, and pre-tool raw reasoning or assistant progress can
be followed by an automatic final reply, so they use the post-progress reply
guard instead of releasing the session lane immediately. Only
final/non-commentary completed `agentMessage` items and pre-tool raw assistant
completions arm the assistant-output release: if Codex then goes quiet without
`turn/completed`, OpenClaw best-effort interrupts the native turn and releases
the session lane. Replay-safe stdio app-server failures, including
turn-completion idle timeouts without assistant, tool, active-item, or
side-effect evidence, are retried once on a fresh app-server attempt. Unsafe
timeouts still retire the stuck app-server client and release the OpenClaw
session lane. They also clear the stale native thread binding and surface a
recoverable timeout message for user or maintainer judgment instead of being
replayed automatically. Timeout diagnostics include the last app-server
notification method and, for raw assistant response items, the item type, role,
id, and a bounded assistant text preview.
because Codex has proven the turn is still alive. Raw `custom_tool_call_output`
completions keep the short post-tool watchdog armed because they are the
turn-scoped tool-result handoff. Completed `agentMessage` items and pre-tool raw
assistant `rawResponseItem/completed` items arm the assistant-output release: if
Codex then goes quiet without `turn/completed`, OpenClaw best-effort interrupts
the native turn and releases the session lane. Post-tool raw assistant progress
keeps waiting for `turn/completed` while a completion-idle guard stays armed; the
guard uses `appServer.postToolRawAssistantCompletionIdleTimeoutMs` when
configured and defaults to five minutes otherwise. Replay-safe stdio app-server
failures, including turn-completion idle timeouts without assistant, tool,
active-item, or side-effect evidence, are retried once on a fresh app-server
attempt. Unsafe timeouts still retire the stuck app-server client and release
the OpenClaw session lane. They also clear the stale native thread binding and
surface a recoverable timeout message for user or maintainer judgment instead of
being replayed automatically. Timeout diagnostics include the last
app-server notification method and, for raw assistant response items, the item
type, role, id, and a bounded assistant text preview.
## Model discovery

View File

@@ -17,10 +17,9 @@ selection, OpenClaw dynamic tools, approvals, media delivery, and the visible
transcript mirror.
The normal setup uses canonical OpenAI model refs such as `openai/gpt-5.5`.
Do not configure legacy Codex GPT refs. Put OpenAI agent auth order
under `auth.order.openai`; older legacy Codex auth profile ids and
legacy Codex auth order entries are legacy state repaired by
`openclaw doctor --fix`.
Do not configure `openai-codex/gpt-*` model refs. Put OpenAI agent auth order
under `auth.order.openai`; older `openai-codex:*` profiles and
`auth.order.openai-codex` entries remain supported for existing installs.
When no OpenClaw sandbox is active, OpenClaw starts Codex app-server threads
with Codex native code mode enabled while leaving code-mode-only off by default.
@@ -123,8 +122,8 @@ harness options in OpenClaw config, and use the CLI only for Codex auth:
Use `openai/gpt-*` model refs for Codex-backed OpenAI agent turns. Prefer
`auth.order.openai` for subscription-first/API-key-backup ordering. Existing
legacy Codex auth profile ids and legacy Codex auth order are doctor-only
legacy state; do not write new legacy Codex GPT refs.
`openai-codex:*` auth profiles and `auth.order.openai-codex` remain valid, but
do not write new `openai-codex/gpt-*` model refs.
Do not set `compaction.model` or `compaction.provider` on Codex-backed agents.
Codex compacts through its native app-server thread state, so OpenClaw ignores
@@ -196,7 +195,7 @@ the harness and account. If `/status` is surprising, see
Keep provider refs and runtime policy separate:
- Use `openai/gpt-*` for OpenAI agent turns through Codex.
- Do not use legacy Codex GPT refs in config. Run `openclaw doctor --fix` to
- Do not use `openai-codex/gpt-*` in config. Run `openclaw doctor --fix` to
repair legacy refs and stale session route pins.
- `agentRuntime.id: "codex"` is optional for normal OpenAI auto mode, but useful
when a deployment should fail closed if Codex is unavailable.
@@ -224,13 +223,13 @@ Common command routing:
| ChatGPT/Codex subscription with native Codex runtime | `openai/gpt-*` plus enabled `codex` plugin | `/status` shows `Runtime: OpenAI Codex` | Recommended path |
| Fail closed if Codex is unavailable | Provider or model `agentRuntime.id: "codex"` | Turn fails instead of embedded fallback | Use for Codex-only deployments |
| Direct OpenAI API-key traffic through OpenClaw | Provider or model `agentRuntime.id: "openclaw"` and normal OpenAI auth | `/status` shows OpenClaw runtime | Use only when OpenClaw is intentional |
| Legacy config | legacy Codex GPT refs | `openclaw doctor --fix` rewrites it | Do not write new config this way |
| Legacy config | `openai-codex/gpt-*` | `openclaw doctor --fix` rewrites it | Do not write new config this way |
| ACP/acpx Codex adapter | ACP `sessions_spawn({ runtime: "acp" })` | ACP task/session status | Separate from native Codex harness |
`agents.defaults.imageModel` follows the same prefix split. Use `openai/gpt-*`
for the normal OpenAI route and `codex/gpt-*` only when image understanding
should run through a bounded Codex app-server turn. Do not use
legacy Codex GPT refs; doctor rewrites that legacy prefix to `openai/gpt-*`.
`openai-codex/gpt-*`; doctor rewrites that legacy prefix to `openai/gpt-*`.
## Deployment patterns
@@ -393,9 +392,6 @@ In `tools.exec.mode: "auto"`, OpenClaw does not preserve legacy unsafe Codex
legacy `plugins.entries.codex.config.appServer.mode: "guardian"` preset still
works, but `tools.exec.mode: "auto"` is the normalized OpenClaw surface.
For the mode-level comparison with host exec approvals and ACPX permissions,
see [Permission modes](/tools/permission-modes).
For every app-server field, auth order, environment isolation, discovery, and
timeout behavior, see [Codex harness reference](/plugins/codex-harness-reference).
@@ -449,7 +445,7 @@ Auth is selected in this order:
1. Ordered OpenAI auth profiles for the agent, preferably under
`auth.order.openai`. Run `openclaw doctor --fix` to migrate older
legacy Codex auth profile ids and legacy Codex auth order.
`openai-codex:*` profile ids and `auth.order.openai-codex`.
2. The app-server's existing account in that agent's Codex home.
3. For local stdio app-server launches only, `CODEX_API_KEY`, then
`OPENAI_API_KEY`, when no app-server account is present and OpenAI auth is
@@ -526,29 +522,29 @@ Supported top-level Codex plugin fields:
| -------------------------- | -------------- | ---------------------------------------------------------------------------------------- |
| `codexDynamicToolsLoading` | `"searchable"` | Use `"direct"` to put OpenClaw dynamic tools directly in the initial Codex tool context. |
| `codexDynamicToolsExclude` | `[]` | Additional OpenClaw dynamic tool names to omit from Codex app-server turns. |
| `codexPlugins` | disabled | Native Codex plugin/app support for configured first-party Codex plugins. |
| `codexPlugins` | disabled | Native Codex plugin/app support for migrated source-installed curated plugins. |
Supported `appServer` fields:
| Field | Default | Meaning |
| --------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `transport` | `"stdio"` | `"stdio"` spawns Codex; `"websocket"` connects to `url`. |
| `command` | managed Codex binary | Executable for stdio transport. Leave unset to use the managed binary; set it only for an explicit override. |
| `args` | `["app-server", "--listen", "stdio://"]` | Arguments for stdio transport. |
| `url` | unset | WebSocket app-server URL. |
| `authToken` | unset | Bearer token for WebSocket transport. |
| `headers` | `{}` | Extra WebSocket headers. |
| `clearEnv` | `[]` | Extra environment variable names removed from the spawned stdio app-server process after OpenClaw builds its inherited environment. OpenClaw keeps per-agent `CODEX_HOME` and inherited `HOME` for local launches. |
| `codeModeOnly` | `false` | Opt into Codex's code-mode-only tool surface. OpenClaw dynamic tools remain registered with Codex so nested `tools.*` calls return through the app-server `item/tool/call` bridge. |
| `requestTimeoutMs` | `60000` | Timeout for app-server control-plane calls. |
| `turnCompletionIdleTimeoutMs` | `60000` | Quiet window after Codex accepts a turn or after a turn-scoped app-server request while OpenClaw waits for `turn/completed`. |
| `postToolRawAssistantCompletionIdleTimeoutMs` | `300000` | Completion-idle and progress guard used after a tool handoff, native tool completion, or post-tool raw assistant progress while OpenClaw waits for `turn/completed`. Use this for trusted or heavy workloads where post-tool synthesis can legitimately stay quiet longer than the final assistant release budget. |
| `mode` | `"yolo"` unless local Codex requirements disallow YOLO | Preset for YOLO or guardian-reviewed execution. Local stdio requirements that omit `danger-full-access`, `never` approval, or the `user` reviewer make the implicit default guardian. |
| `approvalPolicy` | `"never"` or an allowed guardian approval policy | Native Codex approval policy sent to thread start/resume/turn. Guardian defaults prefer `"on-request"` when allowed. |
| `sandbox` | `"danger-full-access"` or an allowed guardian sandbox | Native Codex sandbox mode sent to thread start/resume. Guardian defaults prefer `"workspace-write"` when allowed, otherwise `"read-only"`. When an OpenClaw sandbox is active, `danger-full-access` turns use Codex `workspace-write` with network access derived from the OpenClaw sandbox egress setting. |
| `approvalsReviewer` | `"user"` or an allowed guardian reviewer | Use `"auto_review"` to let Codex review native approval prompts when allowed, otherwise `guardian_subagent` or `user`. `guardian_subagent` remains a legacy alias. |
| `serviceTier` | unset | Optional Codex app-server service tier. `"priority"` enables fast-mode routing, `"flex"` requests flex processing, `null` clears the override, and legacy `"fast"` is accepted as `"priority"`. |
| `experimental.sandboxExecServer` | `false` | Preview opt-in that registers an OpenClaw sandbox-backed Codex environment with Codex app-server 0.132.0 or newer so native Codex execution can run inside the active OpenClaw sandbox. |
| Field | Default | Meaning |
| --------------------------------------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `transport` | `"stdio"` | `"stdio"` spawns Codex; `"websocket"` connects to `url`. |
| `command` | managed Codex binary | Executable for stdio transport. Leave unset to use the managed binary; set it only for an explicit override. |
| `args` | `["app-server", "--listen", "stdio://"]` | Arguments for stdio transport. |
| `url` | unset | WebSocket app-server URL. |
| `authToken` | unset | Bearer token for WebSocket transport. |
| `headers` | `{}` | Extra WebSocket headers. |
| `clearEnv` | `[]` | Extra environment variable names removed from the spawned stdio app-server process after OpenClaw builds its inherited environment. OpenClaw keeps per-agent `CODEX_HOME` and inherited `HOME` for local launches. |
| `codeModeOnly` | `false` | Opt into Codex's code-mode-only tool surface. OpenClaw dynamic tools remain registered with Codex so nested `tools.*` calls return through the app-server `item/tool/call` bridge. |
| `requestTimeoutMs` | `60000` | Timeout for app-server control-plane calls. |
| `turnCompletionIdleTimeoutMs` | `60000` | Quiet window after Codex accepts a turn or after a turn-scoped app-server request while OpenClaw waits for `turn/completed`. Raise this for slow post-tool or status-only synthesis phases. |
| `postToolRawAssistantCompletionIdleTimeoutMs` | `300000` | Completion-idle guard used after a tool handoff when Codex emits raw assistant completion or progress but does not send `turn/completed`. Use this for trusted or heavy workloads where post-tool synthesis can legitimately stay quiet longer than the final assistant release budget. |
| `mode` | `"yolo"` unless local Codex requirements disallow YOLO | Preset for YOLO or guardian-reviewed execution. Local stdio requirements that omit `danger-full-access`, `never` approval, or the `user` reviewer make the implicit default guardian. |
| `approvalPolicy` | `"never"` or an allowed guardian approval policy | Native Codex approval policy sent to thread start/resume/turn. Guardian defaults prefer `"on-request"` when allowed. |
| `sandbox` | `"danger-full-access"` or an allowed guardian sandbox | Native Codex sandbox mode sent to thread start/resume. Guardian defaults prefer `"workspace-write"` when allowed, otherwise `"read-only"`. When an OpenClaw sandbox is active, `danger-full-access` turns use Codex `workspace-write` with network access derived from the OpenClaw sandbox egress setting. |
| `approvalsReviewer` | `"user"` or an allowed guardian reviewer | Use `"auto_review"` to let Codex review native approval prompts when allowed, otherwise `guardian_subagent` or `user`. `guardian_subagent` remains a legacy alias. |
| `serviceTier` | unset | Optional Codex app-server service tier. `"priority"` enables fast-mode routing, `"flex"` requests flex processing, `null` clears the override, and legacy `"fast"` is accepted as `"priority"`. |
| `experimental.sandboxExecServer` | `false` | Preview opt-in that registers an OpenClaw sandbox-backed Codex environment with Codex app-server 0.132.0 or newer so native Codex execution can run inside the active OpenClaw sandbox. |
OpenClaw-owned dynamic tool calls are bounded independently from
`appServer.requestTimeoutMs`: Codex `item/tool/call` requests use a 90 second
@@ -569,23 +565,18 @@ quiet for `appServer.turnCompletionIdleTimeoutMs`, OpenClaw best-effort
interrupts the Codex turn, records a diagnostic timeout, and releases the
OpenClaw session lane so follow-up chat messages are not queued behind a stale
native turn. Most non-terminal notifications for the same turn disarm that short
watchdog because Codex has proven the turn is still alive. Tool handoffs use a
longer post-tool idle budget: after OpenClaw returns an `item/tool/call`
response, after native tool items such as `commandExecution` complete, after raw
`custom_tool_call_output` completions, and after post-tool raw assistant
progress. The guard uses `appServer.postToolRawAssistantCompletionIdleTimeoutMs`
when configured and defaults to five minutes otherwise. That same post-tool
budget also extends the progress watchdog for the silent synthesis window before
Codex emits the next current-turn event. Global app-server notifications, such
as rate-limit updates, do not reset turn-idle progress. Reasoning completions,
commentary `agentMessage` completions, and pre-tool raw reasoning or assistant
progress can be followed by an automatic final reply, so they use the
post-progress reply guard instead of releasing the session lane immediately.
Only final/non-commentary completed `agentMessage` items and pre-tool raw
assistant completions arm the assistant-output release: if Codex then goes quiet
without `turn/completed`, OpenClaw best-effort interrupts the native turn and
releases the session lane. Replay-safe stdio app-server failures, including
turn-completion idle timeouts without assistant, tool, active-item, or
watchdog because Codex has proven the turn is still alive; raw
`custom_tool_call_output` completions keep the short post-tool watchdog armed
because they are the turn-scoped tool-result handoff. Global app-server
notifications, such as rate-limit updates, do not reset turn-idle progress.
Completed `agentMessage` items and pre-tool raw assistant
`rawResponseItem/completed` items arm the assistant-output release: if Codex then
goes quiet without `turn/completed`, OpenClaw best-effort interrupts the native
turn and releases the session lane. Post-tool raw assistant progress keeps
waiting for `turn/completed` while a completion-idle guard stays armed; the guard
uses `appServer.postToolRawAssistantCompletionIdleTimeoutMs` when configured and
defaults to five minutes otherwise. Replay-safe stdio app-server failures,
including turn-completion idle timeouts without assistant, tool, active-item, or
side-effect evidence, are retried once on a fresh app-server attempt. Unsafe
timeouts still retire the stuck app-server client and release the OpenClaw
session lane. They also clear the stale native thread binding and surface a
@@ -709,7 +700,7 @@ Ask affected collaborators to run this read-only command on their OpenClaw host:
```bash
(
pattern='openai/gpt-5\.[45]|openai[-]codex|agentRuntime(\.id)?|harnessRuntime|Runtime: OpenAI Codex|legacy OpenAI Codex prefix|resolveSelectedOpenAIRuntimeProvider|candidateProvider[": ]+openai|status[": ]+401|Incorrect API key|No API key|api-key path|API-key path|OAuth'
pattern='openai/gpt-5\.[45]|agentRuntime(\.id)?|harnessRuntime|Runtime: OpenAI Codex|openai-codex|resolveSelectedOpenAIRuntimeProvider|candidateProvider[": ]+openai|status[": ]+401|Incorrect API key|No API key|api-key path|API-key path|OAuth'
if ls /tmp/openclaw/openclaw-*.log >/dev/null 2>&1; then
grep -E -i -n "$pattern" /tmp/openclaw/openclaw-*.log 2>/dev/null || true
@@ -733,7 +724,7 @@ Useful excerpts usually include `openai/gpt-5.5` or `openai/gpt-5.4`,
`No API key` result. A corrected run should show the OpenAI OAuth
path instead of a plain OpenAI API-key failure.
**Legacy Codex model refs config remains:** run `openclaw doctor --fix`.
**Legacy `openai-codex/*` config remains:** run `openclaw doctor --fix`.
Doctor rewrites legacy model refs to `openai/*`, removes stale session and
whole-agent runtime pins, and preserves existing auth-profile overrides.

View File

@@ -3,7 +3,7 @@ summary: "Configure migrated native Codex plugins for Codex-mode OpenClaw agents
title: "Native Codex plugins"
read_when:
- You want Codex-mode OpenClaw agents to use native Codex plugins
- You are configuring first-party Codex plugin marketplaces
- You are migrating source-installed openai-curated Codex plugins
- You are troubleshooting codexPlugins, app inventory, destructive actions, or plugin app diagnostics
---
@@ -22,9 +22,7 @@ Use this page after the base [Codex harness](/plugins/codex-harness) is working.
- The selected OpenClaw agent runtime must be the native Codex harness.
- `plugins.entries.codex.enabled` must be true.
- `plugins.entries.codex.config.codexPlugins.enabled` must be true.
- V1 supports first-party Codex plugin marketplaces: `openai-curated`,
`openai-bundled`, and `openai-primary-runtime`.
- Migration only auto-discovers `openai-curated` plugins that it observed as
- V1 supports only `openai-curated` plugins that migration observed as
source-installed in the source Codex home.
- The target Codex app-server must be able to see the expected marketplace,
plugin, and app inventory.
@@ -54,11 +52,9 @@ Apply the migration when the plan looks right:
openclaw migrate apply codex --yes
```
Migration writes explicit `codexPlugins` entries for eligible curated plugins
and calls Codex app-server `plugin/install` for selected plugins. Explicit
config may also reference Codex's bundled and primary-runtime first-party
marketplaces when the target app-server inventory exposes those plugin apps. A
typical migrated config looks like this:
Migration writes explicit `codexPlugins` entries for eligible plugins and calls
Codex app-server `plugin/install` for selected plugins. A typical migrated
config looks like this:
```json5
{
@@ -150,10 +146,8 @@ up the updated app set.
V1 is intentionally narrow:
- Runtime config accepts `openai-curated`, `openai-bundled`, and
`openai-primary-runtime` plugin identities.
- Only `openai-curated` plugins that were already installed in the source Codex
app-server inventory are migration-eligible for automatic migration.
app-server inventory are migration-eligible.
- App-backed source plugins must pass the migration-time subscription gate.
`--verify-plugin-apps` adds the source app-inventory gate. Subscription-gated
accounts plus, in verification mode, inaccessible, disabled, missing source
@@ -166,9 +160,7 @@ V1 is intentionally narrow:
- There is no `plugins["*"]` wildcard and no config key that grants arbitrary
install authority.
- Unsupported marketplaces, cached plugin bundles, hooks, and Codex config files
are preserved in the migration report for manual review. Bundled and
primary-runtime first-party plugins can still be added manually through
explicit `codexPlugins` config.
are preserved in the migration report for manual review.
## App inventory and ownership
@@ -256,10 +248,8 @@ app-server auth or rerun with `--verify-plugin-apps` if you want source app
inventory to decide eligibility when account lookup fails.
**`marketplace_missing` or `plugin_missing`:** the target Codex app-server
cannot see the expected first-party marketplace or plugin. Rerun migration
against the target runtime, inspect Codex app-server plugin status, or confirm
the explicit `marketplaceName` is one of `openai-curated`, `openai-bundled`, or
`openai-primary-runtime`.
cannot see the expected `openai-curated` marketplace or plugin. Rerun migration
against the target runtime or inspect Codex app-server plugin status.
**`app_inventory_missing` or `app_inventory_stale`:** app readiness came from an
empty or stale cache. OpenClaw schedules an async refresh and excludes plugin

View File

@@ -141,10 +141,7 @@ observation-only.
**Subagents**
- `subagent_spawned` / `subagent_ended` - observe subagent launch and completion.
- `subagent_delivery_target` - compatibility hook for completion delivery when no core session binding can project a route.
- `subagent_spawning` - deprecated compatibility hook. Core now prepares `thread: true` subagent bindings through channel session-binding adapters before `subagent_spawned` fires.
- `subagent_spawned` includes `resolvedModel` and `resolvedProvider` when OpenClaw has resolved the child session's native model before launch.
- `subagent_spawning` / `subagent_delivery_target` / `subagent_spawned` / `subagent_ended` - coordinate subagent routing and completion delivery
**Lifecycle**
@@ -466,10 +463,6 @@ before the next major release:
- **`before_agent_start`** remains for compatibility. New plugins should use
`before_model_resolve` and `before_prompt_build` instead of the combined
phase.
- **`subagent_spawning`** remains for compatibility with older plugins, but
new plugins should not return thread routing from it. Core prepares
`thread: true` subagent bindings through channel session-binding adapters
before `subagent_spawned` fires.
- **`deactivate`** remains as a deprecated cleanup compatibility alias until
after 2026-08-16. New plugins should use `gateway_stop`.
- **`onResolution` in `before_tool_call`** now uses the typed

View File

@@ -258,14 +258,13 @@ Each metadata entry supports:
Each `configSignals` entry supports:
| Field | Required | Type | What it means |
| ---------------- | -------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `rootPath` | Yes | `string` | Dot path to the plugin-owned config object to inspect, for example `plugins.entries.example.config`. |
| `overlayPath` | No | `string` | Dot path inside the root config whose object should overlay the root object before evaluating the signal. Use this for capability-specific config such as `image`, `video`, or `music`. |
| `overlayMapPath` | No | `string` | Dot path inside the root config whose object values should each overlay the root object. Use this for named account maps such as `accounts`, where any configured account should qualify. |
| `required` | No | `string[]` | Dot paths inside the effective config that must have configured values. Strings must be non-empty; objects and arrays must not be empty. |
| `requiredAny` | No | `string[]` | Dot paths inside the effective config where at least one must have a configured value. |
| `mode` | No | `object` | Optional string mode guard inside the effective config. Use this when config-only availability applies only to one mode. |
| Field | Required | Type | What it means |
| ------------- | -------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `rootPath` | Yes | `string` | Dot path to the plugin-owned config object to inspect, for example `plugins.entries.example.config`. |
| `overlayPath` | No | `string` | Dot path inside the root config whose object should overlay the root object before evaluating the signal. Use this for capability-specific config such as `image`, `video`, or `music`. |
| `required` | No | `string[]` | Dot paths inside the effective config that must have configured values. Strings must be non-empty; objects and arrays must not be empty. |
| `requiredAny` | No | `string[]` | Dot paths inside the effective config where at least one must have a configured value. |
| `mode` | No | `object` | Optional string mode guard inside the effective config. Use this when config-only availability applies only to one mode. |
Each `mode` guard supports:

View File

@@ -120,7 +120,7 @@ commands.
| [senseaudio](/plugins/reference/senseaudio) | Adds media understanding provider support. | `@openclaw/senseaudio-provider`<br />included in OpenClaw | contracts: mediaUnderstandingProviders |
| [sglang](/plugins/reference/sglang) | Adds SGLang model provider support to OpenClaw. | `@openclaw/sglang-provider`<br />included in OpenClaw | providers: sglang |
| [signal](/plugins/reference/signal) | Adds the Signal channel surface for sending and receiving OpenClaw messages. | `@openclaw/signal`<br />included in OpenClaw | channels: signal |
| [sms](/plugins/reference/sms) | Twilio SMS channel plugin for OpenClaw text messages. | `@openclaw/sms`<br />included in OpenClaw | channels: sms |
| [skill-workshop](/plugins/reference/skill-workshop) | Captures repeatable workflows as workspace skills, with pending review, safe writes, and skill prompt refresh. | `@openclaw/skill-workshop`<br />included in OpenClaw | contracts: tools |
| [stepfun](/plugins/reference/stepfun) | Adds StepFun, StepFun Plan model provider support to OpenClaw. | `@openclaw/stepfun-provider`<br />included in OpenClaw | providers: stepfun, stepfun-plan |
| [synthetic](/plugins/reference/synthetic) | Adds Synthetic model provider support to OpenClaw. | `@openclaw/synthetic-provider`<br />included in OpenClaw | providers: synthetic |
| [tavily](/plugins/reference/tavily) | Adds agent-callable tools. Adds web search provider support. | `@openclaw/tavily-plugin`<br />included in OpenClaw | contracts: tools, webSearchProviders; skills |
@@ -138,7 +138,7 @@ commands.
| [webhooks](/plugins/reference/webhooks) | Authenticated inbound webhooks that bind external automation to OpenClaw TaskFlows. | `@openclaw/webhooks`<br />included in OpenClaw | plugin |
| [workboard](/plugins/reference/workboard) | Dashboard workboard for agent-owned issues and sessions. | `@openclaw/workboard`<br />included in OpenClaw | contracts: tools |
| [xai](/plugins/reference/xai) | Adds xAI model provider support to OpenClaw. | `@openclaw/xai-plugin`<br />included in OpenClaw | providers: xai; contracts: imageGenerationProviders, mediaUnderstandingProviders, realtimeTranscriptionProviders, speechProviders, tools, videoGenerationProviders, webSearchProviders |
| [xiaomi](/plugins/reference/xiaomi) | Adds Xiaomi, Xiaomi Token Plan model provider support to OpenClaw. | `@openclaw/xiaomi-provider`<br />included in OpenClaw | providers: xiaomi, xiaomi-token-plan; contracts: speechProviders |
| [xiaomi](/plugins/reference/xiaomi) | Adds Xiaomi MiMo pay-as-you-go and Token Plan provider support to OpenClaw. | `@openclaw/xiaomi-provider`<br />included in OpenClaw | providers: xiaomi, xiaomi-token-plan; contracts: speechProviders |
| [zai](/plugins/reference/zai) | Adds Z.AI model provider support to OpenClaw. | `@openclaw/zai-provider`<br />included in OpenClaw | providers: zai; contracts: mediaUnderstandingProviders |
## Official external packages

View File

@@ -114,8 +114,8 @@ pnpm plugins:inventory:gen
| [senseaudio](/plugins/reference/senseaudio) | Adds media understanding provider support. | `@openclaw/senseaudio-provider`<br />included in OpenClaw | contracts: mediaUnderstandingProviders |
| [sglang](/plugins/reference/sglang) | Adds SGLang model provider support to OpenClaw. | `@openclaw/sglang-provider`<br />included in OpenClaw | providers: sglang |
| [signal](/plugins/reference/signal) | Adds the Signal channel surface for sending and receiving OpenClaw messages. | `@openclaw/signal`<br />included in OpenClaw | channels: signal |
| [skill-workshop](/plugins/reference/skill-workshop) | Captures repeatable workflows as workspace skills, with pending review, safe writes, and skill prompt refresh. | `@openclaw/skill-workshop`<br />included in OpenClaw | contracts: tools |
| [slack](/plugins/reference/slack) | OpenClaw Slack channel plugin for channels, DMs, commands, and app events. | `@openclaw/slack`<br />npm; ClawHub | channels: slack |
| [sms](/plugins/reference/sms) | Twilio SMS channel plugin for OpenClaw text messages. | `@openclaw/sms`<br />included in OpenClaw | channels: sms |
| [stepfun](/plugins/reference/stepfun) | Adds StepFun, StepFun Plan model provider support to OpenClaw. | `@openclaw/stepfun-provider`<br />included in OpenClaw | providers: stepfun, stepfun-plan |
| [synology-chat](/plugins/reference/synology-chat) | Synology Chat channel plugin for OpenClaw channels and direct messages. | `@openclaw/synology-chat`<br />npm; ClawHub | channels: synology-chat |
| [synthetic](/plugins/reference/synthetic) | Adds Synthetic model provider support to OpenClaw. | `@openclaw/synthetic-provider`<br />included in OpenClaw | providers: synthetic |
@@ -139,7 +139,7 @@ pnpm plugins:inventory:gen
| [whatsapp](/plugins/reference/whatsapp) | OpenClaw WhatsApp channel plugin for WhatsApp Web chats. | `@openclaw/whatsapp`<br />ClawHub: `clawhub:@openclaw/whatsapp`; npm | channels: whatsapp |
| [workboard](/plugins/reference/workboard) | Dashboard workboard for agent-owned issues and sessions. | `@openclaw/workboard`<br />included in OpenClaw | contracts: tools |
| [xai](/plugins/reference/xai) | Adds xAI model provider support to OpenClaw. | `@openclaw/xai-plugin`<br />included in OpenClaw | providers: xai; contracts: imageGenerationProviders, mediaUnderstandingProviders, realtimeTranscriptionProviders, speechProviders, tools, videoGenerationProviders, webSearchProviders |
| [xiaomi](/plugins/reference/xiaomi) | Adds Xiaomi, Xiaomi Token Plan model provider support to OpenClaw. | `@openclaw/xiaomi-provider`<br />included in OpenClaw | providers: xiaomi, xiaomi-token-plan; contracts: speechProviders |
| [xiaomi](/plugins/reference/xiaomi) | Adds Xiaomi MiMo pay-as-you-go and Token Plan provider support to OpenClaw. | `@openclaw/xiaomi-provider`<br />included in OpenClaw | providers: xiaomi, xiaomi-token-plan; contracts: speechProviders |
| [zai](/plugins/reference/zai) | Adds Z.AI model provider support to OpenClaw. | `@openclaw/zai-provider`<br />included in OpenClaw | providers: zai; contracts: mediaUnderstandingProviders |
| [zalo](/plugins/reference/zalo) | OpenClaw Zalo channel plugin for bot and webhook chats. | `@openclaw/zalo`<br />npm; ClawHub | channels: zalo |
| [zalouser](/plugins/reference/zalouser) | OpenClaw Zalo Personal Account plugin via native zca-js integration. | `@openclaw/zalouser`<br />npm; ClawHub | channels: zalouser; contracts: tools |

View File

@@ -21,4 +21,3 @@ providers: ollama, ollama-cloud; contracts: memoryEmbeddingProviders, webSearchP
## Related docs
- [ollama](/providers/ollama)
- [ollama-cloud](/providers/ollama-cloud)

View File

@@ -1,5 +1,5 @@
---
summary: "Adds OpenAI model provider support to OpenClaw, including ChatGPT/Codex OAuth."
summary: "Adds OpenAI, OpenAI Codex model provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the openai plugin
title: "OpenAI plugin"
@@ -7,7 +7,7 @@ title: "OpenAI plugin"
# OpenAI plugin
Adds OpenAI model provider support to OpenClaw, including ChatGPT/Codex OAuth.
Adds OpenAI, OpenAI Codex model provider support to OpenClaw.
## Distribution

View File

@@ -21,4 +21,3 @@ providers: qwen, qwencloud, modelstudio, dashscope, qwen-oauth, qwen-portal, qwe
## Related docs
- [qwen](/providers/qwen)
- [qwen-oauth](/providers/qwen-oauth)

View File

@@ -0,0 +1,23 @@
---
summary: "Captures repeatable workflows as workspace skills, with pending review, safe writes, and skill prompt refresh."
read_when:
- You are installing, configuring, or auditing the skill-workshop plugin
title: "Skill Workshop plugin"
---
# Skill Workshop plugin
Captures repeatable workflows as workspace skills, with pending review, safe writes, and skill prompt refresh.
## Distribution
- Package: `@openclaw/skill-workshop`
- Install route: included in OpenClaw
## Surface
contracts: tools
## Related docs
- [skill-workshop](/plugins/skill-workshop)

View File

@@ -1,23 +0,0 @@
---
summary: "Twilio SMS channel plugin for OpenClaw text messages."
read_when:
- You are installing, configuring, or auditing the sms plugin
title: "Sms plugin"
---
# Sms plugin
Twilio SMS channel plugin for OpenClaw text messages.
## Distribution
- Package: `@openclaw/sms`
- Install route: included in OpenClaw
## Surface
channels: sms
## Related docs
- [sms](/channels/sms)

View File

@@ -1,5 +1,5 @@
---
summary: "Adds Xiaomi, Xiaomi Token Plan model provider support to OpenClaw."
summary: "Adds Xiaomi MiMo pay-as-you-go and Token Plan provider support to OpenClaw."
read_when:
- You are installing, configuring, or auditing the xiaomi plugin
title: "Xiaomi plugin"
@@ -7,7 +7,7 @@ title: "Xiaomi plugin"
# Xiaomi plugin
Adds Xiaomi, Xiaomi Token Plan model provider support to OpenClaw.
Adds Xiaomi MiMo pay-as-you-go and Token Plan provider support to OpenClaw.
## Distribution

View File

@@ -188,7 +188,7 @@ The bundled `codex` harness is the native Codex mode for embedded OpenClaw
agent turns. Enable the bundled `codex` plugin first, and include `codex` in
`plugins.allow` if your config uses a restrictive allowlist. Native app-server
configs should use `openai/gpt-*`; OpenAI agent turns select the Codex harness
by default. Legacy Codex model refs routes should be repaired with
by default. Legacy `openai-codex/*` routes should be repaired with
`openclaw doctor --fix`, and legacy `codex/*` model refs remain compatibility
aliases for the native harness.

View File

@@ -792,35 +792,6 @@ canonical replacement.
</Accordion>
<Accordion title="subagent_spawning hook → core thread binding">
**Old**: `api.on("subagent_spawning", handler)` returning
`threadBindingReady` or `deliveryOrigin`.
**New**: let core prepare `thread: true` subagent bindings through the
channel session-binding adapter. Use `api.on("subagent_spawned", handler)`
only for post-launch observation.
```typescript
// Before
api.on("subagent_spawning", async () => ({
status: "ok",
threadBindingReady: true,
deliveryOrigin: { channel: "discord", to: "channel:123", threadId: "456" },
}));
// After
api.on("subagent_spawned", async (event) => {
await observeSubagentLaunch(event);
});
```
`subagent_spawning`, `PluginHookSubagentSpawningEvent`,
`PluginHookSubagentSpawningResult`, and
`SubagentLifecycleHookRunner.runSubagentSpawning(...)` remain only as
deprecated compatibility surfaces while external plugins migrate.
</Accordion>
<Accordion title="Provider discovery types → provider catalog types">
Four discovery type aliases are now thin wrappers over the
catalog-era types:

View File

@@ -660,24 +660,6 @@ API key auth, and dynamic model resolution.
transcribeAudio: async (req) => ({ text: "Transcript..." }),
});
```
Local or self-hosted media providers that intentionally do not require
credentials can expose `resolveSyntheticAuth` and return a non-secret
marker. OpenClaw still keeps the normal auth gate for providers that do
not explicitly opt in.
```typescript
api.registerMediaUnderstandingProvider({
id: "local-audio",
capabilities: ["audio"],
resolveSyntheticAuth: () => ({
apiKey: "custom-local",
source: "local-audio plugin synthetic auth",
mode: "api-key",
}),
transcribeAudio: async (req) => ({ text: "Transcript..." }),
});
```
</Tab>
<Tab title="Embeddings">
```typescript

View File

@@ -0,0 +1,713 @@
---
summary: "Experimental capture of reusable procedures as workspace skills with review, approval, quarantine, and hot skill refresh"
title: "Skill workshop plugin"
read_when:
- You want agents to turn corrections or reusable procedures into workspace skills
- You are configuring procedural skill memory
- You are debugging skill_workshop tool behavior
- You are deciding whether to enable automatic skill creation
---
Skill Workshop is **experimental**. It is disabled by default, its capture
heuristics and reviewer prompts may change between releases, and automatic
writes should be used only in trusted workspaces after reviewing pending-mode
output first.
Skill Workshop is procedural memory for workspace skills. It lets an agent turn
reusable workflows, user corrections, hard-won fixes, and recurring pitfalls
into `SKILL.md` files under:
```text
<workspace>/skills/<skill-name>/SKILL.md
```
This is different from long-term memory:
- **Memory** stores facts, preferences, entities, and past context.
- **Skills** store reusable procedures the agent should follow on future tasks.
- **Skill Workshop** is the bridge from a useful turn to a durable workspace
skill, with safety checks and optional approval.
Skill Workshop is useful when the agent learns a procedure such as:
- how to validate externally sourced animated GIF assets
- how to replace screenshot assets and verify dimensions
- how to run a repo-specific QA scenario
- how to debug a recurring provider failure
- how to repair a stale local workflow note
It is not intended for:
- facts like "the user likes blue"
- broad autobiographical memory
- raw transcript archiving
- secrets, credentials, or hidden prompt text
- one-off instructions that will not repeat
## Default state
The bundled plugin is **experimental** and **disabled by default** unless it is
explicitly enabled in `plugins.entries.skill-workshop`.
The plugin manifest does not set `enabledByDefault: true`. The `enabled: true`
default inside the plugin config schema applies only after the plugin entry has
already been selected and loaded.
Experimental means:
- the plugin is supported enough for opt-in testing and dogfooding
- proposal storage, reviewer thresholds, and capture heuristics can evolve
- pending approval is the recommended starting mode
- auto apply is for trusted personal/workspace setups, not shared or hostile
input-heavy environments
## Enable
Minimal safe config:
```json5
{
plugins: {
entries: {
"skill-workshop": {
enabled: true,
config: {
autoCapture: true,
approvalPolicy: "pending",
reviewMode: "hybrid",
},
},
},
},
}
```
With this config:
- the `skill_workshop` tool is available
- explicit reusable corrections are queued as pending proposals
- threshold-based reviewer passes can propose skill updates
- no skill file is written until a pending proposal is applied
Use automatic writes only in trusted workspaces:
```json5
{
plugins: {
entries: {
"skill-workshop": {
enabled: true,
config: {
autoCapture: true,
approvalPolicy: "auto",
reviewMode: "hybrid",
},
},
},
},
}
```
`approvalPolicy: "auto"` still uses the same scanner and quarantine path. It
does not apply proposals with critical findings.
## Configuration
| Key | Default | Range / values | Meaning |
| -------------------- | ----------- | ------------------------------------------- | -------------------------------------------------------------------- |
| `enabled` | `true` | boolean | Enables the plugin after the plugin entry is loaded. |
| `autoCapture` | `true` | boolean | Enables post-turn capture/review on successful agent turns. |
| `approvalPolicy` | `"pending"` | `"pending"`, `"auto"` | Queue proposals or write safe proposals automatically. |
| `reviewMode` | `"hybrid"` | `"off"`, `"heuristic"`, `"llm"`, `"hybrid"` | Chooses explicit correction capture, LLM reviewer, both, or neither. |
| `reviewInterval` | `15` | `1..200` | Run reviewer after this many successful turns. |
| `reviewMinToolCalls` | `8` | `1..500` | Run reviewer after this many observed tool calls. |
| `reviewTimeoutMs` | `45000` | `5000..180000` | Timeout for the embedded reviewer run. |
| `maxPending` | `50` | `1..200` | Max pending/quarantined proposals kept per workspace. |
| `maxSkillBytes` | `40000` | `1024..200000` | Max generated skill/support file size. |
Recommended profiles:
```json5
// Conservative: explicit tool use only, no automatic capture.
{
autoCapture: false,
approvalPolicy: "pending",
reviewMode: "off",
}
```
```json5
// Review-first: capture automatically, but require approval.
{
autoCapture: true,
approvalPolicy: "pending",
reviewMode: "hybrid",
}
```
```json5
// Trusted automation: write safe proposals immediately.
{
autoCapture: true,
approvalPolicy: "auto",
reviewMode: "hybrid",
}
```
```json5
// Low-cost: no reviewer LLM call, only explicit correction phrases.
{
autoCapture: true,
approvalPolicy: "pending",
reviewMode: "heuristic",
}
```
## Capture paths
Skill Workshop has three capture paths.
### Tool suggestions
The model can call `skill_workshop` directly when it sees a reusable procedure
or when the user asks it to save/update a skill.
This is the most explicit path and works even with `autoCapture: false`.
### Heuristic capture
When `autoCapture` is enabled and `reviewMode` is `heuristic` or `hybrid`, the
plugin scans successful turns for explicit user correction phrases:
- `next time`
- `from now on`
- `remember to`
- `make sure to`
- `always ... use/check/verify/record/save/prefer`
- `prefer ... when/for/instead/use`
- `when asked`
The heuristic creates a proposal from the latest matching user instruction. It
uses topic hints to choose skill names for common workflows:
- animated GIF tasks -> `animated-gif-workflow`
- screenshot or asset tasks -> `screenshot-asset-workflow`
- QA or scenario tasks -> `qa-scenario-workflow`
- GitHub PR tasks -> `github-pr-workflow`
- fallback -> `learned-workflows`
Heuristic capture is intentionally narrow. It is for clear corrections and
repeatable process notes, not for general transcript summarization.
### LLM reviewer
When `autoCapture` is enabled and `reviewMode` is `llm` or `hybrid`, the plugin
runs a compact embedded reviewer after thresholds are reached.
The reviewer receives:
- the recent transcript text, capped to the last 12,000 characters
- up to 12 existing workspace skills
- up to 2,000 characters from each existing skill
- JSON-only instructions
The reviewer has no tools:
- `disableTools: true`
- `toolsAllow: []`
- `disableMessageTool: true`
The reviewer returns either `{ "action": "none" }` or one proposal. The `action` field is `create`, `append`, or `replace` - prefer `append`/`replace` when a relevant skill already exists; use `create` only when no existing skill fits.
Example `create`:
```json
{
"action": "create",
"skillName": "media-asset-qa",
"title": "Media Asset QA",
"reason": "Reusable animated media acceptance workflow",
"description": "Validate externally sourced animated media before product use.",
"body": "## Workflow\n\n- Verify true animation.\n- Record attribution.\n- Store a local approved copy.\n- Verify in product UI before final reply."
}
```
`append` adds `section` + `body`. `replace` swaps `oldText` for `newText` in the named skill.
## Proposal lifecycle
Every generated update becomes a proposal with:
- `id`
- `createdAt`
- `updatedAt`
- `workspaceDir`
- optional `agentId`
- optional `sessionId`
- `skillName`
- `title`
- `reason`
- `source`: `tool`, `agent_end`, or `reviewer`
- `status`
- `change`
- optional `scanFindings`
- optional `quarantineReason`
Proposal statuses:
- `pending` - waiting for approval
- `applied` - written to `<workspace>/skills`
- `rejected` - rejected by operator/model
- `quarantined` - blocked by critical scanner findings
State is stored per workspace under the Gateway state directory:
```text
<stateDir>/skill-workshop/<workspace-hash>.json
```
Pending and quarantined proposals are deduplicated by skill name and change
payload. The store keeps the newest pending/quarantined proposals up to
`maxPending`.
## Tool reference
The plugin registers one agent tool:
```text
skill_workshop
```
### `status`
Count proposals by state for the active workspace.
```json
{ "action": "status" }
```
Result shape:
```json
{
"workspaceDir": "/path/to/workspace",
"pending": 1,
"quarantined": 0,
"applied": 3,
"rejected": 0
}
```
### `list_pending`
List pending proposals.
```json
{ "action": "list_pending" }
```
To list another status:
```json
{ "action": "list_pending", "status": "applied" }
```
Valid `status` values:
- `pending`
- `applied`
- `rejected`
- `quarantined`
### `list_quarantine`
List quarantined proposals.
```json
{ "action": "list_quarantine" }
```
Use this when automatic capture appears to do nothing and the logs mention
`skill-workshop: quarantined <skill>`.
### `inspect`
Fetch a proposal by id.
```json
{
"action": "inspect",
"id": "proposal-id"
}
```
### `suggest`
Create a proposal. With `approvalPolicy: "pending"` (default), this queues instead of writing.
```json
{
"action": "suggest",
"skillName": "animated-gif-workflow",
"title": "Animated GIF Workflow",
"reason": "User established reusable GIF validation rules.",
"description": "Validate animated GIF assets before using them.",
"body": "## Workflow\n\n- Verify the URL resolves to image/gif.\n- Confirm it has multiple frames.\n- Record attribution and license.\n- Avoid hotlinking when a local asset is needed."
}
```
<AccordionGroup>
<Accordion title="Request immediate write in auto mode (apply: true)">
```json
{
"action": "suggest",
"apply": true,
"skillName": "animated-gif-workflow",
"description": "Validate animated GIF assets before using them.",
"body": "## Workflow\n\n- Verify true animation.\n- Record attribution."
}
```
With `approvalPolicy: "pending"`, `apply: true` still queues the proposal. Review it, then use
the `apply` action after approval.
</Accordion>
<Accordion title="Force pending under auto policy (apply: false)">
```json
{
"action": "suggest",
"apply": false,
"skillName": "screenshot-asset-workflow",
"description": "Screenshot replacement workflow.",
"body": "## Workflow\n\n- Verify dimensions.\n- Optimize the PNG.\n- Run the relevant gate."
}
```
</Accordion>
<Accordion title="Append to a named section">
```json
{
"action": "suggest",
"skillName": "qa-scenario-workflow",
"section": "Workflow",
"description": "QA scenario workflow.",
"body": "- For media QA, verify generated assets render and pass final assertions."
}
```
</Accordion>
<Accordion title="Replace exact text">
```json
{
"action": "suggest",
"skillName": "github-pr-workflow",
"oldText": "- Check the PR.",
"newText": "- Check unresolved review threads, CI status, linked issues, and changed files before deciding."
}
```
</Accordion>
</AccordionGroup>
### `apply`
Apply a pending proposal.
With `approvalPolicy: "pending"`, this action asks for operator approval before writing the
workspace skill.
```json
{
"action": "apply",
"id": "proposal-id"
}
```
`apply` refuses quarantined proposals:
```text
quarantined proposal cannot be applied
```
### `reject`
Mark a proposal rejected.
```json
{
"action": "reject",
"id": "proposal-id"
}
```
### `write_support_file`
Write a supporting file inside an existing or proposed skill directory.
Allowed top-level support directories:
- `references/`
- `templates/`
- `scripts/`
- `assets/`
Example:
```json
{
"action": "write_support_file",
"skillName": "release-workflow",
"relativePath": "references/checklist.md",
"body": "# Release Checklist\n\n- Run release docs.\n- Verify changelog.\n"
}
```
Support files are workspace-scoped, path-checked, byte-limited by
`maxSkillBytes`, scanned, and written atomically.
## Skill writes
Skill Workshop writes only under:
```text
<workspace>/skills/<normalized-skill-name>/
```
Skill names are normalized:
- lowercased
- non `[a-z0-9_-]` runs become `-`
- leading/trailing non-alphanumerics are removed
- max length is 80 characters
- final name must match `[a-z0-9][a-z0-9_-]{1,79}`
For `create`:
- if the skill does not exist, Skill Workshop writes a new `SKILL.md`
- if it already exists, Skill Workshop appends the body to `## Workflow`
For `append`:
- if the skill exists, Skill Workshop appends to the requested section
- if it does not exist, Skill Workshop creates a minimal skill then appends
For `replace`:
- the skill must already exist
- `oldText` must be present exactly
- only the first exact match is replaced
All writes are atomic and refresh the in-memory skills snapshot immediately, so
the new or updated skill can become visible without a Gateway restart.
## Safety model
Skill Workshop has a safety scanner on generated `SKILL.md` content and support
files.
Critical findings quarantine proposals:
| Rule id | Blocks content that... |
| -------------------------------------- | --------------------------------------------------------------------- |
| `prompt-injection-ignore-instructions` | tells the agent to ignore prior/higher instructions |
| `prompt-injection-system` | references system prompts, developer messages, or hidden instructions |
| `prompt-injection-tool` | encourages bypassing tool permission/approval |
| `shell-pipe-to-shell` | includes `curl`/`wget` piped into `sh`, `bash`, or `zsh` |
| `secret-exfiltration` | appears to send env/process env data over the network |
Warn findings are retained but do not block by themselves:
| Rule id | Warns on... |
| -------------------- | -------------------------------- |
| `destructive-delete` | broad `rm -rf` style commands |
| `unsafe-permissions` | `chmod 777` style permission use |
Quarantined proposals:
- keep `scanFindings`
- keep `quarantineReason`
- appear in `list_quarantine`
- cannot be applied through `apply`
To recover from a quarantined proposal, create a new safe proposal with the
unsafe content removed. Do not edit the store JSON by hand.
## Prompt guidance
When enabled, Skill Workshop injects a short prompt section that tells the agent
to use `skill_workshop` for durable procedural memory.
The guidance emphasizes:
- procedures, not facts/preferences
- user corrections
- non-obvious successful procedures
- recurring pitfalls
- stale/thin/wrong skill repair through append/replace
- saving reusable procedure after long tool loops or hard fixes
- short imperative skill text
- no transcript dumps
The write mode text changes with `approvalPolicy`:
- pending mode: queue suggestions; use `apply` after explicit approval
- auto mode: apply safe workspace-skill updates unless `apply: false` queues instead
## Costs and runtime behavior
Heuristic capture does not call a model.
LLM review uses an embedded run on the active/default agent model. It is
threshold-based so it does not run on every turn by default.
The reviewer:
- uses the same configured provider/model context when available
- falls back to runtime agent defaults
- has `reviewTimeoutMs`
- uses lightweight bootstrap context
- has no tools
- writes nothing directly
- can only emit a proposal that goes through the normal scanner and
approval/quarantine path
If the reviewer fails, times out, or returns invalid JSON, the plugin logs a
warning/debug message and skips that review pass.
## Operating patterns
Use Skill Workshop when the user says:
- "next time, do X"
- "from now on, prefer Y"
- "make sure to verify Z"
- "save this as a workflow"
- "this took a while; remember the process"
- "update the local skill for this"
Good skill text:
```markdown
## Workflow
- Verify the GIF URL resolves to `image/gif`.
- Confirm the file has multiple frames.
- Record source URL, license, and attribution.
- Store a local copy when the asset will ship with the product.
- Verify the local asset renders in the target UI before final reply.
```
Poor skill text:
```markdown
The user asked about a GIF and I searched two websites. Then one was blocked by
Cloudflare. The final answer said to check attribution.
```
Reasons the poor version should not be saved:
- transcript-shaped
- not imperative
- includes noisy one-off details
- does not tell the next agent what to do
## Debugging
Check whether the plugin is loaded:
```bash
openclaw plugins list --enabled
```
Check proposal counts from an agent/tool context:
```json
{ "action": "status" }
```
Inspect pending proposals:
```json
{ "action": "list_pending" }
```
Inspect quarantined proposals:
```json
{ "action": "list_quarantine" }
```
Common symptoms:
| Symptom | Likely cause | Check |
| ------------------------------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| Tool is unavailable | Plugin entry is not enabled | `plugins.entries.skill-workshop.enabled` and `openclaw plugins list` |
| No automatic proposal appears | `autoCapture: false`, `reviewMode: "off"`, or thresholds not met | Config, proposal status, Gateway logs |
| Heuristic did not capture | User wording did not match correction patterns | Use explicit `skill_workshop.suggest` or enable LLM reviewer |
| Reviewer did not create a proposal | Reviewer returned `none`, invalid JSON, or timed out | Gateway logs, `reviewTimeoutMs`, thresholds |
| Proposal is not applied | `approvalPolicy: "pending"` | `list_pending`, then `apply` |
| Proposal disappeared from pending | Duplicate proposal reused, max pending pruning, or was applied/rejected/quarantined | `status`, `list_pending` with status filters, `list_quarantine` |
| Skill file exists but model misses it | Skill snapshot not refreshed or skill gating excludes it | `openclaw skills` status and workspace skill eligibility |
Relevant logs:
- `skill-workshop: queued <skill>`
- `skill-workshop: applied <skill>`
- `skill-workshop: quarantined <skill>`
- `skill-workshop: heuristic capture skipped: ...`
- `skill-workshop: reviewer skipped: ...`
- `skill-workshop: reviewer found no update`
## QA scenarios
Repo-backed QA scenarios:
- `qa/scenarios/plugins/skill-workshop-animated-gif-autocreate.md`
- `qa/scenarios/plugins/skill-workshop-pending-approval.md`
- `qa/scenarios/plugins/skill-workshop-reviewer-autonomous.md`
Run the deterministic coverage:
```bash
pnpm openclaw qa suite \
--scenario skill-workshop-animated-gif-autocreate \
--scenario skill-workshop-pending-approval \
--concurrency 1
```
Run reviewer coverage:
```bash
pnpm openclaw qa suite \
--scenario skill-workshop-reviewer-autonomous \
--concurrency 1
```
The reviewer scenario is intentionally separate because it enables
`reviewMode: "llm"` and exercises the embedded reviewer pass.
## When not to enable auto apply
Avoid `approvalPolicy: "auto"` when:
- the workspace contains sensitive procedures
- the agent is working on untrusted input
- skills are shared across a broad team
- you are still tuning prompts or scanner rules
- the model frequently handles hostile web/email content
Use pending mode first. Switch to auto mode only after reviewing the kind of
skills the agent proposes in that workspace.
## Related docs
- [Skills](/tools/skills)
- [Plugins](/tools/plugin)
- [Testing](/reference/test)

View File

@@ -50,8 +50,8 @@ Each card stores:
- optional linked session, run, task, or source URL
- optional execution metadata for a Codex or Claude session started from the card
- compact metadata for attempts, comments, links, proof, artifacts, automation,
attachments, worker logs, worker protocol state, claims, diagnostics,
notifications, templates, archive state, and stale-session detection
claims, diagnostics, notifications, templates, archive state, and
stale-session detection
- recent card events such as created, moved, linked, claimed, heartbeat,
attempt, proof, artifact, diagnostic, notification, dispatch, archive, stale,
or agent-updated changes
@@ -108,27 +108,6 @@ Workboard also exposes optional agent tools for board-aware workflows:
final summaries, proof, artifacts, created-card manifests, and blocker
reasons. Created-card manifests must reference cards linked back to the
completed card, which keeps phantom children out of summaries.
- `workboard_attachment_add`, `workboard_attachment_read`, and
`workboard_attachment_delete` store small card attachments in plugin SQLite
state, index them on the card, and expose them in worker context.
- `workboard_worker_log` and `workboard_protocol_violation` record worker log
lines and block cards when an automated worker stops without calling
`workboard_complete` or `workboard_block`.
- `workboard_board_create`, `workboard_board_archive`, and
`workboard_board_delete` manage persisted board metadata such as display name,
description, archive state, and default workspace.
- `workboard_runs` returns the persisted run-attempt history stored on a card.
- `workboard_specify` turns a rough triage or backlog card into a clarified
`todo` card and records the specification summary on the card.
- `workboard_decompose` fans a parent orchestration card into linked children,
inherits board and tenant metadata, and can complete the parent with a
created-card manifest.
- `workboard_notify_subscribe`, `workboard_notify_list`,
`workboard_notify_events`, `workboard_notify_advance`, and
`workboard_notify_unsubscribe` manage notification subscriptions in plugin
state. Event reads are replay-safe; the advance tool moves the durable cursor
so callers can resume without losing or double-reading completed, failed, or
stale card events.
- `workboard_boards`, `workboard_stats`, `workboard_promote`,
`workboard_reassign`, `workboard_reclaim`, `workboard_comment`,
`workboard_proof`, `workboard_unblock`, and `workboard_dispatch` let an agent
@@ -140,112 +119,16 @@ Claimed cards reject agent-tool mutations from other agents unless the caller
has the claim token returned by `workboard_claim`. Dashboard operators still use
the normal Gateway RPC surface and can recover or reassign cards.
Workboard stores durable board data in a plugin-owned relational SQLite database
under the OpenClaw state directory. Boards, cards, labels, lifecycle events,
run attempts, comments, dependency links, proof, artifact references,
attachment metadata and blobs, diagnostics, notifications, worker logs,
protocol state, and subscriptions are persisted in Workboard tables instead of
plugin key-value entries. A card export still preserves the board narrative
without inlining attachment blob contents.
Installations that used Workboard in the `.28` release can run
`openclaw doctor --fix` to migrate the shipped legacy plugin-state namespaces
(`workboard.cards`, `workboard.boards`, and `workboard.notify`) into the
relational database. If a legacy `workboard.attachments` namespace is present,
doctor migrates those attachment blobs too.
Workboard diagnostics are computed from local card metadata. The built-in checks
flag assigned cards that wait too long, running cards without recent heartbeat,
blocked cards that need attention, repeated failures, done cards without proof,
and running cards that only have a loose session link.
Dispatch is intentionally Gateway-local. It does not spawn arbitrary operating
system processes; normal OpenClaw subagent sessions still own execution. A
dispatch nudge promotes dependency-ready cards, records dispatch metadata on
ready cards, blocks expired claims or timed-out runs, marks board-configured
triage cards as orchestration candidates, then claims a small batch of ready
cards and starts worker runs through the Gateway subagent runtime. Workers get
bounded card context plus the claim token they need to heartbeat, complete, or
block the card through the Workboard tools.
### Dispatch worker selection
Each dispatch pass starts at most three workers by default. Ready cards are
ordered by priority, position, and creation time, then filtered to avoid
duplicate active ownership. A dispatch starts only one card for a given owner or
agent in the same pass, and it skips owners that already have running or review
work on the board.
Archived cards, cards with active claims, and cards without `ready` status are
not selected for worker starts. They can still be affected by the data side of
dispatch when stale claims, dependency promotion, or timeout cleanup applies.
### Worker prompt and lifecycle
The worker prompt includes the card title, bounded notes and context, the
assigned board, and the Workboard worker protocol. It also includes the claim
owner and claim token so the worker can call `workboard_heartbeat`,
`workboard_complete`, or `workboard_block` without another actor taking over the
card.
When a worker starts successfully, Workboard stores the session key, run id,
engine, mode, model label, status, and worker log on the card. The session key
is deterministic for the board and card, which makes repeated dispatches route
back to the same worker lane instead of creating unrelated sessions.
If a worker cannot be started after a card is claimed, Workboard blocks the
card, clears the claim, records the run-start failure, and appends a worker log
line. That failure is visible in the dashboard, CLI JSON, agent tools, and card
diagnostics.
### Dispatch entry points
Ready-card worker starts can happen from:
- the dashboard dispatch action
- `openclaw workboard dispatch`
- `/workboard dispatch` on a command-capable channel
All three entry points use the Gateway subagent runtime when the Gateway is
available. The CLI has one extra operator fallback: if the Gateway is offline or
does not expose the Workboard dispatch method and no explicit `--url` or
`--token` target was provided, it runs data-only dispatch against local SQLite
state. That fallback can promote dependencies, clean stale claims, and block
timed-out runs, but it cannot start workers.
Board metadata can include orchestration settings such as `autoDecompose`,
`autoDecomposePerDispatch`, `defaultAssignee`, and `orchestratorProfile`.
OpenClaw records the orchestration intent and exposes it in worker context; the
actual specification and decomposition still happens through the normal
Workboard tools.
## CLI and slash command
The plugin registers a root CLI command:
```bash
openclaw workboard list
openclaw workboard create "Fix stale card lifecycle" --priority high --labels bug,workboard
openclaw workboard show <card-id>
openclaw workboard dispatch
```
`openclaw workboard dispatch` calls the running Gateway so worker starts use the
same subagent runtime as the dashboard. If the Gateway is unavailable, it falls
back to data-only dispatch so dependency promotion, stale-claim cleanup, and
timeout blocking can still run. Auth, permission, and validation failures still
surface as command errors, as do failures for explicit `--url` or `--token`
targets.
The `/workboard` slash command supports the same compact operator path:
`/workboard list`, `/workboard show <card-id>`, `/workboard create <title>`, and
`/workboard dispatch`. List and show are read operations for authorized command
senders. Create and dispatch require owner status on chat surfaces or a Gateway
client with `operator.write` or `operator.admin`.
See [Workboard CLI](/cli/workboard) for command flags, JSON output, Gateway
fallback behavior, unambiguous id-prefix handling, dispatch selection rules, and
troubleshooting.
system processes; normal OpenClaw sessions still own execution. A dispatch nudge
promotes dependency-ready cards, records dispatch metadata on ready cards, and
blocks expired claims or timed-out runs so operators can recover them from the
board.
## Session lifecycle sync
@@ -305,12 +188,9 @@ The plugin registers Gateway RPC methods under the `workboard.*` namespace:
- `workboard.cards.export` requires `operator.read`
- `workboard.cards.diagnostics` requires `operator.read`
- `workboard.cards.diagnostics.refresh` requires `operator.write`
- attachment list/get and notification event reads require `operator.read`
- notification cursor advancement requires `operator.write`
- create, update, move, delete, comment, link, dependency link, proof, artifact,
attachment add/delete, worker log, protocol violation, claim, heartbeat,
release, complete, block, unblock, dispatch, bulk, and archive methods require
`operator.write`
claim, heartbeat, release, complete, block, unblock, dispatch, bulk, and
archive methods require `operator.write`
Browsers connected with read-only operator access can inspect the board but
cannot mutate cards.
@@ -364,26 +244,9 @@ Workboard creates links to normal dashboard sessions. Check the card's agent id
and linked session, then open the Sessions or Chat view to inspect the actual
run state.
### Dispatch does not start a worker
Confirm there is at least one `ready` card without an active claim:
```bash
openclaw workboard list --status ready
```
If the CLI reports data-only dispatch, start or restart the Gateway and retry.
Data-only dispatch updates local board state but cannot start subagent worker
runs.
Cards can also be skipped when another card for the same owner or agent is
already running or waiting for review. Complete, block, or release that active
work before dispatching more work for the same owner.
## Related
- [Control UI](/web/control-ui)
- [Workboard CLI](/cli/workboard)
- [Plugins](/tools/plugin)
- [Manage plugins](/plugins/manage-plugins)
- [Sessions](/concepts/session)

View File

@@ -21,7 +21,7 @@ surfaces such as images, embeddings, speech, and realtime.
OpenAI API-key backup when you intentionally want API-key auth.
- **Non-agent OpenAI APIs** - direct OpenAI Platform access with usage-based
billing through `OPENAI_API_KEY` or OpenAI API-key onboarding.
- **Legacy config** - legacy Codex model refs are repaired by
- **Legacy config** - `openai-codex/*` model refs are repaired by
`openclaw doctor --fix` to `openai/*` plus the Codex runtime.
OpenAI explicitly supports subscription OAuth usage in external tools and workflows like OpenClaw.
@@ -49,7 +49,7 @@ The names are similar but not interchangeable:
| Name you see | Layer | Meaning |
| --------------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------- |
| `openai` | Provider prefix | Canonical OpenAI model route; agent turns use the Codex runtime. |
| legacy OpenAI Codex prefix | Legacy prefix | Older model/profile namespace. `openclaw doctor --fix` migrates it to `openai`. |
| `openai-codex` | Legacy prefix | Older model/profile namespace. `openclaw doctor --fix` migrates it to `openai`. |
| `codex` plugin | Plugin | Bundled OpenClaw plugin that provides native Codex app-server runtime and `/codex` chat controls. |
| provider/model `agentRuntime.id: codex` | Agent runtime | Force the native Codex app-server harness for matching embedded turns. |
| `/codex ...` | Chat command set | Bind/control Codex app-server threads from a conversation. |
@@ -58,8 +58,8 @@ The names are similar but not interchangeable:
This means a config can intentionally contain `openai/*` model refs while auth
profiles point at either API-key or ChatGPT/Codex OAuth credentials. Use
`auth.order.openai` for config; `openclaw doctor --fix` rewrites legacy
legacy Codex model refs, legacy Codex auth profile ids, and
legacy Codex auth order to the canonical OpenAI route.
`openai-codex/*` model refs, `openai-codex:*` profile ids, and
`auth.order.openai-codex` to the canonical OpenAI route.
<Note>
GPT-5.5 is available through both direct OpenAI Platform API-key access and
@@ -75,7 +75,7 @@ OpenClaw runtime config remains available as an opt-in compatibility route. When
explicitly selected with an `openai` OAuth profile, OpenClaw keeps the
public model ref as `openai/*` and routes internally through the Codex-auth
transport. Run `openclaw doctor --fix` to repair stale
legacy Codex model refs, `codex-cli/*`, or old runtime session pins that do not come from
`openai-codex/*`, `codex-cli/*`, or old runtime session pins that do not come from
explicit runtime config.
</Note>
@@ -85,7 +85,7 @@ explicit runtime config.
| ------------------------- | --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| Chat / Responses | `openai/<model>` model provider | Yes |
| Codex subscription models | `openai/<model>` with OpenAI OAuth | Yes |
| Legacy Codex model refs | legacy Codex model refs or `codex-cli/<model>` | Repaired by doctor to `openai/<model>` |
| Legacy Codex model refs | `openai-codex/<model>` or `codex-cli/<model>` | Repaired by doctor to `openai/<model>` |
| Codex app-server harness | `openai/<model>` with omitted runtime or provider/model `agentRuntime.id: codex` | Yes |
| Server-side web search | Native OpenAI Responses tool | Yes, when web search is enabled and no provider pinned |
| Images | `image_generate` | Yes |
@@ -185,7 +185,7 @@ Choose your preferred auth method and follow the setup steps.
auth for an agent model, create a Codex-compatible API-key profile and order
it with `auth.order.openai`; `OPENAI_API_KEY` remains the direct fallback for
non-agent OpenAI API surfaces. Run `openclaw doctor --fix` to migrate older
legacy Codex auth order entries.
`auth.order.openai-codex` entries.
</Note>
### Config example
@@ -266,12 +266,12 @@ Choose your preferred auth method and follow the setup steps.
|-----------|----------------|-------|------|
| `openai/gpt-5.5` | omitted / provider/model `agentRuntime.id: "codex"` | Native Codex app-server harness | Codex sign-in or ordered `openai` auth profile |
| `openai/gpt-5.5` | provider/model `agentRuntime.id: "openclaw"` | OpenClaw embedded runtime with internal Codex-auth transport | Selected `openai` OAuth profile |
| legacy Codex GPT-5.5 ref | repaired by doctor | Legacy route rewritten to `openai/gpt-5.5` | Migrated OpenAI OAuth profile |
| `openai-codex/gpt-5.5` | repaired by doctor | Legacy route rewritten to `openai/gpt-5.5` | Migrated OpenAI OAuth profile |
| `codex-cli/gpt-5.5` | repaired by doctor | Legacy CLI route rewritten to `openai/gpt-5.5` | Codex app-server auth |
<Warning>
Prefer `openai/gpt-5.5` for new subscription-backed agent config. Older
legacy Codex GPT refs are legacy OpenClaw routes, not the native Codex runtime
`openai-codex/gpt-*` refs are legacy OpenClaw routes, not the native Codex runtime
path; run `openclaw doctor --fix` when you want to migrate them to canonical
`openai/*` refs. `gpt-5.3-codex-spark` remains limited to accounts whose
Codex subscription catalog advertises that model; direct OpenAI API-key and
@@ -279,11 +279,11 @@ Choose your preferred auth method and follow the setup steps.
</Warning>
<Note>
The legacy Codex model prefix is legacy config repaired by doctor. For
The `openai-codex/*` model prefix is legacy config repaired by doctor. For
the common subscription plus native runtime setup, sign in with Codex auth
but keep the model ref as `openai/gpt-5.5`. New config should put OpenAI
agent auth order under `auth.order.openai`; doctor migrates older
legacy Codex auth order entries.
`auth.order.openai-codex` entries.
</Note>
### Config example
@@ -345,7 +345,7 @@ Choose your preferred auth method and follow the setup steps.
openclaw models auth list --agent <id> --provider openai
```
If an older config still has legacy Codex GPT refs or a stale OpenAI runtime
If an older config still has `openai-codex/gpt-*` or a stale OpenAI runtime
session pin without explicit runtime config, repair it:
```bash
@@ -370,7 +370,7 @@ Choose your preferred auth method and follow the setup steps.
```
`openai/*` is the model route for OpenAI agent turns through Codex. Run
`openclaw doctor --fix` to migrate older legacy OpenAI Codex prefix profile ids and
`openclaw doctor --fix` to migrate older `openai-codex` profile ids and
order entries before relying on profile ordering.
### Status indicator
@@ -382,7 +382,7 @@ Choose your preferred auth method and follow the setup steps.
### Doctor warning
If legacy Codex model refs or stale OpenAI runtime pins remain in config or
If `openai-codex/*` routes or stale OpenAI runtime pins remain in config or
session state, `openclaw doctor --fix` rewrites them to `openai/*` with the
Codex runtime unless OpenClaw is explicitly configured.
@@ -432,7 +432,7 @@ still account-based. OpenClaw selects auth in this order:
1. Ordered OpenAI auth profiles for the agent, preferably under
`auth.order.openai`. Run `openclaw doctor --fix` to migrate older
legacy Codex auth profile ids and legacy Codex auth order.
`openai-codex:*` profiles and `auth.order.openai-codex`.
2. The app-server's existing account, such as a local Codex CLI ChatGPT sign-in.
3. For local stdio app-server launches only, `CODEX_API_KEY`, then
`OPENAI_API_KEY`, when the app-server reports no account and still requires
@@ -571,7 +571,7 @@ See [Video Generation](/tools/video-generation) for shared tool parameters, prov
## GPT-5 prompt contribution
OpenClaw adds a shared GPT-5 prompt contribution for GPT-5-family runs on OpenClaw-assembled prompt surfaces. It applies by model id, so OpenClaw/provider routes such as legacy pre-repair refs (legacy Codex GPT-5.5 ref), `openrouter/openai/gpt-5.5`, `opencode/gpt-5.5`, and other compatible GPT-5 refs receive the same overlay. Older GPT-4.x models do not.
OpenClaw adds a shared GPT-5 prompt contribution for GPT-5-family runs on OpenClaw-assembled prompt surfaces. It applies by model id, so OpenClaw/provider routes such as legacy pre-repair refs (`openai-codex/gpt-5.5`), `openrouter/openai/gpt-5.5`, `opencode/gpt-5.5`, and other compatible GPT-5 refs receive the same overlay. Older GPT-4.x models do not.
The bundled native Codex harness does not receive this OpenClaw GPT-5 overlay through Codex app-server developer instructions. Native Codex keeps Codex-owned base, model, and project-doc behavior, while OpenClaw disables Codex's built-in personality for native threads so agent workspace personality files stay authoritative. OpenClaw contributes only runtime context such as channel delivery, OpenClaw dynamic tools, ACP delegation, workspace context, and OpenClaw skills.

View File

@@ -24,7 +24,7 @@ The same plugin also registers the `xiaomi` speech (TTS) provider.
| API | OpenAI-compatible (`openai-completions`) |
| Base URLs | Pay-as-you-go: `https://api.xiaomimimo.com/v1`; Token Plan presets: `token-plan-{cn,sgp,ams}...` |
| Default models | `xiaomi/mimo-v2-flash`, `xiaomi-token-plan/mimo-v2.5-pro` |
| TTS default | `mimo-v2.5-tts`, voice `mimo_default`; voicedesign model `mimo-v2.5-tts-voicedesign` |
| TTS default | `mimo-v2.5-tts`, voice `mimo_default` |
## Getting started
@@ -126,34 +126,10 @@ an `assistant` message and optional style guidance as a `user` message.
```
Supported built-in voices include `mimo_default`, `default_zh`, `default_en`,
`Mia`, `Chloe`, `Milo`, and `Dean`. Preset-voice models use `audio.voice`, so
OpenClaw sends `speakerVoice` for `mimo-v2.5-tts` and `mimo-v2-tts`.
Xiaomi's voicedesign model, `mimo-v2.5-tts-voicedesign`, generates the voice
from a natural-language style prompt instead of a preset voice id. Configure
`style` with the desired voice description; OpenClaw sends it as the `user`
message, sends the spoken text as the `assistant` message, and omits
`audio.voice` for this model.
```json5
{
messages: {
tts: {
provider: "xiaomi",
providers: {
xiaomi: {
model: "mimo-v2.5-tts-voicedesign",
format: "wav",
style: "Warm, natural female voice with clear pronunciation.",
},
},
},
},
}
```
For voice-note targets such as Feishu and Telegram, OpenClaw transcodes Xiaomi
output to 48kHz Opus with `ffmpeg` before delivery.
`Mia`, `Chloe`, `Milo`, and `Dean`. `mimo-v2-tts` is supported for older MiMo
TTS accounts; the default uses the current MiMo-V2.5 TTS model. For voice-note
targets such as Feishu and Telegram, OpenClaw transcodes Xiaomi output to 48kHz
Opus with `ffmpeg` before delivery.
## Config example

View File

@@ -1092,11 +1092,9 @@ sessionId})`; create, branch, continue, list, and fork flows live in their
legacy `jobs.json`, `jobs-state.json`, and `runs/*.jsonl` files and removes
the imported sources. Plugin target writebacks update matching `cron_jobs`
rows instead of loading and replacing the whole cron store.
- Doctor and Gateway startup translate legacy `notify: true` webhook fallback
into explicit SQLite delivery before the scheduler runs. Jobs that already
announce to a chat keep that delivery and receive a webhook
`completionDestination`; jobs without `cron.webhook` are reported for manual
repair.
- If doctor cannot safely translate legacy `notify: true` webhook fallback
without replacing an explicit delivery target, it records a warning and leaves
the legacy source in place instead of publishing a lossy SQLite row.
- Outbound and session delivery queues now store queue status, entry kind,
session key, channel, target, account id, retry count, last attempt/error,
recovery state, and platform-send markers as typed columns in the shared

View File

@@ -6,7 +6,6 @@ read_when:
- You want to enable OpenClaw code mode for an agent run
- You need to explain why code mode is different from Codex Code mode
- You are reviewing the exec/wait contract, QuickJS-WASI sandbox, TypeScript transform, or hidden tool-catalog bridge
- You are adding or reviewing an internal code-mode namespace registry integration
---
Code mode is an experimental OpenClaw agent-runtime feature. It is off by
@@ -381,7 +380,6 @@ The guest runtime exposes a small global API:
```typescript
declare const ALL_TOOLS: ToolCatalogEntry[];
declare const tools: ToolCatalog;
declare const namespaces: Record<string, unknown>;
declare function text(value: unknown): void;
declare function json(value: unknown): void;
@@ -435,189 +433,6 @@ const hits = await tools.web_search({ query: "OpenClaw code mode" });
The guest runtime must not expose host objects directly. Inputs and outputs cross
the bridge as JSON-compatible values with explicit size caps.
## Internal namespaces
Internal namespaces give code mode a concise domain API without adding more
model-visible tools. A loader-owned integration can register a namespace such
as `Issues`, `Fictions`, or `Calendar`; guest code then calls that namespace
inside the QuickJS program while OpenClaw still shows only `exec` and `wait` to
the model.
Namespaces are internal for now. There is no public plugin SDK namespace API:
external plugin namespaces need a loader-owned contract so plugin identity,
installed manifests, auth state, and cached catalog descriptors cannot drift
from the plugin tools that back the namespace. Core code mode owns only the
sandbox, serialization, catalog gating, and bridge dispatch.
Guest code can then use either the direct global or the `namespaces` map:
```javascript
const open = await Issues.list({ state: "open" });
const alsoOpen = await namespaces.Issues.list({ state: "open" });
return { count: open.length, alsoCount: alsoOpen.length };
```
### Registry lifecycle
The namespace registry is process-local and keyed by namespace id. A typical
run follows this path:
1. A trusted loader calls `registerCodeModeNamespaceForPlugin(pluginId, registration)`.
2. Code mode creates the hidden `ToolSearchRuntime` for the run and reads its
run-scoped catalog.
3. `createCodeModeNamespaceRuntime(ctx, catalog)` keeps only registrations
whose `requiredToolNames` are all visible and owned by the same `pluginId`.
4. Each visible namespace calls `createScope(ctx)` for the current run. The
scope receives run context such as `agentId`, `sessionKey`, `sessionId`,
`runId`, config, and abort state.
5. Scope data is serialized into a plain descriptor and injected into QuickJS as
direct globals and `namespaces.<globalName>`.
6. Guest calls suspend through the worker bridge, resolve the namespace path on
the host, map the call to a declared plugin-owned catalog tool, and execute
that tool through `ToolSearchRuntime.call`.
7. `wait` resumes the same namespace runtime when a code-mode run suspended on
nested tool work.
8. Plugin rollback or uninstall calls `clearCodeModeNamespacesForPlugin(pluginId)`
so stale globals do not survive a failed plugin load.
The important invariant: namespace calls are catalog tool calls. They use the
same policy hooks, approvals, abort handling, telemetry, transcript projection,
and suspend/resume behavior as `tools.call(...)`.
### Registration shape
Register namespaces from the integration that owns the backing tools. Keep the
scope small and only expose domain verbs that map to declared catalog tools.
```typescript
import {
createCodeModeNamespaceTool,
registerCodeModeNamespaceForPlugin,
} from "../agents/code-mode-namespaces.js";
const pluginId = "github";
registerCodeModeNamespaceForPlugin(pluginId, {
id: "github-issues",
globalName: "Issues",
description: "GitHub issue helpers for the current repository.",
requiredToolNames: ["github_list_issues", "github_update_issue"],
prompt: "Use Issues.list(params) and Issues.update(number, patch).",
createScope: (ctx) => ({
repository: ctx.config,
list: createCodeModeNamespaceTool("github_list_issues", ([params]) => params ?? {}),
update: createCodeModeNamespaceTool("github_update_issue", ([number, patch]) => ({
number,
patch,
})),
}),
});
```
`createCodeModeNamespaceTool(toolName, inputMapper)` marks a scope member as a
callable namespace function. The optional `inputMapper` receives the guest
arguments and returns the input object for the backing catalog tool. Without an
input mapper, the first guest argument is used, or `{}` when omitted.
Raw host functions are rejected before guest code runs:
```typescript
createScope: () => ({
// Wrong: this bypasses the catalog tool lifecycle and will be rejected.
list: async () => githubClient.listIssues(),
});
```
### Ownership and visibility
Namespace ownership is bound to the registration caller's `pluginId`.
`requiredToolNames` is both a visibility gate and an ownership check:
- every required tool must exist in the run catalog
- every required tool must have `sourceName === pluginId`
- the namespace is hidden when any required tool is absent or owned by another
plugin
- each callable path may target only a tool named in `requiredToolNames`
This prevents another plugin from exposing a namespace by registering a
same-named tool. It also keeps namespaces aligned with ordinary agent policy:
if the run cannot see the backing tools, it cannot see the namespace.
For example, a GitHub namespace should live behind a GitHub-owned extension that
owns GitHub auth, REST or GraphQL clients, rate limits, write approvals, and
tests. Core code mode should not embed GitHub-specific APIs, token handling, or
provider policy.
### Scope serialization rules
`createScope(ctx)` may return a plain object containing JSON-compatible values,
arrays, nested objects, and `createCodeModeNamespaceTool(...)` call markers.
Host objects never enter QuickJS directly.
The serializer rejects:
- raw functions
- circular object graphs
- unsafe path segments: `__proto__`, `constructor`, `prototype`, empty keys, or
keys containing the internal path separator
- `globalName` values that are not JavaScript identifiers
- `globalName` collisions with built-in code-mode globals such as `tools`,
`namespaces`, `text`, `json`, `yield_control`, or `__openclaw*`
Values that cannot be JSON-serialized are converted to JSON-safe fallback
values before crossing the bridge. Binary data, handles, sockets, clients, and
class instances should stay behind ordinary catalog tools.
### Prompts
The namespace `description` and optional `prompt` are appended to the model
visible `exec` schema only when the namespace is visible for that run. Use them
to teach the smallest useful surface:
```typescript
{
description: "Fiction production service helpers.",
prompt:
"Use Fictions.riskAudit(), Fictions.promoteIfReady(id, status), and Fictions.unpaidOver(amount).",
}
```
Keep prompts about the namespace contract, not auth setup, implementation
history, or unrelated plugin behavior.
### Cleanup
Namespaces are process-local registrations. Remove them when the owning plugin
is disabled, uninstalled, or rolled back:
```typescript
clearCodeModeNamespacesForPlugin(pluginId);
```
Use `unregisterCodeModeNamespace(namespaceId)` only when removing one known
namespace. Tests can call `clearCodeModeNamespacesForTest()` to avoid leaking
registrations across cases.
### Test checklist
Namespace changes should cover the security boundary and the guest behavior:
- namespace prompt text appears only when backing tools are visible
- same-named tools from another `sourceName` do not expose the namespace
- raw scope functions are rejected
- forged namespace ids and forged paths are rejected
- callable paths cannot target undeclared tools
- nested objects and shared references serialize correctly
- namespace calls execute through catalog tools and return JSON-safe details
- failures can be caught by guest code
- suspended namespace calls resume through `wait`
- plugin rollback clears the owning namespace registrations
Namespaces complement the generic `tools.search` / `tools.call` catalog. Use
the catalog for arbitrary enabled tools; use namespaces for plugin-owned,
documented domain APIs where concise code is more reliable than repeated schema
lookups.
## Output API
`text(value)` appends human-readable output to the `output` array.

View File

@@ -58,11 +58,6 @@ explicitly to use Gemini, Voyage, Mistral, DeepInfra, Bedrock, GitHub Copilot,
Ollama, a local GGUF model, or an OpenAI-compatible `/v1/embeddings` endpoint.
Legacy configs that still say `provider: "auto"` resolve to `openai`.
If OpenAI embeddings are unreachable from your network, memory recall fails open
instead of blocking the turn. Set the existing `memorySearch.provider` field to a
reachable local, Ollama, regional, or OpenAI-compatible provider to restore
semantic ranking.
### Custom provider ids
`memorySearch.provider` can point at a custom `models.providers.<id>` entry for memory-specific provider adapters such as `ollama`, or for OpenAI-compatible model APIs such as `openai-responses` / `openai-completions`. OpenClaw resolves that provider's `api` owner for the embedding adapter while preserving the custom provider id for endpoint, auth, and model-prefix handling. This lets multi-GPU or multi-host setups dedicate memory embeddings to a specific local endpoint:

View File

@@ -13,11 +13,9 @@ to the public blog post.
Two audits are combined here:
- **Release performance sweep:** GitHub Releases from `v2026.5.28` back through
- **Release performance sweep:** GitHub Releases from `v2026.5.27` back through
stable `v2026.4.23`, using the `OpenClaw Performance` workflow,
`profile=smoke`, mock-provider lane. Most tag rows are one sample; the
`v2026.5.27` and `v2026.5.28` rows use the latest repeat-3 release-branch
artifacts.
`profile=smoke`, `repeat=1`, mock-provider lane.
- **Earlier April context:** published `clawgrit-reports` mock-provider
baselines from `v2026.4.1` through `v2026.5.2`, used only to avoid treating
the broken late-April releases as the public performance baseline.
@@ -29,44 +27,42 @@ Two audits are combined here:
file count.
<Warning>
The main performance sweep uses one smoke sample per tag, except the
`v2026.5.27` and `v2026.5.28` rows, which use the latest repeat-3
release-branch artifacts. Earlier April context uses published repeat-3
medians from `clawgrit-reports`. Treat the numbers as trend evidence and
regression-hunting signal, not as release-gate statistics.
The main performance sweep uses one smoke sample per tag. Earlier April context
uses published repeat-3 medians from `clawgrit-reports`. Treat the numbers as
trend evidence and regression-hunting signal, not as release-gate statistics.
</Warning>
## Snapshot
Performance coverage: **77 requested releases**, **74 artifact-backed points**,
and **3 unavailable CI runs**. Latest stable measured point: `v2026.5.28`.
Performance coverage: **76 requested releases**, **73 artifact-backed points**,
and **3 unavailable CI runs**. Latest stable measured point: `v2026.5.27`.
<CardGroup cols={2}>
<Card title="Stable agent turn" icon="gauge">
**5.1x faster cold turn**
**2.9x faster cold turn**
- `v2026.4.14`: 9.8s
- `v2026.5.28`: 1.9s
- `v2026.5.27`: 3.4s
</Card>
<Card title="Published package" icon="package">
**17.9MB tarball**
**17.8MB tarball**
Latest stable package, down from the 43.3MB March package-size peak.
</Card>
<Card title="Latest stable install" icon="hard-drive">
**361.7MiB fresh install**
**786.9MB fresh install**
`v2026.5.28` cuts the nested OpenClaw dependency tree sharply, but a
smaller 259.7MiB nested tree still remains in the local install audit.
`v2026.5.27` still contains the nested OpenClaw dependency tree. The
next-release state on `main` is 407.4MB.
</Card>
<Card title="Dependency graph" icon="boxes">
**300 installed packages**
**371 installed packages**
Latest stable release, measured as unique package name/version roots in a
fresh install with scripts disabled.
Latest stable release. Current `main` is down to 314 after the follow-up
dependency cleanup.
</Card>
</CardGroup>
@@ -88,44 +84,45 @@ and **3 unavailable CI runs**. Latest stable measured point: `v2026.5.28`.
</Card>
<Card title="Latest stable" icon="tag">
**361.7MiB install**
**786.9MB install**
`2026.5.28` cuts fresh install size by 52.8% from `2026.5.27`, but still
installs a 259.7MiB nested OpenClaw tree.
`2026.5.27` reduced the peak but still installed a 675.9MB nested
OpenClaw tree.
</Card>
<Card title="Dependency graph" icon="scissors">
**300 package roots**
<Card title="Next-release state" icon="scissors">
**407.4MB install**
`2026.5.28` installs 71 fewer unique package name/version roots than
`2026.5.27`.
Current `main` keeps shrinkwrap, removes the nested tree, and installs
314 packages.
</Card>
</CardGroup>
<Tip>
Shrinkwrap was not the problem by itself. The bad package shape was.
`v2026.5.28` still ships shrinkwrap, but the nested dependency tree is much
smaller and the all-platform canvas fanout is gone in the local audit.
Shrinkwrap was not the problem by itself. The bad package shape was. Current
`main` still ships shrinkwrap, but npm no longer materializes a second
OpenClaw dependency tree during install.
</Tip>
## What Changed In 5.28
## What Changed After 5.27
The cleanup between `v2026.5.27` and `v2026.5.28` reduced the default-install
graph instead of removing the capabilities themselves.
The cleanup between `v2026.5.27` and current `main` removed the duplicate
default-install graph instead of removing the capabilities themselves.
<CardGroup cols={2}>
<Card title="Root default graph" icon="git-branch">
Unique package name/version roots fell from **371** to **300**. Package
instances fell from **372** to **301**.
Root shrinkwrap package paths fell from **372** to **331**. Unique package
names fell from **357** to **318**.
</Card>
<Card title="Nested tree" icon="unplug">
Nested `openclaw/node_modules` fell from **656.1MiB** to **259.7MiB** in
the same local install audit.
<Card title="Direct root dependencies" icon="unplug">
`@earendil-works/pi-agent-core`, `@earendil-works/pi-ai`,
`@earendil-works/pi-coding-agent`, and `pdfjs-dist` left the default root
dependency path.
</Card>
<Card title="Native optional cones" icon="cpu">
The all-platform `@napi-rs/canvas` native package cone stopped landing in
the default install.
The all-platform `@napi-rs/canvas` and `@mariozechner/clipboard` native
package cones stopped landing in the default install.
</Card>
<Card title="Supply-chain surface" icon="shield">
Fewer default packages means fewer tarballs, maintainers, native binaries,
@@ -141,11 +138,11 @@ Do not use the late-April broken rows as public performance baselines.
For the blog narrative, use the earlier April published baseline as scale:
| Metric | Earlier April baseline | `v2026.5.28` | Delta |
| Metric | Earlier April baseline | `v2026.5.27` | Delta |
| --------------- | ---------------------: | -----------: | -----------------------: |
| Cold agent turn | 9,819ms | 1,908ms | 80.6% lower, 5.1x faster |
| Warm agent turn | 7,458ms | 1,870ms | 74.9% lower, 4.0x faster |
| Agent peak RSS | 686.2MB | 581.0MB | 15.3% lower |
| Cold agent turn | 9,819ms | 3,378ms | 65.6% lower, 2.9x faster |
| Warm agent turn | 7,458ms | 2,973ms | 60.1% lower, 2.5x faster |
| Agent peak RSS | 686.2MB | 635.5MB | 7.4% lower |
The earlier April baseline is `v2026.4.14` from the published
`clawgrit-reports` mock-provider run. That run used repeat 3 and failed only
@@ -153,33 +150,32 @@ because the diagnostic timeline was not emitted; the cold, warm, and RSS
medians are still useful as rough scale. Treat this as narrative context, not a
release-gate statistic.
Within the May sweep, the latest release-branch row moved materially from
`v2026.5.2`:
Within the single-sample stable May sweep, the line moved more modestly:
| Metric | `v2026.5.2` | `v2026.5.28` | Delta |
| Metric | `v2026.5.2` | `v2026.5.27` | Delta |
| --------------- | ----------: | -----------: | ----------: |
| Cold agent turn | 3,897ms | 1,908ms | 51.0% lower |
| Warm agent turn | 3,610ms | 1,870ms | 48.2% lower |
| Agent peak RSS | 613.7MB | 581.0MB | 5.3% lower |
| Cold agent turn | 3,897ms | 3,378ms | 13.3% lower |
| Warm agent turn | 3,610ms | 2,973ms | 17.6% lower |
| Agent peak RSS | 613.7MB | 635.5MB | 3.6% higher |
Compared with the previous stable release:
Best prerelease point in the single-sample sweep:
| Metric | `v2026.5.27` | `v2026.5.28` | Delta |
| --------------- | -----------: | -----------: | ----------: |
| Cold agent turn | 2,231ms | 1,908ms | 14.5% lower |
| Warm agent turn | 2,226ms | 1,870ms | 16.0% lower |
| Agent peak RSS | 649.0MB | 581.0MB | 10.5% lower |
| Metric | `v2026.5.27` | `v2026.5.27-beta.1` | Delta |
| --------------- | -----------: | ------------------: | ----------: |
| Cold agent turn | 3,378ms | 2,575ms | 23.8% lower |
| Warm agent turn | 2,973ms | 2,217ms | 25.4% lower |
| Agent peak RSS | 635.5MB | 635.3MB | flat |
### Install footprint
| Metric | Baseline | `v2026.5.28` | Delta |
| Metric | Baseline | Current main | Delta |
| ----------------------------------------------- | --------: | -----------: | ----------: |
| Install size from `2026.5.22` peak | 1,020.6MB | 361.7MiB | 64.6% lower |
| Install size from latest release `2026.5.27` | 767.1MiB | 361.7MiB | 52.8% lower |
| Dependencies from monthly high `2026.2.26` | 645 | 300 | 53.5% lower |
| Dependencies from latest release `2026.5.27` | 371 | 300 | 19.1% lower |
| Nested `openclaw/node_modules` from `2026.5.22` | 911.8MB | 259.7MiB | 71.5% lower |
| Nested `openclaw/node_modules` from `2026.5.27` | 656.1MiB | 259.7MiB | 60.4% lower |
| Install size from `2026.5.22` peak | 1,020.6MB | 407.4MB | 60.1% lower |
| Install size from latest release `2026.5.27` | 786.9MB | 407.4MB | 48.2% lower |
| Dependencies from monthly high `2026.2.26` | 645 | 314 | 51.3% lower |
| Dependencies from latest release `2026.5.27` | 371 | 314 | 15.4% lower |
| Nested `openclaw/node_modules` from `2026.5.22` | 911.8MB | 0MB | removed |
| Nested `openclaw/node_modules` from `2026.5.27` | 675.9MB | 0MB | removed |
### npm package size
@@ -191,8 +187,7 @@ Compared with the previous stable release:
| `2026.4.29` | 22.9MB | 74.6MB | 9,309 | package pruning visible |
| `2026.5.12` | 23.4MB | 80.1MB | 12,035 | major external-plugin split |
| `2026.5.22` | 17.2MB | 76.9MB | 12,386 | docs/assets excluded from package |
| `2026.5.27` | 17.8MB | 79.0MB | 12,509 | previous stable package |
| `2026.5.28` | 17.9MB | 81.0MB | 9,082 | latest stable package |
| `2026.5.27` | 17.8MB | 79.0MB | 12,509 | latest stable package |
`2026.5.12` is the visible plugin-extraction milestone in the changelog:
Amazon Bedrock, Bedrock Mantle, Slack, OpenShell sandbox, Anthropic Vertex,
@@ -216,7 +211,7 @@ Earlier published context:
| `v2026.4.20` | FAIL | 22,314ms | 18,811ms | 810.8MB |
| `v2026.4.22` | FAIL | 9,630ms | 7,459ms | 743.0MB |
Supplied sweep:
Supplied single-sample sweep:
| Release | Kova | Cold turn | Warm turn | Agent peak RSS |
| ------------------- | ---- | --------: | --------: | -------------: |
@@ -234,8 +229,7 @@ Supplied sweep:
| `v2026.5.22` | PASS | 4,494ms | 4,093ms | 654.3MB |
| `v2026.5.26` | PASS | 2,626ms | 2,282ms | 660.4MB |
| `v2026.5.27-beta.1` | PASS | 2,575ms | 2,217ms | 635.3MB |
| `v2026.5.27` | PASS | 2,231ms | 2,226ms | 649.0MB |
| `v2026.5.28` | PASS | 1,908ms | 1,870ms | 581.0MB |
| `v2026.5.27` | PASS | 3,378ms | 2,973ms | 635.5MB |
## Source probes
@@ -255,8 +249,7 @@ Representative source-probe points:
| `v2026.5.22` | 2,081ms | 1,884ms | 5,095ms | 444.2MB |
| `v2026.5.26` | 1,546ms | 1,634ms | 656ms | 400.4MB |
| `v2026.5.27-beta.1` | 1,462ms | 1,548ms | 548ms | 394.0MB |
| `v2026.5.27` | 1,491ms | 1,571ms | 553ms | 401.5MB |
| `v2026.5.28` | 1,457ms | 1,474ms | 623ms | 386.1MB |
| `v2026.5.27` | 1,874ms | 1,925ms | 660ms | 398.0MB |
The `v2026.5.22` CLI health spike is visible in this table even though the
agent-turn lane still passed. Keep the source probes when investigating
@@ -265,7 +258,8 @@ targeted CLI or gateway regressions.
## Install footprint audit
Dependency samples use one stable release per month, plus the
`2026.5.22` shrinkwrap-introduction event and the latest `2026.5.28` release.
`2026.5.22` shrinkwrap-introduction event, latest `2026.5.27`, and current
`main`.
| Point | Installed deps | Fresh install | OpenClaw package | Nested `openclaw/node_modules` | Root shrinkwrap | Canvas install behavior |
| ------------------ | -------------: | ------------: | ---------------: | -----------------------------: | --------------- | ----------------------------------------- |
@@ -275,8 +269,8 @@ Dependency samples use one stable release per month, plus the
| Apr `2026.4.29` | 392 | 335.0MB | 97.4MB | 0MB | no | none installed |
| `2026.5.22` | 401 | 1,020.6MB | 1,020.4MB | 911.8MB | yes | nested: all 12 `@napi-rs/canvas` packages |
| May `2026.5.26` | 371 | 767.5MB | 767.4MB | 656.4MB | yes | nested: all 12 `@napi-rs/canvas` packages |
| `2026.5.27` | 371 | 767.1MiB | 766.9MiB | 656.1MiB | yes | nested: all 12 `@napi-rs/canvas` packages |
| Latest `2026.5.28` | 300 | 361.7MiB | 361.6MiB | 259.7MiB | yes | none installed |
| Latest `2026.5.27` | 371 | 786.9MB | 786.7MB | 675.9MB | yes | nested: all 12 `@napi-rs/canvas` packages |
| Current `main` | 314 | 407.4MB | 101.0MB | 0MB | yes | top-level wrapper + `darwin-arm64` |
### Shrinkwrap boundary
@@ -290,12 +284,11 @@ Dependency samples use one stable release per month, plus the
`openclaw/node_modules`.
</Card>
<Card title="Latest stable" icon="tag">
`2026.5.28` keeps shrinkwrap and still installs 259.7MiB under nested
`2026.5.27` keeps shrinkwrap and still installs 675.9MB under nested
`openclaw/node_modules`.
</Card>
<Card title="Canvas fanout fixed" icon="check">
`2026.5.28` no longer installs any `@napi-rs/canvas` packages in the local
fresh install audit.
<Card title="Current main" icon="check">
`main` keeps shrinkwrap and removes the nested OpenClaw dependency tree.
</Card>
</CardGroup>
@@ -311,13 +304,12 @@ Published tarball inspection verifies the boundary:
| `2026.5.25` | no | n/a | no stable npm release |
| `2026.5.26` | yes | yes | nested dependency tree still present |
| `2026.5.27` | yes | yes | nested dependency tree still present |
| `2026.5.28` | yes | yes | nested dependency tree much smaller |
| `main` | n/a | yes | nested dependency tree removed |
The important distinction: **shrinkwrap itself is not the problem**.
`v2026.5.28` still ships root shrinkwrap. The problem was the package shape
that made npm materialize a large nested OpenClaw dependency tree and all 12
`@napi-rs/canvas` platform packages. The nested tree is smaller in `v2026.5.28`,
and the canvas platform fanout no longer lands in the local audit.
The important distinction: **shrinkwrap itself is not the problem**. Current
`main` still ships root shrinkwrap. The problem was the package shape that made
npm materialize a large nested OpenClaw dependency tree and all 12
`@napi-rs/canvas` platform packages.
For a plain-English explanation of shrinkwrap and the maintainer-level package
checks, see [npm shrinkwrap](/gateway/security/shrinkwrap).
@@ -345,3 +337,24 @@ Related docs:
- [Plugin dependency resolution](/plugins/dependency-resolution)
- [Plugin inventory](/plugins/plugin-inventory)
- [Full release validation](/reference/full-release-validation)
## Unavailable performance runs
| Release | Run | Result | Reason |
| ------------------- | ---------------------------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------- |
| `v2026.5.3-1` | [26561664645](https://github.com/openclaw/openclaw/actions/runs/26561664645) | failure | mock-provider job failed: CLI startup timed out waiting for qa-channel ready; no qa-channel accounts reported |
| `v2026.5.3` | [26561666722](https://github.com/openclaw/openclaw/actions/runs/26561666722) | failure | mock-provider job failed: CLI startup timed out waiting for qa-channel ready; no qa-channel accounts reported |
| `v2026.4.29-beta.2` | [26561683635](https://github.com/openclaw/openclaw/actions/runs/26561683635) | cancelled | optional baseline fetch hung before artifact upload |
## Follow-up gates
Recommended release checks from this sweep:
1. Run the mock-provider performance smoke for release candidates and retain
artifacts.
2. Track cold turn, warm turn, agent RSS, Gateway `readyz`, and CLI health.
3. Fresh-install the packed tarball with scripts disabled.
4. Record installed dependency count, install size, package size, nested
`openclaw/node_modules` size, and native optional package shape.
5. Fail or hold release review when nested dependency trees or all-platform
native packages appear unexpectedly.

View File

@@ -1,51 +1,59 @@
---
summary: "Rich output protocol for structured media, embeds, audio hints, and replies"
summary: "Rich output shortcode protocol for embeds, media, audio hints, and replies"
read_when:
- Changing assistant output rendering in the Control UI
- Debugging `[embed ...]`, structured media, reply, or audio presentation directives
- Debugging `[embed ...]`, `MEDIA:`, reply, or audio presentation directives
title: "Rich output protocol"
---
Assistant output can carry a small set of delivery/render directives:
- structured `mediaUrl` / `mediaUrls` fields for attachment delivery
- `MEDIA:` for attachment delivery
- `[[audio_as_voice]]` for audio presentation hints
- `[[reply_to_current]]` / `[[reply_to:<id>]]` for reply metadata
- `[embed ...]` for Control UI rich rendering
Remote media attachments must be public `https:` URLs. Plain `http:`,
Remote `MEDIA:` attachments must be public `https:` URLs. Plain `http:`,
loopback, link-local, private, and internal hostnames are ignored as attachment
directives; server-side media fetchers still enforce their own network guards.
Local media attachments can use absolute paths, workspace-relative paths, or
Local `MEDIA:` attachments can use absolute paths, workspace-relative paths, or
home-relative `~/` paths. They still pass through the agent file-read policy and
media type checks before delivery.
<Warning>
Do not emit text commands for attachments from tools, plugins, streaming blocks,
browser output, or message actions. Use structured media fields instead.
`MEDIA:` is parsed only as plain text. Wrapping the directive in Markdown
formatting (bold, inline code, fenced code) prevents the parser from
recognizing it, and the attachment is silently dropped from delivery.
Valid message-tool payload:
Valid:
```json
{ "message": "Here is your image.", "mediaUrl": "/workspace/image.png" }
```text
MEDIA:/workspace/image.png
```
Legacy final assistant reply text may still be normalized for compatibility, but
it is not a general plugin/tool protocol.
Invalid (parsed as prose, no attachment delivered):
```text
**MEDIA:/workspace/image.png**
`MEDIA:/workspace/image.png`
Here is your image: MEDIA:/workspace/image.png
```
Keep `MEDIA:` on its own line, in plain text, with no surrounding formatting.
</Warning>
Plain Markdown image syntax stays text by default. Channels that intentionally
map Markdown image replies to media attachments opt in at their outbound
adapter; Telegram does this so `![alt](url)` can still become a media reply.
These directives are separate. Structured media fields and reply/voice tags are
delivery metadata; `[embed ...]` is the web-only rich render path.
These directives are separate. `MEDIA:` and reply/voice tags remain delivery metadata; `[embed ...]` is the web-only rich render path.
Trusted tool-result media uses the same `MEDIA:` / `[[audio_as_voice]]` parser before delivery, so text tool outputs can still mark an audio attachment as a voice note.
When block streaming is enabled, media must be carried on structured payload
fields. If the same media URL is sent in a streamed block and repeated in the
final assistant payload, OpenClaw delivers the attachment once and strips the
duplicate from the final payload.
When block streaming is enabled, `MEDIA:` remains single-delivery metadata for a
turn. If the same media URL is sent in a streamed block and repeated in the final
assistant payload, OpenClaw delivers the attachment once and strips the duplicate
from the final payload.
## `[embed ...]`
@@ -64,7 +72,7 @@ Rules:
- Only URL-backed embeds are rendered. Use `ref="..."` or `url="..."`.
- Block-form inline HTML embed shortcodes are not rendered.
- The web UI strips the shortcode from visible text and renders the embed inline.
- Structured media is not an embed alias and should not be used for rich embed rendering.
- `MEDIA:` is not an embed alias and should not be used for rich embed rendering.
## Stored rendering shape

View File

@@ -73,8 +73,6 @@ Scope intent:
- `channels.slack.accounts.*.appToken`
- `channels.slack.accounts.*.userToken`
- `channels.slack.accounts.*.signingSecret`
- `channels.sms.authToken`
- `channels.sms.accounts.*.authToken`
- `channels.discord.token`
- `channels.discord.pluralkit.token`
- `channels.discord.voice.tts.providers.*.apiKey`

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