Compare commits

...

429 Commits

Author SHA1 Message Date
Peter Steinberger
751263d789 fix: improve parallels windows smoke logging 2026-04-02 15:11:08 +01:00
Vincent Koc
52a6e354a8 fix(tasks): reset agent events in executor tests 2026-04-02 22:25:59 +09:00
Vincent Koc
ec6a07ef05 fix(secrets): add legacy x_search secret target 2026-04-02 22:24:08 +09:00
Jacob Tomlinson
3528e15817 changelog: add openshell mirror sync fix entry (#58515) 2026-04-02 13:23:58 +00:00
Peter Steinberger
3cca07a983 docs: reorder changelog entries by user interest 2026-04-02 14:22:19 +01:00
Agustin Rivera
b21c9840c2 OpenShell: constrain mirror sync roots (#58515)
* fix(openshell): constrain mirror sync roots

* fix(openshell): restore config test types

* fix(openshell): simplify managed root sync
2026-04-02 06:21:30 -07:00
Vincent Koc
3e4de956c0 !refactor(xai): move x_search config behind plugin boundary (#59674)
* refactor(xai): move x_search config behind plugin boundary

* chore(changelog): note x_search config migration

* fix(xai): include x_search migration helpers
2026-04-02 22:08:59 +09:00
Agustin Rivera
ef7c553dd1 fix(zalo): scope webhook replay dedupe (#58444)
* fix(zalo): scope webhook replay dedupe

* fix(zalo): harden replay metadata reads

* docs(changelog): add Zalo replay scope fix entry

---------

Co-authored-by: Jacob Tomlinson <jtomlinson@nvidia.com>
2026-04-02 06:07:14 -07:00
Vincent Koc
12bd6b7bb9 fix(tasks): address task-flow audit review (#59672) 2026-04-02 22:02:00 +09:00
Devin Robison
7eae9c0e62 Block remaining host env override pivots (#59233)
* Blck remaining host env override pivots

* Feedback update
2026-04-02 06:00:26 -07:00
Agustin Rivera
54a0878517 fix(gateway): enforce session kill HTTP scopes (#59128)
* fix(gateway): enforce session kill HTTP scopes

Co-authored-by: Jacob Tomlinson <jtomlinson@nvidia.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>

* fix(gateway): type session kill auth mock

* fix(gateway): gate session kill before lookup

* docs: add changelog entry for session kill HTTP scopes

---------

Co-authored-by: Jacob Tomlinson <jtomlinson@nvidia.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-04-02 05:56:17 -07:00
Agustin Rivera
be10ecef77 fix(compare): reuse shared secret comparison helper (#58432)
* fix(compare): reuse shared secret comparison helper

* fix(compare): reject empty bluebubbles auth tokens

* docs: add changelog entry for shared secret comparison fix

---------

Co-authored-by: Jacob Tomlinson <jtomlinson@nvidia.com>
2026-04-02 13:53:19 +01:00
Vincent Koc
4c08b0bb08 fix(tasks): allow task-flow registry audit seams 2026-04-02 21:49:26 +09:00
Vincent Koc
cfbad0a4f9 fix(providers): unify request policy resolution (#59653)
* fix(providers): unify request policy resolution

* fix(providers): preserve request config SDK contract

* fix(providers): harden request header policy
2026-04-02 21:42:11 +09:00
Vincent Koc
d4f69878da fix(tasks): close registry stores on test resets 2026-04-02 21:40:40 +09:00
Vincent Koc
6f91f87f3b refactor(tasks): move task-flow ownership under tasks 2026-04-02 21:40:40 +09:00
Vincent Koc
0f45630d19 fix(tasks): harden task-flow restore and maintenance 2026-04-02 21:40:40 +09:00
mappel-nv
9c22d63669 Browser: normalize localhost absolute-form CDP hosts (#59236)
* Browser: normalize localhost absolute-form CDP hosts

* CHANGELOG: note localhost absolute-form CDP fix

---------

Co-authored-by: Jacob Tomlinson <jtomlinson@nvidia.com>
2026-04-02 13:34:55 +01:00
Vincent Koc
e48ee8ae9e test(secrets): update inactive warning coverage 2026-04-02 21:21:38 +09:00
Vincent Koc
b18de06bff test(secrets): fix runtime coverage env allowlist 2026-04-02 21:10:30 +09:00
Vincent Koc
15e6a88c67 fix(config): sync generated base schema 2026-04-02 21:04:06 +09:00
gavyngong
761cdc967d fix(gateway): prune empty node-pending-work state entries to prevent memory leak (#58179)
Merged via squash.

Prepared head SHA: 1efee3099f
Co-authored-by: gavyngong <267269824+gavyngong@users.noreply.github.com>
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Reviewed-by: @hxy91819
2026-04-02 20:00:18 +08:00
Vincent Koc
9823833383 fix(plugins): preserve activation provenance (#59641)
* fix(plugins): preserve activation provenance

* fix(gateway): preserve activation reason metadata

* fix(plugins): harden activation state policy
2026-04-02 20:57:14 +09:00
Vincent Koc
6eca1949d5 refactor(plugins): tighten web fetch provider boundary (#59646)
* refactor(plugins): tighten web fetch provider boundary

* fix(config): sync fetch secret parity and baseline

* fix(ci): enforce web fetch boundary guard
2026-04-02 20:53:57 +09:00
Vincent Koc
5abd5d889f fix(providers): classify copilot native endpoints (#59644)
* fix(providers): classify copilot native endpoints

* fix(changelog): add copilot endpoint note

* fix(providers): handle copilot proxy hints
2026-04-02 20:51:46 +09:00
Shakker
71d49012fc fix: align secretref web-fetch matrix 2026-04-02 12:47:09 +01:00
Vincent Koc
5639e8d242 fix(tasks): stabilize task-flow rename gates 2026-04-02 20:43:04 +09:00
Vincent Koc
e894c7e66e refactor(commands): switch flow tooling to task-flow names 2026-04-02 20:43:03 +09:00
Vincent Koc
b6c3ecedd8 refactor(tasks): update plugin and acp task-flow consumers 2026-04-02 20:43:03 +09:00
Vincent Koc
a7909d46d2 refactor(tasks): migrate task runtime callsites to task-flow 2026-04-02 20:43:03 +09:00
Vincent Koc
a51c976d27 refactor(tasks): rename flow registry modules to task-flow 2026-04-02 20:43:03 +09:00
Vincent Koc
c405bcfa98 refactor(providers): centralize request capabilities (#59636)
* refactor(providers): centralize request capabilities

* fix(providers): harden comparable base url parsing
2026-04-02 20:26:22 +09:00
Vincent Koc
38d2faee20 !feat(plugins): add web fetch provider boundary (#59465)
* feat(plugins): add web fetch provider boundary

* feat(plugins): add web fetch provider modules

* refactor(web-fetch): remove remaining core firecrawl fetch config

* fix(web-fetch): address review follow-ups

* fix(web-fetch): harden provider runtime boundaries

* fix(web-fetch): restore firecrawl compare helper

* fix(web-fetch): restore env-based provider autodetect

* fix(web-fetch): tighten provider hardening

* fix(web-fetch): restore fetch autodetect and compat args

* chore(changelog): note firecrawl fetch config break
2026-04-02 20:25:19 +09:00
Vincent Koc
82d5e6a2f7 fix(ci): isolate task executor delivery runtime cache 2026-04-02 20:21:23 +09:00
Mariano
bbf9800a8e Plugins: add bound TaskFlow runtime (#59622)
Merged via squash.

Prepared head SHA: b4649f3238
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
2026-04-02 13:17:09 +02:00
Vincent Koc
474409deb5 fix(ci): reset flow registry in acp manager tests 2026-04-02 20:04:19 +09:00
Vincent Koc
d49460b417 fix(providers): centralize Anthropic endpoint classification (#59608)
* fix(providers): centralize Anthropic endpoint classification

* fix(agents): share Anthropic thinking recovery gating
2026-04-02 19:54:43 +09:00
Vincent Koc
d87bc6706c fix(plugin-sdk): narrow groups runtime discord seam (#59623) 2026-04-02 19:51:36 +09:00
Vincent Koc
707f5485b9 fix(ci): tighten thinking recovery stream types 2026-04-02 19:47:52 +09:00
Mariano
8bdca2323d TaskFlow: add managed child task execution (#59610)
Merged via squash.

Prepared head SHA: e6cdde6c21
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
2026-04-02 12:45:03 +02:00
Vincent Koc
f65da8711a fix(plugin-sdk): narrow cli discord and matrix contract seams (#59565) 2026-04-02 19:40:04 +09:00
Vincent Koc
dfe95b1e1b fix(ci): align task store flow-link test with runtime guard 2026-04-02 19:32:07 +09:00
Vincent Koc
9aa2ef2736 fix(agents): recover Anthropic thinking after crash (#59062)
* fix(agents): recover Anthropic thinking after crash

* fix(agents): avoid duplicate Anthropic recovery chunks

* fix(agents): preserve Anthropic stream result
2026-04-02 19:30:25 +09:00
Vincent Koc
ec17260e26 docs: rename ClawFlow to TaskFlow and update references 2026-04-02 19:28:49 +09:00
Vincent Koc
f8e67ef698 docs: restore TaskFlow docs and fix Slack attribution 2026-04-02 19:24:36 +09:00
Vincent Koc
ecb4ea9830 fix(ci): restore exec approval masking semantics 2026-04-02 19:23:26 +09:00
Vincent Koc
0e9a9dae84 fix(providers): centralize Google endpoint classification (#59556)
* fix(providers): centralize Google endpoint classification

* fix(providers): tighten Google endpoint fallback parsing

* fix(security): harden provider endpoint fallback parsing
2026-04-02 19:21:31 +09:00
Mariano
2fa4c7cc61 TaskFlow: restore managed substrate (#58930)
Merged via squash.

Prepared head SHA: c99093838f
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
2026-04-02 12:17:56 +02:00
Ayaan Zaidi
52d2bd5cc6 fix: reject stale ACP reconnect prompts 2026-04-02 15:32:46 +05:30
Jacob Tomlinson
ac5bc4fb37 Slack: filter thread context by allowlist (#58380)
* Slack: filter thread context by allowlist

* Slack: honor room thread allowlists

* Slack: keep open-room thread context

* Slack: keep non-room thread context

* Changelog: add Slack thread context fix
2026-04-02 11:01:11 +01:00
Sliverp
0e3da03193 fix(doc):update wecom doc and qq (#57641)
* fix(doc):update wecom doc and qq
doc

* Update CHANGELOG with recent changes and enhancements

Added various updates including new features, improvements, and documentation changes across multiple components.
2026-04-02 17:55:32 +08:00
Ayaan Zaidi
e3319b2a63 fix: guard ACP disconnect clears by epoch 2026-04-02 15:15:21 +05:30
Ayaan Zaidi
d983970704 fix: preserve ACP reconnect epochs 2026-04-02 15:15:21 +05:30
Ayaan Zaidi
73c1b45819 fix: keep active ACP runs alive after reconnect timeout 2026-04-02 15:15:21 +05:30
Ayaan Zaidi
e48a7b9be8 refactor: distill ACP reconnect prompt state 2026-04-02 15:15:21 +05:30
Jacob Tomlinson
657295c347 docs(changelog): add missing merged PR entries 2026-04-02 09:44:43 +00:00
mappel-nv
2eaf5a695e Mattermost: guard probe fetches (#58529) 2026-04-02 10:30:33 +01:00
Jacob Tomlinson
2c45b06afd fix(qqbot): restrict structured payload local paths (#58453)
* fix(qqbot): restrict structured payload local paths

* fix(qqbot): narrow structured payload file access

* test(qqbot): cover payload path traversal guards

* fix(qqbot): reduce structured payload log exposure

* fix(qqbot): preserve inline image payload URLs
2026-04-02 10:20:52 +01:00
Julia Bush
5c36c2d0d2 fix: install devDependencies during ui:build (#59267) (thanks @juliabush)
* fix(ui): install devDependencies during ui:build

* fix: keep ui:build self-heal documented (#59267) (thanks @juliabush)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-02 14:35:05 +05:30
Ayaan Zaidi
304da2cbd7 fix: keep ACP prompts alive across gateway reconnects (#59473)
* fix: keep acp prompts alive across gateway reconnects

* fix: bound ACP prompts after disconnect grace

* fix: preserve ACP send timeout semantics

* fix: defer pre-ack ACP disconnect failures

* fix: reconcile ACP runs after reconnect

* fix: keep ACP reconnect deadlines monotonic

* fix: keep pre-ack ACP deadlines after reconnect

* fix: keep ACP prompts alive across gateway reconnects (#59473)

* fix: reject superseded ACP pre-ack prompts (#59473)

* style: format ACP reconnect regression updates (#59473)

* style: format ACP reconnect regression updates (#59473)

* fix: guard ACP send acceptance by run id (#59473)

* fix: scope ACP reconnect deadline by prompt (#59473)

* fix: recheck ACP prompts at reconnect deadline (#59473)

* fix: key ACP reconnect deadline by run (#59473)
2026-04-02 14:34:11 +05:30
Ayaan Zaidi
c27b45fd12 fix: strip antml thinking tags (#59550) 2026-04-02 14:28:54 +05:30
Ayaan Zaidi
176ff18d18 fix: strip antml thinking tags 2026-04-02 14:28:54 +05:30
scoootscooob
251ba9b4d2 docs(changelog): note invalid exec approvals policy fix 2026-04-02 01:46:16 -07:00
wangchunyue
a597938be8 fix(exec): strip invalid approval policy enums during config normalization (#59112)
* fix(exec): strip invalid security/ask enum values during config normalization

* fix(exec): narrow invalid approvals config cleanup

---------

Co-authored-by: scoootscooob <zhentongfan@gmail.com>
2026-04-02 01:40:10 -07:00
Vincent Koc
d90c8db491 fix(plugin-sdk): narrow discord and matrix core seam imports (#59557) 2026-04-02 17:40:06 +09:00
Vincent Koc
331e835dab fix(providers): centralize stream request headers (#59542)
* fix(providers): centralize stream request headers

* Update src/agents/provider-request-config.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-04-02 17:21:46 +09:00
Vincent Koc
08962b6812 fix(browser): keep static helper seams cold (#59471)
* fix(browser): keep static helper seams cold

* fix(browser): narrow sandbox helper facade imports

* fix(browser): harden host inspection helpers
2026-04-02 17:12:32 +09:00
Ayaan Zaidi
b441cd2f4f fix: normalize kimi anthropic tool payloads (#59440)
* fix: normalize kimi anthropic tool payloads

* fix: normalize kimi anthropic tool payloads (#59440)
2026-04-02 13:39:51 +05:30
Vincent Koc
53f1c9968a fix(ci): restore model override and trash-path fallbacks 2026-04-02 16:59:27 +09:00
Gustavo Madeira Santana
68bb76519a Matrix: fix delayed draft block boundaries 2026-04-02 03:47:57 -04:00
Gustavo Madeira Santana
8748b7c54c Matrix: keep partial previews aligned with block streaming (#59384)
Merged via squash.

Prepared head SHA: 981aa35a7c
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-02 03:39:27 -04:00
wittam-01
ce0ff42ff5 fix: harden Feishu comment-thread delivery (#59129)
* fix: harden Feishu comment-thread delivery

* fix: harden Feishu comment-thread delivery (#59129) (thanks @wittam-01)

---------

Co-authored-by: George Zhang <georgezhangtj97@gmail.com>
2026-04-02 00:31:52 -07:00
Gustavo Madeira Santana
a5cd921053 revert: remove TinyFish bundled plugin 2026-04-02 03:07:33 -04:00
Mingkuan
c15cfeb21c fix(qqbot): lazy-load silk-wasm to avoid hard failure when package is missing (#58829)
* fix(qqbot): lazy-load silk-wasm to avoid hard failure when package is missing

Replace the static top-level import with a cached dynamic import helper.
If silk-wasm is unavailable the plugin loads normally; voice encode/decode
degrades gracefully instead of crashing the module at load time.

* fix(qqbot): store in-flight Promise in loadSilkWasm to prevent duplicate imports

Concurrent cold-start calls to loadSilkWasm() before the first import()
resolves would each fire a separate dynamic import. Storing the Promise
instead of the resolved value (matching the detectFfmpeg pattern in
platform.ts) ensures all concurrent callers await the same import,
keeping the codebase consistent and avoiding redundant parallel loads.

* QQBot: add changelog for silk-wasm lazy load

* QQBot: move changelog entry for PR #58829

---------

Co-authored-by: sliverp <870080352@qq.com>
Co-authored-by: Sliverp <38134380+sliverp@users.noreply.github.com>
2026-04-02 14:46:53 +08:00
Gustavo Madeira Santana
0809c8d29a fix(matrix): preserve legacy mention edits 2026-04-02 02:33:00 -04:00
Vincent Koc
3e52f5a021 docs(changelog): add TinyFish PR number and attribution 2026-04-02 15:29:36 +09:00
Vincent Koc
f28f0f29ba fix(providers): centralize media request shaping (#59469)
* fix(providers): centralize media request shaping

* style(providers): normalize shared request imports

* fix(changelog): add media request shaping entry

* fix(google): preserve private network guard
2026-04-02 15:28:57 +09:00
Gustavo Madeira Santana
9786946b2d fix(matrix): restore guided setup flow (#59462)
Merged via squash.

Prepared head SHA: 9b29023c68
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-02 02:15:32 -04:00
Gustavo Madeira Santana
5c331687ff fix(matrix): ignore escaped backticks in mention masking 2026-04-02 02:06:50 -04:00
Gustavo Madeira Santana
be52594766 fix(matrix): emit spec-compliant mentions (#59323)
Merged via squash.

Prepared head SHA: 4b641e35a2
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-02 02:00:24 -04:00
Vincent Koc
7b748a57f0 fix(contracts): activate runtime-backed binding suites 2026-04-02 14:57:11 +09:00
Simantak Dabhade
b880118d2d feat: add TinyFish as bundled browser automation plugin (#58645)
* feat: add TinyFish as bundled browser automation plugin

Add a default-off bundled `tinyfish` plugin with one tool
(`tinyfish_automation`) for hosted browser automation of complex public
web workflows. Follows the existing plugin architecture pattern.

- Plugin entry, manifest with contracts, config schema, SecretRef support
- SSE stream parser with COMPLETE-terminal, SSRF guards, credential rejection
- Bundled skill with escalation guidance (web_fetch -> web_search -> tinyfish -> browser)
- Docs page, labeler rule, glossary entry, changelog entry
- 21 tests covering request serialization, auth, security, streaming, and error paths

Closes #41300

* plugins: address review feedback and regenerate baselines

- Split API_INTEGRATION into TINYFISH_API_INTEGRATION and CLIENT_SOURCE
  for semantic clarity (Greptile P2)
- Wrap post-finally parseEventBlock in try/catch so trailing malformed
  data does not mask "stream ended before COMPLETE" error (Greptile P2)
- Regenerate config-baseline and plugin-sdk-api-baseline for new plugin

---------

Co-authored-by: Simantak Dabhade <simantak@mac.local>
2026-04-02 01:46:05 -04:00
Vincent Koc
93fa6920b4 perf(memory): lazy-load telegram message context runtime 2026-04-02 14:44:14 +09:00
Vincent Koc
16c5bd466c perf(memory): split telegram body helper surface 2026-04-02 14:41:26 +09:00
Vincent Koc
52a018680d fix(plugins): guard runtime facade activation (#59412)
* fix(plugins): guard runtime facade activation

* refactor(plugin-sdk): localize facade load policy

* fix(plugin-sdk): narrow facade activation guards

* fix(browser): keep cleanup helpers outside activation guard

* style(browser): apply formatter follow-ups

* chore(changelog): note plugin activation guard regressions

* fix(discord): keep cleanup thread unbinds outside activation guard

* fix(browser): fallback when trash exits non-zero
2026-04-02 14:37:12 +09:00
Vincent Koc
ed6012eb5b fix(agents): honor cacheRetention for custom anthropic providers (#59049)
* fix(agents): honor cacheRetention for custom anthropic providers

* docs(changelog): add cache retention entry

* Update CHANGELOG.md

* test(agents): add direct cache retention assertions
2026-04-02 14:34:01 +09:00
Sally O'Malley
41aac73590 chore(docs): sync config baseline (#59461) 2026-04-02 01:33:21 -04:00
Vincent Koc
703a363589 perf(memory): lazy-load telegram context session helpers 2026-04-02 14:31:48 +09:00
Vincent Koc
1707493be4 refactor(providers): add internal request config seam (#59454) 2026-04-02 14:28:25 +09:00
Gustavo Madeira Santana
f69570f820 Exec approvals: fix policy source attribution (#59367)
Merged via squash.

Prepared head SHA: 974945a9f0
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-02 01:28:14 -04:00
Sally O'Malley
ad6e42906f chore(docs): sync generated baselines (#59450) 2026-04-02 01:26:45 -04:00
Vincent Koc
0e8e986c95 perf(memory): narrow telegram bot deps skill/runtime imports 2026-04-02 14:16:13 +09:00
Vincent Koc
7dc065dab0 docs(changelog): add missing PR numbers 2026-04-02 14:12:28 +09:00
Vincent Koc
5b952836e3 perf(memory): trim telegram command runtime imports 2026-04-02 14:11:28 +09:00
Vincent Koc
1a037ff6cd refactor(providers): centralize request attribution policy (#59433)
* refactor(providers): centralize request attribution policy

* style(providers): normalize request policy formatting

* style(providers): normalize request policy formatting

* style(providers): normalize request policy formatting

* docs(changelog): note provider request policy fix

* fix(providers): tighten request policy gates
2026-04-02 14:10:53 +09:00
Vincent Koc
4309dc6d5e perf(memory): lazy-load telegram monitor runtime graphs 2026-04-02 14:07:35 +09:00
Vincent Koc
fcfb9ddb1d fix(matrix): preserve mocked auth context in bootstrap 2026-04-02 14:03:07 +09:00
Gustavo Madeira Santana
e718493ae6 test(matrix): cover draft overflow fallback 2026-04-02 01:02:18 -04:00
Vincent Koc
85928e29f1 perf(memory): lazy-load matrix bootstrap and probe runtimes 2026-04-02 13:57:03 +09:00
Vincent Koc
be1b4e6683 fix(ci): route matrix config helper through local barrel 2026-04-02 13:52:54 +09:00
Vincent Koc
4fd1e1c64f perf(memory): lazy-load matrix client runtime deps 2026-04-02 13:51:48 +09:00
Scott Glover
9bbbee32e1 Docs: replace personal device names with generic placeholders (#50825) 2026-04-02 00:50:25 -04:00
Vincent Koc
6dbdcbda58 perf(memory): lazy-load matrix shared client creation 2026-04-02 13:48:20 +09:00
Vincent Koc
bfa561b1a7 perf(memory): lazy-load matrix secret config input 2026-04-02 13:46:06 +09:00
Vincent Koc
a398520ac8 perf(memory): trim matrix resolved config imports 2026-04-02 13:42:58 +09:00
Priyansh Gupta
b9c74fc884 fix(image-tool): resolve relative paths against workspaceDir (#57222)
Relative paths like "inbox/receipt.png" were resolved against
process.cwd() instead of the agent's workspaceDir, causing the
allowlist check to fail with "Local media path is not under an
allowed directory". This matches how the read tool already behaves.

Fixes #57215

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 00:41:09 -04:00
Marcus Castro
e1c96785ac fix(whatsapp): gate connect-time presence on selfChatMode to preserve phone notifications (#59410) 2026-04-02 01:40:06 -03:00
Vincent Koc
df60fa8d49 perf(memory): trim matrix account resolution imports 2026-04-02 13:39:33 +09:00
Vincent Koc
45adba882f docs: add contributor attribution for diffs viewerBaseUrl 2026-04-02 13:35:23 +09:00
Gustavo Madeira Santana
19c954bd78 diffs: add configurable viewer base URL (#59341)
Merged via squash.

Prepared head SHA: 3c2a84849f
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-02 00:31:29 -04:00
Vincent Koc
d55cefac00 perf(memory): trim matrix config import graph 2026-04-02 13:21:44 +09:00
Vincent Koc
75b5a4c713 perf(memory): lazy-load matrix send client bootstrap 2026-04-02 13:10:24 +09:00
Vincent Koc
4a5102c1bb docs: fix changelog attribution and add missing WhatsApp MIME fix entry 2026-04-02 13:03:35 +09:00
Vincent Koc
d4c7ef3778 perf(memory): lazy-load matrix crypto runtime graph 2026-04-02 12:51:50 +09:00
Sally O'Malley
ee274dbdd1 remove noisy podman output from launch script and update doc (#59368)
Signed-off-by: sallyom <somalley@redhat.com>
2026-04-01 23:28:11 -04:00
bobbyt74
cae1d9bc6d fix(whatsapp): add HTML/XML/CSS to MIME map + fallback for unknown media types (#51562)
Merged via squash.

Prepared head SHA: 83f2eabd49
Co-authored-by: bobbyt74 <262672147+bobbyt74@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
2026-04-02 00:25:12 -03:00
Vincent Koc
8c3167a7c7 perf(memory): trim matrix auth test sdk imports 2026-04-02 11:45:32 +09:00
Vincent Koc
534f0a644b fix(plugins): keep browser facade helpers cold 2026-04-02 11:44:49 +09:00
wangchunyue
51edd30bea fix: restore local loopback role upgrades (#59092) (thanks @openperf)
* fix(gateway ): allow silent role upgrades for local loopback clients

When a local loopback client connects with a role not covered by
existing device tokens, listEffectivePairedDeviceRoles incorrectly
returns an empty role set for devices whose tokens map is an empty
object. This triggers a role-upgrade pairing request that
shouldAllowSilentLocalPairing rejects because it does not recognise
the role-upgrade reason.

Fix listEffectivePairedDeviceRoles to fall back to legacy role fields
when the tokens map has no entries, and extend
shouldAllowSilentLocalPairing to accept role-upgrade for local
clients.

Fixes #59045

* fix: restore local loopback role upgrades (#59092) (thanks @openperf)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-02 08:13:45 +05:30
Vincent Koc
1ea901b107 perf(memory): lazy-load slack action runtime graph 2026-04-02 11:31:19 +09:00
Vincent Koc
a7e3c0b0e1 feat(slack): add scoped prompts and mrkdwn hints (#59100)
* feat(slack): add scoped prompts and mrkdwn hints

* refactor(slack): drop dm prompt override

* refactor(slack): drop exposed prompt config

* chore(changelog): note slack mrkdwn fix
2026-04-02 11:23:43 +09:00
Vincent Koc
7c913f2e13 chore(changelog): record plugin loading hardening 2026-04-02 11:20:50 +09:00
Vincent Koc
7771c69caf fix(plugins): enforce activation before shipped imports (#59136)
* fix(plugins): enforce activation before shipped imports

* fix(plugins): remove more ambient bundled loads

* fix(plugins): tighten scoped loader matching

* fix(plugins): remove channel-id scoped loader matches

* refactor(plugin-sdk): relocate ambient provider helpers

* fix(plugin-sdk): preserve unicode ADC credential paths

* fix(plugins): restore safe setup fallback
2026-04-02 11:18:49 +09:00
Vincent Koc
765e8fb713 perf(memory): trim matrix send media imports 2026-04-02 11:16:50 +09:00
Vincent Koc
f4e2240b85 perf(memory): trim matrix account config imports 2026-04-02 11:12:37 +09:00
Gustavo Madeira Santana
7514324510 Docs: fix plugin architecture table formatting 2026-04-01 22:07:15 -04:00
Brad Groux
03c64df39f fix(msteams): use formatUnknownError instead of String(err) for error logging (#59321)
Replaces String(err) with the existing formatUnknownError() utility across
the msteams extension to prevent [object Object] appearing in error logs
when non-Error objects are caught (e.g., Axios errors, Bot Framework SDK
error objects).

Fixes #53910

thanks @bradgroux
2026-04-01 21:06:44 -05:00
Vincent Koc
474693bdb2 perf(memory): trim matrix monitor allowlist imports 2026-04-02 11:05:27 +09:00
Gustavo Madeira Santana
ba735d0158 Exec approvals: unify effective policy reporting and actions (#59283)
Merged via squash.

Prepared head SHA: d579b97a93
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-01 22:02:39 -04:00
Vincent Koc
dc66c36b9e perf(memory): trim telegram monitor test module churn 2026-04-02 10:57:01 +09:00
Gustavo Madeira Santana
32fa5c3be5 fix(agents): resolve compaction wait before channel flush (#59308)
Merged via squash.

Prepared head SHA: bf17502df8
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-01 21:40:23 -04:00
Vincent Koc
326490ab76 docs: cover compaction notifyUser config and provider replay hooks 2026-04-02 10:23:33 +09:00
Vincent Koc
687030cbf2 perf(memory): trim matrix and telegram runtime seams 2026-04-02 10:18:56 +09:00
Vincent Koc
1cc5526f7f docs: fix Nostr inbound signature verification order in docs 2026-04-02 10:11:09 +09:00
joshavant
c22233d96c Revert "refactor(plugins): remove before_install hook" 2026-04-01 19:57:07 -05:00
Brad Groux
57949397fa fix(msteams): prevent duplicate text when stream exceeds 4000 char limit (#59297)
When a streamed response exceeds TEAMS_MAX_CHARS, the stream sets streamFailed=true and finalizes. Previously, hasContent returned false when streamFailed was true, causing preparePayload to pass through the full payload for block delivery, duplicating already-streamed text.

Now tracks streamed length and strips the already-delivered prefix from fallback payloads.

Fixes #58601

thanks @bradgroux
2026-04-01 19:03:19 -05:00
Gustavo Madeira Santana
560ea25294 Matrix: restore ordered progress delivery with explicit streaming modes (#59266)
Merged via squash.

Prepared head SHA: 523623b7e1
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-01 19:35:03 -04:00
Gustavo Madeira Santana
91a7505af6 fix(tests): serialize shared channel audit state cases 2026-04-01 19:12:05 -04:00
Gustavo Madeira Santana
a204f790ce fix(matrix): package verification bootstrap runtime (#59249)
Merged via squash.

Prepared head SHA: df5891b663
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-01 17:52:51 -04:00
Gustavo Madeira Santana
c87c8e66bf Refactor channel approval capability seams (#58634)
Merged via squash.

Prepared head SHA: c9ad4e4706
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-01 17:10:25 -04:00
Logan Ye
d9a7ffe003 failover: classify AbortError / stream-abort messages as timeout (#58315) (#58324)
Merged via squash.

Prepared head SHA: d8412f27e6
Co-authored-by: yelog <14227866+yelog@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-04-02 00:02:31 +03:00
zqchris
75ab5bce6b fix(bluebubbles): add enrichGroupParticipantsFromContacts to core Zod schema (#56889)
* fix(bluebubbles): add enrichGroupParticipantsFromContacts to core Zod schema

The field was added to the extension config schema in #54984 but not
synced to the core strict Zod validator, causing config validation to
reject the key at startup with 'Unrecognized key'.

* test(config): add BlueBubbles schema regression coverage

* fix(bluebubbles): accept enrichGroupParticipantsFromContacts config

---------

Co-authored-by: Chris Zhang <chris@ChrisdeMac-mini.local>
Co-authored-by: Altay <altay@uinaf.dev>
2026-04-01 23:55:58 +03:00
Josh Lehman
71346940ad refactor: add provider replay runtime hook surfaces (#59143)
Merged via squash.

Prepared head SHA: 56b41e87a5
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-04-01 13:45:41 -07:00
Bruno Lorente
ca76e2fedc fix(cron-tool): add typed properties to job/patch schemas (#55043)
Merged via squash.

Prepared head SHA: 979bb0e8b7
Co-authored-by: brunolorente <127802443+brunolorente@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-04-01 23:41:19 +03:00
Kris Wu
7027dda8cd fix(ui): prevent premature compaction status update on retry (#55132)
Merged via squash.

Prepared head SHA: e7e562f982
Co-authored-by: mpz4life <32388289+mpz4life@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-04-01 13:38:51 -07:00
Joshua Lelon Mitchell
7cb323d84f feat(plugins): add before_agent_reply hook (claiming pattern) (#20067)
Merged via squash.

Prepared head SHA: e40dfbdfb9
Co-authored-by: JoshuaLelon <23615754+JoshuaLelon@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-04-01 13:31:11 -07:00
Nimrod Gutman
017bc5261c fix(gateway): prefer bootstrap auth over tailscale (#59232)
* fix(gateway): prefer bootstrap auth over tailscale

* fix(gateway): prefer bootstrap auth over tailscale (#59232) (thanks @ngutman)
2026-04-01 23:20:10 +03:00
9ra55
5cf254a5f7 fix: honor authHeader provider config by injecting Authorization Bear… (#54390)
Merged via squash.

Prepared head SHA: 9889615571
Co-authored-by: lndyzwdxhs <16411017+lndyzwdxhs@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-04-01 13:18:37 -07:00
Josh Lehman
90eb5b073f fix: pass session identity to plugin commands (#59044)
Merged via squash.

Prepared head SHA: 0f7a23f139
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-04-01 13:07:17 -07:00
VACInc
711c9e7249 fix(gateway): emit before_reset on session reset (#53872)
Merged via squash.

Prepared head SHA: a47894ef16
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-04-01 12:46:53 -07:00
Oguri Cap
1f99c87a44 feat: add agents.defaults.compaction.notifyUser config option (default: false) [Fix #54249] (#54251)
Merged via squash.

Prepared head SHA: 6fd4cdb7c3
Co-authored-by: oguricap0327 <266246182+oguricap0327@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-04-01 12:29:17 -07:00
Luke
5b73108e58 fix: /context detail severely underestimates token count (#28391)
Merged via squash.

Prepared head SHA: 5ea6a074f3
Co-authored-by: ImLukeF <92253590+ImLukeF@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-04-01 12:11:08 -07:00
Josh Lehman
1c83e2eec7 fix: scope session create aliases to requested agent (#58207)
Merged via squash.

Prepared head SHA: 9462848777
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-04-01 11:39:31 -07:00
Peter Steinberger
8abba663c5 chore: bump version to 2026.4.2 2026-04-01 19:39:27 +01:00
Peter Steinberger
8f617bf4d7 fix: validate npm dist-tag auth before publish 2026-04-01 19:39:09 +01:00
Gustavo Madeira Santana
b24961c5d1 fix(matrix): tighten account scoping and default detection 2026-04-01 14:20:02 -04:00
Moliendo
d076153fc9 fix(config): coerce numeric Discord IDs to strings instead of rejecting (#45125)
Merged via squash.

Prepared head SHA: 099ba514a1
Co-authored-by: moliendocode <29582793+moliendocode@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-04-01 21:07:28 +03:00
Josh Lehman
4f407d2658 docs(changelog): move #55336 note to 2026.4.1 2026-04-01 10:57:35 -07:00
Onur
38faa3c767 Docs: clarify release preflight promotion 2026-04-01 19:55:21 +02:00
Daan van der Plas
7fa1a31094 fix(matrix): honor room account scoping (#58449)
Merged via squash.

Prepared head SHA: d83f06ee3f
Co-authored-by: Daanvdplas <93204684+Daanvdplas@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-01 13:49:22 -04:00
Doğu Abaris
5190b3b3fa fix: avoid locally caught ACP session init exception (#55136) (thanks @doguabaris) 2026-04-01 19:46:22 +02:00
Joshua McKiddy
dd7df0753f fix(security): prevent memory exhaustion in inline image decoding (#22325)
thanks @hackersifu
2026-04-01 12:44:05 -05:00
Peter Steinberger
5e3352f367 chore: update appcast for 2026.4.1 2026-04-01 18:33:09 +01:00
Onur
f1f5a3fcf4 Release: trim duplicate preflight work (#59117)
* Release: skip duplicate runtime-deps staging

* Release: trim public mac validation workflow

* Release: require promoted npm publish

* Release: verify promoted npm provenance

* Release: restore public mac validation build

* Release: skip pack check on npm promote

* Release: skip pack check on npm promote
2026-04-01 19:24:37 +02:00
Peter Steinberger
da64a978e5 chore: prepare 2026.4.1 release 2026-04-01 17:57:10 +01:00
Vincent Koc
34332257b0 perf(matrix): cut avoidable startup memory in client and monitor tests 2026-04-02 01:00:28 +09:00
Eric Wong
2427304654 fix(msteams): pass teamId and teamName to resolveAgentRoute() (#50214)
thanks @slbteam08
2026-04-01 10:50:41 -05:00
Lewis
e881e96bd0 fix(msteams): sanitize error messages sent to users (#33343)
thanks @lewiswigmore
2026-04-01 10:44:24 -05:00
Vincent Koc
8c6f31cc6b perf(test): narrow discord chunking imports 2026-04-02 00:41:57 +09:00
Peter Steinberger
79d0c92f3d ci: prefix reused npm tarball paths 2026-04-01 16:39:08 +01:00
Vincent Koc
67f8dc5712 fix(discord): avoid duplicate component id exports 2026-04-02 00:34:48 +09:00
Vincent Koc
0b06c4b352 perf(test): narrow telegram draft chunking imports 2026-04-02 00:32:13 +09:00
Vincent Koc
cb7e391285 fix(discord): restore component custom id barrel exports 2026-04-02 00:31:13 +09:00
Vincent Koc
ec426ac356 perf(test): narrow slack string normalization imports 2026-04-02 00:29:50 +09:00
Peter Steinberger
b569f5d313 fix: normalize local npm publish tarball paths 2026-04-01 16:25:37 +01:00
Vincent Koc
b6ba45c4a4 perf(test): lazy-load discord reply runtime 2026-04-02 00:18:45 +09:00
Vincent Koc
19724340f8 perf(test): narrow line reply context import 2026-04-02 00:16:03 +09:00
Peter Steinberger
2988a68b70 ci: skip reused npm publish metadata check 2026-04-01 16:12:26 +01:00
Vincent Koc
913a9ba367 perf(test): narrow discord auth runtime imports 2026-04-02 00:00:26 +09:00
Menglin Li
d5554491a8 fix(msteams): prevent path-to-regexp crash with express 5 (#55440)
Fixes #55250, #54960, #54889, #54852, #54703

thanks @lml2468
2026-04-01 10:00:06 -05:00
Peter Steinberger
181aef5cbe ci: skip npm publish validation when reusing preflight 2026-04-01 15:59:04 +01:00
Vincent Koc
c942812e5d perf(test): narrow discord component import path 2026-04-01 23:58:06 +09:00
Vincent Koc
0453d355fd perf(test): narrow discord monitor runtime seams 2026-04-01 23:47:22 +09:00
LawrenceLuo
83149ed046 fix(msteams): clear pending upload timeout on removal (#32555)
thanks @PinoHouse
2026-04-01 09:46:24 -05:00
Vincent Koc
cfe4b720a4 docs: add glm-5.1 and glm-5v-turbo to GLM model examples 2026-04-01 23:41:46 +09:00
Vincent Koc
3d647f14d0 perf(test): lazy-load discord preflight runtimes 2026-04-01 23:37:06 +09:00
Vincent Koc
3a7d0938c6 perf(test): keep discord model picker provider runtime lazy 2026-04-01 23:32:33 +09:00
Peter Steinberger
c3490b3c70 fix: keep prepared prepack logs off stdout 2026-04-01 15:31:02 +01:00
Vincent Koc
76c4ecd651 perf(test): narrow sdk seams for channel hotspots 2026-04-01 23:14:48 +09:00
Peter Steinberger
8988894ff7 build: prepare 2026.4.1-beta.1 release 2026-04-01 15:09:19 +01:00
Peter Steinberger
47be52e2cb build: bump version to 2026.4.1-beta.1 2026-04-01 15:09:19 +01:00
Vincent Koc
5a0fd1cffc fix(matrix): narrow lazy test module access 2026-04-01 23:05:51 +09:00
Vincent Koc
1d05cbba7a perf(test): trim matrix setup overhead 2026-04-01 22:56:13 +09:00
Gustavo Madeira Santana
2dab0c518a fix(regression): ship diffs viewer runtime asset 2026-04-01 09:56:07 -04:00
Peter Steinberger
4de1606f4c fix: drain discord startup restart sockets 2026-04-01 22:55:58 +09:00
Vincent Koc
78a58726e7 perf(test): trim more matrix import churn 2026-04-01 22:54:22 +09:00
Peter Steinberger
9065243729 fix: stop stale Windows gateway before upgrade onboard 2026-04-01 14:52:44 +01:00
Vincent Koc
38410705bf perf(test): trim matrix directory reload churn 2026-04-01 22:51:08 +09:00
Vincent Koc
da9ffad368 fix(channels): restore target parsing barrel seam 2026-04-01 22:46:10 +09:00
Ayaan Zaidi
095e7b830a fix: let carbon own gateway reconnects (#59019)
* refactor(discord): let carbon own gateway reconnects

* fix: finalize Discord gateway reconnect landing (#59019)
2026-04-01 19:12:35 +05:30
Vincent Koc
c5cfc05104 perf(test): trim more sdk and telegram reload churn 2026-04-01 22:40:44 +09:00
Vincent Koc
cb7c0e24d0 perf(test): trim more browser reload churn 2026-04-01 22:40:44 +09:00
Vincent Koc
e1b6c9b29b perf(test): trim more matrix and telegram reload churn 2026-04-01 22:40:44 +09:00
Vincent Koc
dd5bf6b1d0 perf(test): cut more hotspot reload churn 2026-04-01 22:40:44 +09:00
Vincent Koc
1673d969e8 test: document reload-churn guardrail 2026-04-01 22:40:31 +09:00
Peter Steinberger
b0ef107b56 docs(changelog): add missing thanks 2026-04-01 14:33:19 +01:00
Peter Steinberger
9cfb792dba docs: fix docs formatting drift 2026-04-01 14:31:28 +01:00
Vincent Koc
fd4dbad38c docs: cover cron --tools allowlist and agents.defaults.params config reference 2026-04-01 22:29:53 +09:00
Peter Steinberger
00218ac8a4 fix(auth): persist codex oauth refresh tokens 2026-04-01 14:25:33 +01:00
Peter Steinberger
af5f4f6716 docs(changelog): drop docs-only breaking note 2026-04-01 14:23:42 +01:00
Vincent Koc
c42659176a docs: cover unreleased feature gaps (Telegram errorPolicy, Android notifications, node pairing, Slack approvals, MCP transport, reactions) 2026-04-01 22:20:20 +09:00
Vincent Koc
7a7549f12f perf(test): reduce hotspot reload churn (#59033) 2026-04-01 22:19:19 +09:00
Peter Steinberger
adb961e056 docs(changelog): refresh unreleased ordering 2026-04-01 14:13:11 +01:00
Jacob Tomlinson
14a779ee8d revert: sandbox: block sensitive external bind sources (#59016)
This reverts commit 8db20c1965.
2026-04-01 14:01:05 +01:00
Ayaan Zaidi
7096819f2b fix(acpx): retry queue-owner repair without resume-session (thanks @obviyus) 2026-04-01 18:30:38 +05:30
Peter Steinberger
fc745db76d ci: remove bun workflow 2026-04-01 21:58:46 +09:00
Peter Steinberger
131f6dac37 refactor: unify failover signal classification 2026-04-01 21:50:58 +09:00
Neerav Makwana
ed482b1ce7 fix: repair queue owner session recovery (#58669) (thanks @neeravmakwana)
* fix(acpx): repair queue owner session recovery

* fix(acpx): avoid duplicate queue owner recovery

* fix: repair queue owner session recovery (#58669) (thanks @neeravmakwana)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-01 18:20:23 +05:30
Neerav Makwana
cd07ebef99 fix: correct flows docs to tasks (#58690) (thanks @neeravmakwana)
* Docs: fix stale flows command references

* Docs: address flows review comments

* docs: remove stale flows subtree from cli index

* fix: correct flows docs to tasks (#58690) (thanks @neeravmakwana)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-01 18:14:31 +05:30
Peter Steinberger
25e2934809 refactor: route session target matching through plugin parsers 2026-04-01 13:42:57 +01:00
Tomsun28
6433e923d4 fix: add ZAI GLM-5.1 and GLM-5V Turbo support (#58793) (thanks @tomsun28)
* provider(zai): add GLM-5.1 and GLM-5V Turbo models

* feat(zai): extract model definition builder for glm-5 forward compat

* test(zai): cover persisted glm-5 dynamic metadata

* fix: add ZAI GLM-5.1 and GLM-5V Turbo support (#58793) (thanks @tomsun28)

* fix: preserve ZAI dynamic model transport config (#58793) (thanks @tomsun28)

---------

Co-authored-by: gongchao <chao.gong@aminer.cn>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-01 18:09:02 +05:30
Peter Steinberger
33fbd9b770 refactor: dedupe auth profile store normalization 2026-04-01 13:37:37 +01:00
Peter Steinberger
ab3c646bb1 fix: preserve telegram exec approval topic routing 2026-04-01 13:34:50 +01:00
Peter Steinberger
f55b6b1acf fix: add changelog for auth profile store load crash (#58923) (thanks @openperf) 2026-04-01 21:33:10 +09:00
openperf
ac68321d4d fix(auth-profiles ): ensure credential key and token are strings to prevent crash
Fixes #58861
2026-04-01 21:33:10 +09:00
Peter Steinberger
cd4b03c568 fix: unify structured provider failover classification (#58856) (thanks @aaron-he-zhu) 2026-04-01 21:31:18 +09:00
Aaron Zhu
c96ee42300 fix(agents): normalize provider errors for better failover
Add provider-specific error patterns for AWS Bedrock, Ollama, Mistral,
Cohere, DeepSeek, Together AI, and Cloudflare Workers AI. These providers
return errors in non-standard formats that the generic classifiers miss,
causing incorrect failover behavior (e.g., context overflow misclassified
as format error, ThrottlingException not recognized as rate limit).

Wire provider patterns into isContextOverflowError() and
classifyFailoverReason() as catch-all layers after generic classifiers.
2026-04-01 21:31:18 +09:00
Chinar Amrutkar
74b9f22a42 fix: add Telegram error suppression controls (#51914) (thanks @chinar-amrutkar)
* feat(telegram): add error policy for suppressing repetitive error messages

Introduces per-account error policy configuration that can suppress
repetitive error messages (e.g., 429 rate limit, ECONNRESET) to
prevent noisy error floods in Telegram channels.

Closes #34498

* fix(telegram): track error cooldown per message

* fix(telegram): prune expired error cooldowns

* fix: add Telegram error suppression controls (#51914) (thanks @chinar-amrutkar)

---------

Co-authored-by: chinar-amrutkar <chinar-amrutkar@users.noreply.github.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-01 17:52:28 +05:30
Ayaan Zaidi
ef286987e7 test: fix context pruning runtime fixtures 2026-04-01 16:48:00 +05:30
Ayaan Zaidi
f70ad924a6 fix: align cache-ttl pruning with thinking replay sanitization 2026-04-01 16:33:57 +05:30
Vincent Koc
c7510e0f1a fix(hooks): skip full gate for docs-only commits 2026-04-01 20:02:54 +09:00
Ayaan Zaidi
c65e152b39 fix: preserve anthropic thinking replay (#58916)
* test: add anthropic thinking replay regressions

* fix: preserve anthropic thinking blocks on replay

* fix: preserve anthropic thinking replay (#58916)

* fix: move anthropic replay changelog entry (#58916)
2026-04-01 16:23:47 +05:30
Vincent Koc
00a49fe8b4 docs: add gateway.webchat.chatHistoryMaxChars config reference 2026-04-01 19:25:17 +09:00
Charles Dusek
32ae841098 feat(web-search): add SearXNG as bundled web search provider plugin (#57317)
* feat(web-search): add bundled searxng plugin

* test(web-search): cover searxng config wiring

* test(web-search): include searxng in bundled provider inventory

* test(web-search): keep searxng ordering aligned

* fix(web-search): sanitize searxng result rows

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-04-01 19:24:33 +09:00
Chinar Amrutkar
3f67581e50 fix: retry safe wrapped Telegram send failures (#51895) (thanks @chinar-amrutkar)
* fix(telegram): traverse error .cause chain in formatErrorMessage and match grammY HttpError

grammY wraps network failures in HttpError with message
'Network request for ... failed!' and the original error in .cause.
formatErrorMessage only checked err.message, so shouldRetry never
fired for the most common transient failure class.

Changes:
- formatErrorMessage now traverses .cause chain, appending nested
  error messages (with cycle protection)
- Added 'Network request' to TELEGRAM_RETRY_RE as belt-and-suspenders
- Added tests for .cause traversal, circular references, and grammY
  HttpError retry behavior

Fixes #51525

* style: fix oxfmt formatting in retry-policy.ts

* fix: add braces to satisfy oxlint requirement

* fix(telegram): keep send retries strict

* test(telegram): cover wrapped retry paths

* fix(telegram): retry rate-limited sends safely

* fix: retry safe wrapped Telegram send failures (#51895) (thanks @chinar-amrutkar)

* fix: preserve wrapped Telegram rate-limit retries (#51895) (thanks @chinar-amrutkar)

---------

Co-authored-by: chinar-amrutkar <chinar-amrutkar@users.noreply.github.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-01 15:54:29 +05:30
Vincent Koc
5c8d9da749 docs: add SearXNG web search provider page and navigation 2026-04-01 19:18:15 +09:00
Vincent Koc
f1595f59b4 fix(ci): allow plugin npm preview without publish token (#58929) 2026-04-01 19:16:46 +09:00
upupc
d766bfc6b2 fix(memory): preserve session indexing during full reindex (#39732)
Merged via squash.

Prepared head SHA: 0dbaf5fffb
Co-authored-by: upupc <12829489+upupc@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-04-01 13:12:30 +03:00
Luke
1654c3a851 feat(gateway): make chat history max chars configurable (#58900)
* feat(gateway): make chat history max chars configurable

* fix(gateway): address review feedback

* docs(changelog): note configurable chat history limits
2026-04-01 21:08:37 +11:00
ImLukeF
b2bb129e2c docs(changelog): note chat error fallback fix 2026-04-01 20:53:35 +11:00
ImLukeF
78b48735fa test: restore fetch stubs in embedding suites 2026-04-01 20:53:16 +11:00
ImLukeF
101c31f5e1 test: harden ci-sensitive unit suites 2026-04-01 20:53:16 +11:00
ImLukeF
4e63dc0b1c fix: hide raw provider errors from chat replies 2026-04-01 20:53:16 +11:00
ryanlee-gemini
fbe3ca4d7d fix(plugins): pass dangerouslyForceUnsafeInstall through archive and … (#58879)
Merged via squash.

Prepared head SHA: 87eb27d902
Co-authored-by: ryanlee-gemini <181323138+ryanlee-gemini@users.noreply.github.com>
Co-authored-by: odysseus0 <8635094+odysseus0@users.noreply.github.com>
Reviewed-by: @odysseus0
2026-04-01 02:52:01 -07:00
Vincent Koc
72af92ba4e qqbot: require explicit allowlist for /bot-logs to prevent info disclosure (#58895)
* qqbot: harden /bot-logs authorization fallback

* fix(qqbot): harden bot logs allowlist guard

* fix(qqbot): normalize bot logs allowlist entries
2026-04-01 18:40:46 +09:00
Vincent Koc
07c60ae461 fix(agent): treat webchat exec approvals as native UI (#58904)
* fix(agent): treat webchat exec approvals as native UI

* docs(changelog): note webchat exec approval UI fix

* test(agent): cover webchat native approval guidance
2026-04-01 18:36:21 +09:00
Peter Steinberger
8b2d24b62b docs(security): clarify node pairing trust boundary 2026-04-01 18:27:23 +09:00
Peter Steinberger
29784af1e2 style(gateway): normalize node reconnect formatting 2026-04-01 18:27:06 +09:00
Peter Steinberger
f6317fb747 fix(gateway): stop pinning node commands to pairing state 2026-04-01 18:27:06 +09:00
Peter Steinberger
fe57ee513f test: drop stale task boundary allowlist entries 2026-04-01 10:17:47 +01:00
Peter Steinberger
d005cc8b42 test: align cron abort regression with #58833 2026-04-01 10:17:47 +01:00
Peter Steinberger
92f1772e93 test: allow boundary test on main 2026-04-01 10:17:47 +01:00
Peter Steinberger
f559ea126d fix: land slash command metadata parsing (#58725) (thanks @Mlightsnow) 2026-04-01 10:17:47 +01:00
HansY
3b1f8e3461 fix: strip inbound metadata before slash command detection (#58674)
Slash commands like /model and /new were silently ignored when the inbound
message body included metadata prefix blocks (Conversation info, Sender info,
timestamps) injected by buildInboundUserContextPrefix. The command detection
functions (hasControlCommand, isControlCommandMessage, parseSendPolicyCommand)
now call stripInboundMetadata before normalizeCommandBody so embedded slash
commands are correctly recognized.
2026-04-01 10:17:20 +01:00
Ayaan Zaidi
fb28b02540 fix: preserve bundled channel plugin compat (#58873)
* fix: preserve bundled channel plugin compat

* fix: preserve bundled channel plugin compat (#58873)

* fix: scope channel plugin compat to bundled plugins (#58873)
2026-04-01 14:42:36 +05:30
Vincent Koc
2d53ffdec1 fix(exec): resolve remote approval regressions (#58792)
* fix(exec): restore remote approval policy defaults

* fix(exec): handle headless cron approval conflicts

* fix(exec): make allow-always durable

* fix(exec): persist exact-command shell trust

* fix(doctor): match host exec fallback

* fix(exec): preserve blocked and inline approval state

* Doctor: surface allow-always ask bypass

* Doctor: match effective exec policy

* Exec: match node durable command text

* Exec: tighten durable approval security

* Exec: restore owner approver fallback

* Config: refresh Slack approval metadata

---------

Co-authored-by: scoootscooob <zhentongfan@gmail.com>
2026-04-01 02:07:20 -07:00
Peter Steinberger
4ceb01f9ed docs(gateway): document node pairing repair flow 2026-04-01 18:02:56 +09:00
Peter Steinberger
db0cea5689 refactor(gateway): extract node pairing reconciliation 2026-04-01 18:02:31 +09:00
Peter Steinberger
4590ac31cc fix: note exec approval continuation in changelog (#58860) (thanks @Nanako0129) 2026-04-01 17:56:55 +09:00
nanakotsai
7f53c1ca00 test(exec): cover delayed Discord approval continuation 2026-04-01 17:56:55 +09:00
nanakotsai
63da2c7034 fix(exec): resume agent session after approval completion 2026-04-01 17:56:55 +09:00
Forgely3D
4fa11632b4 fix: escalate to model fallback after rate-limit profile rotation cap (#58707)
* fix: escalate to model fallback after rate-limit profile rotation cap

Per-model rate limits (e.g. Anthropic Sonnet-only quotas) are not
relieved by rotating auth profiles — if all profiles share the same
model quota, cycling between them loops forever without falling back
to the next model in the configured fallbacks chain.

Apply the same rotation-cap pattern introduced for overloaded_error
(#58348) to rate_limit errors:

- Add `rateLimitedProfileRotations` to auth.cooldowns config (default: 1)
- After N profile rotations on a rate_limit error, throw FailoverError
  to trigger cross-provider model fallback
- Add `resolveRateLimitProfileRotationLimit` helper following the same
  pattern as `resolveOverloadProfileRotationLimit`

Fixes #58572

* fix: cap prompt-side rate-limit failover (#58707) (thanks @Forgely3D)

* fix: restore latest-main gates for #58707

---------

Co-authored-by: Ember (Forgely3D) <ember@forgely.co>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-01 17:54:10 +09:00
Vincent Koc
8fce663861 fix(subagents): harden task-registry lifecycle writes (#58869)
* fix(subagents): harden task-registry lifecycle writes

* chore(changelog): note subagent task-registry hardening

* fix(subagents): align lifecycle terminal timestamps

* fix(subagents): sanitize lifecycle warning metadata
2026-04-01 17:50:52 +09:00
sandpile
1ce410a7be fix(sandbox): use browser image for browser runtime matching (#58759)
* fix(sandbox): compare browser runtimes against sandbox browser image

* refactor(sandbox): route docker runtime matching by config label kind

* fix(sandbox): tag browser runtime removals correctly

* test(sandbox): share docker backend test config

* fix(sandbox): normalize browser runtime image matching

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-04-01 17:44:52 +09:00
scoootscooob
10750fb80e Cron: avoid busy-wait drift for recurring main jobs (#58872) 2026-04-01 01:31:21 -07:00
Peter Steinberger
2b67f96895 docs(anthropic): note oauth context1m fallback 2026-04-01 09:21:49 +01:00
Peter Steinberger
32f392eda4 refactor(core): drop old anthropic stream wrapper file 2026-04-01 09:21:48 +01:00
Peter Steinberger
59c23dee09 refactor(anthropic): move stream wrappers into plugin 2026-04-01 09:21:48 +01:00
Peter Steinberger
2bc8a0d67c refactor: add doctor cron migration helpers 2026-04-01 17:06:24 +09:00
Peter Steinberger
19d0c2dd1d refactor: remove cron legacy delivery from runtime 2026-04-01 17:06:01 +09:00
Vincent Koc
2d79c9cb16 docs: add WhatsApp reactionLevel and Feishu Drive comment actions 2026-04-01 16:56:47 +09:00
Peter Steinberger
95182d51cc fix: harden bundled plugin runtime deps 2026-04-01 08:55:00 +01:00
Vincent Koc
edfac5f2df docs(changelog): note line runtime packaging fix 2026-04-01 13:20:50 +05:30
Vincent Koc
d4643e06bd fix(line): resolve dist runtime contract path 2026-04-01 13:20:50 +05:30
Vincent Koc
facdeb3432 feat(tasks): add chat-native task board (#58828) 2026-04-01 16:48:36 +09:00
Peter Steinberger
7cf8ccf9b3 fix: avoid startup gateway reload loop (#58678) (thanks @yelog) 2026-04-01 16:47:55 +09:00
Vincent Koc
71f341c4b4 docs: add /tasks chat command, cleanup-aware status, and QQ Bot troubleshooting 2026-04-01 16:46:04 +09:00
Peter Steinberger
f5431bc07e docs: clarify doctor cron migration guidance 2026-04-01 16:44:10 +09:00
Peter Steinberger
802bdb099e refactor: move cron legacy delivery migration to doctor 2026-04-01 16:44:10 +09:00
Peter Steinberger
31ed09bc96 fix: run bundled deps postinstall for global npm 2026-04-01 08:38:24 +01:00
Vincent Koc
cfa307baed fix(status): keep task snapshots pure 2026-04-01 16:36:57 +09:00
Ayaan Zaidi
5a95d65f1e fix: restore bundled runtime dependency provisioning (#58782) (thanks @obviyus)
* fix: restore bundled runtime dependency provisioning

* fix: ship npm runner in packed installs

* fix: address bundled runtime staging review feedback

* fix: include npm runner in docker build contexts

* fix: restore bundled runtime dependency provisioning (#58782) (thanks @obviyus)

* fix: allow caret specs through windows npm cmd (#58782) (thanks @obviyus)
2026-04-01 13:03:36 +05:30
Peter Steinberger
86b519850e refactor: consolidate cron delivery boundary parsing 2026-04-01 16:31:51 +09:00
Vincent Koc
340c99d657 fix(status): filter stale task rows from status cards (#58810)
* fix(status): filter stale task rows

* test(status): use real task snapshot semantics

* fix(status): prefer failure task context in recent failures
2026-04-01 16:19:02 +09:00
Peter Steinberger
9ab3352b1a fix: avoid duplicate discord resolve logs 2026-04-01 08:14:54 +01:00
Peter Steinberger
622b91d04e fix: queue model switches behind busy runs 2026-04-01 16:14:10 +09:00
Peter Steinberger
6776306387 fix: preserve telegram topic delivery routing (#58489) (thanks @cwmine) 2026-04-01 16:13:24 +09:00
yi-bot
e643ba2f5e fix: preserve telegram topic routing in announce and delivery context 2026-04-01 16:13:24 +09:00
wittam-01
1b94e8ca14 feat: feishu comment event (#58497)
Merged via squash.

Prepared head SHA: a9dfeb0d62
Co-authored-by: wittam-01 <271711640+wittam-01@users.noreply.github.com>
Co-authored-by: odysseus0 <8635094+odysseus0@users.noreply.github.com>
Reviewed-by: @odysseus0
2026-04-01 00:12:38 -07:00
chi
cad3da52c9 fix(memory): prefer --mask over --glob for qmd collection pattern flag (#58736)
* fix(memory): prefer --mask over --glob for qmd collection pattern flag

qmd 2.0.1 silently ignores the --glob flag when creating collections,
causing all patterns (e.g. MEMORY.md, memory.md) to fall back to the
default **/*.md glob. This leads to collection conflicts when multiple
collections target the same workspace directory with different patterns.

The existing flag negotiation logic in addCollection() tries --glob
first (when collectionPatternFlag is null), and since qmd accepts the
flag without error, OpenClaw never falls back to --mask. The result is
that memory-root-{agent} gets created with **/*.md instead of MEMORY.md,
and memory-alt-{agent} fails with a duplicate path+pattern conflict.

Fix: default collectionPatternFlag to '--mask' so the working flag is
tried first. The fallback to --glob is preserved for older qmd versions
that may not support --mask.

* docs(changelog): note qmd collection flag fix

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-04-01 16:11:56 +09:00
Peter Steinberger
bd6c017192 fix: skip failing gateway HTTP stages (#58746) (thanks @yelog) 2026-04-01 16:09:36 +09:00
yelog
ffa1e5fa92 test: assert console.error in async-rejection stage test 2026-04-01 16:09:36 +09:00
yelog
0a636aef24 fix: catch per-stage errors in HTTP request pipeline to prevent cascade 500s (#58689) 2026-04-01 16:09:36 +09:00
Peter Steinberger
d9a2690535 test: trim mattermost setup cases 2026-04-01 08:03:26 +01:00
Peter Steinberger
035028208f test: trim line webhook/slack setup prompts 2026-04-01 08:02:26 +01:00
Peter Steinberger
e441e8bb17 test: stabilize timed-heavy channel planner checks 2026-04-01 07:46:25 +01:00
Peter Steinberger
709668ccd1 test: trim line/twitch setup validations 2026-04-01 07:46:25 +01:00
Peter Steinberger
add54e1d26 test: trim low-signal matrix monitor tests 2026-04-01 07:46:25 +01:00
Peter Steinberger
25eaebb9b6 test: drop duplicate telegram/discord command tests 2026-04-01 07:46:25 +01:00
Peter Steinberger
c130ebad35 fix: verify linux gateway in parallels smoke 2026-04-01 07:38:49 +01:00
Tars
5f3737f229 fix: auto-enable minimax plugin for API key auth route (#57127)
Merged via squash.

Prepared head SHA: 5782b26738
Co-authored-by: tars90percent <252094836+tars90percent@users.noreply.github.com>
Co-authored-by: odysseus0 <8635094+odysseus0@users.noreply.github.com>
Reviewed-by: @odysseus0
2026-03-31 22:52:19 -07:00
Neerav Makwana
26a891aaeb fix: preserve rewritten stream snapshots in webchat (#58641) (thanks @neeravmakwana) 2026-04-01 11:09:19 +05:30
Kenny Xie
e1d963ed2e fix: bound discord inbound media downloads (#58593) (thanks @aquaright1)
* fix(discord): bound attachment downloads by timeout

* fix(ci): unblock check and clarify discord timeouts

* fix: bound discord inbound media downloads (#58593) (thanks @aquaright1)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-01 10:59:58 +05:30
Josh Lehman
5836ddea3f test: fix amazon-bedrock extension test boundary (#58753)
* Tests: stop amazon-bedrock from importing private core plugin types

* Config: refresh generated doc baseline
2026-03-31 22:24:38 -07:00
Marcus Castro
ac6db066d3 feat(whatsapp): add reaction guidance levels (#58622)
* WhatsApp: add reaction guidance policy

* WhatsApp: expose reaction guidance to agents
2026-04-01 01:42:10 -03:00
Owen Wang
21403a3898 fix(whatsapp): pass Timestamp to finalizeInboundContext (#58590)
Merged via squash.

Prepared head SHA: 74aa9a1408
Co-authored-by: Maninae <9339187+Maninae@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
2026-04-01 01:02:23 -03:00
Ayaan Zaidi
2c5796c924 fix(tasks): recheck current state during maintenance sweep 2026-04-01 09:25:38 +05:30
joshavant
ccb67bd4bf config: regenerate base config schema baseline 2026-03-31 22:54:36 -05:00
joshavant
ed83d79a05 fix: tighten reply payload typing and safe text coercion 2026-03-31 22:54:36 -05:00
Ayaan Zaidi
05c311e67d fix: record task sweep gateway hang fix (#58670) (thanks @openperf) 2026-04-01 09:12:57 +05:30
Ayaan Zaidi
2dbfd4ebe2 refactor(tasks): distill task registry sweep scheduling 2026-04-01 09:12:57 +05:30
openperf
97fd6c27a1 fix(tasks): prevent synchronous task registry sweep from blocking event loop 2026-04-01 09:12:57 +05:30
Jamil Zakirov
69685f99fe fix: preserve Telegram local Bot API MIME types (#54603) (thanks @jzakirov)
* fix(telegram): preserve content type for local Bot API media files

* fix: preserve Telegram local Bot API MIME types (#54603) (thanks @jzakirov)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-01 09:08:31 +05:30
Peter Steinberger
098125e998 test: merge channel reply pipeline typing cases 2026-04-01 03:26:24 +01:00
Peter Steinberger
7ae093cf0f test: merge command auth cases 2026-04-01 03:25:39 +01:00
Peter Steinberger
ba808573ef test: merge allowlist config helper cases 2026-04-01 03:24:41 +01:00
Peter Steinberger
a217e97fe5 test: merge approval renderer cases 2026-04-01 03:23:41 +01:00
Peter Steinberger
cf3d7c8d57 test: merge account status helper cases 2026-04-01 03:22:33 +01:00
Peter Steinberger
d11df8e13e test: merge approval auth helper cases 2026-04-01 03:21:32 +01:00
Peter Steinberger
d65c290748 test: merge temp download path cases 2026-04-01 03:20:28 +01:00
Peter Steinberger
fbca5bcc12 test: merge status helper default/explicit cases 2026-04-01 03:19:35 +01:00
Peter Steinberger
cb131a7938 test: merge dm allowlist pairing policy cases 2026-04-01 03:18:35 +01:00
Peter Steinberger
54f2c8e939 test: merge mattermost setup registration checks 2026-04-01 03:17:10 +01:00
Peter Steinberger
655d52815d test: merge channel send result stamping coverage 2026-04-01 03:16:06 +01:00
Peter Steinberger
6e2738ef00 test: merge kilocode provider registration coverage 2026-04-01 03:13:26 +01:00
Peter Steinberger
a59f2f43b6 test: drop thread-ownership hook registration smoke 2026-04-01 03:12:19 +01:00
Peter Steinberger
3c6e0cfe25 test: drop feishu plugin registration smoke 2026-04-01 03:11:33 +01:00
Peter Steinberger
8076c78b2e test: drop subagent hook registration smokes 2026-04-01 03:10:47 +01:00
Peter Steinberger
5e371fe875 test: drop discord command registration smoke 2026-04-01 03:09:52 +01:00
Peter Steinberger
6e773cc3b6 test: drop webhook registration smokes 2026-04-01 03:08:33 +01:00
Peter Steinberger
35c9372dc4 test: merge diffs registration smoke into config defaults 2026-04-01 03:05:46 +01:00
Peter Steinberger
5c27f15fe6 test: drop browser plugin registration smoke 2026-04-01 03:03:27 +01:00
Peter Steinberger
4765ce3ad7 test: drop low-signal extension registration smokes 2026-04-01 03:02:40 +01:00
Peter Steinberger
042a9ab48a test: fix plugin-sdk subpaths contract imports 2026-04-01 03:02:34 +01:00
Peter Steinberger
73ead2425b test: drop redundant web search registration smokes 2026-04-01 02:57:08 +01:00
Peter Steinberger
49ac85b56d test: merge secret input schema coverage 2026-04-01 02:53:40 +01:00
Peter Steinberger
5816294b4c test: merge request-url coverage into fetch auth 2026-04-01 02:52:44 +01:00
Peter Steinberger
08bbb51bf7 test: merge allowlist resolution coverage 2026-04-01 02:51:26 +01:00
Peter Steinberger
f5a23b710c test: move plugin-sdk index and root alias guardrails 2026-04-01 02:50:22 +01:00
Peter Steinberger
016f065d7e test: move remaining plugin-sdk guardrails to contracts 2026-04-01 02:46:50 +01:00
Peter Steinberger
7e02005ca9 test: move plugin-sdk guardrails to contracts suite 2026-04-01 02:41:02 +01:00
Peter Steinberger
219116e862 test: drop redundant status-issues skip checks 2026-04-01 02:32:55 +01:00
Peter Steinberger
09c03fcfed test: drop low-signal memory plugin metadata check 2026-04-01 02:30:53 +01:00
Peter Steinberger
3c69e1ea4e test: drop low-signal plugin runtime type contract 2026-04-01 02:29:18 +01:00
Peter Steinberger
0614d992a4 test: drop redundant openai registration smoke 2026-04-01 02:26:50 +01:00
Peter Steinberger
f9c18186a8 test: move openai live smoke to live suite 2026-04-01 02:24:12 +01:00
Peter Steinberger
1226361c6d test: move memory lancedb live smoke to live suite 2026-04-01 02:18:20 +01:00
Peter Steinberger
beb2171ab5 test: move openrouter live test to live suite 2026-04-01 02:15:35 +01:00
Morrow
be5a035d97 fix: harden embedded text normalization (#58555)
Co-authored-by: Morrow <271612559+agent-morrow@users.noreply.github.com>
2026-03-31 21:10:49 -04:00
Owen Wang
50cc28c559 fix: differentiate overloaded vs rate-limit user-facing error messages (#58562) 2026-03-31 21:10:38 -04:00
dudu1111685
ed8e6b0a74 plugins: suppress provenance warning for allowlisted local plugins (#58604)
Co-authored-by: me <shlomo@vmi1916417.contaboserver.net>
2026-03-31 21:10:30 -04:00
Zhang
d2663262d4 Fix broken URL in Twitch extension README (#58563)
Remove stray `%20` (URL-encoded space) from the StreamWeasels username-to-ID
converter link, which caused a 404 when clicked.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 21:10:28 -04:00
Andy Tien
6c3eea3ce9 fix(session): prevent heartbeat/cron/exec events from triggering session reset (#58605)
Fixes #58409 - Heartbeat system causes silent session reset leading to user data loss.

The issue occurred when automated system events (heartbeat, cron-event, exec-event)
triggered the session initialization logic, which evaluated session freshness based on
idle/daily reset policies. Stale sessions were reset, causing complete context loss.

Changes:
- Detect system event providers (heartbeat, cron-event, exec-event) in initSessionState
- Force freshEntry=true for system events to skip reset policy evaluation
- Add comprehensive test coverage for heartbeat no-reset behavior

This ensures automated check-ins preserve session continuity and never cause
accidental data loss.
2026-03-31 21:10:24 -04:00
OfflynAI
b554516f21 routing: support wildcard peer bindings (peer.id="*") for multi-agent routing (#58609)
* routing: support wildcard peer bindings (peer.id="*") for multi-agent routing

Bindings with `peer: { kind: "direct", id: "*" }` were treated as a literal
peer ID "*" instead of a wildcard. This caused the binding to be indexed
exclusively in the byPeer map under key "direct:*", which never matches
actual incoming peer IDs like "direct:12345678". The binding silently fell
through to the default agent ("main"), breaking multi-agent setups that use
wildcard peer constraints to route all DMs on a named account to a specific
agent.

Add a "wildcard-kind" peer constraint state that restricts on chat type
(direct/group/channel) without requiring an exact peer ID match. Wildcard
peer bindings now fall through to the byAccount/byChannel index tiers and
correctly match via matchesBindingScope with kind-only filtering.

Resolves #58546

Made-with: Cursor

* routing: add dedicated binding.peer.wildcard tier for clarity

Address Greptile feedback: wildcard-peer bindings now report
matchedBy: "binding.peer.wildcard" instead of "binding.account",
making logs/debugging clearer for operators.

- Add byPeerWildcard index bucket
- Add binding.peer.wildcard tier between peer.parent and guild+roles
- Update tests to expect the new matchedBy value

Made-with: Cursor
2026-03-31 21:10:18 -04:00
Reed
b86f5d5ea4 fix(sandbox): resolve pinned fs helper python without PATH (#58573) 2026-03-31 21:10:17 -04:00
zssggle-rgb
a37c66906c fix(acpx): retry backend health probes after ensure (#58612)
* fix(acpx): retry backend health probes after ensure

* fix(acpx): keep doctor checks diagnostic-only
2026-03-31 21:10:09 -04:00
zssggle-rgb
8e0f495197 fix(acpx): preserve control command error details (#58613) 2026-03-31 21:10:04 -04:00
Sharoon Sharif
7941f21bef fix(voice-call): clear connection timeout on successful STT connect (#58586)
The 10-second connection timeout in OpenAIRealtimeSTTSession.doConnect()
was never cleared on success or teardown, leaking a timer on every
connection and accumulating stale timers across reconnect cycles.

Store the timeout handle and clear it in both the open handler and
close(), matching the existing clearTimeout pattern in
waitForTranscript().

Co-authored-by: Sharoon Sharif <ssharif@Hosanna.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 21:10:02 -04:00
zssggle-rgb
187d3ed053 fix(acpx): fall back to PATH node for shebang wrappers (#58614) 2026-03-31 21:09:58 -04:00
Michael Flanagan
eee185af99 feat(amazon-bedrock): add Bedrock Guardrails support (#58588)
* feat(amazon-bedrock): just the kiro plans, need to remove before PR

* docs(bedrock-guardrails): add environment setup instructions

* docs(bedrock-guardrails): mark environment setup tasks as completed

* feat(amazon-bedrock): add trace configuration to guardrail settings

* feat(amazon-bedrock): implement guardrail wrapper factory and wire into registration

* test(amazon-bedrock): add comprehensive guardrail configuration tests

* docs(bedrock): add guardrails configuration documentation

* docs(bedrock-guardrails): add comprehensive manual testing guide for Docker deployment

* docs(bedrock-guardrails): expand manual testing guide with STS credentials and config options

* docs(bedrock-guardrails): complete manual testing verification with 8 test scenarios

* chore: remove kiro spec files from PR

* fix(docs): correct guardrail config path to plugins.entries.*.config

* style: format docs and test files
2026-03-31 21:09:52 -04:00
狼哥
40b24dfa6b fix(session-status): infer custom runtime providers from config (#58474)
* fix(session-status): infer custom runtime providers from config

* test(session-status): satisfy custom provider type checks
2026-03-31 21:09:42 -04:00
Han Yang
547154865b Fix: live session model switch no longer blocks failover (Resolves #58466) (#58589)
* fix: prevent infinite retry loop when live session model switch blocks failover (#58466)

* fix: remove unused resolveOllamaBaseUrlForRun import after rebase
2026-03-31 21:09:41 -04:00
Phillip Hampton
350fe63bbf feat(macos): Voice Wake option to trigger Talk Mode (#58490)
* feat(macos): add "Trigger Talk Mode" option to Voice Wake settings

When enabled, detecting a wake phrase activates Talk Mode (full voice
conversation: STT -> LLM -> TTS playback) instead of sending a text
message to the chat. Enables hands-free voice assistant UX.

Implementation:
- Constants.swift: new `openclaw.voiceWakeTriggersTalkMode` defaults key
- AppState.swift: new property with UserDefaults persistence + runtime
  refresh on change so the toggle takes effect immediately
- VoiceWakeSettings.swift: "Trigger Talk Mode" toggle under Voice Wake,
  disabled when Voice Wake is off
- VoiceWakeRuntime.swift: `beginCapture` checks `triggersTalkMode` and
  activates Talk Mode directly, skipping the capture/overlay/forward
  flow. Pauses the wake listener via `pauseForPushToTalk()` to prevent
  two audio pipelines competing on the mic.
- TalkModeController.swift: resumes voice wake listener when Talk Mode
  exits by calling `VoiceWakeRuntime.refresh`, mirroring PTT teardown.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address review feedback

- TalkModeController: move VoiceWakeRuntime.refresh() after
  TalkModeRuntime.setEnabled(false) completes, preventing mic
  contention race where wake listener restarts before Talk Mode
  finishes tearing down its audio engine (P1)
- VoiceWakeRuntime: remove redundant haltRecognitionPipeline()
  before pauseForPushToTalk() which already calls it via stop() (P2)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: resume wake listener based on enabled state, not toggle value

Check swabbleEnabled instead of voiceWakeTriggersTalkMode when deciding
whether to resume the wake listener after Talk Mode exits. This ensures
the paused listener resumes even if the user toggled "Trigger Talk Mode"
off during an active session. (P2)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: play trigger chime on Talk Mode activation + send chime before TTS

- VoiceWakeRuntime: play the configured trigger chime in the
  triggersTalkMode branch before pausing the wake listener. The early
  return was skipping the chime that plays in the normal capture flow.
- TalkModeRuntime: play the Voice Wake "send" chime before TTS playback
  starts, giving audible feedback that the AI is about to respond. Talk
  Mode never used this chime despite it being configurable in settings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: move send chime to transcript finalization (on send, not on reply)

The send chime now plays when the user's speech is finalized and about
to be sent to the AI, not when the TTS response starts. This matches
the semantics of "send sound" -- it confirms your input was captured.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 21:09:36 -04:00
Han Yang
68ee3113a9 Fix: CDP profiles prefer cdpPort over stale WebSocket cdpUrl (Resolves #58494) (#58499)
* fix(browser): prefer cdpPort over stale WebSocket cdpUrl for attach-only profiles

* fix(browser): preserve profile host when dropping stale devtools WS path
2026-03-31 21:09:31 -04:00
Kenny Xie
2650ce31fc fix(media): resolve relative MEDIA paths against agent workspace (#58624)
* fix(media): resolve relative MEDIA: paths against agent workspace dir

* fix(agents): remove stale ollama compat import

* fix(media): preserve workspace dir in outbound access
2026-03-31 21:09:28 -04:00
ryanngit
0b3d31c0ce feat(auth): WHAM-aware Codex cooldown for multi-profile setups (#58625)
Instead of exponential backoff guesses on Codex 429, probe the WHAM
usage API to determine real availability and write accurate cooldowns.

- Burst/concurrency contention: 15s circuit-break
- Genuine rate limit: proportional to real reset time (capped 2-4h)
- Expired token: 12h cooldown
- Dead account: 24h cooldown
- Probe failure: 30s fail-open

This prevents cascade lockouts when multiple agents share a pool of
Codex profiles, and avoids wasted retries on genuinely exhausted
profiles.

Closes #26329, relates to #1815, #1522, #23996, #54060

Co-authored-by: ryanngit <ryanngit@users.noreply.github.com>
2026-03-31 21:09:25 -04:00
Jalen
915e15c13d fix(gateway): skip restart when config.patch has no actual changes (#58502)
config.patch unconditionally writes the config file and sends SIGUSR1
even when diffConfigPaths detects zero changed paths. This causes a
full gateway restart (~10s downtime, all SSE/WebSocket connections
dropped) on every control-plane config.patch call, even when the
config is identical — e.g. a model hot-apply that doesn't change any
gateway.* paths.

Fix: when changedPaths is empty, return early with `noop: true`
without writing the file or scheduling SIGUSR1. The validated config
is still returned so the caller knows the current state.

This lets control-plane clients safely call config.patch for
idempotent updates without triggering unnecessary restarts.
2026-03-31 21:09:23 -04:00
Rico0919x
ee42e44d88 fix(auth): add qwen-dashscope and anthropic-openai to known API key env vars (#58503) 2026-03-31 21:09:20 -04:00
Andy
4d8c07b97c feat(cron): add --tools flag for per-job tool allow-list (#58504)
Add toolsAllow field to cron agent-turn payloads, enabling users to
restrict which tool schemas are sent to the model for a given cron job.

When --tools is set:
- Only listed tools are included in the provider request
- promptMode is forced to 'minimal' (strips skills catalog, reply tags,
  heartbeat, messaging, docs, memory, model aliases, silent replies)
- Dramatically reduces input tokens for small local models (~16K to ~800)

CLI surface:
- openclaw cron add --tools exec,read,write
- openclaw cron edit <id> --tools exec
- openclaw cron edit <id> --clear-tools (remove allow-list)

Closes #58435

Co-authored-by: andyk-ms <andyk-ms@users.noreply.github.com>
2026-03-31 21:09:17 -04:00
Qkal
3a52b475ab Docs: clarify first-contribution fallback when no good-first-issue labels are open (#58530) 2026-03-31 21:09:10 -04:00
Lee Pender
8b6b4b18a8 feat: add agents.defaults.params for global default provider params (#58548)
Allow setting provider params (e.g. cacheRetention) once at the
agents.defaults level instead of repeating them per-model. The merge
order is now: defaults.params -> defaults.models[key].params ->
list[agentId].params.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 21:09:07 -04:00
hcl
b8fea43bf2 fix(gateway): return default scopes when trusted HTTP request has no scope header (#58603)
resolveTrustedHttpOperatorScopes() returns [] when the x-openclaw-scopes
header is absent, even for trusted requests (--auth none). This causes
403 "missing scope: operator.write" on /v1/chat/completions.

Root cause: src/gateway/http-utils.ts:138-140. PR #57783 (f0af18672)
replaced the old resolveGatewayRequestedOperatorScopes which had an
explicit fallback to CLI_DEFAULT_OPERATOR_SCOPES when no header was
present. The new function treats absent header the same as empty header
— both return [].

Fix: distinguish absent header (undefined → return defaults) from empty
header ("" → return []). Trusted clients without an explicit scope
header get the default operator scopes, matching pre-#57783 behavior.

Closes #58357

Signed-off-by: HCL <chenglunhu@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 21:09:05 -04:00
Peter Steinberger
5b8f0cf1d5 test: centralize inbound contract suites 2026-04-01 02:04:53 +01:00
Peter Steinberger
b59adf9d2a test: fix outbound payload contract import 2026-04-01 02:02:07 +01:00
Peter Steinberger
051e31fb55 test: centralize outbound payload contracts 2026-04-01 02:01:48 +01:00
Peter Steinberger
ddf39180a4 test: remove extension dm policy wrappers 2026-04-01 01:59:22 +01:00
Peter Steinberger
2db2b078ca test: remove extension group policy wrappers 2026-04-01 01:57:18 +01:00
Peter Steinberger
aea016d02c test: fix registry-backed contract import 2026-04-01 01:54:03 +01:00
Peter Steinberger
1f97f907b2 test: centralize registry-backed channel contracts 2026-04-01 01:53:23 +01:00
Peter Steinberger
7614c45980 test: fix channel catalog contract import 2026-04-01 01:52:01 +01:00
Peter Steinberger
ba5b373ad4 test: centralize channel catalog contracts 2026-04-01 01:51:26 +01:00
Peter Steinberger
85679252c4 test: remove extension provider contract wrappers 2026-04-01 01:49:55 +01:00
Peter Steinberger
4af52a7428 test: centralize provider runtime, discovery, and auth contracts 2026-04-01 01:49:11 +01:00
Peter Steinberger
78be556299 test: consolidate plugin registration contracts 2026-04-01 01:46:56 +01:00
Peter Steinberger
63819bb383 test: consolidate provider and web-search contracts 2026-04-01 01:44:43 +01:00
Peter Steinberger
b910cc5869 test: remove extension manifest and core-extension wrappers 2026-04-01 01:44:43 +01:00
Peter Steinberger
c41df4873e test: consolidate package manifest and core-extension contracts 2026-04-01 01:44:43 +01:00
Mingxuan
302c047d86 hotfix(ollama): Show only Ollama models after provider selection (#55290)
* Fix: Add ollama to NON_PI_NATIVE_MODEL_PROVIDERS to ensure correct model selection

* Add test coverage for ollama provider to ensure models are merged correctly

* Fix test case for ollama provider by adding required model properties

* Changelog: add Ollama model picker fix

* Changelog: move Ollama fix entry to section tail

---------

Co-authored-by: Bruce MacDonald <brucewmacdonald@gmail.com>
2026-03-31 16:48:22 -07:00
Gustavo Madeira Santana
bea53d7a3f Fix: move bootstrap session grammar into plugin-owned session-key surfaces (#58400)
Merged via squash.

Prepared head SHA: b062b18b03
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-03-31 19:41:01 -04:00
oliviareid-svg
bf0f33db32 fix(compaction): resolve model override in runtime context for all context engines (#56710)
Merged via squash.

Prepared head SHA: 72550aa5f0
Co-authored-by: oliviareid-svg <269669958+oliviareid-svg@users.noreply.github.com>
Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com>
Reviewed-by: @jalehman
2026-03-31 15:25:16 -07:00
Peter Steinberger
78d1120a41 test: retry gateway acp bind warmup 2026-03-31 23:20:25 +01:00
Peter Steinberger
d771f7dcb7 fix: harden acpx live startup 2026-03-31 23:20:24 +01:00
Peter Steinberger
f21abb2151 fix: harden queue cleanup lane resolution 2026-03-31 23:20:24 +01:00
Peter Steinberger
cdaf6d5749 docs: allow sponsor table markup in markdownlint 2026-03-31 23:18:55 +01:00
Josh Lehman
adc329b26b test: dedupe extension-owned coverage (#58554)
* test: dedupe extension-owned coverage

* test: remove duplicate coverage files

* test: move helper coverage into extensions

* test: trim duplicate helper assertions

* test: remove cloudflare helper import from agent test

* test: align stale expectations with current main
2026-03-31 15:18:29 -07:00
Peter Steinberger
d7e9d341cc fix: require npm auth for dist-tag mirror 2026-03-31 23:14:19 +01:00
Peter Steinberger
4f83409345 docs: add theme-aware sponsor logos 2026-04-01 07:14:05 +09:00
Peter Steinberger
091c6105a4 style(test): format skills install test 2026-03-31 23:11:53 +01:00
Peter Steinberger
aa6cf87814 refactor(approvals): share origin target reconciliation 2026-03-31 23:11:53 +01:00
Peter Steinberger
ddce362d34 refactor(approvals): share native delivery runtime 2026-03-31 23:11:53 +01:00
Peter Steinberger
5997317c09 docs: add NVIDIA sponsor logo 2026-04-01 06:59:06 +09:00
Peter Steinberger
9ea7e06460 build: bump version to 2026.4.1 2026-03-31 22:53:17 +01:00
Peter Steinberger
313a27d82f docs: update appcast for 2026.3.31 2026-03-31 22:51:49 +01:00
Vincent Koc
11318ef9b9 fix(status): align session_status with /status 2026-04-01 06:40:50 +09:00
Vincent Koc
94d72efedc fix(slack): accept bare approve fallback 2026-04-01 06:34:01 +09:00
Vincent Koc
ee8baf6766 fix(reply): stop mention-wrapped status double replies 2026-04-01 06:32:34 +09:00
Peter Steinberger
ad06d5ab4d build: reuse release preflight artifacts 2026-04-01 06:30:36 +09:00
Gustavo Madeira Santana
6679690737 fix(regression): restore diffs viewer toolbar buttons 2026-03-31 17:26:20 -04:00
Vincent Koc
db0f7c2cd5 changelog: note discord and telegram approval UX fixes 2026-04-01 06:21:56 +09:00
Vincent Koc
b73dd9b326 fix(approvals): suppress manual native approval narration 2026-04-01 06:21:56 +09:00
Vincent Koc
211b5a51af docs(changelog): note status followups 2026-04-01 06:16:15 +09:00
Vincent Koc
e1d2b299f6 fix(reply): avoid double status replies 2026-04-01 06:12:47 +09:00
Peter Steinberger
968bc3d5b0 fix(ci): preserve workspace openclaw plugin links 2026-03-31 22:05:59 +01:00
Vincent Koc
f85aba43a9 fix(approvals): restore native DM approval behavior 2026-04-01 06:02:04 +09:00
Vincent Koc
fdad8ea3b0 fix(status): show agent-local task counts when session tasks are empty 2026-04-01 06:01:29 +09:00
Vincent Koc
93e2d0e3de build(bluebubbles): align openclaw dependency specifiers 2026-04-01 06:00:55 +09:00
Peter Steinberger
213a704b71 fix: unblock 2026.3.31 release preflight 2026-03-31 21:54:12 +01:00
Vincent Koc
44baf3bb2b build(pnpm): exclude openclaw from minimum release age 2026-04-01 05:50:35 +09:00
Vincent Koc
107fefd255 docs(changelog): note pi tui reply flush fix 2026-04-01 05:47:10 +09:00
Peter Steinberger
6f111516ef docs: refresh plugin sdk api baseline 2026-03-31 21:46:21 +01:00
Vincent Koc
f425ea06bf fix(pi): flush message-boundary block replies on message end 2026-04-01 05:44:10 +09:00
Vincent Koc
0a7024e209 test(tasks): allow status command task-registry import 2026-04-01 05:42:45 +09:00
Peter Steinberger
418fa12dfa fix: make overload failover configurable 2026-03-31 21:34:35 +01:00
Peter Steinberger
2a60e34f2a build: prepare 2026.3.31 stable release 2026-03-31 21:32:38 +01:00
Peter Steinberger
eee37bf836 fix(slack): prevent duplicate draft replies 2026-03-31 21:22:50 +01:00
Vincent Koc
fc169215d7 fix(exec): deliver approval followups directly to chat 2026-04-01 05:22:35 +09:00
Vincent Koc
58ee76fc84 feat(status): show session task counts in slash status 2026-04-01 05:09:37 +09:00
Peter Steinberger
913e7d5eba fix: correct callable plugin sdk facades 2026-03-31 21:00:52 +01:00
Vincent Koc
a4f45c55b2 fix(slack): restore callable directory facade exports 2026-04-01 04:51:36 +09:00
1450 changed files with 63618 additions and 15537 deletions

View File

@@ -66,7 +66,8 @@ Use this skill for Parallels guest workflows and smoke interpretation. Do not lo
- Windows global `npm install -g` phases can stay quiet for a minute or more even when healthy; inspect the phase log before calling it hung, and only treat it as a regression once the retry wrapper or timeout trips.
- Fresh Windows ref-mode onboard should use the same background PowerShell runner plus done-file/log-drain pattern as the npm-update helper, including startup materialization checks, host-side timeouts on short poll `prlctl exec` calls, and retry-on-poll-failure behavior for transient transport flakes.
- Fresh Windows ref-mode agent verification should set `OPENAI_API_KEY` in the PowerShell environment before invoking `openclaw.cmd agent`, for the same pairing-required fallback reason as macOS.
- The Windows upgrade smoke lane should restart the managed gateway after `upgrade.install-main` and before `upgrade.onboard-ref`, or the old process can keep the previous gateway token and fail `gateway-health` with `unauthorized: gateway token mismatch`.
- The standalone Windows upgrade smoke lane should stop the managed gateway after `upgrade.install-main` and before `upgrade.onboard-ref`. Restarting before onboard can leave the old process alive on the pre-onboard token while onboard rewrites `~/.openclaw/openclaw.json`, which then fails `gateway-health` with `unauthorized: gateway token mismatch`.
- If standalone Windows upgrade fails with a gateway token mismatch but `pnpm test:parallels:npm-update` passes, trust the mismatch as a standalone ref-onboard ordering bug first; the npm-update helper does not re-run ref-mode onboard on the same guest.
- Keep onboarding and status output ASCII-clean in logs; fancy punctuation becomes mojibake in current capture paths.
- If you hit an older run with `rc=255` plus an empty `fresh.install-main.log` or `upgrade.install-main.log`, treat it as a likely `prlctl exec` transport drop after guest start-up, not immediate proof of an npm/package failure.
@@ -79,8 +80,8 @@ Use this skill for Parallels guest workflows and smoke interpretation. Do not lo
- Fresh snapshots may be missing `curl`, and `apt-get update` can fail on clock skew. Bootstrap with `apt-get -o Acquire::Check-Date=false update` and install `curl ca-certificates`.
- Fresh `main` tgz smoke still needs the latest-release installer first because the snapshot has no Node or npm before bootstrap.
- This snapshot does not have a usable `systemd --user` session; managed daemon install is unsupported.
- `prlctl exec` reaps detached Linux child processes on this snapshot, so detached background gateway runs are not trustworthy smoke signals.
- Treat `gateway=skipped-no-detached-linux-gateway` plus `daemon=systemd-user-unavailable` as baseline on that Linux lane, not a regression.
- The Linux smoke now falls back to a manual `setsid openclaw gateway run --bind loopback --port 18789 --force` launch with `HOME=/root` and the provider secret exported, then verifies `gateway status --deep --require-rpc` when available.
- If Linux gateway bring-up fails, inspect `/tmp/openclaw-parallels-linux-gateway.log` in the guest phase logs first; the common failure mode is a missing provider secret in the launched gateway environment.
## Discord roundtrip

View File

@@ -64,7 +64,8 @@ Use this skill for release and publish-time workflow. Keep ordinary development
Before tagging or publishing, run:
```bash
node --import tsx scripts/release-check.ts
pnpm build
pnpm ui:build
pnpm release:check
pnpm test:install:smoke
```
@@ -92,7 +93,7 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
- Default release checks:
- `pnpm check`
- `pnpm build`
- `node --import tsx scripts/release-check.ts`
- `pnpm ui:build`
- `pnpm release:check`
- `OPENCLAW_INSTALL_SMOKE_SKIP_NONROOT=1 pnpm test:install:smoke`
- Check all release-related build surfaces touched by the release, not only the npm package.
@@ -119,6 +120,11 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
- The npm workflow and the private mac publish workflow accept
`preflight_only=true` to run validation/build/package steps without uploading
public release assets.
- Real npm publish requires a prior successful npm preflight run id so the
publish job promotes the prepared tarball instead of rebuilding it.
- Real private mac publish requires a prior successful private mac preflight
run id so the publish job promotes the prepared artifacts instead of
rebuilding or renotarizing them again.
- The private mac workflow also accepts `smoke_test_only=true` for branch-safe
workflow smoke tests that use ad-hoc signing, skip notarization, skip shared
appcast generation, and do not prove release readiness.
@@ -129,17 +135,23 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
workflow change before merge.
- `.github/workflows/macos-release.yml` in `openclaw/openclaw` is now a
public validation-only handoff. It validates the tag/release state and points
operators to the private repo; it does not build or publish macOS artifacts.
operators to the private repo. It still rebuilds the JS outputs needed for
release validation, but it does not sign, notarize, or publish macOS
artifacts.
- `openclaw/releases-private/.github/workflows/openclaw-macos-validate.yml`
is the required private mac validation lane for `swift test`; keep it green
before any real mac publish run starts.
- Real mac preflight and real mac publish both use
`openclaw/releases-private/.github/workflows/openclaw-macos-publish.yml`.
- The private mac workflow runs on GitHub's xlarge macOS runner and uses a
SwiftPM cache because the Swift build/test/package path is CPU-heavy.
- The private mac validation lane runs on GitHub's standard macOS runner.
- The private mac preflight path runs on GitHub's xlarge macOS runner and uses
a SwiftPM cache because the build/sign/notarize/package path is CPU-heavy.
- Private mac preflight uploads notarized build artifacts as workflow artifacts
instead of uploading public GitHub release assets.
- Private smoke-test runs upload ad-hoc, non-notarized build artifacts as
workflow artifacts and intentionally skip stable `appcast.xml` generation.
- npm preflight, public mac validation, and private mac preflight must all pass
before any real publish run starts.
- npm preflight, public mac validation, private mac validation, and private mac
preflight must all pass before any real publish run starts.
- Real publish runs must be dispatched from `main`; branch-dispatched publish
attempts should fail before the protected environment is reached.
- The release workflows stay tag-based; rely on the documented release sequence
@@ -147,8 +159,8 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
- The `npm-release` environment must be approved by `@openclaw/openclaw-release-managers` before publish continues.
- Mac publish uses
`openclaw/releases-private/.github/workflows/openclaw-macos-publish.yml` for
build, signing, notarization, packaged mac artifact generation, and
stable-feed `appcast.xml` artifact generation.
private mac preflight artifact preparation and real publish artifact
promotion.
- Real private mac publish uploads the packaged `.zip`, `.dmg`, and
`.dSYM.zip` assets to the existing GitHub release in `openclaw/openclaw`
automatically when `OPENCLAW_PUBLIC_REPO_RELEASE_TOKEN` is present in the
@@ -206,31 +218,37 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
7. Create and push the git tag.
8. Create or refresh the matching GitHub release.
9. Start `.github/workflows/openclaw-npm-release.yml` with `preflight_only=true`
and wait for it to pass.
and wait for it to pass. Save that run id because the real publish requires
it to reuse the prepared npm tarball.
10. Start `.github/workflows/macos-release.yml` in `openclaw/openclaw` and wait
for the public validation-only run to pass.
11. Start
`openclaw/releases-private/.github/workflows/openclaw-macos-validate.yml`
with the same tag and wait for the private mac validation lane to pass.
12. Start
`openclaw/releases-private/.github/workflows/openclaw-macos-publish.yml`
with `preflight_only=true` and wait for it to pass.
12. If any preflight or validation run fails, fix the issue on a new commit,
with `preflight_only=true` and wait for it to pass. Save that run id because
the real publish requires it to reuse the notarized mac artifacts.
13. If any preflight or validation run fails, fix the issue on a new commit,
delete the tag and matching GitHub release, recreate them from the fixed
commit, and rerun all relevant preflights from scratch before continuing.
Never reuse old preflight results after the commit changes.
13. Start `.github/workflows/openclaw-npm-release.yml` with the same tag for
the real publish.
14. Wait for `npm-release` approval from `@openclaw/openclaw-release-managers`.
15. Start
14. Start `.github/workflows/openclaw-npm-release.yml` with the same tag for
the real publish and pass the successful npm `preflight_run_id`.
15. Wait for `npm-release` approval from `@openclaw/openclaw-release-managers`.
16. Start
`openclaw/releases-private/.github/workflows/openclaw-macos-publish.yml`
for the real publish and wait for success.
16. Verify the successful real private mac run uploaded the `.zip`, `.dmg`,
for the real publish with the successful private mac `preflight_run_id` and
wait for success.
17. Verify the successful real private mac run uploaded the `.zip`, `.dmg`,
and `.dSYM.zip` artifacts to the existing GitHub release in
`openclaw/openclaw`.
17. For stable releases, download `macos-appcast-<tag>` from the successful
18. For stable releases, download `macos-appcast-<tag>` from the successful
private mac run, update `appcast.xml` on `main`, and verify the feed.
18. For beta releases, publish the mac assets but expect no shared production
19. For beta releases, publish the mac assets but expect no shared production
`appcast.xml` artifact and do not update the shared production feed unless a
separate beta feed exists.
19. After publish, verify npm and the attached release artifacts.
20. After publish, verify npm and the attached release artifacts.
## GHSA advisory work

View File

@@ -1,110 +0,0 @@
name: CI Bun
on:
push:
branches: [main]
concurrency:
group: ci-bun-push-${{ github.run_id }}
cancel-in-progress: false
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
jobs:
preflight:
runs-on: blacksmith-16vcpu-ubuntu-2404
timeout-minutes: 20
outputs:
run_bun_checks: ${{ steps.manifest.outputs.run_bun_checks }}
bun_checks_matrix: ${{ steps.manifest.outputs.bun_checks_matrix }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
submodules: false
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
install-deps: "false"
use-sticky-disk: "false"
- name: Build Bun CI manifest
id: manifest
env:
OPENCLAW_CI_DOCS_ONLY: "false"
OPENCLAW_CI_DOCS_CHANGED: "false"
OPENCLAW_CI_RUN_NODE: "true"
OPENCLAW_CI_RUN_MACOS: "false"
OPENCLAW_CI_RUN_ANDROID: "false"
OPENCLAW_CI_RUN_WINDOWS: "false"
OPENCLAW_CI_RUN_SKILLS_PYTHON: "false"
OPENCLAW_CI_HAS_CHANGED_EXTENSIONS: "false"
OPENCLAW_CI_CHANGED_EXTENSIONS_MATRIX: '{"include":[]}'
run: node scripts/ci-write-manifest-outputs.mjs --workflow ci-bun
build-bun-artifacts:
needs: [preflight]
if: needs.preflight.outputs.run_bun_checks == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@v6
with:
submodules: false
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
use-sticky-disk: "false"
- name: Build A2UI bundle
run: pnpm canvas:a2ui:bundle
- name: Upload A2UI bundle artifact
uses: actions/upload-artifact@v7
with:
name: canvas-a2ui-bundle
path: src/canvas-host/a2ui/
include-hidden-files: true
retention-days: 1
bun-checks:
name: ${{ matrix.check_name }}
needs: [preflight, build-bun-artifacts]
if: needs.preflight.outputs.run_bun_checks == 'true'
runs-on: blacksmith-16vcpu-ubuntu-2404
timeout-minutes: 60
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.preflight.outputs.bun_checks_matrix) }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
submodules: false
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "true"
use-sticky-disk: "false"
- name: Download A2UI bundle artifact
uses: actions/download-artifact@v8
with:
name: canvas-a2ui-bundle
path: src/canvas-host/a2ui/
- name: Run Bun test shard
env:
SHARD_COUNT: ${{ matrix.shard_count }}
SHARD_INDEX: ${{ matrix.shard_index }}
shell: bash
run: |
set -euo pipefail
OPENCLAW_TEST_ISOLATE=1 bunx vitest run --config vitest.unit.config.ts --shard "$SHARD_INDEX/$SHARD_COUNT"

View File

@@ -546,6 +546,11 @@ jobs:
continue-on-error: true
run: pnpm run lint:web-search-provider-boundaries
- name: Run web fetch provider boundary guard
id: web_fetch_provider_boundary
continue-on-error: true
run: pnpm run lint:web-fetch-provider-boundaries
- name: Run extension src boundary guard
id: extension_src_outside_plugin_sdk_boundary
continue-on-error: true
@@ -593,6 +598,7 @@ jobs:
NO_EXTENSION_TEST_CORE_IMPORTS_OUTCOME: ${{ steps.no_extension_test_core_imports.outcome }}
PLUGIN_SDK_SUBPATHS_EXPORTED_OUTCOME: ${{ steps.plugin_sdk_subpaths_exported.outcome }}
WEB_SEARCH_PROVIDER_BOUNDARY_OUTCOME: ${{ steps.web_search_provider_boundary.outcome }}
WEB_FETCH_PROVIDER_BOUNDARY_OUTCOME: ${{ steps.web_fetch_provider_boundary.outcome }}
EXTENSION_SRC_OUTSIDE_PLUGIN_SDK_BOUNDARY_OUTCOME: ${{ steps.extension_src_outside_plugin_sdk_boundary.outcome }}
EXTENSION_PLUGIN_SDK_INTERNAL_BOUNDARY_OUTCOME: ${{ steps.extension_plugin_sdk_internal_boundary.outcome }}
EXTENSION_RELATIVE_OUTSIDE_PACKAGE_BOUNDARY_OUTCOME: ${{ steps.extension_relative_outside_package_boundary.outcome }}
@@ -612,6 +618,7 @@ jobs:
"lint:plugins:no-extension-test-core-imports|$NO_EXTENSION_TEST_CORE_IMPORTS_OUTCOME" \
"lint:plugins:plugin-sdk-subpaths-exported|$PLUGIN_SDK_SUBPATHS_EXPORTED_OUTCOME" \
"web-search-provider-boundary|$WEB_SEARCH_PROVIDER_BOUNDARY_OUTCOME" \
"web-fetch-provider-boundary|$WEB_FETCH_PROVIDER_BOUNDARY_OUTCOME" \
"extension-src-outside-plugin-sdk-boundary|$EXTENSION_SRC_OUTSIDE_PLUGIN_SDK_BOUNDARY_OUTCOME" \
"extension-plugin-sdk-internal-boundary|$EXTENSION_PLUGIN_SDK_INTERNAL_BOUNDARY_OUTCOME" \
"extension-relative-outside-package-boundary|$EXTENSION_RELATIVE_OUTSIDE_PACKAGE_BOUNDARY_OUTCOME" \

View File

@@ -82,11 +82,12 @@ jobs:
{
echo "## Public macOS validation only"
echo
echo "This workflow no longer builds, signs, notarizes, or uploads macOS assets."
echo "This workflow validates the public release handoff and still builds JS artifacts needed for release checks."
echo "It does not sign, notarize, or upload macOS assets."
echo
echo "Next step:"
echo "- Run \`openclaw/releases-private/.github/workflows/openclaw-macos-publish.yml\` with tag \`${RELEASE_TAG}\`."
echo "- Use \`preflight_only=true\` there for the full private mac preflight."
echo "- For the real publish path, the private run uploads the packaged \`.zip\`, \`.dmg\`, and \`.dSYM.zip\` files to the existing GitHub release in \`openclaw/openclaw\` automatically."
echo "- Run \`openclaw/releases-private/.github/workflows/openclaw-macos-validate.yml\` with tag \`${RELEASE_TAG}\` and wait for the private mac validation lane to pass."
echo "- Run \`openclaw/releases-private/.github/workflows/openclaw-macos-publish.yml\` with tag \`${RELEASE_TAG}\` and \`preflight_only=true\` for the full private mac preflight."
echo "- For the real publish path, run the same private mac publish workflow from \`main\` with the successful private preflight \`preflight_run_id\` so it promotes the prepared artifacts instead of rebuilding them."
echo "- For stable releases, also download \`macos-appcast-${RELEASE_TAG}\` from the successful private run and commit \`appcast.xml\` back to \`main\` in \`openclaw/openclaw\`."
} >> "$GITHUB_STEP_SUMMARY"

View File

@@ -12,6 +12,10 @@ on:
required: true
default: false
type: boolean
preflight_run_id:
description: Existing successful preflight workflow run id to promote without rebuilding
required: false
type: string
concurrency:
group: openclaw-npm-release-${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }}
@@ -24,6 +28,7 @@ env:
jobs:
preflight_openclaw_npm:
if: ${{ inputs.preflight_only }}
runs-on: ubuntu-latest
permissions:
contents: read
@@ -38,6 +43,12 @@ jobs:
exit 1
fi
- name: Forbid preflight artifact promotion on validation-only runs
if: ${{ inputs.preflight_only && inputs.preflight_run_id != '' }}
run: |
echo "preflight_run_id is only valid for real publish runs."
exit 1
- name: Checkout
uses: actions/checkout@v6
with:
@@ -82,7 +93,9 @@ jobs:
run: pnpm ui:build
- name: Validate release tag and package metadata
if: ${{ inputs.preflight_run_id == '' }}
env:
OPENCLAW_NPM_RELEASE_SKIP_PACK_CHECK: "1"
RELEASE_TAG: ${{ inputs.tag }}
RELEASE_MAIN_REF: origin/main
run: |
@@ -97,7 +110,37 @@ jobs:
- name: Verify release contents
run: pnpm release:check
validate_publish_dispatch_ref:
- name: Pack prepared npm tarball
id: packed_tarball
env:
OPENCLAW_PREPACK_PREPARED: "1"
RELEASE_TAG: ${{ inputs.tag }}
run: |
set -euo pipefail
PACK_JSON="$(npm pack --json)"
echo "$PACK_JSON"
PACK_PATH="$(printf '%s\n' "$PACK_JSON" | node -e 'const chunks=[]; process.stdin.on("data", (chunk) => chunks.push(chunk)); process.stdin.on("end", () => { const parsed = JSON.parse(Buffer.concat(chunks).toString("utf8")); const first = Array.isArray(parsed) ? parsed[0] : null; if (!first || typeof first.filename !== "string" || !first.filename) { process.exit(1); } process.stdout.write(first.filename); });')"
if [[ -z "$PACK_PATH" || ! -f "$PACK_PATH" ]]; then
echo "npm pack did not produce a tarball file." >&2
exit 1
fi
RELEASE_SHA="$(git rev-parse HEAD)"
ARTIFACT_DIR="$RUNNER_TEMP/openclaw-npm-preflight"
rm -rf "$ARTIFACT_DIR"
mkdir -p "$ARTIFACT_DIR"
cp "$PACK_PATH" "$ARTIFACT_DIR/"
printf '%s\n' "$RELEASE_TAG" > "$ARTIFACT_DIR/release-tag.txt"
printf '%s\n' "$RELEASE_SHA" > "$ARTIFACT_DIR/release-sha.txt"
echo "dir=$ARTIFACT_DIR" >> "$GITHUB_OUTPUT"
- name: Upload prepared npm publish bundle
uses: actions/upload-artifact@v7
with:
name: openclaw-npm-preflight-${{ inputs.tag }}
path: ${{ steps.packed_tarball.outputs.dir }}
if-no-files-found: error
validate_publish_request:
if: ${{ !inputs.preflight_only }}
runs-on: ubuntu-latest
permissions:
@@ -113,13 +156,24 @@ jobs:
exit 1
fi
- name: Require preflight artifact promotion on real publish
env:
PREFLIGHT_RUN_ID: ${{ inputs.preflight_run_id }}
run: |
set -euo pipefail
if [[ -z "${PREFLIGHT_RUN_ID}" ]]; then
echo "Real publish requires preflight_run_id from a successful npm preflight run." >&2
exit 1
fi
publish_openclaw_npm:
# npm trusted publishing + provenance requires a GitHub-hosted runner.
needs: [preflight_openclaw_npm, validate_publish_dispatch_ref]
needs: [validate_publish_request]
if: ${{ !inputs.preflight_only }}
runs-on: ubuntu-latest
environment: npm-release
permissions:
actions: read
contents: read
id-token: write
steps:
@@ -159,14 +213,28 @@ jobs:
echo "Publishing openclaw@${PACKAGE_VERSION}"
- name: Build
run: pnpm build
- name: Verify preflight run metadata
env:
GH_TOKEN: ${{ github.token }}
PREFLIGHT_RUN_ID: ${{ inputs.preflight_run_id }}
run: |
set -euo pipefail
RUN_JSON="$(gh run view "$PREFLIGHT_RUN_ID" --repo "$GITHUB_REPOSITORY" --json workflowName,headBranch,event,conclusion,url)"
printf '%s' "$RUN_JSON" | node -e 'const fs = require("node:fs"); const run = JSON.parse(fs.readFileSync(0, "utf8")); const checks = [["workflowName", "OpenClaw NPM Release"], ["headBranch", "main"], ["event", "workflow_dispatch"], ["conclusion", "success"]]; for (const [key, expected] of checks) { if (run[key] !== expected) { console.error(`Referenced npm preflight run ${process.env.PREFLIGHT_RUN_ID} must have ${key}=${expected}, got ${run[key] ?? "<missing>"}.`); process.exit(1); } } console.log(`Using npm preflight run ${process.env.PREFLIGHT_RUN_ID}: ${run.url}`);'
- name: Build Control UI
run: pnpm ui:build
- name: Download prepared npm tarball
uses: actions/download-artifact@v8
with:
name: openclaw-npm-preflight-${{ inputs.tag }}
path: preflight-tarball
repository: ${{ github.repository }}
run-id: ${{ inputs.preflight_run_id }}
github-token: ${{ github.token }}
- name: Validate release tag and package metadata
if: ${{ inputs.preflight_run_id == '' }}
env:
OPENCLAW_NPM_RELEASE_SKIP_PACK_CHECK: "1"
RELEASE_TAG: ${{ inputs.tag }}
RELEASE_MAIN_REF: origin/main
run: |
@@ -178,5 +246,51 @@ jobs:
git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main
pnpm release:openclaw:npm:check
- name: Verify prepared tarball provenance
env:
RELEASE_TAG: ${{ inputs.tag }}
run: |
set -euo pipefail
EXPECTED_RELEASE_SHA="$(git rev-parse HEAD)"
TAG_FILE="preflight-tarball/release-tag.txt"
SHA_FILE="preflight-tarball/release-sha.txt"
if [[ ! -f "$TAG_FILE" || ! -f "$SHA_FILE" ]]; then
echo "Prepared preflight metadata is missing." >&2
ls -la preflight-tarball >&2 || true
exit 1
fi
ARTIFACT_RELEASE_TAG="$(tr -d '\r\n' < "$TAG_FILE")"
ARTIFACT_RELEASE_SHA="$(tr -d '\r\n' < "$SHA_FILE")"
if [[ "$ARTIFACT_RELEASE_TAG" != "$RELEASE_TAG" ]]; then
echo "Prepared preflight tag mismatch: expected $RELEASE_TAG, got $ARTIFACT_RELEASE_TAG" >&2
exit 1
fi
if [[ "$ARTIFACT_RELEASE_SHA" != "$EXPECTED_RELEASE_SHA" ]]; then
echo "Prepared preflight SHA mismatch: expected $EXPECTED_RELEASE_SHA, got $ARTIFACT_RELEASE_SHA" >&2
exit 1
fi
- name: Resolve publish tarball
id: publish_tarball
run: |
set -euo pipefail
TARBALL_PATH="$(find preflight-tarball -type f -name '*.tgz' -print | sort | tail -n 1)"
if [[ -z "$TARBALL_PATH" ]]; then
echo "Prepared preflight tarball not found." >&2
ls -la preflight-tarball >&2 || true
exit 1
fi
echo "path=$TARBALL_PATH" >> "$GITHUB_OUTPUT"
- name: Publish
run: bash scripts/openclaw-npm-publish.sh --publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
OPENCLAW_PREPACK_PREPARED: "1"
run: |
set -euo pipefail
publish_target="${{ steps.publish_tarball.outputs.path }}"
if [[ -n "${publish_target}" ]]; then
publish_target="./${publish_target}"
fi
bash scripts/openclaw-npm-publish.sh --publish "${publish_target}"

View File

@@ -211,4 +211,7 @@ jobs:
fi
- name: Publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: bash scripts/plugin-npm-publish.sh --publish "${{ matrix.plugin.packageDir }}"

View File

@@ -33,6 +33,9 @@
"img",
"a",
"br",
"table",
"tr",
"td",
"details",
"summary",
"p",

View File

@@ -181,6 +181,7 @@
- Run `pnpm test` (or `pnpm test:coverage`) before pushing when you touch logic.
- Write tests to clean up timers, env, globals, mocks, sockets, temp dirs, and module state so `--isolate=false` stays green.
- Test performance guardrail: do not put `vi.resetModules()` plus `await import(...)` in `beforeEach`/per-test loops for heavy modules unless module state truly requires it. Prefer static imports or one-time `beforeAll` imports, then reset mocks/runtime state directly.
- Test performance guardrail: if a test file uses stable `vi.mock(...)` hoists or other static module mocks, do not pair them with `vi.resetModules()` and a fresh `await import(...)` in every `beforeEach`. Import the heavy module once in `beforeAll`, then reset/prime mocks in `beforeEach` so Browser/Matrix-style hotspot tests do not pay the module graph cost per case.
- Test performance guardrail: inside an extension package, prefer a thin local seam (`./api.ts`, `./runtime-api.ts`, or a narrower local `*.runtime-api.ts`) over direct `openclaw/plugin-sdk/*` imports for internal production code. Keep local seams curated and lightweight; only reach for direct `plugin-sdk/*` imports when you are crossing a real package boundary or when no suitable local seam exists yet.
- Test performance guardrail: keep expensive runtime fallback work such as snapshotting, migration, installs, or bootstrap behind dedicated `*.runtime.ts` boundaries so tests can mock the seam instead of accidentally invoking real work.
- Test performance guardrail: for import-only/runtime-wrapper tests, keep the wrapper lazy. Do not eagerly load heavy verification/bootstrap/runtime modules at module top level if the exported function can import them on demand.

View File

@@ -4,6 +4,258 @@ Docs: https://docs.openclaw.ai
## Unreleased
### Breaking
- Plugins/web fetch: move Firecrawl `web_fetch` config from the legacy core `tools.web.fetch.firecrawl.*` path to the plugin-owned `plugins.entries.firecrawl.config.webFetch.*` path, route `web_fetch` fallback through the new fetch-provider boundary instead of a Firecrawl-only core branch, and migrate legacy config with `openclaw doctor --fix`. Thanks @vincentkoc.
- Plugins/xAI: move `x_search` settings from the legacy core `tools.web.x_search.*` path to the plugin-owned `plugins.entries.xai.config.xSearch.*` path, standardize `x_search` auth on `plugins.entries.xai.config.webSearch.apiKey` / `XAI_API_KEY`, and migrate legacy config with `openclaw doctor --fix`. Thanks @vincentkoc.
### Changes
- Matrix/plugin: emit spec-compliant `m.mentions` metadata across text sends, media captions, edits, poll fallback text, and action-driven edits so Matrix mentions notify reliably in clients like Element. (#59323) Thanks @gumadeiras.
- Feishu/comments: add a dedicated Drive comment-event flow with comment-thread context resolution, in-thread replies, and `feishu_drive` comment actions for document collaboration workflows. (#58497) thanks @wittam-01.
- WhatsApp/reactions: add `reactionLevel` guidance for agent reactions. Thanks @mcaxtr.
- Diffs: add plugin-owned `viewerBaseUrl` so viewer links can use a stable proxy/public origin without passing `baseUrl` on every tool call. (#59341) Related #59227. Thanks @gumadeiras.
- Agents/compaction: add `agents.defaults.compaction.notifyUser` so the `🧹 Compacting context...` start notice is opt-in instead of always being shown. (#54251) Thanks @oguricap0327.
- Agents/compaction: resolve `agents.defaults.compaction.model` consistently for manual `/compact` and other context-engine compaction paths, so engine-owned compaction uses the configured override model across runtime entrypoints. (#56710) Thanks @oliviareid-svg
- Channels/session routing: move provider-specific session conversation grammar into plugin-owned session-key surfaces, preserving Telegram topic routing and Feishu scoped inheritance across bootstrap, model override, restart, and tool-policy paths.
- Plugins/hooks: add `before_agent_reply` so plugins can short-circuit the LLM with synthetic replies after inline actions. (#20067) Thanks @JoshuaLelon
- Providers/runtime: add provider-owned replay hook surfaces for transcript policy, replay cleanup, and reasoning-mode dispatch. (#59143) Thanks @jalehman.
- Tasks/TaskFlow: restore the core TaskFlow substrate with managed-vs-mirrored sync modes, durable flow state/revision tracking, and `openclaw flows` inspection/recovery primitives so background orchestration can persist and be operated separately from plugin authoring layers. (#58930) Thanks @mbelinky.
- Tasks/TaskFlow: add managed child task spawning plus sticky cancel intent, so external orchestrators can stop scheduling immediately and let parent TaskFlows settle to `cancelled` once active child tasks finish. (#59610) Thanks @mbelinky.
- Plugins/TaskFlow: add a bound `api.runtime.taskFlow` seam so plugins and trusted authoring layers can create and drive managed TaskFlows from host-resolved OpenClaw context without passing owner identifiers on each call. (#59622) Thanks @mbelinky.
### Fixes
- Slack/mrkdwn formatting: add built-in Slack mrkdwn guidance in inbound context so Slack replies stop falling back to generic Markdown patterns that render poorly in Slack. (#59100) Thanks @jadewon.
- WhatsApp/presence: send `unavailable` presence on connect in self-chat mode so personal-phone users stop losing all push notifications while the gateway is running. (#59410) Thanks @mcaxtr.
- WhatsApp/media: add HTML, XML, and CSS to the MIME map and fall back gracefully for unknown media types instead of dropping the attachment. (#51562) Thanks @bobbyt74.
- Matrix/onboarding: restore guided setup in `openclaw channels add` and `openclaw configure --section channels`, while keeping custom plugin wizards on the shared `setupWizard` seam. (#59462) Thanks @gumadeiras.
- Matrix/streaming: keep live partial previews for the current assistant block while preserving completed block updates as separate messages when `channels.matrix.blockStreaming` is enabled. (#59384) thanks @gumadeiras
- Feishu/comment threads: harden document comment-thread delivery so whole-document comments fall back to `add_comment`, delayed reply lookups retry more reliably, and user-visible replies avoid reasoning/planning spillover. (#59129) Thanks @wittam-01.
- MS Teams/streaming: strip already-streamed text from fallback block delivery when replies exceed the 4000-character streaming limit so long responses stop duplicating content. (#59297) Thanks @bradgroux.
- Slack/thread context: filter thread starter and history by the effective conversation allowlist without dropping valid open-room, DM, or group DM context. (#58380) Thanks @jacobtomlinson.
- Mattermost/probes: route status probes through the SSRF guard and honor `allowPrivateNetwork` so connectivity checks stay safe for self-hosted Mattermost deployments. (#58529) Thanks @mappel-nv.
- Zalo/webhook replay: scope replay dedupe key by chat and sender so reused message IDs across different chats or senders no longer collide, and harden metadata reads for partially missing payloads. (#58444)
- QQBot/structured payloads: restrict local file paths to QQ Bot-owned media storage, block traversal outside that root, reduce path leakage in logs, and keep inline image data URLs working. (#58453) Thanks @jacobtomlinson.
- Gateway/exec loopback: restore legacy-role fallback for empty paired-device token maps and allow silent local role upgrades so local exec and node clients stop failing with pairing-required errors after `2026.3.31`. (#59092) Thanks @openperf.
- Agents/output sanitization: strip namespaced `antml:thinking` blocks from user-visible text so Anthropic-style internal monologue tags do not leak into replies. (#59550) Thanks @obviyus.
- Kimi Coding/tools: normalize Anthropic tool payloads into the OpenAI-compatible function shape Kimi Coding expects so tool calls stop losing required arguments. (#59440) Thanks @obviyus.
- Image tool/paths: resolve relative local media paths against the agent `workspaceDir` instead of `process.cwd()` so inputs like `inbox/receipt.png` pass the local-path allowlist reliably. (#57222) Thanks Priyansh Gupta.
- Browser/CDP: normalize trailing-dot localhost absolute-form hosts before loopback checks so remote CDP websocket URLs like `ws://localhost.:...` rewrite back to the configured remote host. (#59236) Thanks @mappel-nv.
- Browser/host inspection: keep static Chrome inspection helpers out of the activated browser runtime so `openclaw doctor browser` and related checks do not eagerly load the bundled browser plugin. (#59471) Thanks @vincentkoc.
- Podman/launch: remove noisy container output from `scripts/run-openclaw-podman.sh` and align the Podman install guidance with the quieter startup flow. (#59368) Thanks @sallyom.
- Plugins/runtime: keep LINE reply directives and browser-backed cleanup/reset flows working even when those plugins are disabled while tightening bundled plugin activation guards. (#59412) Thanks @vincentkoc.
- Providers/OpenAI-compatible routing: centralize native-vs-proxy request policy so hidden attribution and related OpenAI-family defaults only apply on verified native endpoints across stream, websocket, and shared audio HTTP paths. (#59433) Thanks @vincentkoc.
- Providers/media HTTP: centralize base URL normalization, default auth/header injection, and explicit header override handling across shared OpenAI-compatible audio, Deepgram audio, Gemini media/image, and Moonshot video request paths. (#59469) Thanks @vincentkoc.
- Providers/streaming headers: centralize default and attribution header merging across OpenAI websocket, embedded-runner, and proxy stream paths so provider-specific headers stay consistent and caller overrides only win where intended. (#59542) Thanks @vincentkoc.
- Providers/Anthropic routing: centralize native-vs-proxy endpoint classification for direct Anthropic `service_tier` handling so spoofed or proxied hosts do not inherit native Anthropic defaults. (#59608) Thanks @vincentkoc.
- Providers/Copilot: classify native GitHub Copilot API hosts in the shared provider endpoint resolver and harden token-derived proxy endpoint parsing so Copilot base URL routing stays centralized and fails closed on malformed hints. Thanks @vincentkoc.
- ACP/gateway reconnects: keep ACP prompts alive across transient websocket drops while still failing boundedly when reconnect recovery does not complete. (#59473) Thanks @obviyus.
- ACP/gateway reconnects: reject stale pre-ack ACP prompts after reconnect grace expiry so callers fail cleanly instead of hanging indefinitely when the gateway never confirms the run.
- Exec approvals/doctor: report host policy sources from the real approvals file path and ignore malformed host override values when attributing effective policy conflicts. (#59367) Thanks @gumadeiras.
- Exec approvals/config: strip invalid `security`, `ask`, and `askFallback` values from `~/.openclaw/exec-approvals.json` during normalization so malformed policy enums fall back cleanly to the documented defaults instead of corrupting runtime policy resolution. (#59112) Thanks @openperf.
- Gateway/session kill: enforce HTTP operator scopes on session kill requests and gate authorization before session lookup so unauthenticated callers cannot probe session existence. (#59128) Thanks @jacobtomlinson.
- MS Teams/logging: format non-`Error` failures with the shared unknown-error helper so logs stop collapsing caught SDK or Axios objects into `[object Object]`. (#59321) Thanks @bradgroux.
- Gateway: prune empty `node-pending-work` state entries after explicit acknowledgments and natural expiry so the per-node state map no longer grows indefinitely. (#58179) Thanks @gavyngong.
- Webhooks/secret comparison: replace ad-hoc timing-safe secret comparisons across BlueBubbles, Feishu, Mattermost, Telegram, Twilio, and Zalo webhook handlers with the shared `safeEqualSecret` helper and reject empty auth tokens in BlueBubbles. Thanks @eleqtrizit.
- OpenShell/mirror sync: constrain mirror sync to managed roots only so user-added shell roots are no longer overwritten or removed during config synchronization. (#58515) Thanks @eleqtrizit.
## 2026.4.1-beta.1
- Plugins/runtime: stop ambient core helper and setup paths from loading non-selected bundled plugins, keep channel-setup snapshot scoping safe for custom channel plugins, and honor env-scoped plugin auth paths. (#59136) Thanks @vincentkoc.
- Matrix/multi-account: keep room-level `account` scoping, inherited room overrides, and implicit account selection consistent across top-level default auth, named accounts, and cached-credential env setups. (#58449) thanks @Daanvdplas and @gumadeiras.
- Gateway/pairing: prefer explicit QR bootstrap auth over earlier Tailscale auth classification so iOS `/pair qr` silent bootstrap pairing does not fall through to `pairing required`. (#59232) Thanks @ngutman.
- Config/Discord: coerce safe integer numeric Discord IDs to strings during config validation, keep unsafe or precision-losing numeric snowflakes rejected, and align `openclaw doctor` repair guidance with the same fail-closed behavior. (#45125) Thanks @moliendocode.
- Gateway/sessions: scope bare `sessions.create` aliases like `main` to the requested agent while preserving the canonical `global` and `unknown` sentinel keys. (#58207) thanks @jalehman.
- `/context detail` now compares the tracked prompt estimate with cached context usage and surfaces untracked provider/runtime overhead when present. (#28391) thanks @ImLukeF.
- Gateway/session reset: emit the typed `before_reset` hook for gateway `/new` and `/reset`, preserving reset-hook behavior even when the previous transcript has already been archived. (#53872) thanks @VACInc
- Plugins/commands: pass the active host `sessionKey` into plugin command contexts, and include `sessionId` when it is already available from the active session entry, so bundled and third-party commands can resolve the current conversation reliably. (#59044) Thanks @jalehman.
- Agents/auth: honor `models.providers.*.authHeader` for pi embedded runner model requests by injecting `Authorization: Bearer <apiKey>` when requested. (#54390) Thanks @lndyzwdxhs.
- UI/compaction: keep the compaction indicator in a retry-pending state until the run actually finishes, so the UI does not show `Context compacted` before compaction actually finishes. (#55132) Thanks @mpz4life.
- Cron/tool schemas: keep cron tool schemas strict-model-friendly while still preserving `failureAlert=false`, nullable `agentId`/`sessionKey`, and flattened add/update recovery for the newly exposed cron job fields. (#55043) Thanks @brunolorente.
- BlueBubbles/config: accept `enrichGroupParticipantsFromContacts` in the core strict config schema so gateways no longer fail validation or startup when the BlueBubbles plugin writes that field. (#56889) Thanks @zqchris.
- Agents/failover: classify AbortError and stream-abort messages as timeout so Ollama NDJSON stream aborts stop showing `reason=unknown` in model fallback logs. (#58324) Thanks @yelog
- Exec approvals: route Slack, Discord, and Telegram approvals through the shared channel approval-capability path so native approval auth, delivery, and `/approve` handling stay aligned across channels while preserving Telegram session-key agent filtering. (#58634) thanks @gumadeiras
- Matrix/runtime: resolve the verification/bootstrap runtime from a distinct packaged Matrix entry so global npm installs stop failing on crypto bootstrap with missing-module or recursive runtime alias errors. (#59249) Thanks @gumadeiras.
- Matrix/streaming: preserve ordered block flushes before tool, message, and agent boundaries, add explicit `channels.matrix.blockStreaming` opt-in so Matrix `streaming: "off"` stays final-only by default, and move MiniMax plain-text final handling into the MiniMax provider runtime instead of the shared core heuristic. (#59266) thanks @gumadeiras
- Agents/compaction: resolve compaction wait before final reply/channel flush completion so slow end-of-run delivery drains no longer delay compaction completion. (#59308) thanks @gumadeiras
- Exec approvals: align approval UX, effective-policy reporting, and `allow-always` availability with the host policy so CLI, doctor, and approval surfaces explain the real host-effective decision path. (#59283) Thanks @gumadeiras.
## 2026.4.2
### Changes
- macOS/Voice Wake: add the Voice Wake option to trigger Talk Mode. (#58490) Thanks @SmoothExec.
- Tasks/chat: add `/tasks` as a chat-native background task board for the current session, with recent task details and agent-local fallback counts when no linked tasks are visible. Related #54226. Thanks @vincentkoc.
- Web search/SearXNG: add the bundled SearXNG provider plugin for `web_search` with configurable host support. (#57317) Thanks @cgdusek.
- Feishu/comments: add a dedicated Drive comment-event flow with comment-thread context resolution, in-thread replies, and `feishu_drive` comment actions for document collaboration workflows. (#58497) Thanks @wittam-01.
- WhatsApp/reactions: add `reactionLevel` guidance for agent reactions. Thanks @mcaxtr.
- Telegram/errors: add configurable `errorPolicy` and `errorCooldownMs` controls so Telegram can suppress repeated delivery errors per account, chat, and topic without muting distinct failures. (#51914) Thanks @chinar-amrutkar
- Gateway/webchat: make `chat.history` text truncation configurable with `gateway.webchat.chatHistoryMaxChars` and per-request `maxChars`, while preserving silent-reply filtering and existing default payload limits. (#58900)
- Amazon Bedrock/Guardrails: add Bedrock Guardrails support to the bundled provider. (#58588) Thanks @MikeORed.
- ZAI/models: add `glm-5.1` and `glm-5v-turbo` to the bundled Z.AI provider catalog. (#58793) Thanks @tomsun28
- Agents/default params: add `agents.defaults.params` for global default provider parameters. (#58548) Thanks @lpender.
- Agents/failover: cap prompt-side and assistant-side same-provider auth-profile retries for rate-limit failures before cross-provider model fallback, add the `auth.cooldowns.rateLimitedProfileRotations` knob, and document the new fallback behavior. (#58707) Thanks @Forgely3D
- Agents/compaction: resolve `agents.defaults.compaction.model` consistently for manual `/compact` and other context-engine compaction paths, so engine-owned compaction uses the configured override model across runtime entrypoints. (#56710) Thanks @oliviareid-svg
- Cron/tools allowlist: add `openclaw cron --tools` for per-job tool allowlists. (#58504) Thanks @andyk-ms.
- Channels/session routing: move provider-specific session conversation grammar into plugin-owned session-key surfaces, preserving Telegram topic routing and Feishu scoped inheritance across bootstrap, model override, restart, and tool-policy paths.
### Fixes
- Chat/error replies: stop leaking raw provider/runtime failures into external chat channels, return a friendly retry message instead, and add a specific `/new` hint for Bedrock toolResult/toolUse session mismatches. (#58831) Thanks @ImLukeF.
- Sessions/model switching: keep `/model` changes queued behind busy runs instead of interrupting the active turn, and retarget queued followups so later work picks up the new model as soon as the current turn finishes.
- Web UI/OpenResponses: preserve rewritten stream snapshots in webchat and keep OpenResponses final streamed text aligned when models rewind earlier output. (#58641) Thanks @neeravmakwana
- Discord/inbound media: pass Discord attachment and sticker downloads through the shared idle-timeout and worker-abort path so slow or stuck inbound media fetches stop hanging message processing. (#58593) Thanks @aquaright1
- Telegram/retries: keep non-idempotent sends on the strict safe-send path, retry wrapped pre-connect failures, and preserve `429` / `retry_after` backoff for safe delivery retries. (#51895) Thanks @chinar-amrutkar
- Telegram/exec approvals: route topic-aware exec approval followups through Telegram-owned threading and approval-target parsing, so forum-topic approvals stay in the originating topic instead of falling back to the root chat. (#58783)
- Telegram/local Bot API: preserve media MIME types for absolute-path downloads so local audio files still trigger transcription and other MIME-based handling. (#54603) Thanks @jzakirov
- Channels/WhatsApp: pass inbound message timestamp to model context so the AI can see when WhatsApp messages were sent. (#58590) Thanks @Maninae
- QQBot/voice: lazy-load `silk-wasm` in `audio-convert.ts` so qqbot still starts when the optional voice dependency is missing, while voice encode/decode degrades gracefully instead of crashing at module load time. (#58829) Thanks @WideLee.
- Config/Telegram: migrate removed `channels.telegram.groupMentionsOnly` into `channels.telegram.groups["*"].requireMention` on load so legacy configs no longer crash at startup. (#55336) thanks @jameslcowan.
- Ollama/model picker: show only Ollama models after provider selection in the CLI picker. (#55290) Thanks @Luckymingxuan.
- MiniMax/plugins: auto-enable the bundled MiniMax plugin for API-key auth/config so MiniMax image generation and other plugin-owned capabilities load without manual plugin allowlisting. (#57127) Thanks @tars90percent.
- Plugins/bundled runtimes: restore externalized bundled plugin runtime dependency staging across packed installs, Docker builds, and local runtime staging so bundled plugins keep their declared runtime deps after the 2026.3.31 externalization change. (#58782)
- LINE/runtime: resolve the packaged runtime contract from the built `dist/plugins/runtime` layout so LINE channels start correctly again after global npm installs on `2026.3.31`. (#58799) Thanks @vincentkoc.
- Tasks/status: hide stale completed background tasks from `/status` and `session_status`, prefer live task context, and show recent failures only when no active work remains. (#58661) Thanks @vincentkoc
- Tasks/gateway: keep the task registry maintenance sweep from stalling the gateway event loop under synchronous SQLite pressure, so upgraded gateways stop hanging about a minute after startup. (#58670) Thanks @openperf
- Tasks/gateway: re-check the current task record before maintenance marks runs lost or prunes them, so a task heartbeat or cleanup update that lands during a sweep no longer gets overwritten by stale snapshot state.
- Subagents/tasks: keep subagent completion and cleanup from crashing when task-registry writes fail, so a corrupt or missing task row no longer takes down the gateway during lifecycle finalization. Thanks @vincentkoc.
- Gateway/reload: ignore startup config writes by persisted hash in the config reloader so generated auth tokens and seeded Control UI origins do not trigger a restart loop, while real `gateway.auth.*` edits still require restart. (#58678) Thanks @yelog
- Exec/approvals: honor `exec-approvals.json` security defaults when inline or configured tool policy is unset, and keep Slack and Discord native approval handling aligned with inferred approvers and real channel enablement so remote exec stops falling into false approval timeouts and disabled states. Thanks @scoootscooob and @vincentkoc.
- Exec/approvals: make `allow-always` persist as durable user-approved trust instead of behaving like `allow-once`, reuse exact-command trust on shell-wrapper paths that cannot safely persist an executable allowlist entry, keep static allowlist entries from silently bypassing `ask:"always"`, and require explicit approval when Windows cannot build an allowlist execution plan instead of hard-dead-ending remote exec. Thanks @scoootscooob and @vincentkoc.
- Exec/cron: resolve isolated cron no-route approval dead-ends from the effective host fallback policy when trusted automation is allowed, and make `openclaw doctor` warn when `tools.exec` is broader than `~/.openclaw/exec-approvals.json` so stricter host-policy conflicts are explicit. Thanks @scoootscooob and @vincentkoc.
- Gateway/HTTP: skip failing HTTP request stages so one broken facade no longer forces every HTTP endpoint to return 500. (#58746) Thanks @yelog
- Gateway/nodes: stop pinning live node commands to the approved node-pair record. Node pairing remains a trust/token flow, while per-node `system.run` policy stays in that node's exec approvals config. Fixes #58824.
- WebChat/exec approvals: use native approval UI guidance in agent system prompts instead of telling agents to paste manual `/approve` commands in webchat sessions. Thanks @vincentkoc.
- Channels/QQ Bot: keep `/bot-logs` export gated behind a truly explicit QQBot allowlist, rejecting wildcard and mixed wildcard entries while preserving the real framework command path. Thanks @vincentkoc.
- Channels/plugins: keep bundled channel plugins loadable from legacy `channels.<id>` config even under restrictive plugin allowlists, and make `openclaw doctor` warn only on real plugin blockers instead of misleading setup guidance. (#58873) Thanks @obviyus
- CDP/profiles: prefer `cdpPort` over stale WebSocket URLs so browser automation reconnects cleanly. (#58499) Thanks @Mlightsnow.
- Media/paths: resolve relative `MEDIA` paths against the agent workspace so local attachment references keep working. (#58624) Thanks @aquaright1.
- Memory/session indexing: keep full reindexes from skipping session transcripts when sync is triggered by `session-start` or `watch`, so restart-driven reindexes preserve session memory. (#39732) Thanks @upupc
- Memory/QMD: prefer `--mask` over `--glob` when creating QMD collections so default memory collections keep their intended patterns and stop colliding on restart. (#58643) Thanks @GitZhangChi.
- Sandbox/browser: compare browser runtime inspection against `agents.defaults.sandbox.browser.image` so `openclaw sandbox list --browser` stops reporting healthy browser containers as image mismatches. (#58759) Thanks @sandpile.
- Plugins/install: forward `--dangerously-force-unsafe-install` through archive and npm-spec plugin installs so the documented override reaches the security scanner on those install paths. (#58879) Thanks @ryanlee-gemini.
- Auto-reply/commands: strip inbound metadata before slash command detection so wrapped `/model`, `/new`, and `/status` commands are recognized. (#58725) Thanks @Mlightsnow.
- Agents/Anthropic: preserve thinking blocks and signatures across replay, cache-control patching, and context pruning so compacted Anthropic sessions continue working instead of failing on later turns. (#58916) Thanks @obviyus
- Agents/Anthropic: recover cleanly after a crash leaves the latest assistant turn with incomplete thinking blocks, dropping or retrying the corrupted turn instead of getting stuck on later Anthropic requests. Thanks @explainanalyze. Maintainer refresh: vincentkoc.
- Agents/failover: unify structured and raw provider error classification so provider-specific `400`/`422` payloads no longer get forced into generic format failures before retry, billing, or compaction logic can inspect them. (#58856) Thanks @aaron-he-zhu.
- Auth profiles/store: coerce misplaced SecretRef objects out of plaintext `key` and `token` fields during store load so agents without ACP runtime stop crashing on `.trim()` after upgrade. (#58923) Thanks @openperf.
- ACPX/runtime: repair `queue owner unavailable` session recovery by replacing dead named sessions and resuming the backend session when ACPX exposes a stable session id, so the first ACP prompt no longer inherits a dead handle. (#58669) Thanks @neeravmakwana
- ACPX/runtime: retry dead-session queue-owner repair without `--resume-session` when the reported ACPX session id is stale, so recovery still creates a fresh named session instead of failing session init. Thanks @obviyus.
- Auth/OpenAI Codex: persist plugin-refreshed OAuth credentials to `auth-profiles.json` before returning them, so rotated Codex refresh tokens survive restart and stop falling into `refresh_token_reused` loops. (#53082)
- Agents/Anthropic: honor explicit `cacheRetention` for custom providers using `anthropic-messages`, so Anthropic-compatible proxy providers can reuse prompt caching when they opt in. (#59049) Thanks @wwerst and @vincentkoc.
- Discord/gateway: hand reconnect ownership back to Carbon, keep runtime status aligned with close/reconnect state, and force-stop sockets that open without reaching READY so Discord monitors recover promptly instead of waiting on stale health timeouts. (#59019) Thanks @obviyus
- Control UI/build: stop `pnpm ui:build` from reinstalling the UI with production-only dependencies, so fresh self-healing UI builds keep `vite` available instead of failing before asset generation. (#59267) Thanks @juliabush.
## 2026.3.31
### Breaking
- Nodes/exec: remove the duplicated `nodes.run` shell wrapper from the CLI and agent `nodes` tool so node shell execution always goes through `exec host=node`, keeping node-specific capabilities on `nodes invoke` and the dedicated media/location/notify actions.
- Plugin SDK: deprecate the legacy provider compat subpaths plus the older bundled provider setup and channel-runtime compatibility shims, emit migration warnings, and keep the current documented `openclaw/plugin-sdk/*` entrypoints plus local `api.ts` / `runtime-api.ts` barrels as the forward path ahead of a future major-release removal.
- Skills/install and Plugins/install: built-in dangerous-code `critical` findings and install-time scan failures now fail closed by default, so plugin installs and gateway-backed skill dependency installs that previously succeeded may now require an explicit dangerous override such as `--dangerously-force-unsafe-install` to proceed.
- Gateway/auth: `trusted-proxy` now rejects mixed shared-token configs, and local-direct fallback requires the configured token instead of implicitly authenticating same-host callers. Thanks @zhangning-agent, @jacobtomlinson, and @vincentkoc.
- Gateway/node commands: node commands now stay disabled until node pairing is approved, so device pairing alone is no longer enough to expose declared node commands. (#57777) Thanks @jacobtomlinson.
- Gateway/node events: node-originated runs now stay on a reduced trusted surface, so notification-driven or node-triggered flows that previously relied on broader host/session tool access may need adjustment. (#57691) Thanks @jacobtomlinson.
### Changes
- ACP/plugins: add an explicit default-off ACPX plugin-tools MCP bridge config, document the trust boundary, and harden the built-in bridge packaging/logging path so global installs and stdio MCP sessions work reliably. (#56867) Thanks @joe2643.
- Agents/LLM: add a configurable idle-stream timeout for embedded runner requests so stalled model streams abort cleanly instead of hanging until the broader run timeout fires. (#55072) Thanks @liuy.
- Docs/plugins: update the community wecom and qqbot plugin listing to the docs catalog. (#57641) Thanks @sliverp.
- Agents/MCP: materialize bundle MCP tools with provider-safe names (`serverName__toolName`), support optional `streamable-http` transport selection plus per-server connection timeouts, and preserve real tool results from aborted/error turns unless truncation explicitly drops them. (#49505) Thanks @ziomancer.
- Android/notifications: add notification-forwarding controls with package filtering, quiet hours, rate limiting, and safer picker behavior for forwarded notification events. (#40175) Thanks @nimbleenigma.
- Background tasks: turn tasks into a real shared background-run control plane instead of ACP-only bookkeeping by unifying ACP, subagent, cron, and background CLI execution under one SQLite-backed ledger, routing detached lifecycle updates through the executor seam, adding audit/maintenance/status visibility, tightening auto-cleanup and lost-run recovery, improving task awareness in internal status/tool surfaces, and clarifying the split between heartbeat/main-session automation and detached scheduled runs. Thanks @mbelinky and @vincentkoc.
- Background tasks: add the first linear task flow control surface with `openclaw tasks list|show|cancel`, keep manual multi-task flows separate from one-task auto-sync flows, and surface doctor recovery hints for obviously orphaned or broken flow/task linkage. Thanks @mbelinky and @vincentkoc.
- Channels/QQ Bot: add QQ Bot as a bundled channel plugin with multi-account setup, SecretRef-aware credentials, slash commands, reminders, and media send/receive support. (#52986) Thanks @sliverp.
- Diffs: skip unused viewer-versus-file SSR preload work so `diffs` view-only and file-only runs do less render work while keeping mode outputs aligned. (#57909) thanks @gumadeiras.
- Tasks: add a minimal SQLite-backed task flow registry plus task-to-flow linkage scaffolding, so orchestrated work can start gaining a first-class parent record without changing current task delivery behavior. Thanks @mbelinky and @vincentkoc.
- Tasks: persist blocked state on one-task task flows and let the same flow reopen cleanly on retry, so blocked detached work can carry a parent-level reason and continue without fragmenting into a new job. Thanks @mbelinky and @vincentkoc.
- Tasks: route one-task ACP and subagent updates through a parent task-flow owner context, so detached work can emerge back through the intended parent thread/session instead of speaking only as a raw child task. Thanks @mbelinky and @vincentkoc.
- LINE/outbound media: add LINE image, video, and audio outbound sends on the LINE-specific delivery path, including explicit preview/tracking handling for videos while keeping generic media sends on the existing image-only route. (#45826) Thanks @masatohoshino.
- Matrix/history: add optional room history context for Matrix group triggers via `channels.matrix.historyLimit`, with per-agent watermarks and retry-safe snapshots so failed trigger retries do not drift into newer room messages. (#57022) thanks @chain710.
- Matrix/network: add explicit `channels.matrix.proxy` config for routing Matrix traffic through an HTTP(S) proxy, including account-level overrides and matching probe/runtime behavior. (#56931) thanks @patrick-yingxi-pan.
- Matrix/streaming: add draft streaming so partial Matrix replies update the same message in place instead of sending a new message for each chunk. (#56387) Thanks @jrusz.
- Matrix/threads: add per-DM `threadReplies` overrides and keep thread session isolation aligned with the effective room or DM thread policy from the triggering message onward. (#57995) thanks @teconomix.
- MCP: add remote HTTP/SSE server support for `mcp.servers` URL configs, including auth headers and safer config redaction for MCP credentials. (#50396) Thanks @dhananjai1729.
- Memory/QMD: add per-agent `memorySearch.qmd.extraCollections` so agents can opt into cross-agent session search without flattening every transcript collection into one shared QMD namespace. Thanks @vincentkoc.
- Microsoft Teams/member info: add a Graph-backed member info action so Teams automations and tools can resolve channel member details directly from Microsoft Graph. (#57528) Thanks @sudie-codes.
- Nostr/inbound DMs: verify inbound event signatures before pairing or sender-authorization side effects, so forged DM events no longer create pairing requests or trigger reply attempts. Thanks @smaeljaish771 and @vincentkoc.
- OpenAI/Responses: forward configured `text.verbosity` across Responses HTTP and WebSocket transports, surface it in `/status`, and keep per-agent verbosity precedence aligned with runtime behavior. (#47106) Thanks @merc1305 and @vincentkoc.
- Pi/Codex: add native Codex web search support for embedded Pi runs, including config/docs/wizard coverage and managed-tool suppression when native Codex search is active. (#46579) Thanks @Evizero.
- Slack/exec approvals: add native Slack approval routing and approver authorization so exec approval prompts can stay in Slack instead of falling back to the Web UI or terminal. Thanks @vincentkoc.
- TTS: Add structured provider diagnostics and fallback attempt analytics. (#57954) Thanks @joshavant.
- WhatsApp/reactions: agents can now react with emoji on incoming WhatsApp messages, enabling more natural conversational interactions like acknowledging a photo with ❤️ instead of typing a reply. Thanks @mcaxtr.
- Agents/BTW: force `/btw` side questions to disable provider reasoning so Anthropic adaptive-thinking sessions stop failing with `No BTW response generated`. Fixes #55376. Thanks @Catteres and @vincentkoc.
- CLI/onboarding: reset the remote gateway URL prompt to the safe loopback default after declining a discovered endpoint, so onboarding does not keep a previously rejected remote URL. (#57828)
- Agents/exec defaults: honor per-agent `tools.exec` defaults when no inline directive or session override is present, so configured exec host, security, ask, and node settings actually apply. (#57689)
- Sandbox/networking: sanitize SSH subprocess env vars through the shared sandbox policy and route marketplace archive downloads plus Ollama discovery, auth, and pull requests through the guarded fetch path so sandboxed execution and remote fetches follow the repo's trust boundaries. (#57848, #57850)
### Fixes
- Slack: stop retry-driven duplicate replies when draft-finalization edits fail ambiguously, and log configured allowlisted users/channels by readable name instead of raw IDs.
- Agents/OpenAI Responses: normalize raw bundled MCP tool schemas on the WebSocket/Responses path so bare-object, object-ish, and top-level union MCP tools no longer get rejected by OpenAI during tool registration. (#58299) Thanks @yelog.
- ACP/security: replace ACP's dangerous-tool name override with semantic approval classes, so only narrow readonly reads/searches can auto-approve while indirect exec-capable and control-plane tools always require explicit prompt approval. Thanks @vincentkoc.
- ACP/sessions_spawn: register ACP child runs for completion tracking and lifecycle cleanup, and make registration-failure cleanup explicitly best-effort so callers do not assume an already-started ACP turn was fully aborted. (#40885) Thanks @xaeon2026 and @vincentkoc.
- ACP/tasks: mark cleanly exited ACP runs as blocked when they end on deterministic write or authorization blockers, and wake the parent session with a follow-up instead of falsely reporting success.
- ACPX/runtime: derive the bundled ACPX expected version from the extension package metadata instead of hardcoding a separate literal, so plugin-local ACPX installs stop drifting out of health-check parity after version bumps. (#49089) Thanks @jiejiesks and @vincentkoc.
- Agents/Anthropic failover: treat Anthropic `api_error` payloads with `An unexpected error occurred while processing the response` as transient so retry/fallback can engage instead of surfacing a terminal failure. (#57441) Thanks @zijiess and @vincentkoc.
- Agents/compaction: keep late compaction-retry completions from double-resolving finished compaction futures, so interrupted or timed-out compactions stop surfacing spurious second-completion races. (#57796) Thanks @joshavant.
- Agents/disabled providers: make disabled providers disappear from default model selection and embedded provider fallback, while letting explicitly pinned disabled providers fail with a clear config error instead of silently taking traffic. (#57735) Thanks @rileybrown-dev and @vincentkoc.
- Agents/OAuth output: force exec-host OAuth output readers through the gateway fs policy so embedded gateway runs stop crashing when provider auth writes land outside the current sandbox workspace. (#58249) Thanks @joshavant.
- Agents/system prompt: fix `agent.name` interpolation in the embedded runtime system prompt and make provider/model fallback text reflect the effective runtime selection after start. (#57625) Thanks @StllrSvr and @vincentkoc.
- Android/device info: read the app's version metadata from the package manager instead of hidden APIs so Android 15+ onboarding and device info no longer fail to compile or report placeholder values. (#58126) Thanks @L3ER0Y.
- Android/pairing: stop appending duplicate push receiver entries to `gateway-service.conf` on repeated QR pairing and keep push registration bounded to the current successful pairing, so Android push delivery stays healthy across re-pair and token rotation. (#58256) Thanks @surrealroad.
- App install smoke: pin the latest-release lookup to `latest`, cache the first stable install version across the rerun, and relax prerelease package assertions so the Parallels smoke lane can validate stable-to-main upgrades even when `beta` moves ahead or the guest starts from an older stable. (#58177) Thanks @vincentkoc.
- Auth/profiles: keep the last successful config load in memory for the running process and refresh that snapshot on successful writes/reloads, so hot paths stop reparsing `openclaw.json` between watcher-driven swaps.
- Config/SecretRef + Control UI: harden SecretRef redaction round-trip restore, block unsafe raw fallback (force Form mode when raw is unavailable), and preflight submitted-config SecretRefs before config write RPC persistence. (#58044) Thanks @joshavant.
- Config/update: stop `openclaw doctor` write-backs from persisting plugin-injected channel defaults, so `openclaw update` no longer seeds config keys that later break service refresh validation. (#56834) Thanks @openperf.
- Control UI/agents: auto-load agent workspace files on initial Files panel open, and populate overview model/workspace/fallbacks from effective runtime agent metadata so defaulted models no longer show as `Not set`. (#56637) Thanks @dxsx84.
- Control UI/slash commands: make `/steer` and `/redirect` work from the chat command palette with visible pending state for active-run `/steer`, correct redirected-run tracking, and a single canonical `/steer` entry in the command menu. (#54625) Thanks @fuller-stack-dev.
- Cron/announce: preserve all deliverable text payloads for announce mode instead of collapsing to the last chunk, so multi-line cron reports deliver in full to Telegram forum topics.
- Cron/isolated sessions: carry the full live-session provider, model, and auth-profile selection across retry restarts so cron jobs with model overrides no longer fail or loop on mid-run model-switch requests. (#57972) Thanks @issaba1.
- Diffs/config: preserve schema-shaped plugin config parsing from `diffsPluginConfigSchema.safeParse()`, so direct callers keep `defaults` and `security` sections instead of receiving flattened tool defaults. (#57904) Thanks @gumadeiras.
- Diffs: fall back to plain text when `lang` hints are invalid during diff render and viewer hydration, so bad or stale language values no longer break the diff viewer. (#57902) Thanks @gumadeiras.
- Discord/voice: enforce the same guild channel and member allowlist checks on spoken voice ingress before transcription, so joined voice channels no longer accept speech from users outside the configured Discord access policy. Thanks @cyjhhh and @vincentkoc.
- Docker/setup: force BuildKit for local image builds (including sandbox image builds) so `./docker-setup.sh` no longer fails on `RUN --mount=...` when hosts default to Docker's legacy builder. (#56681) Thanks @zhanghui-china.
- Docs/anchors: fix broken English docs links and make Mint anchor audits run against the English-source docs tree. (#57039) thanks @velvet-shark.
- Doctor/plugins: skip false Matrix legacy-helper warnings when no migration plans exist, and keep bundled `enabledByDefault` plugins in the gateway startup set. (#57931) Thanks @dinakars777.
- Exec approvals/macOS: unwrap `arch` and `xcrun` before deriving shell payloads and allow-always patterns, so wrapper approvals stay bound to the carried command instead of the outer carrier. Thanks @tdjackey and @vincentkoc.
- Exec approvals: unwrap `caffeinate` and `sandbox-exec` before persisting allow-always trust so later shell payload changes still require a fresh approval. Thanks @tdjackey and @vincentkoc.
- Exec/approvals: infer Discord and Telegram exec approvers from existing owner config when `execApprovals.approvers` is unset, extend the default approval window to 30 minutes, and clarify approval-unavailable guidance so approvals do not appear to silently disappear.
- Pi/TUI: flush message-boundary replies at `message_end` so turns stop looking stuck until the next nudge when the final reply was already ready. Thanks @vincentkoc.
- Status/tasks: fall back to same-agent task counts in `/status` when the current session has no linked tasks, keeping the default view useful without exposing other sessions' task details. Thanks @vincentkoc.
- Status/auto-reply: stop status-only turns from replying twice when inline `/status` handling already produced the reply, so Discord and other chat surfaces no longer emit duplicate status cards. Thanks @vincentkoc.
- Exec/approvals: keep `awk` and `sed` family binaries out of the low-risk `safeBins` fast path, and stop doctor profile scaffolding from treating them like ordinary custom filters. Thanks @vincentkoc.
- Exec/env: block proxy, TLS, and Docker endpoint env overrides in host execution so request-scoped commands cannot silently reroute outbound traffic or trust attacker-supplied certificate settings. Thanks @AntAISecurityLab.
- Exec/env: block Python package index override variables from request-scoped host exec environment sanitization so package fetches cannot be redirected through a caller-supplied index. Thanks @nexrin and @vincentkoc.
- Exec/node: stop gateway-side workdir fallback from rewriting explicit `host=node` cwd values to the gateway filesystem, so remote node exec approval and runs keep using the intended node-local directory. (#50961) Thanks @openperf.
- Exec/runtime: default implicit exec to `host=auto`, resolve that target to sandbox only when a sandbox runtime exists, keep explicit `host=sandbox` fail-closed without sandbox, and show `/exec` effective host state in runtime status/docs.
- Exec: fail closed when the implicit sandbox host has no sandbox runtime, and stop denied async approval followups from reusing prior command output from the same session. (#56800) Thanks @scoootscooob.
- Feishu/groups: keep quoted replies and topic bootstrap context aligned with group sender allowlists so only allowlisted thread messages seed agent context. Thanks @AntAISecurityLab and @vincentkoc.
- Gateway/attachments: offload large inbound images without leaking `media://` markers into text-only runs, preserve mixed attachment order for model input/transcripts, and fail closed when model image capability cannot be resolved. (#55513) Thanks @Syysean.
- Gateway/auth: keep shared-auth rate limiting active during WebSocket handshake attempts even when callers also send device-token candidates, so bogus device-token fields no longer suppress shared-secret brute-force tracking. Thanks @kexinoh and @vincentkoc.
- Gateway/auth: reject mismatched browser `Origin` headers on trusted-proxy HTTP operator requests while keeping origin-less headless proxy clients working. Thanks @AntAISecurityLab and @vincentkoc.
- Gateway/device tokens: disconnect active device sessions after token rotation so newly rotated credentials revoke existing live connections immediately instead of waiting for those sockets to close naturally. Thanks @zsxsoft and @vincentkoc.
- Gateway/health: carry webhook-vs-polling account mode from channel descriptors into runtime snapshots so passive channels like LINE and BlueBubbles skip false stale-socket health failures. (#47488) Thanks @karesansui-u.
- Gateway/pairing: restore QR bootstrap onboarding handoff so fresh `/pair qr` iPhone setup can auto-approve the initial node pairing, receive a reusable node device token, and stop retrying with spent bootstrap auth. (#58382) Thanks @ngutman.
- Gateway/OpenAI compatibility: accept flat Responses API function tool definitions on `/v1/responses` and preserve `strict` when normalizing hosted tools into the embedded runner, so spec-compliant clients like Codex no longer fail validation or silently lose strict tool enforcement. Thanks @malaiwah and @vincentkoc.
- Gateway/OpenAI HTTP: restore default operator scopes for bearer-authenticated requests that omit `x-openclaw-scopes`, so headless `/v1/chat/completions` and session-history callers work again after the recent method-scope hardening. (#57596) Thanks @openperf.
- Gateway/plugins: scope plugin-auth HTTP route runtime clients to read-only access and keep gateway-authenticated plugin routes on write scope, so plugin-owned webhook handlers do not inherit write-capable runtime access by default. Thanks @davidluzsilva and @vincentkoc.
- Gateway/SecretRef: resolve restart token drift checks with merged service/runtime env sources and hard-fail unsupported mutable SecretRef plus OAuth-profile combinations so restart warnings and policy enforcement match runtime behavior. (#58141) Thanks @joshavant.
- Gateway/tools HTTP: tighten HTTP tool-invoke authorization so owner-only tools stay off HTTP invoke paths. (#57773) Thanks @jacobtomlinson.
- Harden async approval followup delivery in webchat-only sessions (#57359) Thanks @joshavant.
- Heartbeat/auth: prevent exec-event heartbeat runs from inheriting owner-only tool access from the session delivery target, so node exec output stays on the non-owner tool surface even when the target session belongs to the owner. Thanks @AntAISecurityLab and @vincentkoc.
- Hooks/config: accept runtime channel plugin ids in `hooks.mappings[].channel` (for example `feishu`) instead of rejecting non-core channels during config validation. (#56226) Thanks @AiKrai001.
- Hooks/session routing: rebind hook-triggered `agent:` session keys to the actual target agent before isolated dispatch so dedicated hook agents keep their own session-scoped tool and plugin identity. Thanks @kexinoh and @vincentkoc.
- Host exec/env: block additional request-scoped env overrides that can redirect Docker endpoints, trust roots, compiler include paths, package resolution, or Python environment roots during approved host runs. Thanks @tdjackey and @vincentkoc.
- Image generation/build: write stable runtime alias files into `dist/` and route provider-auth runtime lookups through those aliases so image-generation providers keep resolving auth/runtime modules after rebuilds instead of crashing on missing hashed chunk files.
- iOS/Live Activities: mark the `ActivityKit` import in `LiveActivityManager.swift` as `@preconcurrency` so Xcode 26.4 / Swift 6 builds stop failing on strict concurrency checks. (#57180) Thanks @ngutman.
- LINE/ACP: add current-conversation binding and inbound binding-routing parity so `/acp spawn ... --thread here`, configured ACP bindings, and active conversation-bound ACP sessions work on LINE like the other conversation channels.
- LINE/markdown: preserve underscores inside Latin, Cyrillic, and CJK words when stripping markdown, while still removing standalone `_italic_` markers on the shared text-runtime path used by LINE and TTS. (#47465) Thanks @jackjin1997.
- Agents/failover: make overloaded same-provider retry count and retry delay configurable via `auth.cooldowns`, default to one retry with no delay, and document the model-fallback behavior.
- Ollama/model picker: include configured Ollama models in the opted-in non-PI-native model catalog path so Ollama onboarding shows available models directly after provider selection. (#55290) Thanks @Luckymingxuan.
## 2026.3.31-beta.1
### Breaking
@@ -22,7 +274,7 @@ Docs: https://docs.openclaw.ai
- Agents/MCP: materialize bundle MCP tools with provider-safe names (`serverName__toolName`), support optional `streamable-http` transport selection plus per-server connection timeouts, and preserve real tool results from aborted/error turns unless truncation explicitly drops them. (#49505) Thanks @ziomancer.
- Android/notifications: add notification-forwarding controls with package filtering, quiet hours, rate limiting, and safer picker behavior for forwarded notification events. (#40175) Thanks @nimbleenigma.
- Background tasks: turn tasks into a real shared background-run control plane instead of ACP-only bookkeeping by unifying ACP, subagent, cron, and background CLI execution under one SQLite-backed ledger, routing detached lifecycle updates through the executor seam, adding audit/maintenance/status visibility, tightening auto-cleanup and lost-run recovery, improving task awareness in internal status/tool surfaces, and clarifying the split between heartbeat/main-session automation and detached scheduled runs. Thanks @mbelinky and @vincentkoc.
- Background tasks: add the first linear task flow control surface with `openclaw flows list|show|cancel`, keep manual multi-task flows separate from one-task auto-sync flows, and surface doctor recovery hints for obviously orphaned or broken flow/task linkage. Thanks @mbelinky and @vincentkoc.
- Background tasks: add the first linear task flow control surface with `openclaw tasks list|show|cancel`, keep manual multi-task flows separate from one-task auto-sync flows, and surface doctor recovery hints for obviously orphaned or broken flow/task linkage. Thanks @mbelinky and @vincentkoc.
- Channels/QQ Bot: add QQ Bot as a bundled channel plugin with multi-account setup, SecretRef-aware credentials, slash commands, reminders, and media send/receive support. (#52986) Thanks @sliverp.
- Diffs: skip unused viewer-versus-file SSR preload work so `diffs` view-only and file-only runs do less render work while keeping mode outputs aligned. (#57909) thanks @gumadeiras.
- Tasks: add a minimal SQLite-backed task flow registry plus task-to-flow linkage scaffolding, so orchestrated work can start gaining a first-class parent record without changing current task delivery behavior. Thanks @mbelinky and @vincentkoc.
@@ -182,6 +434,8 @@ Docs: https://docs.openclaw.ai
- TTS: Restore 3.28 schema compatibility and fallback observability. (#57953) Thanks @joshavant.
- TUI/chat: keep optimistic outbound user messages visible during active runs by deferring local-run binding until the first gateway chat event reveals the real run id, preventing premature history reloads from wiping pending local sends. (#54722) Thanks @seanturner001.
- TUI/model picker: keep searchable `/model` and `/models` input mode from hijacking `j`/`k` as navigation keys, and harden width bounds under `m`-filtered model lists so search no longer crashes on long rows. (#30156) Thanks @briannicholls.
- Discord/exec approvals: stop mixing native interactive approvals with extra plain `/approve` narration, so Discord approval prompts stay button-driven instead of showing both manual and interactive flows. Thanks @vincentkoc.
- Telegram/exec approvals: normalize 1:1 approval routing and suppress duplicate approval prompts, so Telegram direct chats show a single working interactive approval instead of multiple conflicting approval messages. Thanks @vincentkoc.
- Voice Call/media stream: cap inbound WebSocket frame size before `start` validation so oversized pre-start frames are dropped before JSON parsing. Thanks @Kazamayc and @vincentkoc.
- Voice call/Plivo: pin stored callback bases to the configured public webhook URL so later call-control redirects stay on the intended origin even if webhook transport metadata differs. Thanks @zsxsoft and @vincentkoc.
- Web UI/markdown: stop bare auto-links from swallowing adjacent CJK text while preserving valid mixed-script path and query characters in rendered links. (#48410) Thanks @jnuyao.
@@ -264,6 +518,9 @@ Docs: https://docs.openclaw.ai
- Telegram/splitting: replace proportional text estimate with verified HTML-length search so long messages split at word boundaries instead of mid-word; gracefully degrade when tag overhead exceeds the limit. (#56595)
- Telegram/delivery: skip whitespace-only and hook-blanked text replies in bot delivery to prevent GrammyError 400 empty-text crashes. (#56620)
- Telegram/send: validate `replyToMessageId` at all four API sinks with a shared normalizer that rejects non-numeric, NaN, and mixed-content strings. (#56587)
- Telegram/cron topics: route announce target parsing through the Telegram extension seam and carry explicit `delivery.threadId` through cron delivery resolution, so legacy `group:` routes and topic-targeted cron sends keep their forum topic destination. (#58489) Thanks @cwmine.
- Approvals/UI: keep the newest pending approval at the front of the Control UI queue so approving one request does not accidentally target an older expired id. Thanks @vincentkoc.
- Plugin approvals: accept unique short approval-id prefixes on `plugin.approval.resolve`, matching exec approvals and restoring `/approve` fallback flows on chat approval surfaces. Thanks @vincentkoc.
- Mistral: normalize OpenAI-compatible request flags so official Mistral API runs no longer fail with remaining `422 status code (no body)` chat errors.
- Control UI/config: keep sensitive raw config hidden by default, replace the blank blocked editor with an explicit reveal-to-edit state, and restore raw JSON editing without auto-exposing secrets. Fixes #55322.
- CLI/zsh: defer `compdef` registration until `compinit` is available so zsh completion loads cleanly with plugin managers and manual setups. (#56555)
@@ -411,6 +668,7 @@ Docs: https://docs.openclaw.ai
- Security/path resolution: prefer non-user-writable absolute helper binaries for OpenClaw CLI, ffmpeg, and OpenSSL resolution so PATH hijacks cannot replace trusted helpers with attacker-controlled executables.
- Security/gateway command scopes: require `operator.admin` before Telegram target writeback and Talk Voice `/voice set` config writes persist through gateway message flows.
- Security/OpenShell mirror: exclude workspace `hooks/` from mirror sync so untrusted sandbox files cannot become trusted host hooks on gateway startup.
- Exec approvals/channels: unify Discord and Telegram exec approval runtime handling, move approval buttons onto the shared interactive reply model, and fix Telegram approval buttons and typed `/approve` commands so configured approvers can resolve requests reliably again. (#57516) Thanks @scoootscooob.
## 2026.3.24-beta.2
@@ -820,6 +1078,7 @@ Docs: https://docs.openclaw.ai
- Exec: harden host env override handling across gateway and node (#51207) Thanks @gladiator9797 and @joshavant.
- Voice Call: enforce spoken-output contract and fix stream TTS silence regression (#51500) Thanks @joshavant.
- xAI/models: rename the bundled Grok 4.20 catalog entries to the GA IDs and normalize saved deprecated beta IDs at runtime so existing configs and sessions keep resolving. (#50772) thanks @Jaaneek
- WhatsApp/outbound media: fix HTML, XML, and CSS files being silently dropped on outbound send by adding missing MIME entries and falling back to `application/octet-stream` for unknown media types. (#51562) Thanks @bobbyt74
- Agents/bootstrap warnings: move bootstrap truncation warnings out of the system prompt and into the per-turn prompt body so prompt-cache reuse stays stable when truncation warnings appear or disappear. (#48753) Thanks @scoootscooob and @obviyus.
- Telegram/DM topic session keys: route named-account DM topics through the same per-account base session key across inbound messages, native commands, and session-state lookups so `/status` and thread recovery stop creating phantom `agent:main:main:thread:...` sessions. (#48204) Thanks @vincentkoc.
- ACP/configured bindings: reinitialize configured ACP sessions that are stuck in `error` state instead of reusing the failed runtime.

View File

@@ -159,7 +159,10 @@ We are currently prioritizing:
- **Skills**: For skill contributions, head to [ClawHub](https://clawhub.ai/) — the community hub for OpenClaw skills.
- **Performance**: Optimizing token usage and compaction logic.
Check the [GitHub Issues](https://github.com/openclaw/openclaw/issues) for "good first issue" labels!
Check the [GitHub Issues](https://github.com/openclaw/openclaw/issues) for
["good first issue"](https://github.com/openclaw/openclaw/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
labels. If none are open, pick a small docs or bug issue and leave a quick comment saying
you'd like to work on it.
## Maintainers

View File

@@ -64,7 +64,7 @@ WORKDIR /app
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
COPY ui/package.json ./ui/package.json
COPY patches ./patches
COPY scripts/postinstall-bundled-plugins.mjs ./scripts/postinstall-bundled-plugins.mjs
COPY scripts/postinstall-bundled-plugins.mjs scripts/npm-runner.mjs ./scripts/
COPY --from=ext-deps /out/ ./${OPENCLAW_BUNDLED_PLUGIN_DIR}/

View File

@@ -32,9 +32,50 @@ New install? Start here: [Getting started](https://docs.openclaw.ai/start/gettin
## Sponsors
| OpenAI | Vercel | Blacksmith | Convex |
| ----------------------------------------------------------------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| [![OpenAI](docs/assets/sponsors/openai.svg)](https://openai.com/) | [![Vercel](docs/assets/sponsors/vercel.svg)](https://vercel.com/) | [![Blacksmith](docs/assets/sponsors/blacksmith.svg)](https://blacksmith.sh/) | [![Convex](docs/assets/sponsors/convex.svg)](https://www.convex.dev/) |
<table>
<tr>
<td align="center" width="20%">
<a href="https://openai.com/">
<picture>
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/openclaw/openclaw/main/docs/assets/sponsors/openai-light.svg">
<img src="https://raw.githubusercontent.com/openclaw/openclaw/main/docs/assets/sponsors/openai.svg" alt="OpenAI" height="28">
</picture>
</a>
</td>
<td align="center" width="20%">
<a href="https://www.nvidia.com/">
<picture>
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/openclaw/openclaw/main/docs/assets/sponsors/nvidia.svg">
<img src="https://raw.githubusercontent.com/openclaw/openclaw/main/docs/assets/sponsors/nvidia-dark.svg" alt="NVIDIA" height="28">
</picture>
</a>
</td>
<td align="center" width="20%">
<a href="https://vercel.com/">
<picture>
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/openclaw/openclaw/main/docs/assets/sponsors/vercel-light.svg">
<img src="https://raw.githubusercontent.com/openclaw/openclaw/main/docs/assets/sponsors/vercel.svg" alt="Vercel" height="24">
</picture>
</a>
</td>
<td align="center" width="20%">
<a href="https://blacksmith.sh/">
<picture>
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/openclaw/openclaw/main/docs/assets/sponsors/blacksmith-light.svg">
<img src="https://raw.githubusercontent.com/openclaw/openclaw/main/docs/assets/sponsors/blacksmith.svg" alt="Blacksmith" height="28">
</picture>
</a>
</td>
<td align="center" width="20%">
<a href="https://www.convex.dev/">
<picture>
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/openclaw/openclaw/main/docs/assets/sponsors/convex-light.svg">
<img src="https://raw.githubusercontent.com/openclaw/openclaw/main/docs/assets/sponsors/convex.svg" alt="Convex" height="24">
</picture>
</a>
</td>
</tr>
</table>
**Subscriptions (OAuth):**

View File

@@ -2,6 +2,193 @@
<rss xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0">
<channel>
<title>OpenClaw</title>
<item>
<title>2026.4.1</title>
<pubDate>Wed, 01 Apr 2026 17:14:12 +0000</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>2026040190</sparkle:version>
<sparkle:shortVersionString>2026.4.1</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.4.1</h2>
<h3>Changes</h3>
<ul>
<li>Tasks/chat: add <code>/tasks</code> as a chat-native background task board for the current session, with recent task details and agent-local fallback counts when no linked tasks are visible. Related #54226. Thanks @vincentkoc.</li>
<li>Web search/SearXNG: add the bundled SearXNG provider plugin for <code>web_search</code> with configurable host support. (#57317) Thanks @cgdusek.</li>
<li>Amazon Bedrock/Guardrails: add Bedrock Guardrails support to the bundled provider. (#58588) Thanks @MikeORed.</li>
<li>macOS/Voice Wake: add the Voice Wake option to trigger Talk Mode. (#58490) Thanks @SmoothExec.</li>
<li>Feishu/comments: add a dedicated Drive comment-event flow with comment-thread context resolution, in-thread replies, and <code>feishu_drive</code> comment actions for document collaboration workflows. (#58497) Thanks @wittam-01.</li>
<li>Gateway/webchat: make <code>chat.history</code> text truncation configurable with <code>gateway.webchat.chatHistoryMaxChars</code> and per-request <code>maxChars</code>, while preserving silent-reply filtering and existing default payload limits. (#58900)</li>
<li>Agents/default params: add <code>agents.defaults.params</code> for global default provider parameters. (#58548) Thanks @lpender.</li>
<li>Agents/failover: cap prompt-side and assistant-side same-provider auth-profile retries for rate-limit failures before cross-provider model fallback, add the <code>auth.cooldowns.rateLimitedProfileRotations</code> knob, and document the new fallback behavior. (#58707) Thanks @Forgely3D</li>
<li>Cron/tools allowlist: add <code>openclaw cron --tools</code> for per-job tool allowlists. (#58504) Thanks @andyk-ms.</li>
<li>Channels/session routing: move provider-specific session conversation grammar into plugin-owned session-key surfaces, preserving Telegram topic routing and Feishu scoped inheritance across bootstrap, model override, restart, and tool-policy paths.</li>
<li>WhatsApp/reactions: add <code>reactionLevel</code> guidance for agent reactions. Thanks @mcaxtr.</li>
<li>Telegram/errors: add configurable <code>errorPolicy</code> and <code>errorCooldownMs</code> controls so Telegram can suppress repeated delivery errors per account, chat, and topic without muting distinct failures. (#51914) Thanks @chinar-amrutkar</li>
<li>ZAI/models: add <code>glm-5.1</code> and <code>glm-5v-turbo</code> to the bundled Z.AI provider catalog. (#58793) Thanks @tomsun28</li>
<li>Agents/compaction: resolve <code>agents.defaults.compaction.model</code> consistently for manual <code>/compact</code> and other context-engine compaction paths, so engine-owned compaction uses the configured override model across runtime entrypoints. (#56710) Thanks @oliviareid-svg</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Chat/error replies: stop leaking raw provider/runtime failures into external chat channels, return a friendly retry message instead, and add a specific <code>/new</code> hint for Bedrock toolResult/toolUse session mismatches. (#58831) Thanks @ImLukeF.</li>
<li>Gateway/reload: ignore startup config writes by persisted hash in the config reloader so generated auth tokens and seeded Control UI origins do not trigger a restart loop, while real <code>gateway.auth.*</code> edits still require restart. (#58678) Thanks @yelog</li>
<li>Tasks/gateway: keep the task registry maintenance sweep from stalling the gateway event loop under synchronous SQLite pressure, so upgraded gateways stop hanging about a minute after startup. (#58670) Thanks @openperf</li>
<li>Tasks/status: hide stale completed background tasks from <code>/status</code> and <code>session_status</code>, prefer live task context, and show recent failures only when no active work remains. (#58661) Thanks @vincentkoc</li>
<li>Tasks/gateway: re-check the current task record before maintenance marks runs lost or prunes them, so a task heartbeat or cleanup update that lands during a sweep no longer gets overwritten by stale snapshot state.</li>
<li>Exec/approvals: honor <code>exec-approvals.json</code> security defaults when inline or configured tool policy is unset, and keep Slack and Discord native approval handling aligned with inferred approvers and real channel enablement so remote exec stops falling into false approval timeouts and disabled states. Thanks @scoootscooob and @vincentkoc.</li>
<li>Exec/approvals: make <code>allow-always</code> persist as durable user-approved trust instead of behaving like <code>allow-once</code>, reuse exact-command trust on shell-wrapper paths that cannot safely persist an executable allowlist entry, keep static allowlist entries from silently bypassing <code>ask:"always"</code>, and require explicit approval when Windows cannot build an allowlist execution plan instead of hard-dead-ending remote exec. Thanks @scoootscooob and @vincentkoc.</li>
<li>Exec/cron: resolve isolated cron no-route approval dead-ends from the effective host fallback policy when trusted automation is allowed, and make <code>openclaw doctor</code> warn when <code>tools.exec</code> is broader than <code>~/.openclaw/exec-approvals.json</code> so stricter host-policy conflicts are explicit. Thanks @scoootscooob and @vincentkoc.</li>
<li>Sessions/model switching: keep <code>/model</code> changes queued behind busy runs instead of interrupting the active turn, and retarget queued followups so later work picks up the new model as soon as the current turn finishes.</li>
<li>Gateway/HTTP: skip failing HTTP request stages so one broken facade no longer forces every HTTP endpoint to return 500. (#58746) Thanks @yelog</li>
<li>Gateway/nodes: stop pinning live node commands to the approved node-pair record. Node pairing remains a trust/token flow, while per-node <code>system.run</code> policy stays in that node's exec approvals config. Fixes #58824.</li>
<li>WebChat/exec approvals: use native approval UI guidance in agent system prompts instead of telling agents to paste manual <code>/approve</code> commands in webchat sessions. Thanks @vincentkoc.</li>
<li>Web UI/OpenResponses: preserve rewritten stream snapshots in webchat and keep OpenResponses final streamed text aligned when models rewind earlier output. (#58641) Thanks @neeravmakwana</li>
<li>Discord/inbound media: pass Discord attachment and sticker downloads through the shared idle-timeout and worker-abort path so slow or stuck inbound media fetches stop hanging message processing. (#58593) Thanks @aquaright1</li>
<li>Telegram/retries: keep non-idempotent sends on the strict safe-send path, retry wrapped pre-connect failures, and preserve <code>429</code> / <code>retry_after</code> backoff for safe delivery retries. (#51895) Thanks @chinar-amrutkar</li>
<li>Telegram/exec approvals: route topic-aware exec approval followups through Telegram-owned threading and approval-target parsing, so forum-topic approvals stay in the originating topic instead of falling back to the root chat. (#58783)</li>
<li>Telegram/local Bot API: preserve media MIME types for absolute-path downloads so local audio files still trigger transcription and other MIME-based handling. (#54603) Thanks @jzakirov</li>
<li>Channels/WhatsApp: pass inbound message timestamp to model context so the AI can see when WhatsApp messages were sent. (#58590) Thanks @Maninae</li>
<li>Channels/QQ Bot: keep <code>/bot-logs</code> export gated behind a truly explicit QQBot allowlist, rejecting wildcard and mixed wildcard entries while preserving the real framework command path. Thanks @vincentkoc.</li>
<li>Channels/plugins: keep bundled channel plugins loadable from legacy <code>channels.<id></code> config even under restrictive plugin allowlists, and make <code>openclaw doctor</code> warn only on real plugin blockers instead of misleading setup guidance. (#58873) Thanks @obviyus</li>
<li>Plugins/bundled runtimes: restore externalized bundled plugin runtime dependency staging across packed installs, Docker builds, and local runtime staging so bundled plugins keep their declared runtime deps after the 2026.3.31 externalization change. (#58782)</li>
<li>LINE/runtime: resolve the packaged runtime contract from the built <code>dist/plugins/runtime</code> layout so LINE channels start correctly again after global npm installs on <code>2026.3.31</code>. (#58799) Thanks @vincentkoc.</li>
<li>MiniMax/plugins: auto-enable the bundled MiniMax plugin for API-key auth/config so MiniMax image generation and other plugin-owned capabilities load without manual plugin allowlisting. (#57127) Thanks @tars90percent.</li>
<li>Ollama/model picker: show only Ollama models after provider selection in the CLI picker. (#55290) Thanks @Luckymingxuan.</li>
<li>CDP/profiles: prefer <code>cdpPort</code> over stale WebSocket URLs so browser automation reconnects cleanly. (#58499) Thanks @Mlightsnow.</li>
<li>Media/paths: resolve relative <code>MEDIA</code> paths against the agent workspace so local attachment references keep working. (#58624) Thanks @aquaright1.</li>
<li>Memory/session indexing: keep full reindexes from skipping session transcripts when sync is triggered by <code>session-start</code> or <code>watch</code>, so restart-driven reindexes preserve session memory. (#39732) Thanks @upupc</li>
<li>Memory/QMD: prefer <code>--mask</code> over <code>--glob</code> when creating QMD collections so default memory collections keep their intended patterns and stop colliding on restart. (#58643) Thanks @GitZhangChi.</li>
<li>Subagents/tasks: keep subagent completion and cleanup from crashing when task-registry writes fail, so a corrupt or missing task row no longer takes down the gateway during lifecycle finalization. Thanks @vincentkoc.</li>
<li>Sandbox/browser: compare browser runtime inspection against <code>agents.defaults.sandbox.browser.image</code> so <code>openclaw sandbox list --browser</code> stops reporting healthy browser containers as image mismatches. (#58759) Thanks @sandpile.</li>
<li>Plugins/install: forward <code>--dangerously-force-unsafe-install</code> through archive and npm-spec plugin installs so the documented override reaches the security scanner on those install paths. (#58879) Thanks @ryanlee-gemini.</li>
<li>Auto-reply/commands: strip inbound metadata before slash command detection so wrapped <code>/model</code>, <code>/new</code>, and <code>/status</code> commands are recognized. (#58725) Thanks @Mlightsnow.</li>
<li>Agents/Anthropic: preserve thinking blocks and signatures across replay, cache-control patching, and context pruning so compacted Anthropic sessions continue working instead of failing on later turns. (#58916) Thanks @obviyus</li>
<li>Agents/failover: unify structured and raw provider error classification so provider-specific <code>400</code>/<code>422</code> payloads no longer get forced into generic format failures before retry, billing, or compaction logic can inspect them. (#58856) Thanks @aaron-he-zhu.</li>
<li>Auth profiles/store: coerce misplaced SecretRef objects out of plaintext <code>key</code> and <code>token</code> fields during store load so agents without ACP runtime stop crashing on <code>.trim()</code> after upgrade. (#58923) Thanks @openperf.</li>
<li>ACPX/runtime: repair <code>queue owner unavailable</code> session recovery by replacing dead named sessions and resuming the backend session when ACPX exposes a stable session id, so the first ACP prompt no longer inherits a dead handle. (#58669) Thanks @neeravmakwana</li>
<li>ACPX/runtime: retry dead-session queue-owner repair without <code>--resume-session</code> when the reported ACPX session id is stale, so recovery still creates a fresh named session instead of failing session init. Thanks @obviyus.</li>
<li>Auth/OpenAI Codex: persist plugin-refreshed OAuth credentials to <code>auth-profiles.json</code> before returning them, so rotated Codex refresh tokens survive restart and stop falling into <code>refresh_token_reused</code> loops. (#53082)</li>
<li>Discord/gateway: hand reconnect ownership back to Carbon, keep runtime status aligned with close/reconnect state, and force-stop sockets that open without reaching READY so Discord monitors recover promptly instead of waiting on stale health timeouts. (#59019) Thanks @obviyus</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.4.1/OpenClaw-2026.4.1.zip" length="25841903" type="application/octet-stream" sparkle:edSignature="0TPiyshScmwDbgs626JU08NOUUFJmIsVFa5g0xmizfl64Fr+IoT4l/dkXarFqbZAJidtj5WN7Bff7fG8ye/7AA=="/>
</item>
<item>
<title>2026.3.31</title>
<pubDate>Tue, 31 Mar 2026 21:47:15 +0000</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>2026033190</sparkle:version>
<sparkle:shortVersionString>2026.3.31</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.3.31</h2>
<h3>Breaking</h3>
<ul>
<li>Nodes/exec: remove the duplicated <code>nodes.run</code> shell wrapper from the CLI and agent <code>nodes</code> tool so node shell execution always goes through <code>exec host=node</code>, keeping node-specific capabilities on <code>nodes invoke</code> and the dedicated media/location/notify actions.</li>
<li>Plugin SDK: deprecate the legacy provider compat subpaths plus the older bundled provider setup and channel-runtime compatibility shims, emit migration warnings, and keep the current documented <code>openclaw/plugin-sdk/*</code> entrypoints plus local <code>api.ts</code> / <code>runtime-api.ts</code> barrels as the forward path ahead of a future major-release removal.</li>
<li>Skills/install and Plugins/install: built-in dangerous-code <code>critical</code> findings and install-time scan failures now fail closed by default, so plugin installs and gateway-backed skill dependency installs that previously succeeded may now require an explicit dangerous override such as <code>--dangerously-force-unsafe-install</code> to proceed.</li>
<li>Gateway/auth: <code>trusted-proxy</code> now rejects mixed shared-token configs, and local-direct fallback requires the configured token instead of implicitly authenticating same-host callers. Thanks @zhangning-agent, @jacobtomlinson, and @vincentkoc.</li>
<li>Gateway/node commands: node commands now stay disabled until node pairing is approved, so device pairing alone is no longer enough to expose declared node commands. (#57777) Thanks @jacobtomlinson.</li>
<li>Gateway/node events: node-originated runs now stay on a reduced trusted surface, so notification-driven or node-triggered flows that previously relied on broader host/session tool access may need adjustment. (#57691) Thanks @jacobtomlinson.</li>
</ul>
<h3>Changes</h3>
<ul>
<li>ACP/plugins: add an explicit default-off ACPX plugin-tools MCP bridge config, document the trust boundary, and harden the built-in bridge packaging/logging path so global installs and stdio MCP sessions work reliably. (#56867) Thanks @joe2643.</li>
<li>Agents/LLM: add a configurable idle-stream timeout for embedded runner requests so stalled model streams abort cleanly instead of hanging until the broader run timeout fires. (#55072) Thanks @liuy.</li>
<li>Agents/MCP: materialize bundle MCP tools with provider-safe names (<code>serverName__toolName</code>), support optional <code>streamable-http</code> transport selection plus per-server connection timeouts, and preserve real tool results from aborted/error turns unless truncation explicitly drops them. (#49505) Thanks @ziomancer.</li>
<li>Android/notifications: add notification-forwarding controls with package filtering, quiet hours, rate limiting, and safer picker behavior for forwarded notification events. (#40175) Thanks @nimbleenigma.</li>
<li>Background tasks: turn tasks into a real shared background-run control plane instead of ACP-only bookkeeping by unifying ACP, subagent, cron, and background CLI execution under one SQLite-backed ledger, routing detached lifecycle updates through the executor seam, adding audit/maintenance/status visibility, tightening auto-cleanup and lost-run recovery, improving task awareness in internal status/tool surfaces, and clarifying the split between heartbeat/main-session automation and detached scheduled runs. Thanks @mbelinky and @vincentkoc.</li>
<li>Background tasks: add the first linear task flow control surface with <code>openclaw flows list|show|cancel</code>, keep manual multi-task flows separate from one-task auto-sync flows, and surface doctor recovery hints for obviously orphaned or broken flow/task linkage. Thanks @mbelinky and @vincentkoc.</li>
<li>Channels/QQ Bot: add QQ Bot as a bundled channel plugin with multi-account setup, SecretRef-aware credentials, slash commands, reminders, and media send/receive support. (#52986) Thanks @sliverp.</li>
<li>Diffs: skip unused viewer-versus-file SSR preload work so <code>diffs</code> view-only and file-only runs do less render work while keeping mode outputs aligned. (#57909) thanks @gumadeiras.</li>
<li>Tasks: add a minimal SQLite-backed task flow registry plus task-to-flow linkage scaffolding, so orchestrated work can start gaining a first-class parent record without changing current task delivery behavior. Thanks @mbelinky and @vincentkoc.</li>
<li>Tasks: persist blocked state on one-task task flows and let the same flow reopen cleanly on retry, so blocked detached work can carry a parent-level reason and continue without fragmenting into a new job. Thanks @mbelinky and @vincentkoc.</li>
<li>Tasks: route one-task ACP and subagent updates through a parent task-flow owner context, so detached work can emerge back through the intended parent thread/session instead of speaking only as a raw child task. Thanks @mbelinky and @vincentkoc.</li>
<li>LINE/outbound media: add LINE image, video, and audio outbound sends on the LINE-specific delivery path, including explicit preview/tracking handling for videos while keeping generic media sends on the existing image-only route. (#45826) Thanks @masatohoshino.</li>
<li>Matrix/history: add optional room history context for Matrix group triggers via <code>channels.matrix.historyLimit</code>, with per-agent watermarks and retry-safe snapshots so failed trigger retries do not drift into newer room messages. (#57022) thanks @chain710.</li>
<li>Matrix/network: add explicit <code>channels.matrix.proxy</code> config for routing Matrix traffic through an HTTP(S) proxy, including account-level overrides and matching probe/runtime behavior. (#56931) thanks @patrick-yingxi-pan.</li>
<li>Matrix/streaming: add draft streaming so partial Matrix replies update the same message in place instead of sending a new message for each chunk. (#56387) Thanks @jrusz.</li>
<li>Matrix/threads: add per-DM <code>threadReplies</code> overrides and keep thread session isolation aligned with the effective room or DM thread policy from the triggering message onward. (#57995) thanks @teconomix.</li>
<li>MCP: add remote HTTP/SSE server support for <code>mcp.servers</code> URL configs, including auth headers and safer config redaction for MCP credentials. (#50396) Thanks @dhananjai1729.</li>
<li>Memory/QMD: add per-agent <code>memorySearch.qmd.extraCollections</code> so agents can opt into cross-agent session search without flattening every transcript collection into one shared QMD namespace. Thanks @vincentkoc.</li>
<li>Microsoft Teams/member info: add a Graph-backed member info action so Teams automations and tools can resolve channel member details directly from Microsoft Graph. (#57528) Thanks @sudie-codes.</li>
<li>Nostr/inbound DMs: verify inbound event signatures before pairing or sender-authorization side effects, so forged DM events no longer create pairing requests or trigger reply attempts. Thanks @smaeljaish771 and @vincentkoc.</li>
<li>OpenAI/Responses: forward configured <code>text.verbosity</code> across Responses HTTP and WebSocket transports, surface it in <code>/status</code>, and keep per-agent verbosity precedence aligned with runtime behavior. (#47106) Thanks @merc1305 and @vincentkoc.</li>
<li>Pi/Codex: add native Codex web search support for embedded Pi runs, including config/docs/wizard coverage and managed-tool suppression when native Codex search is active. (#46579) Thanks @Evizero.</li>
<li>Slack/exec approvals: add native Slack approval routing and approver authorization so exec approval prompts can stay in Slack instead of falling back to the Web UI or terminal. Thanks @vincentkoc.</li>
<li>TTS: Add structured provider diagnostics and fallback attempt analytics. (#57954) Thanks @joshavant.</li>
<li>WhatsApp/reactions: agents can now react with emoji on incoming WhatsApp messages, enabling more natural conversational interactions like acknowledging a photo with ❤️ instead of typing a reply. Thanks @mcaxtr.</li>
<li>Agents/BTW: force <code>/btw</code> side questions to disable provider reasoning so Anthropic adaptive-thinking sessions stop failing with <code>No BTW response generated</code>. Fixes #55376. Thanks @Catteres and @vincentkoc.</li>
<li>CLI/onboarding: reset the remote gateway URL prompt to the safe loopback default after declining a discovered endpoint, so onboarding does not keep a previously rejected remote URL. (#57828)</li>
<li>Agents/exec defaults: honor per-agent <code>tools.exec</code> defaults when no inline directive or session override is present, so configured exec host, security, ask, and node settings actually apply. (#57689)</li>
<li>Sandbox/networking: sanitize SSH subprocess env vars through the shared sandbox policy and route marketplace archive downloads plus Ollama discovery, auth, and pull requests through the guarded fetch path so sandboxed execution and remote fetches follow the repo's trust boundaries. (#57848, #57850)</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Slack: stop retry-driven duplicate replies when draft-finalization edits fail ambiguously, and log configured allowlisted users/channels by readable name instead of raw IDs.</li>
<li>Agents/OpenAI Responses: normalize raw bundled MCP tool schemas on the WebSocket/Responses path so bare-object, object-ish, and top-level union MCP tools no longer get rejected by OpenAI during tool registration. (#58299) Thanks @yelog.</li>
<li>ACP/security: replace ACP's dangerous-tool name override with semantic approval classes, so only narrow readonly reads/searches can auto-approve while indirect exec-capable and control-plane tools always require explicit prompt approval. Thanks @vincentkoc.</li>
<li>ACP/sessions_spawn: register ACP child runs for completion tracking and lifecycle cleanup, and make registration-failure cleanup explicitly best-effort so callers do not assume an already-started ACP turn was fully aborted. (#40885) Thanks @xaeon2026 and @vincentkoc.</li>
<li>ACP/tasks: mark cleanly exited ACP runs as blocked when they end on deterministic write or authorization blockers, and wake the parent session with a follow-up instead of falsely reporting success.</li>
<li>ACPX/runtime: derive the bundled ACPX expected version from the extension package metadata instead of hardcoding a separate literal, so plugin-local ACPX installs stop drifting out of health-check parity after version bumps. (#49089) Thanks @jiejiesks and @vincentkoc.</li>
<li>Agents/Anthropic failover: treat Anthropic <code>api_error</code> payloads with <code>An unexpected error occurred while processing the response</code> as transient so retry/fallback can engage instead of surfacing a terminal failure. (#57441) Thanks @zijiess and @vincentkoc.</li>
<li>Agents/compaction: keep late compaction-retry completions from double-resolving finished compaction futures, so interrupted or timed-out compactions stop surfacing spurious second-completion races. (#57796) Thanks @joshavant.</li>
<li>Agents/disabled providers: make disabled providers disappear from default model selection and embedded provider fallback, while letting explicitly pinned disabled providers fail with a clear config error instead of silently taking traffic. (#57735) Thanks @rileybrown-dev and @vincentkoc.</li>
<li>Agents/OAuth output: force exec-host OAuth output readers through the gateway fs policy so embedded gateway runs stop crashing when provider auth writes land outside the current sandbox workspace. (#58249) Thanks @joshavant.</li>
<li>Agents/system prompt: fix <code>agent.name</code> interpolation in the embedded runtime system prompt and make provider/model fallback text reflect the effective runtime selection after start. (#57625) Thanks @StllrSvr and @vincentkoc.</li>
<li>Android/device info: read the app's version metadata from the package manager instead of hidden APIs so Android 15+ onboarding and device info no longer fail to compile or report placeholder values. (#58126) Thanks @L3ER0Y.</li>
<li>Android/pairing: stop appending duplicate push receiver entries to <code>gateway-service.conf</code> on repeated QR pairing and keep push registration bounded to the current successful pairing, so Android push delivery stays healthy across re-pair and token rotation. (#58256) Thanks @surrealroad.</li>
<li>App install smoke: pin the latest-release lookup to <code>latest</code>, cache the first stable install version across the rerun, and relax prerelease package assertions so the Parallels smoke lane can validate stable-to-main upgrades even when <code>beta</code> moves ahead or the guest starts from an older stable. (#58177) Thanks @vincentkoc.</li>
<li>Auth/profiles: keep the last successful config load in memory for the running process and refresh that snapshot on successful writes/reloads, so hot paths stop reparsing <code>openclaw.json</code> between watcher-driven swaps.</li>
<li>Config/SecretRef + Control UI: harden SecretRef redaction round-trip restore, block unsafe raw fallback (force Form mode when raw is unavailable), and preflight submitted-config SecretRefs before config write RPC persistence. (#58044) Thanks @joshavant.</li>
<li>Config/Telegram: migrate removed <code>channels.telegram.groupMentionsOnly</code> into <code>channels.telegram.groups[\"*\"].requireMention</code> on load so legacy configs no longer crash at startup. (#55336) thanks @jameslcowan.</li>
<li>Config/update: stop <code>openclaw doctor</code> write-backs from persisting plugin-injected channel defaults, so <code>openclaw update</code> no longer seeds config keys that later break service refresh validation. (#56834) Thanks @openperf.</li>
<li>Control UI/agents: auto-load agent workspace files on initial Files panel open, and populate overview model/workspace/fallbacks from effective runtime agent metadata so defaulted models no longer show as <code>Not set</code>. (#56637) Thanks @dxsx84.</li>
<li>Control UI/slash commands: make <code>/steer</code> and <code>/redirect</code> work from the chat command palette with visible pending state for active-run <code>/steer</code>, correct redirected-run tracking, and a single canonical <code>/steer</code> entry in the command menu. (#54625) Thanks @fuller-stack-dev.</li>
<li>Cron/announce: preserve all deliverable text payloads for announce mode instead of collapsing to the last chunk, so multi-line cron reports deliver in full to Telegram forum topics.</li>
<li>Cron/isolated sessions: carry the full live-session provider, model, and auth-profile selection across retry restarts so cron jobs with model overrides no longer fail or loop on mid-run model-switch requests. (#57972) Thanks @issaba1.</li>
<li>Diffs/config: preserve schema-shaped plugin config parsing from <code>diffsPluginConfigSchema.safeParse()</code>, so direct callers keep <code>defaults</code> and <code>security</code> sections instead of receiving flattened tool defaults. (#57904) Thanks @gumadeiras.</li>
<li>Diffs: fall back to plain text when <code>lang</code> hints are invalid during diff render and viewer hydration, so bad or stale language values no longer break the diff viewer. (#57902) Thanks @gumadeiras.</li>
<li>Discord/voice: enforce the same guild channel and member allowlist checks on spoken voice ingress before transcription, so joined voice channels no longer accept speech from users outside the configured Discord access policy. Thanks @cyjhhh and @vincentkoc.</li>
<li>Docker/setup: force BuildKit for local image builds (including sandbox image builds) so <code>./docker-setup.sh</code> no longer fails on <code>RUN --mount=...</code> when hosts default to Docker's legacy builder. (#56681) Thanks @zhanghui-china.</li>
<li>Docs/anchors: fix broken English docs links and make Mint anchor audits run against the English-source docs tree. (#57039) thanks @velvet-shark.</li>
<li>Doctor/plugins: skip false Matrix legacy-helper warnings when no migration plans exist, and keep bundled <code>enabledByDefault</code> plugins in the gateway startup set. (#57931) Thanks @dinakars777.</li>
<li>Exec approvals/macOS: unwrap <code>arch</code> and <code>xcrun</code> before deriving shell payloads and allow-always patterns, so wrapper approvals stay bound to the carried command instead of the outer carrier. Thanks @tdjackey and @vincentkoc.</li>
<li>Exec approvals: unwrap <code>caffeinate</code> and <code>sandbox-exec</code> before persisting allow-always trust so later shell payload changes still require a fresh approval. Thanks @tdjackey and @vincentkoc.</li>
<li>Exec/approvals: infer Discord and Telegram exec approvers from existing owner config when <code>execApprovals.approvers</code> is unset, extend the default approval window to 30 minutes, and clarify approval-unavailable guidance so approvals do not appear to silently disappear.</li>
<li>Pi/TUI: flush message-boundary replies at <code>message_end</code> so turns stop looking stuck until the next nudge when the final reply was already ready. Thanks @vincentkoc.</li>
<li>Exec/approvals: keep <code>awk</code> and <code>sed</code> family binaries out of the low-risk <code>safeBins</code> fast path, and stop doctor profile scaffolding from treating them like ordinary custom filters. Thanks @vincentkoc.</li>
<li>Exec/env: block proxy, TLS, and Docker endpoint env overrides in host execution so request-scoped commands cannot silently reroute outbound traffic or trust attacker-supplied certificate settings. Thanks @AntAISecurityLab.</li>
<li>Exec/env: block Python package index override variables from request-scoped host exec environment sanitization so package fetches cannot be redirected through a caller-supplied index. Thanks @nexrin and @vincentkoc.</li>
<li>Exec/node: stop gateway-side workdir fallback from rewriting explicit <code>host=node</code> cwd values to the gateway filesystem, so remote node exec approval and runs keep using the intended node-local directory. (#50961) Thanks @openperf.</li>
<li>Exec/runtime: default implicit exec to <code>host=auto</code>, resolve that target to sandbox only when a sandbox runtime exists, keep explicit <code>host=sandbox</code> fail-closed without sandbox, and show <code>/exec</code> effective host state in runtime status/docs.</li>
<li>Exec: fail closed when the implicit sandbox host has no sandbox runtime, and stop denied async approval followups from reusing prior command output from the same session. (#56800) Thanks @scoootscooob.</li>
<li>Feishu/groups: keep quoted replies and topic bootstrap context aligned with group sender allowlists so only allowlisted thread messages seed agent context. Thanks @AntAISecurityLab and @vincentkoc.</li>
<li>Gateway/attachments: offload large inbound images without leaking <code>media://</code> markers into text-only runs, preserve mixed attachment order for model input/transcripts, and fail closed when model image capability cannot be resolved. (#55513) Thanks @Syysean.</li>
<li>Gateway/auth: keep shared-auth rate limiting active during WebSocket handshake attempts even when callers also send device-token candidates, so bogus device-token fields no longer suppress shared-secret brute-force tracking. Thanks @kexinoh and @vincentkoc.</li>
<li>Gateway/auth: reject mismatched browser <code>Origin</code> headers on trusted-proxy HTTP operator requests while keeping origin-less headless proxy clients working. Thanks @AntAISecurityLab and @vincentkoc.</li>
<li>Gateway/device tokens: disconnect active device sessions after token rotation so newly rotated credentials revoke existing live connections immediately instead of waiting for those sockets to close naturally. Thanks @zsxsoft and @vincentkoc.</li>
<li>Gateway/health: carry webhook-vs-polling account mode from channel descriptors into runtime snapshots so passive channels like LINE and BlueBubbles skip false stale-socket health failures. (#47488) Thanks @karesansui-u.</li>
<li>Gateway/pairing: restore QR bootstrap onboarding handoff so fresh <code>/pair qr</code> iPhone setup can auto-approve the initial node pairing, receive a reusable node device token, and stop retrying with spent bootstrap auth. (#58382) Thanks @ngutman.</li>
<li>Gateway/OpenAI compatibility: accept flat Responses API function tool definitions on <code>/v1/responses</code> and preserve <code>strict</code> when normalizing hosted tools into the embedded runner, so spec-compliant clients like Codex no longer fail validation or silently lose strict tool enforcement. Thanks @malaiwah and @vincentkoc.</li>
<li>Gateway/OpenAI HTTP: restore default operator scopes for bearer-authenticated requests that omit <code>x-openclaw-scopes</code>, so headless <code>/v1/chat/completions</code> and session-history callers work again after the recent method-scope hardening. (#57596) Thanks @openperf.</li>
<li>Gateway/plugins: scope plugin-auth HTTP route runtime clients to read-only access and keep gateway-authenticated plugin routes on write scope, so plugin-owned webhook handlers do not inherit write-capable runtime access by default. Thanks @davidluzsilva and @vincentkoc.</li>
<li>Gateway/SecretRef: resolve restart token drift checks with merged service/runtime env sources and hard-fail unsupported mutable SecretRef plus OAuth-profile combinations so restart warnings and policy enforcement match runtime behavior. (#58141) Thanks @joshavant.</li>
<li>Gateway/tools HTTP: tighten HTTP tool-invoke authorization so owner-only tools stay off HTTP invoke paths. (#57773) Thanks @jacobtomlinson.</li>
<li>Harden async approval followup delivery in webchat-only sessions (#57359) Thanks @joshavant.</li>
<li>Heartbeat/auth: prevent exec-event heartbeat runs from inheriting owner-only tool access from the session delivery target, so node exec output stays on the non-owner tool surface even when the target session belongs to the owner. Thanks @AntAISecurityLab and @vincentkoc.</li>
<li>Hooks/config: accept runtime channel plugin ids in <code>hooks.mappings[].channel</code> (for example <code>feishu</code>) instead of rejecting non-core channels during config validation. (#56226) Thanks @AiKrai001.</li>
<li>Hooks/session routing: rebind hook-triggered <code>agent:</code> session keys to the actual target agent before isolated dispatch so dedicated hook agents keep their own session-scoped tool and plugin identity. Thanks @kexinoh and @vincentkoc.</li>
<li>Host exec/env: block additional request-scoped env overrides that can redirect Docker endpoints, trust roots, compiler include paths, package resolution, or Python environment roots during approved host runs. Thanks @tdjackey and @vincentkoc.</li>
<li>Image generation/build: write stable runtime alias files into <code>dist/</code> and route provider-auth runtime lookups through those aliases so image-generation providers keep resolving auth/runtime modules after rebuilds instead of crashing on missing hashed chunk files.</li>
<li>iOS/Live Activities: mark the <code>ActivityKit</code> import in <code>LiveActivityManager.swift</code> as <code>@preconcurrency</code> so Xcode 26.4 / Swift 6 builds stop failing on strict concurrency checks. (#57180) Thanks @ngutman.</li>
<li>LINE/ACP: add current-conversation binding and inbound binding-routing parity so <code>/acp spawn ... --thread here</code>, configured ACP bindings, and active conversation-bound ACP sessions work on LINE like the other conversation channels.</li>
<li>LINE/markdown: preserve underscores inside Latin, Cyrillic, and CJK words when stripping markdown, while still removing standalone <code>_italic_</code> markers on the shared text-runtime path used by LINE and TTS. (#47465) Thanks @jackjin1997.</li>
<li>Agents/failover: make overloaded same-provider retry count and retry delay configurable via <code>auth.cooldowns</code>, default to one retry with no delay, and document the model-fallback behavior.</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.3.31/OpenClaw-2026.3.31.zip" length="25820093" type="application/octet-stream" sparkle:edSignature="NjpuH/j7OaNASEatBTpQ4uQy6+oUNq/lIwjrY69rJfkgGSk3/kU8vgxo9osjSgx034m7TpuZvWyulu57OBsQCg=="/>
</item>
<item>
<title>2026.3.28</title>
<pubDate>Sun, 29 Mar 2026 02:10:40 +0000</pubDate>
@@ -143,98 +330,5 @@
]]></description>
<enclosure url="https://github.com/openclaw/openclaw/releases/download/v2026.3.28/OpenClaw-2026.3.28.zip" length="25811288" type="application/octet-stream" sparkle:edSignature="SJp4ptVaGlOIXRPevS89DbfN2WKP0bKMXQoaT0fmLhy7pataDfHN0kxC3zu6P0Q/HtsxaESEhJUw48SCUNNKDA=="/>
</item>
<item>
<title>2026.3.24</title>
<pubDate>Wed, 25 Mar 2026 17:06:31 +0000</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>2026032490</sparkle:version>
<sparkle:shortVersionString>2026.3.24</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.3.24</h2>
<h3>Breaking</h3>
<h3>Changes</h3>
<ul>
<li>Gateway/OpenAI compatibility: add <code>/v1/models</code> and <code>/v1/embeddings</code>, and forward explicit model overrides through <code>/v1/chat/completions</code> and <code>/v1/responses</code> for broader client and RAG compatibility. Thanks @vincentkoc.</li>
<li>Agents/tools: make <code>/tools</code> show the tools the current agent can actually use right now, add a compact default view with an optional detailed mode, and add a live "Available Right Now" section in the Control UI so it is easier to see what will work before you ask.</li>
<li>Microsoft Teams: migrate to the official Teams SDK and add AI-agent UX best practices including streaming 1:1 replies, welcome cards with prompt starters, feedback/reflection, informative status updates, typing indicators, and native AI labeling. (#51808)</li>
<li>Microsoft Teams: add message edit and delete support for sent messages, including in-thread fallbacks when no explicit target is provided. (#49925)</li>
<li>Skills/install metadata: add one-click install recipes to bundled skills (coding-agent, gh-issues, openai-whisper-api, session-logs, tmux, trello, weather) so the CLI and Control UI can offer dependency installation when requirements are missing. (#53411) Thanks @BunsDev.</li>
<li>Control UI/skills: add status-filter tabs (All / Ready / Needs Setup / Disabled) with counts, replace inline skill cards with a click-to-detail dialog showing requirements, toggle switch, install action, API key entry, source metadata, and homepage link. (#53411) Thanks @BunsDev.</li>
<li>Slack/interactive replies: restore rich reply parity for direct deliveries, auto-render simple trailing <code>Options:</code> lines as buttons/selects, improve Slack interactive setup defaults, and isolate reply controls from plugin interactive handlers. (#53389) Thanks @vincentkoc.</li>
<li>CLI/containers: add <code>--container</code> and <code>OPENCLAW_CONTAINER</code> to run <code>openclaw</code> commands inside a running Docker or Podman OpenClaw container. (#52651) Thanks @sallyom.</li>
<li>Discord/auto threads: add optional <code>autoThreadName: "generated"</code> naming so new auto-created threads can be renamed asynchronously with concise LLM-generated titles while keeping the existing message-based naming as the default. (#43366) Thanks @davidguttman.</li>
<li>Plugins/hooks: add <code>before_dispatch</code> with canonical inbound metadata and route handled replies through the normal final-delivery path, preserving TTS and routed delivery semantics. (#50444) Thanks @gfzhx.</li>
<li>Control UI/agents: convert agent workspace file rows to expandable <code><details></code> with lazy-loaded inline markdown preview, and add comprehensive <code>.sidebar-markdown</code> styles for headings, lists, code blocks, tables, blockquotes, and details/summary elements. (#53411) Thanks @BunsDev.</li>
<li>Control UI/markdown preview: restyle the agent workspace file preview dialog with a frosted backdrop, sized panel, and styled header, and integrate <code>@create-markdown/preview</code> v2 system theme for rich markdown rendering (headings, tables, code blocks, callouts, blockquotes) that auto-adapts to the app's light/dark design tokens. (#53411) Thanks @BunsDev.</li>
<li>macOS app/config: replace horizontal pill-based subsection navigation with a collapsible tree sidebar using disclosure chevrons and indented subsection rows. (#53411) Thanks @BunsDev.</li>
<li>CLI/skills: soften missing-requirements label from "missing" to "needs setup" and surface API key setup guidance (where to get a key, CLI save command, storage path) in <code>openclaw skills info</code> output. (#53411) Thanks @BunsDev.</li>
<li>macOS app/skills: add "Get your key" homepage link and storage-path hint to the API key editor dialog, and show the config path in save confirmation messages. (#53411) Thanks @BunsDev.</li>
<li>Control UI/agents: add a "Not set" placeholder to the default agent model selector dropdown. (#53411) Thanks @BunsDev.</li>
<li>Runtime/install: lower the supported Node 22 floor to <code>22.14+</code> while continuing to recommend Node 24, so npm installs and self-updates do not strand Node 22.14 users on older releases.</li>
<li>CLI/update: preflight the target npm package <code>engines.node</code> before <code>openclaw update</code> runs a global package install, so outdated Node runtimes fail with a clear upgrade message instead of attempting an unsupported latest release.</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Outbound media/local files: align outbound media access with the configured fs policy so host-local files and inbound-media paths keep sending when <code>workspaceOnly</code> is off, while strict workspace-only agents remain sandboxed.</li>
<li>Security/sandbox media dispatch: close the <code>mediaUrl</code>/<code>fileUrl</code> alias bypass so outbound tool and message actions cannot escape media-root restrictions. (#54034)</li>
<li>Gateway/restart sentinel: wake the interrupted agent session via heartbeat after restart instead of only sending a best-effort restart note, retry outbound delivery once on transient failure, and preserve explicit thread/topic routing through the wake path so replies land in the correct Telegram topic or Slack thread. (#53940) Thanks @VACInc.</li>
<li>Docker/setup: avoid the pre-start <code>openclaw-cli</code> shared-network namespace loop by routing setup-time onboard/config writes through <code>openclaw-gateway</code>, so fresh Docker installs stop failing before the gateway comes up. (#53385) Thanks @amsminn.</li>
<li>Gateway/channels: keep channel startup sequential while isolating per-channel boot failures, so one broken channel no longer blocks later channels from starting. (#54215) Thanks @JonathanJing.</li>
<li>Embedded runs/secrets: stop unresolved <code>SecretRef</code> config from crashing embedded agent runs by falling back to the resolved runtime snapshot when needed. Fixes #45838.</li>
<li>WhatsApp/groups: track recent gateway-sent message IDs and suppress only matching group echoes, preserving owner <code>/status</code>, <code>/new</code>, and <code>/activation</code> commands from linked-account <code>fromMe</code> traffic. (#53624) Thanks @w-sss.</li>
<li>WhatsApp/reply-to-bot detection: restore implicit group reply detection by unwrapping <code>botInvokeMessage</code> payloads and reading <code>selfLid</code> from <code>creds.json</code>, so reply-based mentions reach the bot again in linked-account group chats.</li>
<li>Telegram/forum topics: recover <code>#General</code> topic <code>1</code> routing when Telegram omits forum metadata, including native commands, interactive callbacks, inbound message context, and fallback error replies. (#53699) thanks @huntharo</li>
<li>Discord/gateway supervision: centralize gateway error handling behind a lifetime-owned supervisor so early, active, and late-teardown Carbon gateway errors stay classified consistently and stop surfacing as process-killing teardown crashes.</li>
<li>Discord/timeouts: send a visible timeout reply when the inbound Discord worker times out before a final reply starts, including created auto-thread targets and queued-run ordering. (#53823) Thanks @Kimbo7870.</li>
<li>ACP/direct chats: always deliver a terminal ACP result when final TTS does not yield audio, even if block text already streamed earlier, and skip redundant empty-text final synthesis. (#53692) Thanks @w-sss.</li>
<li>Telegram/outbound errors: preserve actionable 403 membership/block/kick details and treat <code>bot not a member</code> as a permanent delivery failure so Telegram sends stop retrying doomed chats. (#53635) Thanks @w-sss.</li>
<li>Telegram/photos: preflight Telegram photo dimension and aspect-ratio rules, and fall back to document sends when image metadata is invalid or unavailable so photo uploads stop failing with <code>PHOTO_INVALID_DIMENSIONS</code>. (#52545) Thanks @hnshah.</li>
<li>Slack/runtime defaults: trim Slack DM reply overhead, restore Codex auto transport, and tighten Slack/web-search runtime defaults around DM preview threading, cache scoping, warning dedupe, and explicit web-search opt-in. (#53957) Thanks @vincentkoc.</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.3.24/OpenClaw-2026.3.24.zip" length="24749233" type="application/octet-stream" sparkle:edSignature="gLm2VvI+PPEnNy4klYSs9WmZLkJTF5BcfFparrtPdnmeE4xgc8kFfICg445I039ev9/A6xGav7pm08reUHDcAg=="/>
</item>
<item>
<title>2026.3.23</title>
<pubDate>Mon, 23 Mar 2026 16:59:51 -0700</pubDate>
<link>https://raw.githubusercontent.com/openclaw/openclaw/main/appcast.xml</link>
<sparkle:version>2026032390</sparkle:version>
<sparkle:shortVersionString>2026.3.23</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>15.0</sparkle:minimumSystemVersion>
<description><![CDATA[<h2>OpenClaw 2026.3.23</h2>
<h3>Breaking</h3>
<h3>Changes</h3>
<h3>Fixes</h3>
<ul>
<li>Browser/Chrome MCP: wait for existing-session browser tabs to become usable after attach instead of treating the initial Chrome MCP handshake as ready, which reduces user-profile timeouts and repeated consent churn on macOS Chrome attach flows. Fixes #52930. Thanks @vincentkoc.</li>
<li>Browser/CDP: reuse an already-running loopback browser after a short initial reachability miss instead of immediately falling back to relaunch detection, which fixes second-run browser start/open regressions on slower headless Linux setups. Fixes #53004. Thanks @vincentkoc.</li>
<li>ClawHub/macOS auth: honor macOS auth config and XDG auth paths for saved ClawHub credentials, so <code>openclaw skills ...</code> and gateway skill browsing keep using the signed-in auth state instead of silently falling back to unauthenticated mode. Fixes #53034.</li>
<li>ClawHub/macOS: read the local ClawHub login from the macOS Application Support path and still honor XDG config on macOS, so skill browsing uses the logged-in token on both default and XDG-style setups. Fixes #52949. Thanks @scoootscooob.</li>
<li>ClawHub/skills: resolve the local ClawHub auth token for gateway skill browsing and switch browse-all requests to search so ClawControl stops falling into unauthenticated 429s and empty authenticated skill lists. Fixes #52949. Thanks @vincentkoc.</li>
<li>Plugins/message tool: make Discord <code>components</code> and Slack <code>blocks</code> optional again, and route Feishu <code>message(..., media=...)</code> sends through the outbound media path, so pin/unpin/react flows stop failing schema validation and Feishu file/image attachments actually send. Fixes #52970 and #52962. Thanks @vincentkoc.</li>
<li>Gateway/model pricing: stop <code>openrouter/auto</code> pricing refresh from recursing indefinitely during bootstrap, so OpenRouter auto routes can populate cached pricing and <code>usage.cost</code> again. Fixes #53035. Thanks @vincentkoc.</li>
<li>Mistral/models: lower bundled Mistral max-token defaults to safe output budgets and teach <code>openclaw doctor --fix</code> to repair old persisted Mistral provider configs that still carry context-sized output limits, avoiding deterministic Mistral 422 rejects on fresh and existing setups. Fixes #52599. Thanks @vincentkoc.</li>
<li>Agents/web_search: use the active runtime <code>web_search</code> provider instead of stale/default selection, so agent turns keep hitting the provider you actually configured. Fixes #53020. Thanks @jzakirov.</li>
<li>Models/OpenAI Codex OAuth: bootstrap the env-configured HTTP/HTTPS proxy dispatcher on the stored-credential refresh path before token renewal runs, so expired Codex OAuth profiles can refresh successfully in proxy-required environments instead of locking users out after the first token expiry.</li>
<li>Plugins/memory-lancedb: bootstrap LanceDB into plugin runtime state on first use when the bundled npm install does not already have it, so <code>plugins.slots.memory="memory-lancedb"</code> works again after global npm installs without moving LanceDB into OpenClaw core dependencies. Fixes #26100.</li>
<li>Config/plugins: treat stale unknown <code>plugins.allow</code> ids as warnings instead of fatal config errors, so recovery commands like <code>plugins install</code>, <code>doctor --fix</code>, and <code>status</code> still run when a plugin is missing locally. Fixes #52992. Thanks @vincentkoc.</li>
<li>Doctor/WhatsApp: stop auto-enable from appending built-in channel ids like <code>whatsapp</code> to <code>plugins.allow</code>, so <code>openclaw doctor --fix</code> no longer writes schema-invalid plugin allowlist entries when repairing built-in channels. Fixes #52931. Thanks @vincentkoc.</li>
<li>Telegram/auto-reply: preserve same-chat inbound debounce order without stranding stale busy-session followups, and keep same-key overflow turns ordered when tracked debounce keys are saturated. (#52998) Thanks @osolmaz.</li>
<li>Discord/commands: return an explicit unauthorized reply for privileged native slash commands instead of falling through to Discord's misleading generic completion when auth gates reject the sender. Fixes #53041. Thanks @scoootscooob.</li>
<li>Channels/catalog: let external channel catalogs override shipped fallback metadata and honor overridden npm specs during channel setup, so custom channel catalogs no longer fall back to bundled packages when a channel id matches. (#52988)</li>
<li>Voice-call/Plivo: stabilize Plivo v2 replay keys so webhook retries and replay protection stop colliding on valid follow-up deliveries.</li>
<li>Agents/skills: prefer the active resolved runtime snapshot for embedded skill config and env injection, so <code>skills.entries.<skill>.apiKey</code> SecretRefs resolve correctly during embedded startup instead of failing on raw source config. Fixes #53098. Thanks @vincentkoc.</li>
<li>Agents/subagents: recheck timed-out worker waits against the latest runtime snapshot before sending completion events, so fast-finishing workers stop being reported as timed out when they actually succeeded. Fixes #53106. Thanks @vincentkoc.</li>
<li>Agents/Anthropic: preserve latest assistant thinking and redacted-thinking block ordering during transcript image sanitization so follow-up turns do not trip Anthropic's unmodified-thinking validation. (#52961) Thanks @vincentkoc.</li>
<li>Gateway/probe: stop successful gateway handshakes from timing out as unreachable while post-connect detail RPCs are still loading, so slow devices report a reachable RPC failure instead of a false negative dead gateway. Fixes #52927. Thanks @vincentkoc.</li>
<li>Gateway/supervision: stop lock conflicts from crash-looping under launchd and systemd by keeping the duplicate process in a retry wait instead of exiting as a failure while another healthy gateway still owns the lock. Fixes #52922. Thanks @vincentkoc.</li>
<li>Gateway/auth: require auth for canvas routes and admin scope for agent session reset, so anonymous canvas access and non-admin reset requests fail closed.</li>
<li>Release/install: keep previously released bundled plugins and Control UI assets in published openclaw npm installs, and fail release checks when those shipped artifacts are missing. Thanks @vincentkoc.</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.3.23/OpenClaw-2026.3.23.zip" length="24522883" type="application/octet-stream" sparkle:edSignature="ptBgHYLBqq/TSdONYCfIB5d6aP/ij/9G0gYQ5mJI9jf8Y31sbQIh5CqpJVxEEWLTMIGQKsHQir/kXZjtRvvZAg=="/>
</item>
</channel>
</rss>
</rss>

View File

@@ -65,8 +65,8 @@ android {
applicationId = "ai.openclaw.app"
minSdk = 31
targetSdk = 36
versionCode = 2026033101
versionName = "2026.3.31-beta.1"
versionCode = 2026040101
versionName = "2026.4.2"
ndk {
// Support all major ABIs — native libs are tiny (~47 KB per ABI)
abiFilters += listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")

View File

@@ -1,8 +1,8 @@
// Shared iOS version defaults.
// Generated overrides live in build/Version.xcconfig (git-ignored).
OPENCLAW_GATEWAY_VERSION = 2026.3.31-beta.1
OPENCLAW_MARKETING_VERSION = 2026.3.31
OPENCLAW_BUILD_VERSION = 2026033101
OPENCLAW_GATEWAY_VERSION = 2026.4.2
OPENCLAW_MARKETING_VERSION = 2026.4.2
OPENCLAW_BUILD_VERSION = 2026040101
#include? "../build/Version.xcconfig"

View File

@@ -65,9 +65,9 @@ Release behavior:
- Beta release also switches the app to `OpenClawPushTransport=relay`, `OpenClawPushDistribution=official`, and `OpenClawPushAPNsEnvironment=production`.
- The beta flow does not modify `apps/ios/.local-signing.xcconfig` or `apps/ios/LocalSigning.xcconfig`.
- Root `package.json.version` is the only version source for iOS.
- A root version like `2026.3.31-beta.1` becomes:
- `CFBundleShortVersionString = 2026.3.31`
- `CFBundleVersion = next TestFlight build number for 2026.3.31`
- A root version like `2026.4.1-beta.1` becomes:
- `CFBundleShortVersionString = 2026.4.1`
- `CFBundleVersion = next TestFlight build number for 2026.4.1`
Required env for beta builds:

View File

@@ -136,6 +136,17 @@ final class AppState {
forKey: voicePushToTalkEnabledKey) } }
}
var voiceWakeTriggersTalkMode: Bool {
didSet {
self.ifNotPreview {
UserDefaults.standard.set(self.voiceWakeTriggersTalkMode, forKey: voiceWakeTriggersTalkModeKey)
if self.swabbleEnabled {
Task { await VoiceWakeRuntime.shared.refresh(state: self) }
}
}
}
}
var talkEnabled: Bool {
didSet {
self.ifNotPreview {
@@ -275,6 +286,8 @@ final class AppState {
.stringArray(forKey: voiceWakeAdditionalLocalesKey) ?? []
self.voicePushToTalkEnabled = UserDefaults.standard
.object(forKey: voicePushToTalkEnabledKey) as? Bool ?? false
self.voiceWakeTriggersTalkMode = UserDefaults.standard
.object(forKey: voiceWakeTriggersTalkModeKey) as? Bool ?? false
self.talkEnabled = UserDefaults.standard.bool(forKey: talkEnabledKey)
self.seamColorHex = nil
if let storedHeartbeats = UserDefaults.standard.object(forKey: heartbeatsEnabledKey) as? Bool {

View File

@@ -22,6 +22,7 @@ let voiceWakeMicNameKey = "openclaw.voiceWakeMicName"
let voiceWakeLocaleKey = "openclaw.voiceWakeLocaleID"
let voiceWakeAdditionalLocalesKey = "openclaw.voiceWakeAdditionalLocaleIDs"
let voicePushToTalkEnabledKey = "openclaw.voicePushToTalkEnabled"
let voiceWakeTriggersTalkModeKey = "openclaw.voiceWakeTriggersTalkMode"
let talkEnabledKey = "openclaw.talkEnabled"
let iconOverrideKey = "openclaw.iconOverride"
let connectionModeKey = "openclaw.connectionMode"

View File

@@ -618,11 +618,13 @@ extension GatewayConnection {
func chatHistory(
sessionKey: String,
limit: Int? = nil,
maxChars: Int? = nil,
timeoutMs: Int? = nil) async throws -> OpenClawChatHistoryPayload
{
let resolvedKey = self.canonicalizeSessionKey(sessionKey)
var params: [String: AnyCodable] = ["sessionKey": AnyCodable(resolvedKey)]
if let limit { params["limit"] = AnyCodable(limit) }
if let maxChars { params["maxChars"] = AnyCodable(maxChars) }
let timeout = timeoutMs.map { Double($0) }
return try await self.requestDecoded(
method: .chatHistory,

View File

@@ -88,6 +88,7 @@ enum HostEnvSecurityPolicy {
"PHP_INI_SCAN_DIR",
"DENO_DIR",
"BUN_CONFIG_REGISTRY",
"YARN_RC_FILENAME",
"HTTP_PROXY",
"HTTPS_PROXY",
"ALL_PROXY",
@@ -146,7 +147,8 @@ enum HostEnvSecurityPolicy {
static let blockedOverridePrefixes: [String] = [
"GIT_CONFIG_",
"NPM_CONFIG_"
"NPM_CONFIG_",
"CARGO_REGISTRIES_"
]
static let blockedPrefixes: [String] = [

View File

@@ -15,9 +15,9 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2026.3.31-beta.1</string>
<string>2026.4.2</string>
<key>CFBundleVersion</key>
<string>2026033101</string>
<string>2026040101</string>
<key>CFBundleIconFile</key>
<string>OpenClaw</string>
<key>CFBundleURLTypes</key>

View File

@@ -18,6 +18,12 @@ final class TalkModeController {
TalkOverlayController.shared.dismiss()
}
await TalkModeRuntime.shared.setEnabled(enabled)
// Resume voice wake listener *after* TalkMode audio is fully torn down.
// Check swabbleEnabled (not voiceWakeTriggersTalkMode) so the paused wake listener
// resumes even if the user toggled "Trigger Talk Mode" off during the session.
if !enabled, AppStateStore.shared.swabbleEnabled {
Task { await VoiceWakeRuntime.shared.refresh(state: AppStateStore.shared) }
}
}
func updatePhase(_ phase: TalkModePhase) {

View File

@@ -335,6 +335,11 @@ actor TalkModeRuntime {
self.lastHeard = nil
self.phase = .thinking
await MainActor.run { TalkModeController.shared.updatePhase(.thinking) }
// Play "send" chime when the user's speech is finalized and about to be sent
let sendChime = await MainActor.run { AppStateStore.shared.voiceWakeSendChime }
if sendChime != .none {
await MainActor.run { VoiceWakeChimePlayer.play(sendChime, reason: "talk.send") }
}
await self.stopRecognition()
await self.sendAndSpeak(text)
}
@@ -456,6 +461,7 @@ actor TalkModeRuntime {
private func playAssistant(text: String) async {
guard let input = await self.preparePlaybackInput(text: text) else { return }
switch Self.playbackPlan(apiKey: input.apiKey, voiceId: input.voiceId) {
case let .elevenLabsThenSystemVoice(apiKey, voiceId):
do {

View File

@@ -82,6 +82,7 @@ actor VoiceWakeRuntime {
let localeID: String?
let triggerChime: VoiceWakeChime
let sendChime: VoiceWakeChime
let triggersTalkMode: Bool
}
private struct RecognitionUpdate {
@@ -100,7 +101,8 @@ actor VoiceWakeRuntime {
micID: state.voiceWakeMicID.isEmpty ? nil : state.voiceWakeMicID,
localeID: state.voiceWakeLocaleID.isEmpty ? nil : state.voiceWakeLocaleID,
triggerChime: state.voiceWakeTriggerChime,
sendChime: state.voiceWakeSendChime)
sendChime: state.voiceWakeSendChime,
triggersTalkMode: state.voiceWakeTriggersTalkMode)
return (enabled, config)
}
@@ -529,6 +531,21 @@ actor VoiceWakeRuntime {
}
private func beginCapture(command: String, triggerEndTime: TimeInterval?, config: RuntimeConfig) async {
// When "Trigger Talk Mode" is enabled, skip the capture/overlay flow entirely
// and activate Talk Mode immediately. Talk Mode handles its own STT pipeline.
// Pause the wake listener to avoid two audio pipelines competing on the mic
// (mirrors the push-to-talk coordination pattern).
if config.triggersTalkMode {
self.logger.info("voicewake trigger -> activating Talk Mode (skipping capture)")
DiagnosticsFileLog.shared.log(category: "voicewake.runtime", event: "triggerTalkMode")
if config.triggerChime != .none {
await MainActor.run { VoiceWakeChimePlayer.play(config.triggerChime, reason: "voicewake.trigger") }
}
self.pauseForPushToTalk()
await AppStateStore.shared.setTalkEnabled(true)
return
}
self.listeningState = .voiceWake
self.isCapturing = true
DiagnosticsFileLog.shared.log(category: "voicewake.runtime", event: "beginCapture")

View File

@@ -53,6 +53,16 @@ struct VoiceWakeSettings: View {
binding: self.voiceWakeBinding)
.disabled(!voiceWakeSupported)
SettingsToggleRow(
title: "Trigger Talk Mode",
subtitle: """
When a wake phrase is detected, activate Talk Mode for a full voice \
conversation (STT, LLM response, TTS playback) instead of sending a \
text message to the chat.
""",
binding: self.$state.voiceWakeTriggersTalkMode)
.disabled(!self.state.swabbleEnabled)
SettingsToggleRow(
title: "Hold Right Option to talk",
subtitle: """

View File

@@ -3710,18 +3710,22 @@ public struct DevicePairResolvedEvent: Codable, Sendable {
public struct ChatHistoryParams: Codable, Sendable {
public let sessionkey: String
public let limit: Int?
public let maxchars: Int?
public init(
sessionkey: String,
limit: Int?)
limit: Int?,
maxchars: Int?)
{
self.sessionkey = sessionkey
self.limit = limit
self.maxchars = maxchars
}
private enum CodingKeys: String, CodingKey {
case sessionkey = "sessionKey"
case limit
case maxchars = "maxChars"
}
}

View File

@@ -3710,18 +3710,22 @@ public struct DevicePairResolvedEvent: Codable, Sendable {
public struct ChatHistoryParams: Codable, Sendable {
public let sessionkey: String
public let limit: Int?
public let maxchars: Int?
public init(
sessionkey: String,
limit: Int?)
limit: Int?,
maxchars: Int?)
{
self.sessionkey = sessionkey
self.limit = limit
self.maxchars = maxchars
}
private enum CodingKeys: String, CodingKey {
case sessionkey = "sessionKey"
case limit
case maxchars = "maxChars"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
{"generatedBy":"scripts/generate-config-doc-baseline.ts","recordType":"meta","totalPaths":5718}
{"generatedBy":"scripts/generate-config-doc-baseline.ts","recordType":"meta","totalPaths":5781}
{"recordType":"path","path":"acp","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"ACP","help":"ACP runtime controls for enabling dispatch, selecting backends, constraining allowed agent targets, and tuning streamed turn projection behavior.","hasChildren":true}
{"recordType":"path","path":"acp.allowedAgents","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"ACP Allowed Agents","help":"Allowlist of ACP target agent ids permitted for ACP runtime sessions. Empty means no additional allowlist restriction.","hasChildren":true}
{"recordType":"path","path":"acp.allowedAgents.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@@ -92,6 +92,7 @@
{"recordType":"path","path":"agents.defaults.compaction.memoryFlush.systemPrompt","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Compaction Memory Flush System Prompt","help":"System-prompt override for the pre-compaction memory flush turn to control extraction style and safety constraints. Use carefully so custom instructions do not reduce memory quality or leak sensitive context.","hasChildren":false}
{"recordType":"path","path":"agents.defaults.compaction.mode","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Compaction Mode","help":"Compaction strategy mode: \"default\" uses baseline behavior, while \"safeguard\" applies stricter guardrails to preserve recent context. Keep \"default\" unless you observe aggressive history loss near limit boundaries.","hasChildren":false}
{"recordType":"path","path":"agents.defaults.compaction.model","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["models"],"label":"Compaction Model Override","help":"Optional provider/model override used only for compaction summarization. Set this when you want compaction to run on a different model than the session default, and leave it unset to keep using the primary agent model.","hasChildren":false}
{"recordType":"path","path":"agents.defaults.compaction.notifyUser","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Compaction Notify User","help":"When enabled, sends a brief compaction notice to the user (e.g. '🧹 Compacting context...') when compaction starts. Disabled by default to keep compaction silent and non-intrusive.","hasChildren":false}
{"recordType":"path","path":"agents.defaults.compaction.postCompactionSections","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Post-Compaction Context Sections","help":"AGENTS.md H2/H3 section names re-injected after compaction so the agent reruns critical startup guidance. Leave unset to use \"Session Startup\"/\"Red Lines\" with legacy fallback to \"Every Session\"/\"Safety\"; set to [] to disable reinjection entirely.","hasChildren":true}
{"recordType":"path","path":"agents.defaults.compaction.postCompactionSections.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"agents.defaults.compaction.postIndexSync","kind":"core","type":"string","required":false,"enumValues":["off","async","await"],"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Compaction Post-Index Sync","help":"Controls post-compaction session memory reindex mode: \"off\", \"async\", or \"await\" (default: \"async\"). Use \"await\" for strongest freshness, \"async\" for lower compaction latency, and \"off\" only when session-memory sync is handled elsewhere.","hasChildren":false}
@@ -251,6 +252,8 @@
{"recordType":"path","path":"agents.defaults.models.*.params","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"agents.defaults.models.*.params.*","kind":"core","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"agents.defaults.models.*.streaming","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"agents.defaults.params","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"agents.defaults.params.*","kind":"core","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"agents.defaults.pdfMaxBytesMb","kind":"core","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":["performance"],"label":"PDF Max Size (MB)","help":"Maximum PDF file size in megabytes for the PDF tool (default: 10).","hasChildren":false}
{"recordType":"path","path":"agents.defaults.pdfMaxPages","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance"],"label":"PDF Max Pages","help":"Maximum number of PDF pages to process for the PDF tool (default: 20).","hasChildren":false}
{"recordType":"path","path":"agents.defaults.pdfModel","kind":"core","type":["object","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
@@ -697,6 +700,9 @@
{"recordType":"path","path":"auth.cooldowns.billingBackoffHoursByProvider.*","kind":"core","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"auth.cooldowns.billingMaxHours","kind":"core","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":["access","auth","performance"],"label":"Billing Backoff Cap (hours)","help":"Cap (hours) for billing backoff (default: 24).","hasChildren":false}
{"recordType":"path","path":"auth.cooldowns.failureWindowHours","kind":"core","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":["access","auth"],"label":"Failover Window (hours)","help":"Failure window (hours) for backoff counters (default: 24).","hasChildren":false}
{"recordType":"path","path":"auth.cooldowns.overloadedBackoffMs","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["access","auth","reliability","storage"],"label":"Overloaded Backoff (ms)","help":"Fixed delay in milliseconds before retrying an overloaded provider/profile rotation (default: 0).","hasChildren":false}
{"recordType":"path","path":"auth.cooldowns.overloadedProfileRotations","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["access","auth","storage"],"label":"Overloaded Profile Rotations","help":"Maximum same-provider auth-profile rotations allowed for overloaded errors before switching to model fallback (default: 1).","hasChildren":false}
{"recordType":"path","path":"auth.cooldowns.rateLimitedProfileRotations","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["access","auth","performance","storage"],"label":"Rate-Limited Profile Rotations","help":"Maximum same-provider auth-profile rotations allowed for rate-limit errors before switching to model fallback (default: 1).","hasChildren":false}
{"recordType":"path","path":"auth.order","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["access","auth"],"label":"Auth Profile Order","help":"Ordered auth profile IDs per provider (used for automatic failover).","hasChildren":true}
{"recordType":"path","path":"auth.order.*","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"auth.order.*.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@@ -2824,7 +2830,7 @@
{"recordType":"path","path":"channels.slack.execApprovals","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["channels","network"],"label":"Slack Exec Approvals","help":"Slack-native exec approval routing and approver authorization. Enable this only when Slack should act as an explicit exec-approval client for the selected workspace account.","hasChildren":true}
{"recordType":"path","path":"channels.slack.execApprovals.agentFilter","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["channels","network"],"label":"Slack Exec Approval Agent Filter","help":"Optional allowlist of agent IDs eligible for Slack exec approvals, for example `[\"main\", \"ops-agent\"]`. Use this to keep approval prompts scoped to the agents you actually operate from Slack.","hasChildren":true}
{"recordType":"path","path":"channels.slack.execApprovals.agentFilter.*","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.slack.execApprovals.approvers","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["channels","network"],"label":"Slack Exec Approval Approvers","help":"Slack user IDs allowed to approve exec requests for this workspace account. Use Slack user IDs or user targets such as `U123`, `user:U123`, or `<@U123>`. If you leave this unset, OpenClaw falls back to owner IDs inferred from channels.slack.allowFrom, channels.slack.dm.allowFrom, and defaultTo when possible.","hasChildren":true}
{"recordType":"path","path":"channels.slack.execApprovals.approvers","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["channels","network"],"label":"Slack Exec Approval Approvers","help":"Slack user IDs allowed to approve exec requests for this workspace account. Use Slack user IDs or user targets such as `U123`, `user:U123`, or `<@U123>`. If you leave this unset, OpenClaw falls back to commands.ownerAllowFrom when possible.","hasChildren":true}
{"recordType":"path","path":"channels.slack.execApprovals.approvers.*","kind":"channel","type":["number","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.slack.execApprovals.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["channels","network"],"label":"Slack Exec Approvals Enabled","help":"Enable Slack exec approvals for this account. When false or unset, Slack messages/buttons cannot approve exec requests.","hasChildren":false}
{"recordType":"path","path":"channels.slack.execApprovals.sessionFilter","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["channels","network","storage"],"label":"Slack Exec Approval Session Filter","help":"Optional session-key filters matched as substring or regex-style patterns before Slack approval routing is used. Use narrow patterns so Slack approvals only appear for intended sessions.","hasChildren":true}
@@ -2931,6 +2937,8 @@
{"recordType":"path","path":"channels.telegram.accounts.*.direct.*.autoTopicLabel.prompt","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.direct.*.dmPolicy","kind":"channel","type":"string","required":false,"enumValues":["pairing","allowlist","open","disabled"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.direct.*.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.direct.*.errorCooldownMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.direct.*.errorPolicy","kind":"channel","type":"string","required":false,"enumValues":["always","once","silent"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.direct.*.requireTopic","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.direct.*.skills","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"channels.telegram.accounts.*.direct.*.skills.*","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@@ -2957,6 +2965,8 @@
{"recordType":"path","path":"channels.telegram.accounts.*.direct.*.topics.*.allowFrom.*","kind":"channel","type":["number","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.direct.*.topics.*.disableAudioPreflight","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.direct.*.topics.*.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.direct.*.topics.*.errorCooldownMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.direct.*.topics.*.errorPolicy","kind":"channel","type":"string","required":false,"enumValues":["always","once","silent"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.direct.*.topics.*.groupPolicy","kind":"channel","type":"string","required":false,"enumValues":["open","disabled","allowlist"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.direct.*.topics.*.requireMention","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.direct.*.topics.*.skills","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
@@ -2972,6 +2982,8 @@
{"recordType":"path","path":"channels.telegram.accounts.*.draftChunk.maxChars","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.draftChunk.minChars","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.errorCooldownMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.errorPolicy","kind":"channel","type":"string","required":false,"enumValues":["always","once","silent"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.execApprovals","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"channels.telegram.accounts.*.execApprovals.agentFilter","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"channels.telegram.accounts.*.execApprovals.agentFilter.*","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@@ -2990,6 +3002,8 @@
{"recordType":"path","path":"channels.telegram.accounts.*.groups.*.allowFrom.*","kind":"channel","type":["number","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.groups.*.disableAudioPreflight","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.groups.*.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.groups.*.errorCooldownMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.groups.*.errorPolicy","kind":"channel","type":"string","required":false,"enumValues":["always","once","silent"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.groups.*.groupPolicy","kind":"channel","type":"string","required":false,"enumValues":["open","disabled","allowlist"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.groups.*.requireMention","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.groups.*.skills","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
@@ -3017,6 +3031,8 @@
{"recordType":"path","path":"channels.telegram.accounts.*.groups.*.topics.*.allowFrom.*","kind":"channel","type":["number","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.groups.*.topics.*.disableAudioPreflight","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.groups.*.topics.*.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.groups.*.topics.*.errorCooldownMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.groups.*.topics.*.errorPolicy","kind":"channel","type":"string","required":false,"enumValues":["always","once","silent"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.groups.*.topics.*.groupPolicy","kind":"channel","type":"string","required":false,"enumValues":["open","disabled","allowlist"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.groups.*.topics.*.requireMention","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.accounts.*.groups.*.topics.*.skills","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
@@ -3116,6 +3132,8 @@
{"recordType":"path","path":"channels.telegram.direct.*.autoTopicLabel.prompt","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.direct.*.dmPolicy","kind":"channel","type":"string","required":false,"enumValues":["pairing","allowlist","open","disabled"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.direct.*.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.direct.*.errorCooldownMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.direct.*.errorPolicy","kind":"channel","type":"string","required":false,"enumValues":["always","once","silent"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.direct.*.requireTopic","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.direct.*.skills","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"channels.telegram.direct.*.skills.*","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@@ -3142,6 +3160,8 @@
{"recordType":"path","path":"channels.telegram.direct.*.topics.*.allowFrom.*","kind":"channel","type":["number","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.direct.*.topics.*.disableAudioPreflight","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.direct.*.topics.*.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.direct.*.topics.*.errorCooldownMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.direct.*.topics.*.errorPolicy","kind":"channel","type":"string","required":false,"enumValues":["always","once","silent"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.direct.*.topics.*.groupPolicy","kind":"channel","type":"string","required":false,"enumValues":["open","disabled","allowlist"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.direct.*.topics.*.requireMention","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.direct.*.topics.*.skills","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
@@ -3157,6 +3177,8 @@
{"recordType":"path","path":"channels.telegram.draftChunk.maxChars","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.draftChunk.minChars","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.errorCooldownMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.errorPolicy","kind":"channel","type":"string","required":false,"enumValues":["always","once","silent"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.execApprovals","kind":"channel","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["channels","network"],"label":"Telegram Exec Approvals","help":"Telegram-native exec approval routing and approver authorization. Enable this only when Telegram should act as an explicit exec-approval client for the selected bot account.","hasChildren":true}
{"recordType":"path","path":"channels.telegram.execApprovals.agentFilter","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["channels","network"],"label":"Telegram Exec Approval Agent Filter","help":"Optional allowlist of agent IDs eligible for Telegram exec approvals, for example `[\"main\", \"ops-agent\"]`. Use this to keep approval prompts scoped to the agents you actually operate from Telegram.","hasChildren":true}
{"recordType":"path","path":"channels.telegram.execApprovals.agentFilter.*","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@@ -3175,6 +3197,8 @@
{"recordType":"path","path":"channels.telegram.groups.*.allowFrom.*","kind":"channel","type":["number","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.groups.*.disableAudioPreflight","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.groups.*.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.groups.*.errorCooldownMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.groups.*.errorPolicy","kind":"channel","type":"string","required":false,"enumValues":["always","once","silent"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.groups.*.groupPolicy","kind":"channel","type":"string","required":false,"enumValues":["open","disabled","allowlist"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.groups.*.requireMention","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.groups.*.skills","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
@@ -3202,6 +3226,8 @@
{"recordType":"path","path":"channels.telegram.groups.*.topics.*.allowFrom.*","kind":"channel","type":["number","string"],"required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.groups.*.topics.*.disableAudioPreflight","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.groups.*.topics.*.enabled","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.groups.*.topics.*.errorCooldownMs","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.groups.*.topics.*.errorPolicy","kind":"channel","type":"string","required":false,"enumValues":["always","once","silent"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.groups.*.topics.*.groupPolicy","kind":"channel","type":"string","required":false,"enumValues":["open","disabled","allowlist"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.groups.*.topics.*.requireMention","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.telegram.groups.*.topics.*.skills","kind":"channel","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
@@ -3392,6 +3418,7 @@
{"recordType":"path","path":"channels.whatsapp.accounts.*.mediaMaxMb","kind":"channel","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.whatsapp.accounts.*.messagePrefix","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.whatsapp.accounts.*.name","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.whatsapp.accounts.*.reactionLevel","kind":"channel","type":"string","required":false,"enumValues":["off","ack","minimal","extensive"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.whatsapp.accounts.*.responsePrefix","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.whatsapp.accounts.*.selfChatMode","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.whatsapp.accounts.*.sendReadReceipts","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@@ -3456,6 +3483,7 @@
{"recordType":"path","path":"channels.whatsapp.markdown.tables","kind":"channel","type":"string","required":false,"enumValues":["off","bullets","code","block"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.whatsapp.mediaMaxMb","kind":"channel","type":"integer","required":true,"defaultValue":50,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.whatsapp.messagePrefix","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.whatsapp.reactionLevel","kind":"channel","type":"string","required":false,"enumValues":["off","ack","minimal","extensive"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.whatsapp.responsePrefix","kind":"channel","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"channels.whatsapp.selfChatMode","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["channels","network"],"label":"WhatsApp Self-Phone Mode","help":"Same-phone setup (bot uses your personal WhatsApp number).","hasChildren":false}
{"recordType":"path","path":"channels.whatsapp.sendReadReceipts","kind":"channel","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@@ -3790,6 +3818,8 @@
{"recordType":"path","path":"gateway.tools.deny.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"gateway.trustedProxies","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["network"],"label":"Gateway Trusted Proxy CIDRs","help":"CIDR/IP allowlist of upstream proxies permitted to provide forwarded client identity headers. Keep this list narrow so untrusted hops cannot impersonate users.","hasChildren":true}
{"recordType":"path","path":"gateway.trustedProxies.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"gateway.webchat","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"gateway.webchat.chatHistoryMaxChars","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["network","performance"],"label":"WebChat History Max Chars","help":"Max characters per text field in chat.history responses before truncation (default: 12000).","hasChildren":false}
{"recordType":"path","path":"hooks","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Hooks","help":"Inbound webhook automation surface for mapping external events into wake or agent actions in OpenClaw. Keep this locked down with explicit token/session/agent controls before exposing it beyond trusted networks.","hasChildren":true}
{"recordType":"path","path":"hooks.allowedAgentIds","kind":"core","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Hooks Allowed Agent IDs","help":"Allowlist of agent IDs that hook mappings are allowed to target when selecting execution agents. Use this to constrain automation events to dedicated service agents and reduce blast radius if a hook token is exposed.","hasChildren":true}
{"recordType":"path","path":"hooks.allowedAgentIds.*","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
@@ -4145,7 +4175,12 @@
{"recordType":"path","path":"plugins.entries.acpx.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.acpx.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.amazon-bedrock","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/amazon-bedrock-provider","help":"OpenClaw Amazon Bedrock provider plugin (plugin: amazon-bedrock)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/amazon-bedrock-provider Config","help":"Plugin-defined config payload for amazon-bedrock.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/amazon-bedrock-provider Config","help":"Plugin-defined config payload for amazon-bedrock.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.config.guardrail","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.config.guardrail.guardrailIdentifier","kind":"plugin","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.config.guardrail.guardrailVersion","kind":"plugin","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.config.guardrail.streamProcessingMode","kind":"plugin","type":"string","required":false,"enumValues":["sync","async"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.config.guardrail.trace","kind":"plugin","type":"string","required":false,"enumValues":["enabled","disabled","enabled_full"],"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/amazon-bedrock-provider","hasChildren":false}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.amazon-bedrock.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
@@ -4298,6 +4333,7 @@
{"recordType":"path","path":"plugins.entries.diffs.config.defaults.wordWrap","kind":"plugin","type":"boolean","required":false,"defaultValue":true,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Default Word Wrap","help":"Wrap long lines by default.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.diffs.config.security","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"plugins.entries.diffs.config.security.allowRemoteViewer","kind":"plugin","type":"boolean","required":false,"defaultValue":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Remote Viewer","help":"Allow non-loopback access to diff viewer URLs when the token path is known.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.diffs.config.viewerBaseUrl","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Viewer Base URL","help":"Persistent gateway base URL used for returned viewer links when a tool call does not pass baseUrl.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.diffs.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable Diffs","hasChildren":false}
{"recordType":"path","path":"plugins.entries.diffs.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.diffs.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
@@ -4366,6 +4402,12 @@
{"recordType":"path","path":"plugins.entries.feishu.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.firecrawl","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/firecrawl-plugin","help":"OpenClaw Firecrawl plugin (plugin: firecrawl)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.firecrawl.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/firecrawl-plugin Config","help":"Plugin-defined config payload for firecrawl.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.firecrawl.config.webFetch","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"plugins.entries.firecrawl.config.webFetch.apiKey","kind":"plugin","type":["object","string"],"required":false,"deprecated":false,"sensitive":true,"tags":["auth","security"],"label":"Firecrawl Fetch API Key","help":"Firecrawl API key for web fetch fallback (fallback: FIRECRAWL_API_KEY env var).","hasChildren":false}
{"recordType":"path","path":"plugins.entries.firecrawl.config.webFetch.baseUrl","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced","url-secret"],"label":"Firecrawl Fetch Base URL","help":"Firecrawl Fetch base URL override.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.firecrawl.config.webFetch.maxAgeMs","kind":"plugin","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.firecrawl.config.webFetch.onlyMainContent","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.firecrawl.config.webFetch.timeoutSeconds","kind":"plugin","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.firecrawl.config.webSearch","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"plugins.entries.firecrawl.config.webSearch.apiKey","kind":"plugin","type":["object","string"],"required":false,"deprecated":false,"sensitive":true,"tags":["auth","security"],"label":"Firecrawl Search API Key","help":"Firecrawl API key for web search (fallback: FIRECRAWL_API_KEY env var).","hasChildren":false}
{"recordType":"path","path":"plugins.entries.firecrawl.config.webSearch.baseUrl","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced","url-secret"],"label":"Firecrawl Search Base URL","help":"Firecrawl Search base URL override.","hasChildren":false}
@@ -4778,6 +4820,19 @@
{"recordType":"path","path":"plugins.entries.qqbot.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.qqbot.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.qqbot.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.searxng","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/searxng-plugin","help":"OpenClaw SearXNG plugin (plugin: searxng)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.searxng.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/searxng-plugin Config","help":"Plugin-defined config payload for searxng.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.searxng.config.webSearch","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"plugins.entries.searxng.config.webSearch.baseUrl","kind":"plugin","type":["object","string"],"required":false,"deprecated":false,"sensitive":false,"tags":["advanced","url-secret"],"label":"SearXNG Base URL","help":"Base URL of your SearXNG instance, such as http://localhost:8080 or https://search.example.com/searxng.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.searxng.config.webSearch.categories","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"SearXNG Categories","help":"Optional comma-separated categories such as general, news, or science.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.searxng.config.webSearch.language","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"SearXNG Language","help":"Optional language code for results such as en, de, or fr.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.searxng.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/searxng-plugin","hasChildren":false}
{"recordType":"path","path":"plugins.entries.searxng.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.searxng.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.searxng.subagent","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Subagent Policy","help":"Per-plugin subagent runtime controls for model override trust and allowlists. Keep this unset unless a plugin must explicitly steer subagent model selection.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.searxng.subagent.allowedModels","kind":"plugin","type":"array","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Plugin Subagent Allowed Models","help":"Allowed override targets for trusted plugin subagent runs as canonical \"provider/model\" refs. Use \"*\" only when you intentionally allow any model.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.searxng.subagent.allowedModels.*","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"plugins.entries.searxng.subagent.allowModelOverride","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Plugin Subagent Model Override","help":"Explicitly allows this plugin to request provider/model overrides in background subagent runs. Keep false unless the plugin is trusted to steer model selection.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.sglang","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/sglang-provider","help":"OpenClaw SGLang provider plugin (plugin: sglang)","hasChildren":true}
{"recordType":"path","path":"plugins.entries.sglang.config","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"@openclaw/sglang-provider Config","help":"Plugin-defined config payload for sglang.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.sglang.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/sglang-provider","hasChildren":false}
@@ -5087,6 +5142,13 @@
{"recordType":"path","path":"plugins.entries.xai.config.webSearch.apiKey","kind":"plugin","type":["object","string"],"required":false,"deprecated":false,"sensitive":true,"tags":["auth","security"],"label":"Grok Search API Key","help":"xAI API key for Grok web search (fallback: XAI_API_KEY env var).","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xai.config.webSearch.inlineCitations","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Inline Citations","help":"Include inline markdown citations in Grok responses.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xai.config.webSearch.model","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["models"],"label":"Grok Search Model","help":"Grok model override for web search.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xai.config.xSearch","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"plugins.entries.xai.config.xSearch.cacheTtlMinutes","kind":"plugin","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":["performance","storage"],"label":"X Search Cache TTL","help":"Cache TTL in minutes for x_search results.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xai.config.xSearch.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable X Search","help":"Enable the x_search tool for searching X posts with xAI.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xai.config.xSearch.inlineCitations","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"X Search Inline Citations","help":"Keep inline markdown citations from xAI in x_search responses when available.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xai.config.xSearch.maxTurns","kind":"plugin","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":["performance"],"label":"X Search Max Turns","help":"Optional max internal tool turns xAI may use per x_search request.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xai.config.xSearch.model","kind":"plugin","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["models"],"label":"X Search Model","help":"xAI model override for x_search.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xai.config.xSearch.timeoutSeconds","kind":"plugin","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":["performance"],"label":"X Search Timeout","help":"Timeout in seconds for x_search requests.","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xai.enabled","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Enable @openclaw/xai-plugin","hasChildren":false}
{"recordType":"path","path":"plugins.entries.xai.hooks","kind":"plugin","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":["advanced"],"label":"Plugin Hook Policy","help":"Per-plugin typed hook policy controls for core-enforced safety gates. Use this to constrain high-impact hook categories without disabling the entire plugin.","hasChildren":true}
{"recordType":"path","path":"plugins.entries.xai.hooks.allowPromptInjection","kind":"plugin","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["access"],"label":"Allow Prompt Injection Hooks","help":"Controls whether this plugin may mutate prompts through typed hooks. Set false to block `before_prompt_build` and ignore prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride` behavior.","hasChildren":false}
@@ -5646,19 +5708,20 @@
{"recordType":"path","path":"tools.web.fetch.cacheTtlMinutes","kind":"core","type":"number","required":false,"deprecated":false,"sensitive":false,"tags":["performance","storage","tools"],"label":"Web Fetch Cache TTL (min)","help":"Cache TTL in minutes for web_fetch results.","hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.enabled","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["tools"],"label":"Enable Web Fetch Tool","help":"Enable the web_fetch tool (lightweight HTTP fetch).","hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.firecrawl","kind":"core","type":"object","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":true}
{"recordType":"path","path":"tools.web.fetch.firecrawl.apiKey","kind":"core","type":["object","string"],"required":false,"deprecated":false,"sensitive":true,"tags":["auth","security","tools"],"label":"Firecrawl API Key","help":"Firecrawl API key (fallback: FIRECRAWL_API_KEY env var).","hasChildren":true}
{"recordType":"path","path":"tools.web.fetch.firecrawl.apiKey","kind":"core","type":["object","string"],"required":false,"deprecated":false,"sensitive":true,"tags":["auth","security","tools"],"hasChildren":true}
{"recordType":"path","path":"tools.web.fetch.firecrawl.apiKey.id","kind":"core","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.firecrawl.apiKey.provider","kind":"core","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.firecrawl.apiKey.source","kind":"core","type":"string","required":true,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.firecrawl.baseUrl","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["tools","url-secret"],"label":"Firecrawl Base URL","help":"Firecrawl base URL (e.g. https://api.firecrawl.dev or custom endpoint).","hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.firecrawl.enabled","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["tools"],"label":"Enable Firecrawl Fallback","help":"Enable Firecrawl fallback for web_fetch (if configured).","hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.firecrawl.maxAgeMs","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance","tools"],"label":"Firecrawl Cache Max Age (ms)","help":"Firecrawl maxAge (ms) for cached results when supported by the API.","hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.firecrawl.onlyMainContent","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["tools"],"label":"Firecrawl Main Content Only","help":"When true, Firecrawl returns only the main content (default: true).","hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.firecrawl.timeoutSeconds","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance","tools"],"label":"Firecrawl Timeout (sec)","help":"Timeout in seconds for Firecrawl requests.","hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.firecrawl.baseUrl","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["tools","url-secret"],"hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.firecrawl.enabled","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.firecrawl.maxAgeMs","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.firecrawl.onlyMainContent","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.firecrawl.timeoutSeconds","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":[],"hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.maxChars","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance","tools"],"label":"Web Fetch Max Chars","help":"Max characters returned by web_fetch (truncated).","hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.maxCharsCap","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance","tools"],"label":"Web Fetch Hard Max Chars","help":"Hard cap for web_fetch maxChars (applies to config and tool calls).","hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.maxRedirects","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance","storage","tools"],"label":"Web Fetch Max Redirects","help":"Maximum redirects allowed for web_fetch (default: 3).","hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.maxResponseBytes","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance","tools"],"label":"Web Fetch Max Download Size (bytes)","help":"Max download size before truncation.","hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.provider","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["tools"],"label":"Web Fetch Provider","help":"Web fetch fallback provider id.","hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.readability","kind":"core","type":"boolean","required":false,"deprecated":false,"sensitive":false,"tags":["tools"],"label":"Web Fetch Readability Extraction","help":"Use Readability to extract main content from HTML (fallbacks to basic HTML cleanup).","hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.timeoutSeconds","kind":"core","type":"integer","required":false,"deprecated":false,"sensitive":false,"tags":["performance","tools"],"label":"Web Fetch Timeout (sec)","help":"Timeout in seconds for web_fetch requests.","hasChildren":false}
{"recordType":"path","path":"tools.web.fetch.userAgent","kind":"core","type":"string","required":false,"deprecated":false,"sensitive":false,"tags":["tools"],"label":"Web Fetch User-Agent","help":"Override User-Agent header for web_fetch requests.","hasChildren":false}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@@ -0,0 +1,16 @@
<svg width="126" height="20" viewBox="0 0 126 20" fill="black" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5_2)">
<path d="M3.18483 17.4674C1.30005 15.782 0.357666 13.2908 0.357666 10.0003C0.357666 6.70977 1.31835 4.2186 3.24278 2.53321C5.16415 0.847812 7.79308 0.00350952 11.1265 0.00350952C12.5111 0.00350952 13.7341 0.103028 14.7985 0.308486C15.8629 0.510733 16.8815 0.854231 17.8544 1.34219V6.68088C16.3417 5.92646 14.6246 5.54765 12.7033 5.54765C11.0106 5.54765 9.76021 5.88473 8.95506 6.55889C8.14686 7.23304 7.74429 8.37911 7.74429 10.0003C7.74429 11.5669 8.14076 12.7001 8.93676 13.4C9.72971 14.103 10.9862 14.453 12.7063 14.453C14.527 14.453 16.2563 14.0067 17.8971 13.1175V18.7034C16.0763 19.5669 13.8073 19.9971 11.0899 19.9971C7.70159 19.9971 5.06961 19.1528 3.18483 17.4674Z" />
<path d="M19.538 9.99679C19.538 6.73194 20.4224 4.2504 22.1913 2.54896C23.9602 0.847512 26.6257 0 30.1909 0C33.7805 0 36.4644 0.850722 38.2485 2.54896C40.0296 4.24719 40.9201 6.73194 40.9201 9.99679C40.9201 16.6613 37.3427 19.9936 30.1909 19.9936C23.0879 19.9968 19.538 16.6645 19.538 9.99679ZM32.7497 13.3997C33.2743 12.6966 33.5365 11.5634 33.5365 10C33.5365 8.46228 33.2743 7.33547 32.7497 6.61958C32.2251 5.90369 31.3712 5.54735 30.1909 5.54735C29.0381 5.54735 28.2024 5.9069 27.6901 6.61958C27.1777 7.33547 26.9215 8.46228 26.9215 10C26.9215 11.5666 27.1777 12.6998 27.6901 13.3997C28.2024 14.1027 29.035 14.4526 30.1909 14.4526C31.3712 14.4526 32.2221 14.0995 32.7497 13.3997Z" />
<path d="M42.6029 0.404494H49.3704L49.5626 1.86196C50.3067 1.32263 51.2552 0.876404 52.408 0.526485C53.5608 0.176565 54.7533 0 55.9854 0C58.2667 0 59.9319 0.5939 60.9841 1.7817C62.0363 2.9695 62.5608 4.80257 62.5608 7.28732V19.5923H55.3328V8.05458C55.3328 7.19101 55.1467 6.57143 54.7747 6.19262C54.4026 5.8138 53.7804 5.62761 52.9082 5.62761C52.3714 5.62761 51.8194 5.75602 51.2552 6.01284C50.691 6.26966 50.2183 6.60032 49.8309 7.00482V19.5923H42.6029V0.404494Z" />
<path d="M62.5818 0.404617H70.1178L73.5794 11.6566L77.0409 0.404617H84.5769L77.3855 19.5924H69.7702L62.5818 0.404617Z" />
<path d="M86.8523 17.9422C84.6809 16.2279 83.6653 13.252 83.6653 10.0385C83.6653 6.90851 84.4735 4.33066 86.3186 2.54896C88.1637 0.767255 90.9757 0 94.5256 0C97.792 0 100.36 0.796147 102.236 2.38844C104.108 3.98074 105.047 6.15409 105.047 8.9053V12.2665H91.302C91.6436 13.2648 92.0766 13.9872 93.141 14.4334C94.2054 14.8796 95.6907 15.1011 97.5907 15.1011C98.7252 15.1011 99.8841 15.008 101.061 14.8186C101.476 14.7512 102.159 14.6453 102.519 14.565V19.2295C100.723 19.7432 98.3287 20 95.6297 20C91.9973 19.9968 89.0238 19.6565 86.8523 17.9422ZM97.4534 8.13804C97.4534 7.1878 96.4135 5.14286 94.3243 5.14286C92.4396 5.14286 91.1952 7.1557 91.1952 8.13804H97.4534Z" />
<path d="M110.723 9.8364L103.955 0.404617H111.799L125.642 19.5924H117.722L114.645 15.3003L111.567 19.5924H103.684L110.723 9.8364Z" />
<path d="M117.548 0.404617H125.356L119.363 8.8059L115.398 3.42227L117.548 0.404617Z" />
</g>
<defs>
<clipPath id="clip0_5_2">
<rect width="126" height="20" />
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 164 30" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g>
<path d="M160.352,24.069L160.352,23.62L160.64,23.62C160.797,23.62 161.011,23.632 161.011,23.824C161.011,24.032 160.901,24.069 160.715,24.069L160.352,24.069M160.352,24.384L160.544,24.384L160.991,25.168L161.481,25.168L160.987,24.352C161.242,24.333 161.452,24.212 161.452,23.868C161.452,23.441 161.157,23.303 160.659,23.303L159.938,23.303L159.938,25.168L160.352,25.168L160.352,24.384M162.45,24.238C162.45,23.143 161.599,22.508 160.65,22.508C159.695,22.508 158.845,23.143 158.845,24.238C158.845,25.333 159.695,25.971 160.65,25.971C161.598,25.971 162.45,25.333 162.45,24.238M161.93,24.238C161.93,25.036 161.343,25.572 160.65,25.572L160.65,25.566C159.937,25.572 159.361,25.036 159.361,24.238C159.361,23.441 159.938,22.907 160.65,22.907C161.344,22.907 161.93,23.441 161.93,24.238" style="fill:white;"/>
<path d="M96.374,5.707L96.376,25.367L101.928,25.367L101.928,5.707L96.374,5.707ZM52.697,5.681L52.697,25.367L58.3,25.367L58.3,10.086L62.67,10.1C64.107,10.1 65.1,10.445 65.793,11.184C66.672,12.12 67.03,13.628 67.03,16.389L67.03,25.367L72.457,25.367L72.457,14.49C72.457,6.727 67.509,5.68 62.668,5.68L52.698,5.68L52.697,5.681ZM105.314,5.708L105.314,25.367L114.32,25.367C119.118,25.367 120.684,24.569 122.377,22.78C123.575,21.524 124.348,18.766 124.348,15.753C124.348,12.99 123.693,10.525 122.551,8.99C120.494,6.245 117.531,5.708 113.106,5.708L105.314,5.708ZM110.822,9.988L113.209,9.988C116.672,9.988 118.912,11.544 118.912,15.579C118.912,19.616 116.672,21.171 113.209,21.171L110.822,21.171L110.822,9.988ZM88.369,5.708L83.735,21.288L79.295,5.709L73.302,5.708L79.642,25.367L87.645,25.367L94.036,5.708L88.369,5.708ZM126.932,25.367L132.485,25.367L132.485,5.709L126.93,5.708L126.932,25.367ZM142.496,5.715L134.743,25.36L140.218,25.36L141.445,21.888L150.62,21.888L151.781,25.36L157.725,25.36L149.913,5.714L142.496,5.715ZM146.1,9.3L149.464,18.504L142.631,18.504L146.101,9.3L146.1,9.3Z" style="fill:white;"/>
<path d="M16.889,8.985L16.889,6.28C17.151,6.26 17.417,6.247 17.687,6.238C25.087,6.006 29.942,12.597 29.942,12.597C29.942,12.597 24.698,19.879 19.076,19.879C18.333,19.882 17.594,19.764 16.889,19.529L16.889,11.325C19.769,11.673 20.349,12.945 22.081,15.833L25.933,12.585C25.933,12.585 23.121,8.897 18.381,8.897C17.866,8.897 17.373,8.933 16.889,8.985ZM16.889,0.047L16.889,4.09C17.154,4.069 17.42,4.052 17.687,4.042C27.977,3.696 34.682,12.482 34.682,12.482C34.682,12.482 26.982,21.846 18.959,21.846C18.224,21.846 17.535,21.778 16.889,21.663L16.889,24.161C17.442,24.231 18.015,24.273 18.613,24.273C26.078,24.273 31.477,20.461 36.705,15.948C37.572,16.642 41.121,18.331 41.85,19.071C36.879,23.231 25.295,26.586 18.727,26.586C18.113,26.584 17.5,26.552 16.889,26.49L16.889,30L45.264,30L45.264,0.047L16.889,0.047ZM16.889,19.529L16.889,21.662C9.984,20.432 8.067,13.254 8.067,13.254C8.067,13.254 11.383,9.58 16.889,8.985L16.889,11.325L16.878,11.324C13.988,10.977 11.731,13.677 11.731,13.677C11.731,13.677 12.996,18.221 16.889,19.529ZM4.625,12.943C4.625,12.943 8.717,6.903 16.889,6.28L16.889,4.088C7.838,4.815 0,12.48 0,12.48C0,12.48 4.439,25.313 16.889,26.488L16.889,24.16C7.753,23.011 4.625,12.943 4.625,12.943Z" style="fill:rgb(118,185,0);"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 164 30" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g>
<path d="M160.352,24.069L160.352,23.62L160.64,23.62C160.797,23.62 161.011,23.632 161.011,23.824C161.011,24.032 160.901,24.069 160.715,24.069L160.352,24.069M160.352,24.384L160.544,24.384L160.991,25.168L161.481,25.168L160.987,24.352C161.242,24.333 161.452,24.212 161.452,23.868C161.452,23.441 161.157,23.303 160.659,23.303L159.938,23.303L159.938,25.168L160.352,25.168L160.352,24.384M162.45,24.238C162.45,23.143 161.599,22.508 160.65,22.508C159.695,22.508 158.845,23.143 158.845,24.238C158.845,25.333 159.695,25.971 160.65,25.971C161.598,25.971 162.45,25.333 162.45,24.238M161.93,24.238C161.93,25.036 161.343,25.572 160.65,25.572L160.65,25.566C159.937,25.572 159.361,25.036 159.361,24.238C159.361,23.441 159.938,22.907 160.65,22.907C161.344,22.907 161.93,23.441 161.93,24.238" style="fill:black;"/>
<path d="M96.374,5.707L96.376,25.367L101.928,25.367L101.928,5.707L96.374,5.707ZM52.697,5.681L52.697,25.367L58.3,25.367L58.3,10.086L62.67,10.1C64.107,10.1 65.1,10.445 65.793,11.184C66.672,12.12 67.03,13.628 67.03,16.389L67.03,25.367L72.457,25.367L72.457,14.49C72.457,6.727 67.509,5.68 62.668,5.68L52.698,5.68L52.697,5.681ZM105.314,5.708L105.314,25.367L114.32,25.367C119.118,25.367 120.684,24.569 122.377,22.78C123.575,21.524 124.348,18.766 124.348,15.753C124.348,12.99 123.693,10.525 122.551,8.99C120.494,6.245 117.531,5.708 113.106,5.708L105.314,5.708ZM110.822,9.988L113.209,9.988C116.672,9.988 118.912,11.544 118.912,15.579C118.912,19.616 116.672,21.171 113.209,21.171L110.822,21.171L110.822,9.988ZM88.369,5.708L83.735,21.288L79.295,5.709L73.302,5.708L79.642,25.367L87.645,25.367L94.036,5.708L88.369,5.708ZM126.932,25.367L132.485,25.367L132.485,5.709L126.93,5.708L126.932,25.367ZM142.496,5.715L134.743,25.36L140.218,25.36L141.445,21.888L150.62,21.888L151.781,25.36L157.725,25.36L149.913,5.714L142.496,5.715ZM146.1,9.3L149.464,18.504L142.631,18.504L146.101,9.3L146.1,9.3Z" style="fill:black;"/>
<path d="M16.889,8.985L16.889,6.28C17.151,6.26 17.417,6.247 17.687,6.238C25.087,6.006 29.942,12.597 29.942,12.597C29.942,12.597 24.698,19.879 19.076,19.879C18.333,19.882 17.594,19.764 16.889,19.529L16.889,11.325C19.769,11.673 20.349,12.945 22.081,15.833L25.933,12.585C25.933,12.585 23.121,8.897 18.381,8.897C17.866,8.897 17.373,8.933 16.889,8.985ZM16.889,0.047L16.889,4.09C17.154,4.069 17.42,4.052 17.687,4.042C27.977,3.696 34.682,12.482 34.682,12.482C34.682,12.482 26.982,21.846 18.959,21.846C18.224,21.846 17.535,21.778 16.889,21.663L16.889,24.161C17.442,24.231 18.015,24.273 18.613,24.273C26.078,24.273 31.477,20.461 36.705,15.948C37.572,16.642 41.121,18.331 41.85,19.071C36.879,23.231 25.295,26.586 18.727,26.586C18.113,26.584 17.5,26.552 16.889,26.49L16.889,30L45.264,30L45.264,0.047L16.889,0.047ZM16.889,19.529L16.889,21.662C9.984,20.432 8.067,13.254 8.067,13.254C8.067,13.254 11.383,9.58 16.889,8.985L16.889,11.325L16.878,11.324C13.988,10.977 11.731,13.677 11.731,13.677C11.731,13.677 12.996,18.221 16.889,19.529ZM4.625,12.943C4.625,12.943 8.717,6.903 16.889,6.28L16.889,4.088C7.838,4.815 0,12.48 0,12.48C0,12.48 4.439,25.313 16.889,26.488L16.889,24.16C7.753,23.011 4.625,12.943 4.625,12.943Z" style="fill:rgb(118,185,0);"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black">
<path d="M22.282 9.821a5.985 5.985 0 0 0-.516-4.91 6.046 6.046 0 0 0-6.51-2.9A6.065 6.065 0 0 0 4.981 4.18a5.985 5.985 0 0 0-3.998 2.9 6.046 6.046 0 0 0 .743 7.097 5.98 5.98 0 0 0 .51 4.911 6.051 6.051 0 0 0 6.515 2.9A5.985 5.985 0 0 0 13.26 24a6.056 6.056 0 0 0 5.772-4.206 5.99 5.99 0 0 0 3.997-2.9 6.056 6.056 0 0 0-.747-7.073zM13.26 22.43a4.476 4.476 0 0 1-2.876-1.04l.141-.081 4.779-2.758a.795.795 0 0 0 .392-.681v-6.737l2.02 1.168a.071.071 0 0 1 .038.052v5.583a4.504 4.504 0 0 1-4.494 4.494zM3.6 18.304a4.47 4.47 0 0 1-.535-3.014l.142.085 4.783 2.759a.771.771 0 0 0 .78 0l5.843-3.369v2.332a.08.08 0 0 1-.033.062L9.74 19.95a4.5 4.5 0 0 1-6.14-1.646zM2.34 7.896a4.485 4.485 0 0 1 2.366-1.973V11.6a.766.766 0 0 0 .388.676l5.815 3.355-2.02 1.168a.076.076 0 0 1-.071 0l-4.83-2.786A4.504 4.504 0 0 1 2.34 7.872zm16.597 3.855l-5.833-3.387L15.119 7.2a.076.076 0 0 1 .071 0l4.83 2.791a4.494 4.494 0 0 1-.676 8.105v-5.678a.79.79 0 0 0-.407-.667zm2.01-3.023l-.141-.085-4.774-2.782a.776.776 0 0 0-.785 0L9.409 9.23V6.897a.066.066 0 0 1 .028-.061l4.83-2.787a4.5 4.5 0 0 1 6.68 4.66zm-12.64 4.135l-2.02-1.164a.08.08 0 0 1-.038-.057V6.075a4.5 4.5 0 0 1 7.375-3.453l-.142.08L8.704 5.46a.795.795 0 0 0-.393.681zm1.097-2.365l2.602-1.5 2.607 1.5v2.999l-2.597 1.5-2.607-1.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,5 @@
<svg width="256" height="51" viewBox="0 0 256 50.875" fill="none" xmlns="http://www.w3.org/2000/svg">
<g transform="scale(0.125)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M467.444 406.809L233.722 0.335938L0 406.809H467.444ZM703.186 388.306L898.51 18.813H814.024L679.286 287.152L544.547 18.813H460.061L655.385 388.306H703.186ZM2034.31 18.813V388.307H1964.37V18.813H2034.31ZM1644.98 250.395C1644.98 221.599 1650.99 196.272 1663.01 174.415C1675.03 152.557 1691.79 135.731 1713.28 123.935C1734.77 112.139 1759.91 106.241 1788.69 106.241C1814.19 106.241 1837.14 111.792 1857.54 122.894C1877.94 133.996 1894.15 150.476 1906.17 172.333C1918.19 194.191 1924.39 220.905 1924.75 252.477V268.61H1718.75C1720.2 291.508 1726.94 309.549 1738.96 322.733C1751.35 335.57 1767.93 341.988 1788.69 341.988C1801.8 341.988 1813.83 338.519 1824.75 331.58C1835.68 324.641 1843.88 315.274 1849.34 303.478L1920.93 308.682C1912.18 334.702 1895.79 355.519 1871.75 371.131C1847.7 386.744 1820.02 394.55 1788.69 394.55C1759.91 394.55 1734.77 388.652 1713.28 376.856C1691.79 365.06 1675.03 348.233 1663.01 326.376C1650.99 304.518 1644.98 279.192 1644.98 250.395ZM1852.62 224.375C1850.07 201.823 1842.97 185.344 1831.31 174.935C1819.65 164.18 1805.45 158.802 1788.69 158.802C1769.38 158.802 1753.72 164.527 1741.7 175.976C1729.67 187.425 1722.21 203.558 1719.29 224.375H1852.62ZM1526.96 174.935C1538.62 184.303 1545.9 197.313 1548.82 213.966L1620.94 210.323C1618.39 189.16 1610.93 170.772 1598.54 155.159C1586.15 139.547 1570.13 127.578 1550.45 119.251C1531.15 110.577 1509.84 106.241 1486.52 106.241C1457.74 106.241 1432.61 112.139 1411.11 123.935C1389.62 135.731 1372.86 152.557 1360.84 174.415C1348.82 196.272 1342.81 221.599 1342.81 250.395C1342.81 279.192 1348.82 304.518 1360.84 326.376C1372.86 348.233 1389.62 365.06 1411.11 376.856C1432.61 388.652 1457.74 394.55 1486.52 394.55C1510.56 394.55 1532.42 390.213 1552.09 381.54C1571.77 372.519 1587.79 359.856 1600.18 343.549C1612.57 327.243 1620.03 308.161 1622.58 286.304L1549.91 283.181C1547.36 301.569 1540.25 315.794 1528.6 325.855C1516.94 335.57 1502.91 340.427 1486.52 340.427C1463.94 340.427 1446.45 332.621 1434.06 317.008C1421.68 301.396 1415.49 279.192 1415.49 250.395C1415.49 221.599 1421.68 199.395 1434.06 183.782C1446.45 168.17 1463.94 160.364 1486.52 160.364C1502.19 160.364 1515.66 165.221 1526.96 174.935ZM1172.15 112.473H1237.24L1239.12 165.559C1243.74 150.533 1250.16 138.864 1258.39 130.552C1270.32 118.5 1286.96 112.473 1308.29 112.473H1334.87V169.293H1307.75C1292.56 169.293 1280.09 171.359 1270.32 175.491C1260.92 179.624 1253.69 186.166 1248.63 195.12C1243.93 204.073 1241.58 215.437 1241.58 229.211V388.306H1172.15V112.473ZM871.925 174.415C859.904 196.272 853.893 221.599 853.893 250.395C853.893 279.192 859.904 304.518 871.925 326.376C883.947 348.233 900.704 365.06 922.198 376.856C943.691 388.652 968.827 394.55 997.606 394.55C1028.93 394.55 1056.62 386.744 1080.66 371.131C1104.71 355.519 1121.1 334.702 1129.84 308.682L1058.26 303.478C1052.8 315.274 1044.6 324.641 1033.67 331.58C1022.74 338.519 1010.72 341.988 997.606 341.988C976.841 341.988 960.266 335.57 947.88 322.733C935.858 309.549 929.119 291.508 927.662 268.61H1133.67V252.477C1133.3 220.905 1127.11 194.191 1115.09 172.333C1103.07 150.476 1086.86 133.996 1066.46 122.894C1046.06 111.792 1023.11 106.241 997.606 106.241C968.827 106.241 943.691 112.139 922.198 123.935C900.704 135.731 883.947 152.557 871.925 174.415ZM1040.23 174.935C1051.88 185.344 1058.99 201.823 1061.54 224.375H928.208C931.123 203.558 938.591 187.425 950.612 175.976C962.634 164.527 978.298 158.802 997.606 158.802C1014.36 158.802 1028.57 164.18 1040.23 174.935Z" fill="black"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -1,109 +1,8 @@
---
summary: "ClawFlow workflow orchestration for background tasks and detached runs"
read_when:
- You want a flow to own one or more detached tasks
- You want to inspect or cancel a background job as a unit
- You want to understand how flows relate to tasks and background work
summary: "Redirect to TaskFlow"
title: "ClawFlow"
---
# ClawFlow
ClawFlow is the flow layer above [Background Tasks](/automation/tasks). Tasks still track detached work. ClawFlow groups those task runs into a single job, keeps the parent owner context, and gives you a flow-level control surface.
Use ClawFlow when the work is more than a single detached run. A flow can still be one task, but it can also coordinate multiple tasks in a simple linear sequence.
## TL;DR
- Tasks are the execution records.
- ClawFlow is the job-level wrapper above tasks.
- A flow keeps one owner/session context for the whole job.
- Use `openclaw flows list`, `openclaw flows show`, and `openclaw flows cancel` to inspect or manage flows.
## Quick start
```bash
openclaw flows list
openclaw flows show <flow-id-or-owner-session>
openclaw flows cancel <flow-id-or-owner-session>
```
## How it relates to tasks
Background tasks still do the low-level work:
- ACP runs
- subagent runs
- cron executions
- CLI-initiated runs
ClawFlow sits above that ledger:
- it keeps related task runs under one flow id
- it tracks the flow state separately from the individual task state
- it makes blocked or multi-step work easier to inspect from one place
For a single detached run, the flow can be a one-task flow. For more structured work, ClawFlow can keep multiple task runs under the same job.
## Runtime substrate
ClawFlow is the runtime substrate, not a workflow language.
It owns:
- the flow id
- the owner session and return context
- waiting state
- small persisted outputs
- finish, fail, cancel, and blocked state
It does **not** own branching or business logic. Put that in the authoring layer that sits above it:
- Lobster
- acpx
- plain TypeScript helpers
- bundled skills
In practice, authoring layers target a small runtime surface:
- `createFlow(...)`
- `runTaskInFlow(...)`
- `setFlowWaiting(...)`
- `setFlowOutput(...)`
- `appendFlowOutput(...)`
- `emitFlowUpdate(...)`
- `resumeFlow(...)`
- `finishFlow(...)`
- `failFlow(...)`
That keeps flow ownership and return-to-thread behavior in core without forcing a single DSL on top of it.
## Authoring pattern
The intended shape is linear:
1. Create one flow for the job.
2. Run one detached task under that flow.
3. Wait for the child task or outside event.
4. Resume the flow in the caller.
5. Spawn the next child task or finish.
ClawFlow persists the minimal state needed to resume that job: the current step, the task it is waiting on, and a small output bag for handoff between steps.
## CLI surface
The flow CLI is intentionally small:
- `openclaw flows list` shows active and recent flows
- `openclaw flows show <lookup>` shows one flow and its linked tasks
- `openclaw flows cancel <lookup>` cancels the flow and any active child tasks
`flows show` also surfaces the current wait target and any stored output keys, which is often enough to answer "what is this job waiting on?" without digging into every child task.
The lookup token accepts either a flow id or the owner session key.
## Related
- [Background Tasks](/automation/tasks) — detached work ledger
- [CLI: flows](/cli/flows) — flow inspection and control commands
- [Cron Jobs](/automation/cron-jobs) — scheduled jobs that may create tasks
ClawFlow was renamed to [TaskFlow](/automation/taskflow). See [TaskFlow](/automation/taskflow) for the current documentation.

View File

@@ -36,7 +36,7 @@ Troubleshooting: [/automation/troubleshooting](/automation/troubleshooting)
- Wakeups are first-class: a job can request “wake now” vs “next heartbeat”.
- Webhook posting is per job via `delivery.mode = "webhook"` + `delivery.to = "<url>"`.
- Legacy fallback remains for stored jobs with `notify: true` when `cron.webhook` is set, migrate those jobs to webhook delivery mode.
- For upgrades, `openclaw doctor --fix` can normalize legacy cron store fields before the scheduler touches them.
- For upgrades, `openclaw doctor --fix` can normalize legacy cron store fields, including old top-level delivery hints such as `threadId`.
## Quick start (actionable)
@@ -198,12 +198,14 @@ Common `agentTurn` fields:
- `model` / `thinking`: optional overrides (see below).
- `timeoutSeconds`: optional timeout override.
- `lightContext`: optional lightweight bootstrap mode for jobs that do not need workspace bootstrap file injection.
- `toolsAllow`: optional array of tool names to restrict which tools the job can use (e.g. `["exec", "read", "write"]`).
Delivery config:
- `delivery.mode`: `none` | `announce` | `webhook`.
- `delivery.channel`: `last` or a specific channel.
- `delivery.to`: channel-specific target (announce) or webhook URL (webhook mode).
- `delivery.threadId`: optional explicit thread or topic id when the target channel supports threaded delivery.
- `delivery.bestEffort`: avoid failing the job if announce delivery fails.
Announce delivery suppresses messaging tool sends for the run; use `delivery.channel`/`delivery.to`
@@ -272,6 +274,7 @@ Isolated jobs can deliver output to a channel via the top-level `delivery` confi
- `delivery.mode`: `announce` (channel delivery), `webhook` (HTTP POST), or `none`.
- `delivery.channel`: `last` or any deliverable channel id, for example `discord`, `matrix`, `telegram`, or `whatsapp`.
- `delivery.to`: channel-specific recipient target.
- `delivery.threadId`: optional thread/topic override for channels like Telegram, Slack, Discord, or Matrix when you want a specific thread without encoding it into `delivery.to`.
`announce` delivery is only valid for isolated jobs (`sessionTarget: "isolated"`).
`webhook` delivery is valid for both main and isolated jobs.
@@ -378,7 +381,8 @@ Notes:
- `"current"` is resolved to `"session:<sessionKey>"` at creation time.
- Custom sessions (`session:xxx`) maintain persistent context across runs.
- Optional fields: `agentId`, `description`, `enabled`, `deleteAfterRun` (defaults to true for `at`),
`delivery`.
`delivery`, `toolsAllow`.
- `toolsAllow`: optional array of tool names to restrict which tools the job can use (e.g. `["exec", "read"]`). Omit or set `null` to use all tools.
- `wakeMode` defaults to `"now"` when omitted.
### cron.update params
@@ -665,6 +669,19 @@ openclaw cron edit <jobId> --agent ops
openclaw cron edit <jobId> --clear-agent
```
Tool allowlists (restrict which tools a job can use):
```bash
# Only allow exec and read tools for this job
openclaw cron add --name "Scoped job" --cron "0 8 * * *" --session isolated --message "Run scoped checks" --tools exec,read
# Update an existing job's tool allowlist
openclaw cron edit <jobId> --tools exec,read,write
# Remove a tool allowlist (use all tools)
openclaw cron edit <jobId> --clear-tools
```
Manual run (force is the default, use `--due` to only run when due):
```bash

View File

@@ -607,7 +607,7 @@ Compaction lifecycle hooks exposed through the plugin hook runner:
### Complete Plugin Hook Reference
All 27 hooks registered via the Plugin SDK. Hooks marked **sequential** run in priority order and can modify results; **parallel** hooks are fire-and-forget.
All 28 hooks registered via the Plugin SDK. Hooks marked **sequential** run in priority order and can modify results; **parallel** hooks are fire-and-forget.
#### Model and prompt hooks
@@ -616,6 +616,7 @@ All 27 hooks registered via the Plugin SDK. Hooks marked **sequential** run in p
| `before_model_resolve` | Before model/provider lookup | Sequential | `{ modelOverride?, providerOverride? }` |
| `before_prompt_build` | After model resolved, session messages ready | Sequential | `{ systemPrompt?, prependContext?, appendSystemContext? }` |
| `before_agent_start` | Legacy combined hook (prefer the two above) | Sequential | Union of both result shapes |
| `before_agent_reply` | After inline actions, before the LLM runs | Sequential | `{ handled: boolean, reply?, reason? }` |
| `llm_input` | Immediately before the LLM API call | Parallel | `void` |
| `llm_output` | Immediately after LLM response received | Parallel | `void` |

View File

@@ -51,19 +51,16 @@ The most effective setups combine multiple mechanisms:
3. **Hooks** react to specific events (tool calls, session resets, compaction) with custom scripts.
4. **Standing Orders** give the agent persistent context ("always check the project board before replying").
5. **Background Tasks** automatically track all detached work so you can inspect and audit it.
6. **ClawFlow** groups related detached tasks into a single flow when the work needs a higher-level job view.
See [Cron vs Heartbeat](/automation/cron-vs-heartbeat) for a detailed comparison of the two scheduling mechanisms.
## ClawFlow
## TaskFlow
ClawFlow sits above [Background Tasks](/automation/tasks). Tasks still track the detached runs, while ClawFlow groups related task runs into one job that you can inspect or cancel from the CLI.
See [ClawFlow](/automation/clawflow) for the flow overview and [CLI: flows](/cli/flows) for the command surface.
[TaskFlow](/automation/taskflow) is the flow orchestration substrate above background tasks. It manages durable multi-step flows with managed and mirrored sync modes, and exposes `openclaw flows list|show|cancel` for inspection and recovery. See [TaskFlow](/automation/taskflow) for details.
## Related
- [Cron vs Heartbeat](/automation/cron-vs-heartbeat) — detailed comparison guide
- [ClawFlow](/automation/clawflow) — flow-level orchestration above tasks
- [TaskFlow](/automation/taskflow) — flow orchestration above tasks
- [Troubleshooting](/automation/troubleshooting) — debugging automation issues
- [Configuration Reference](/gateway/configuration-reference) — all config keys

View File

@@ -0,0 +1,51 @@
---
summary: "TaskFlow flow orchestration layer above background tasks"
read_when:
- You want to understand how TaskFlow relates to background tasks
- You encounter TaskFlow or openclaw flows in release notes or docs
- You want to inspect or manage durable flow state
title: "TaskFlow"
---
# TaskFlow
TaskFlow is the flow orchestration substrate that sits above [background tasks](/automation/tasks). It manages durable multi-step flows with their own state, revision tracking, and sync semantics while individual tasks remain the unit of detached work.
## Sync modes
TaskFlow supports two sync modes:
- **Managed** — TaskFlow owns the lifecycle end-to-end, creating and driving tasks as flow steps progress.
- **Mirrored** — TaskFlow observes externally created tasks and keeps flow state in sync without taking ownership of task creation.
## Durable state and revision tracking
Each flow persists its own state and tracks revisions so progress survives gateway restarts. Revision tracking enables conflict detection when multiple sources attempt to advance the same flow.
## CLI commands
```bash
# List active and recent flows
openclaw flows list
# Show details for a specific flow
openclaw flows show <lookup>
# Cancel a running flow
openclaw flows cancel <lookup>
```
- `openclaw flows list` — shows tracked flows with status and sync mode
- `openclaw flows show <lookup>` — inspect one flow by flow id or lookup key
- `openclaw flows cancel <lookup>` — cancel a running flow and its active tasks
## How flows relate to tasks
Flows coordinate tasks, not replace them. A single flow may drive multiple background tasks over its lifetime. Use `openclaw tasks` to inspect individual task records and `openclaw flows` to inspect the orchestrating flow.
## Related
- [Background Tasks](/automation/tasks) — the detached work ledger that flows coordinate
- [CLI: flows](/cli/flows) — CLI command reference for `openclaw flows`
- [Automation Overview](/automation) — all automation mechanisms at a glance
- [Cron Jobs](/automation/cron-jobs) — scheduled jobs that may feed into flows

View File

@@ -172,6 +172,16 @@ Surfaces operational issues. Findings also appear in `openclaw status` when issu
| `missing_cleanup` | warn | Terminal task with no cleanup timestamp |
| `inconsistent_timestamps` | warn | Timeline violation (for example ended before started) |
## Chat task board (`/tasks`)
Use `/tasks` in any chat session to see background tasks linked to that session. The board shows
active and recently completed tasks with runtime, status, timing, and progress or error detail.
When the current session has no visible linked tasks, `/tasks` falls back to agent-local task counts
so you still get an overview without leaking other-session details.
For the full operator ledger, use the CLI: `openclaw tasks list`.
## Status integration (task pressure)
`openclaw status` includes an at-a-glance task summary:
@@ -186,6 +196,10 @@ The summary reports:
- **failures** — count of `failed` + `timed_out` + `lost`
- **byRuntime** — breakdown by `acp`, `subagent`, `cron`, `cli`
Both `/status` and the `session_status` tool use a cleanup-aware task snapshot: active tasks are
preferred, stale completed rows are hidden, and recent failures only surface when no active work
remains. This keeps the status card focused on what matters right now.
## Storage and maintenance
### Where tasks live
@@ -210,11 +224,11 @@ A sweeper runs every **60 seconds** and handles three things:
## How tasks relate to other systems
### Tasks and ClawFlow
### Tasks and TaskFlow
ClawFlow is the flow layer above tasks. A flow groups one or more task runs into a single job, owns the parent session context, and gives you a higher-level control surface for blocked or multi-step work.
[TaskFlow](/automation/taskflow) is the flow orchestration layer above background tasks. A single flow may coordinate multiple tasks over its lifetime using managed or mirrored sync modes. Use `openclaw tasks` to inspect individual task records and `openclaw flows` to inspect the orchestrating flow.
See [ClawFlow](/automation/clawflow) for the flow overview and [CLI: flows](/cli/flows) for the command surface.
See [TaskFlow](/automation/taskflow) and [CLI: flows](/cli/flows) for details.
### Tasks and cron
@@ -239,9 +253,9 @@ A task's `runId` links to the agent run doing the work. Agent lifecycle events (
## Related
- [Automation Overview](/automation) — all automation mechanisms at a glance
- [ClawFlow](/automation/clawflow) — job-level orchestration above tasks
- [TaskFlow](/automation/taskflow) — flow orchestration above tasks
- [Cron Jobs](/automation/cron-jobs) — scheduling background work
- [Cron vs Heartbeat](/automation/cron-vs-heartbeat) — choosing the right mechanism
- [Heartbeat](/gateway/heartbeat) — periodic main-session turns
- [CLI: flows](/cli/flows) — flow inspection and control commands
- [CLI: flows](/cli/flows) — CLI reference for `openclaw flows`
- [CLI: Tasks](/cli/index#tasks) — CLI command reference

View File

@@ -192,7 +192,7 @@ In group `120363403215116621@g.us` with agents `["alfred", "baerbel"]`:
```
Session: agent:alfred:whatsapp:group:120363403215116621@g.us
History: [user message, alfred's previous responses]
Workspace: /Users/pascal/openclaw-alfred/
Workspace: /Users/user/openclaw-alfred/
Tools: read, write, exec
```
@@ -201,7 +201,7 @@ Tools: read, write, exec
```
Session: agent:baerbel:whatsapp:group:120363403215116621@g.us
History: [user message, baerbel's previous responses]
Workspace: /Users/pascal/openclaw-baerbel/
Workspace: /Users/user/openclaw-baerbel/
Tools: read only
```

View File

@@ -148,6 +148,7 @@ In **Event Subscription**:
1. Choose **Use long connection to receive events** (WebSocket)
2. Add the event: `im.message.receive_v1`
3. (Optional) For Drive comment workflows, also add: `drive.notice.comment_add_v1`
⚠️ If the gateway is not running, the long-connection setup may fail to save.
@@ -735,6 +736,36 @@ Key options:
- ✅ Topic-thread replies where Feishu exposes `reply_in_thread`
- ✅ Media replies stay thread-aware when replying to a thread/topic message
## Drive comments
Feishu can trigger the agent when someone adds a comment on a Feishu Drive document (Docs, Sheets,
etc.). The agent receives the comment text, document context, and the comment thread so it can
respond in-thread or make document edits.
Requirements:
- Subscribe to `drive.notice.comment_add_v1` in your Feishu app event subscription settings
(alongside the existing `im.message.receive_v1`)
- The Drive tool is enabled by default; disable with `channels.feishu.tools.drive: false`
The `feishu_drive` tool exposes these comment actions:
| Action | Description |
| ---------------------- | ----------------------------------- |
| `list_comments` | List comments on a document |
| `list_comment_replies` | List replies in a comment thread |
| `add_comment` | Add a new top-level comment |
| `reply_comment` | Reply to an existing comment thread |
When the agent handles a Drive comment event, it receives:
- the comment text and sender
- document metadata (title, type, URL)
- the comment thread context for in-thread replies
After making document edits, the agent is guided to use `feishu_drive.reply_comment` to notify the
commenter and then output `NO_REPLY` to avoid duplicate sends.
## Runtime action surface
Feishu currently exposes these runtime actions:
@@ -750,6 +781,7 @@ Feishu currently exposes these runtime actions:
- `channel-info`
- `channel-list`
- `react` and `reactions` when reactions are enabled in config
- `feishu_drive` comment actions: `list_comments`, `list_comment_replies`, `add_comment`, `reply_comment`
## Related

View File

@@ -183,7 +183,9 @@ done:
```
- `streaming: "off"` is the default. OpenClaw waits for the final reply and sends it once.
- `streaming: "partial"` creates one editable preview message instead of sending multiple partial messages.
- `streaming: "partial"` creates one editable preview message for the current assistant block instead of sending multiple partial messages.
- `blockStreaming: true` enables separate Matrix progress messages. With `streaming: "partial"`, Matrix keeps the live draft for the current block and preserves completed blocks as separate messages.
- When `streaming: "partial"` and `blockStreaming` is off, Matrix only edits the live draft and sends the completed reply once that block or turn finishes.
- If the preview no longer fits in one Matrix event, OpenClaw stops preview streaming and falls back to normal final delivery.
- Media replies still send attachments normally. If a stale preview can no longer be reused safely, OpenClaw redacts it before sending the final media reply.
- Preview edits cost extra Matrix API calls. Leave streaming off if you want the most conservative rate-limit behavior.
@@ -656,6 +658,9 @@ See [Pairing](/channels/pairing) for the shared DM pairing flow and storage layo
```
Top-level `channels.matrix` values act as defaults for named accounts unless an account overrides them.
You can scope inherited room entries to one Matrix account with `groups.<room>.account` (or legacy `rooms.<room>.account`).
Entries without `account` stay shared across all Matrix accounts, and entries with `account: "default"` still work when the default account is configured directly on top-level `channels.matrix.*`.
Partial shared auth defaults do not create a separate implicit default account by themselves. OpenClaw only synthesizes the top-level `default` account when that default has fresh auth (`homeserver` plus `accessToken`, or `homeserver` plus `userId` and `password`); named accounts can still stay discoverable from `homeserver` plus `userId` when cached credentials satisfy auth later.
Set `defaultAccount` when you want OpenClaw to prefer one named Matrix account for implicit routing, probing, and CLI operations.
If you configure multiple named accounts, set `defaultAccount` or pass `--account <id>` for CLI commands that rely on implicit account selection.
Pass `--account <id>` to `openclaw matrix verify ...` and `openclaw matrix devices ...` when you want to override that implicit selection for one command.
@@ -749,6 +754,7 @@ Live directory lookup uses the logged-in Matrix account:
- `historyLimit`: max room messages to include as group history context. Falls back to `messages.groupChat.historyLimit`. Set `0` to disable.
- `replyToMode`: `off`, `first`, or `all`.
- `streaming`: `off` (default) or `partial`. `partial` enables single-message draft previews with edit-in-place updates.
- `blockStreaming`: `true` enables separate progress messages; when unset, Matrix keeps `streaming: "off"` as final-only delivery.
- `threadReplies`: `off`, `inbound`, or `always`.
- `threadBindings`: per-channel overrides for thread-bound session routing and lifecycle.
- `startupVerification`: automatic self-verification request mode on startup (`if-unverified`, `off`).

View File

@@ -132,7 +132,7 @@ Notes:
Enforcement notes:
- Sender policy is checked before signature verification and NIP-04 decryption.
- Inbound event signatures are verified before sender policy and NIP-04 decryption, so forged events are rejected early.
- Pairing replies are sent without processing the original DM body.
- Inbound DMs are rate-limited and oversized payloads are dropped before decrypt.
@@ -240,7 +240,7 @@ docker run -p 7777:7777 ghcr.io/hoytech/strfry
- Never commit private keys.
- Use environment variables for keys.
- Consider `allowlist` for production bots.
- Pairing and allowlist policy is enforced before decrypt, so unknown senders cannot force full crypto work.
- Signatures are verified before sender policy, and sender policy is enforced before decrypt, so forged events are rejected early and unknown senders cannot force full crypto work.
## Limitations (MVP)

View File

@@ -481,6 +481,27 @@ Notes:
</Accordion>
</AccordionGroup>
## Exec approvals in Slack
Exec approval prompts can route natively through Slack using interactive buttons and interactions, instead of falling back to the Web UI or terminal. Approver authorization is enforced: only users identified as approvers can approve or deny requests through Slack.
This uses the same shared approval button surface as other channels. When `interactivity` is enabled in your Slack app settings, approval prompts render as Block Kit buttons directly in the conversation.
Configuration uses the shared `approvals.exec` config with Slack targets:
```json5
{
approvals: {
exec: {
enabled: true,
targets: [{ channel: "slack", to: "U12345678" }],
},
},
}
```
Same-chat `/approve` also works in Slack channels and DMs that already support commands. See [Exec approvals](/tools/exec-approvals) for the full approval forwarding model.
## Troubleshooting
<AccordionGroup>

View File

@@ -831,6 +831,33 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \
</Accordion>
</AccordionGroup>
## Error reply controls
When the agent encounters a delivery or provider error, Telegram can either reply with the error text or suppress it. Two config keys control this behavior:
| Key | Values | Default | Description |
| ----------------------------------- | ----------------- | ------- | ----------------------------------------------------------------------------------------------- |
| `channels.telegram.errorPolicy` | `reply`, `silent` | `reply` | `reply` sends a friendly error message to the chat. `silent` suppresses error replies entirely. |
| `channels.telegram.errorCooldownMs` | number (ms) | `60000` | Minimum time between error replies to the same chat. Prevents error spam during outages. |
Per-account, per-group, and per-topic overrides are supported (same inheritance as other Telegram config keys).
```json5
{
channels: {
telegram: {
errorPolicy: "reply",
errorCooldownMs: 120000,
groups: {
"-1001234567890": {
errorPolicy: "silent", // suppress errors in this group
},
},
},
},
}
```
## Troubleshooting
<AccordionGroup>
@@ -963,6 +990,8 @@ Primary reference:
- `channels.telegram.actions.sticker`: gate Telegram sticker actions — send and search (default: false).
- `channels.telegram.reactionNotifications`: `off | own | all` — control which reactions trigger system events (default: `own` when not set).
- `channels.telegram.reactionLevel`: `off | ack | minimal | extensive` — control agent's reaction capability (default: `minimal` when not set).
- `channels.telegram.errorPolicy`: `reply | silent` — control error reply behavior (default: `reply`). Per-account/group/topic overrides supported.
- `channels.telegram.errorCooldownMs`: minimum ms between error replies to the same chat (default: `60000`). Prevents error spam during outages.
- [Configuration reference - Telegram](/gateway/configuration-reference#telegram)
@@ -979,6 +1008,7 @@ Telegram-specific high-signal fields:
- webhook: `webhookUrl`, `webhookSecret`, `webhookPath`, `webhookHost`
- actions/capabilities: `capabilities.inlineButtons`, `actions.sendMessage|editMessage|deleteMessage|reactions|sticker`
- reactions: `reactionNotifications`, `reactionLevel`
- errors: `errorPolicy`, `errorCooldownMs`
- writes/history: `configWrites`, `historyLimit`, `dmHistoryLimit`, `dms.*.historyLimit`
## Related

View File

@@ -105,6 +105,19 @@ Full troubleshooting:
Full troubleshooting: [/channels/signal#troubleshooting](/channels/signal#troubleshooting)
## QQ Bot
### QQ Bot failure signatures
| Symptom | Fastest check | Fix |
| ------------------------------- | ------------------------------------------- | --------------------------------------------------------------- |
| Bot replies "gone to Mars" | Verify `appId` and `clientSecret` in config | Set credentials or restart the gateway. |
| No inbound messages | `openclaw channels status --probe` | Verify credentials on the QQ Open Platform. |
| Voice not transcribed | Check STT provider config | Configure `channels.qqbot.stt` or `tools.media.audio`. |
| Proactive messages not arriving | Check QQ platform interaction requirements | QQ may block bot-initiated messages without recent interaction. |
Full troubleshooting: [/channels/qqbot#troubleshooting](/channels/qqbot#troubleshooting)
## Matrix
### Matrix failure signatures

View File

@@ -330,9 +330,35 @@ When the linked self number is also present in `allowFrom`, WhatsApp self-chat s
</Accordion>
</AccordionGroup>
## Reaction level
`channels.whatsapp.reactionLevel` controls how broadly the agent uses emoji reactions on WhatsApp:
| Level | Ack reactions | Agent-initiated reactions | Description |
| ------------- | ------------- | ------------------------- | ------------------------------------------------ |
| `"off"` | No | No | No reactions at all |
| `"ack"` | Yes | No | Ack reactions only (pre-reply receipt) |
| `"minimal"` | Yes | Yes (conservative) | Ack + agent reactions with conservative guidance |
| `"extensive"` | Yes | Yes (encouraged) | Ack + agent reactions with encouraged guidance |
Default: `"minimal"`.
Per-account overrides use `channels.whatsapp.accounts.<id>.reactionLevel`.
```json5
{
channels: {
whatsapp: {
reactionLevel: "ack",
},
},
}
```
## Acknowledgment reactions
WhatsApp supports immediate ack reactions on inbound receipt via `channels.whatsapp.ackReaction`.
Ack reactions are gated by `reactionLevel` — they are suppressed when `reactionLevel` is `"off"`.
```json5
{
@@ -447,7 +473,7 @@ Primary reference:
High-signal WhatsApp fields:
- access: `dmPolicy`, `allowFrom`, `groupPolicy`, `groupAllowFrom`, `groups`
- delivery: `textChunkLimit`, `chunkMode`, `mediaMaxMb`, `sendReadReceipts`, `ackReaction`
- delivery: `textChunkLimit`, `chunkMode`, `mediaMaxMb`, `sendReadReceipts`, `ackReaction`, `reactionLevel`
- multi-account: `accounts.<id>.enabled`, `accounts.<id>.authDir`, account-level overrides
- operations: `configWrites`, `debounceMs`, `web.enabled`, `web.heartbeatSeconds`, `web.reconnect.*`
- session behavior: `session.dmScope`, `historyLimit`, `dmHistoryLimit`, `dms.<id>.historyLimit`

View File

@@ -24,6 +24,19 @@ openclaw approvals get --node <id|name|ip>
openclaw approvals get --gateway
```
`openclaw approvals get` now shows the effective exec policy for local, gateway, and node targets:
- requested `tools.exec` policy
- host approvals-file policy
- effective result after precedence rules are applied
Precedence is intentional:
- the host approvals file is the enforceable source of truth
- requested `tools.exec` policy can narrow or broaden intent, but the effective result is still derived from the host rules
- `--node` combines the node host approvals file with gateway `tools.exec` policy, because both still apply at runtime
- if gateway config is unavailable, the CLI falls back to the node approvals snapshot and notes that the final runtime policy could not be computed
## Replace approvals from a file
```bash

View File

@@ -35,7 +35,7 @@ Note: retention/pruning is controlled in config:
Upgrade note: if you have older cron jobs from before the current delivery/store format, run
`openclaw doctor --fix`. Doctor now normalizes legacy cron fields (`jobId`, `schedule.cron`,
top-level delivery fields, payload `provider` delivery aliases) and migrates simple
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.

View File

@@ -1,54 +1,43 @@
---
summary: "CLI reference for `openclaw flows` (list, inspect, cancel)"
summary: "CLI reference for `openclaw flows` commands"
read_when:
- You want to inspect or cancel a flow
- You want to see how background tasks roll up into a higher-level job
- You want to list, inspect, or cancel TaskFlow flows from the CLI
- You encounter openclaw flows in release notes or docs
title: "flows"
---
# `openclaw flows`
Inspect and manage [ClawFlow](/automation/clawflow) jobs.
```bash
openclaw flows list
openclaw flows show <lookup>
openclaw flows cancel <lookup>
```
Inspect and manage [TaskFlow](/automation/taskflow) flows from the command line.
## Commands
### `flows list`
List tracked flows and their task counts.
```bash
openclaw flows list
openclaw flows list --status blocked
openclaw flows list --json
openclaw flows list [--json]
```
List active and recent flows with status and sync mode.
### `flows show`
Show one flow by flow id or owner session key.
```bash
openclaw flows show <lookup>
openclaw flows show <lookup> --json
```
The output includes the flow status, current step, wait target, blocked summary when present, stored output keys, and linked tasks.
Show details for a specific flow by flow id or lookup key, including state, revision history, and associated tasks.
### `flows cancel`
Cancel a flow and any active child tasks.
```bash
openclaw flows cancel <lookup>
```
Cancel a running flow and its active tasks.
## Related
- [ClawFlow](/automation/clawflow) — job-level orchestration above tasks
- [Background Tasks](/automation/tasks) — detached work ledger
- [TaskFlow](/automation/taskflow) — flow orchestration overview
- [Background Tasks](/automation/tasks) — the detached work ledger
- [CLI reference](/cli/index) — full command tree

View File

@@ -45,6 +45,7 @@ This page describes the current CLI behavior. If commands change, update this do
- [`tui`](/cli/tui)
- [`browser`](/cli/browser)
- [`cron`](/cli/cron)
- [`tasks`](/cli/index#tasks)
- [`flows`](/cli/flows)
- [`dns`](/cli/dns)
- [`docs`](/cli/docs)
@@ -814,14 +815,6 @@ List and manage [background task](/automation/tasks) runs across agents.
- `tasks cancel <id>` — cancel a running task
- `tasks audit` — surface operational issues (stale, lost, delivery failures)
### `flows`
List and manage [ClawFlow](/automation/clawflow) jobs across agents.
- `flows list` — show active and recent flows
- `flows show <id>` — show details for a specific flow
- `flows cancel <id>` — cancel a flow and its active child tasks
## Gateway
### `gateway`

View File

@@ -425,10 +425,11 @@ Launches a local child process and communicates over stdin/stdout.
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) |
| Field | Description |
| ------------------- | ---------------------------------------------------------------- |
| `url` | HTTP or HTTPS URL of the remote server (required) |
| `headers` | Optional key-value map of HTTP headers (for example auth tokens) |
| `connectionTimeout` | Per-server connection timeout in ms (optional) |
Example:
@@ -450,6 +451,36 @@ Example:
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 |
| `headers` | Optional key-value map of HTTP headers (for example auth tokens) |
| `connectionTimeout` | Per-server connection timeout in ms (optional) |
Example:
```json
{
"mcp": {
"servers": {
"streaming-tools": {
"url": "https://mcp.example.com/stream",
"transport": "streamable-http",
"connectionTimeout": 10000,
"headers": {
"Authorization": "Bearer <token>"
}
}
}
}
}
```
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.
@@ -462,6 +493,6 @@ Current limits:
- conversation discovery depends on existing Gateway session route metadata
- no generic push protocol beyond the Claude-specific adapter
- no message edit or react tools yet
- HTTP/SSE transport connects to a single remote server; no multiplexed upstream yet
- HTTP/SSE/streamable-http transport connects to a single remote server; no multiplexed upstream yet
- `permissions_list_open` only includes approvals observed while the bridge is
connected

View File

@@ -84,6 +84,7 @@ These run inside the agent loop or gateway pipeline:
- **`before_model_resolve`**: runs pre-session (no `messages`) to deterministically override provider/model before model resolution.
- **`before_prompt_build`**: runs after session load (with `messages`) to inject `prependContext`, `systemPrompt`, `prependSystemContext`, or `appendSystemContext` before prompt submission. Use `prependContext` for per-turn dynamic text and system-context fields for stable guidance that should sit in system prompt space.
- **`before_agent_start`**: legacy compatibility hook that may run in either phase; prefer the explicit hooks above.
- **`before_agent_reply`**: runs after inline actions and before the LLM call, letting a plugin claim the turn and return a synthetic reply or silence the turn entirely.
- **`agent_end`**: inspect the final message list and run metadata after completion.
- **`before_compaction` / `after_compaction`**: observe or annotate compaction cycles.
- **`before_tool_call` / `after_tool_call`**: intercept tool params/results.

View File

@@ -58,6 +58,26 @@ capable model for better summaries:
}
```
## Compaction start notice
By default, compaction runs silently. To show a brief notice when compaction
starts, enable `notifyUser`:
```json5
{
agents: {
defaults: {
compaction: {
notifyUser: true,
},
},
},
}
```
When enabled, the user sees a short message (for example, "Compacting
context...") at the start of each compaction run.
## Compaction vs pruning
| | Compaction | Pruning |

View File

@@ -129,6 +129,8 @@ Defaults:
- Billing backoff starts at **5 hours**, doubles per billing failure, and caps at **24 hours**.
- Backoff counters reset if the profile hasnt failed for **24 hours** (configurable).
- Overloaded retries allow **1 same-provider profile rotation** before model fallback.
- Overloaded retries use **0 ms backoff** by default.
## Model fallback
@@ -136,6 +138,13 @@ If all profiles for a provider fail, OpenClaw moves to the next model in
`agents.defaults.model.fallbacks`. This applies to auth failures, rate limits, and
timeouts that exhausted profile rotation (other errors do not advance fallback).
Overloaded and rate-limit errors are handled more aggressively than billing
cooldowns. By default, OpenClaw allows one same-provider auth-profile retry,
then switches to the next configured model fallback without waiting. Tune this
with `auth.cooldowns.overloadedProfileRotations`,
`auth.cooldowns.overloadedBackoffMs`, and
`auth.cooldowns.rateLimitedProfileRotations`.
When a run starts with a model override (hooks or CLI), fallbacks still end at
`agents.defaults.model.primary` after trying any configured fallbacks.
@@ -146,6 +155,8 @@ See [Gateway configuration](/gateway/configuration) for:
- `auth.profiles` / `auth.order`
- `auth.cooldowns.billingBackoffHours` / `auth.cooldowns.billingBackoffHoursByProvider`
- `auth.cooldowns.billingMaxHours` / `auth.cooldowns.failureWindowHours`
- `auth.cooldowns.overloadedProfileRotations` / `auth.cooldowns.overloadedBackoffMs`
- `auth.cooldowns.rateLimitedProfileRotations`
- `agents.defaults.model.primary` / `agents.defaults.model.fallbacks`
- `agents.defaults.imageModel` routing

View File

@@ -108,6 +108,7 @@ Notes:
- `/model` (and `/model list`) is a compact, numbered picker (model family + available providers).
- On Discord, `/model` and `/models` open an interactive picker with provider and model dropdowns plus a Submit step.
- `/model <#>` selects from that picker.
- `/model` updates the session selection immediately. If the agent is idle, the next run uses the new model right away. If the agent is busy, the in-flight run finishes first and queued/future work uses the new model after that.
- `/model status` is the detailed view (auth candidates and, when configured, provider endpoint `baseUrl` + `api` mode).
- Model refs are parsed by splitting on the **first** `/`. Use `provider/model` when typing `/model <ref>`.
- If the model ID itself contains `/` (OpenRouter-style), you must include the provider prefix (example: `/model openrouter/moonshotai/kimi-k2`).

View File

@@ -879,6 +879,10 @@
{
"source": "/gateway/trusted-proxy",
"destination": "/gateway/trusted-proxy-auth"
},
{
"source": "/automation/clawflow",
"destination": "/automation/taskflow"
}
],
"navigation": {
@@ -1122,7 +1126,7 @@
"automation/cron-jobs",
"automation/cron-vs-heartbeat",
"automation/tasks",
"automation/clawflow",
"automation/taskflow",
"automation/troubleshooting",
"automation/webhook",
"automation/gmail-pubsub",
@@ -1156,6 +1160,7 @@
"tools/grok-search",
"tools/kimi-search",
"tools/perplexity-search",
"tools/searxng-search",
"tools/tavily"
]
},

View File

@@ -923,6 +923,7 @@ Time format in system prompt. Default: `auto` (OS preference).
primary: "anthropic/claude-opus-4-6",
fallbacks: ["openai/gpt-5-mini"],
},
params: { cacheRetention: "long" }, // global default provider params
pdfMaxBytesMb: 10,
pdfMaxPages: 20,
thinkingDefault: "low",
@@ -957,7 +958,8 @@ Time format in system prompt. Default: `auto` (OS preference).
- `elevatedDefault`: default elevated-output level for agents. Values: `"off"`, `"on"`, `"ask"`, `"full"`. Default: `"on"`.
- `model.primary`: format `provider/model` (e.g. `anthropic/claude-opus-4-6`). If you omit the provider, OpenClaw assumes `anthropic` (deprecated).
- `models`: the configured model catalog and allowlist for `/model`. Each entry can include `alias` (shortcut) and `params` (provider-specific, for example `temperature`, `maxTokens`, `cacheRetention`, `context1m`).
- `params` merge precedence (config): `agents.defaults.models["provider/model"].params` is the base, then `agents.list[].params` (matching agent id) overrides by key.
- `params`: global default provider parameters applied to all models. Set at `agents.defaults.params` (e.g. `{ cacheRetention: "long" }`).
- `params` merge precedence (config): `agents.defaults.params` (global base) is overridden by `agents.defaults.models["provider/model"].params` (per-model), then `agents.list[].params` (matching agent id) overrides by key. See [Prompt Caching](/reference/prompt-caching) for details.
- Config writers that mutate these fields (for example `/models set`, `/models set-image`, and fallback add/remove commands) save canonical object form and preserve existing fallback lists when possible.
- `maxConcurrent`: max parallel agent runs across sessions (each session still serialized). Default: 4.
@@ -1062,6 +1064,7 @@ Periodic heartbeat runs.
identifierInstructions: "Preserve deployment IDs, ticket IDs, and host:port pairs exactly.", // used when identifierPolicy=custom
postCompactionSections: ["Session Startup", "Red Lines"], // [] disables reinjection
model: "openrouter/anthropic/claude-sonnet-4-6", // optional compaction-only model override
notifyUser: true, // send a brief notice when compaction starts (default: false)
memoryFlush: {
enabled: true,
softThresholdTokens: 6000,
@@ -1080,6 +1083,7 @@ Periodic heartbeat runs.
- `identifierInstructions`: optional custom identifier-preservation text used when `identifierPolicy=custom`.
- `postCompactionSections`: optional AGENTS.md H2/H3 section names to re-inject after compaction. Defaults to `["Session Startup", "Red Lines"]`; set `[]` to disable reinjection. When unset or explicitly set to that default pair, older `Every Session`/`Safety` headings are also accepted as a legacy fallback.
- `model`: optional `provider/model-id` override for compaction summarization only. Use this when the main session should keep one model but compaction summaries should run on another; when unset, compaction uses the session's primary model.
- `notifyUser`: when `true`, sends a brief notice to the user when compaction starts (for example, "Compacting context..."). Disabled by default to keep compaction silent.
- `memoryFlush`: silent agentic turn before auto-compaction to store durable memories. Skipped when workspace is read-only.
### `agents.defaults.contextPruning`
@@ -3029,6 +3033,9 @@ Notes:
billingBackoffHoursByProvider: { anthropic: 3, openai: 8 },
billingMaxHours: 24,
failureWindowHours: 24,
overloadedProfileRotations: 1,
overloadedBackoffMs: 0,
rateLimitedProfileRotations: 1,
},
},
}
@@ -3038,6 +3045,9 @@ Notes:
- `billingBackoffHoursByProvider`: optional per-provider overrides for billing backoff hours.
- `billingMaxHours`: cap in hours for billing backoff exponential growth (default: `24`).
- `failureWindowHours`: rolling window in hours used for backoff counters (default: `24`).
- `overloadedProfileRotations`: maximum same-provider auth-profile rotations for overloaded errors before switching to model fallback (default: `1`).
- `overloadedBackoffMs`: fixed delay before retrying an overloaded provider/profile rotation (default: `0`).
- `rateLimitedProfileRotations`: maximum same-provider auth-profile rotations for rate-limit errors before switching to model fallback (default: `1`).
---

View File

@@ -117,6 +117,7 @@ Doctor will:
The Gateway also auto-runs doctor migrations on startup when it detects a
legacy config format, so stale configs are repaired without manual intervention.
Cron job store migrations are handled by `openclaw doctor --fix`.
Current migrations:
@@ -303,6 +304,13 @@ catalog and allowlist and warns when it wont resolve or is disallowed.
When sandboxing is enabled, doctor checks Docker images and offers to build or
switch to legacy names if the current image is missing.
### 7b) Bundled plugin runtime deps
Doctor verifies that bundled plugin runtime dependencies (for example the
Discord plugin runtime packages) are present in the OpenClaw install root.
If any are missing, doctor reports the packages and installs them in
`openclaw doctor --fix` / `openclaw doctor --repair` mode.
### 8) Gateway service migrations and cleanup hints
Doctor detects legacy gateway services (launchd/systemd/schtasks) and

View File

@@ -65,10 +65,43 @@ Notes:
- `node.pair.request` is idempotent per node: repeated calls return the same
pending request.
- Repeated requests for the same pending node also refresh the stored node
metadata and the latest allowlisted declared command snapshot for operator visibility.
- Approval **always** generates a fresh token; no token is ever returned from
`node.pair.request`.
- Requests may include `silent: true` as a hint for auto-approval flows.
Important:
- Node pairing is a trust/identity flow plus token issuance.
- It does **not** pin the live node command surface per node.
- Live node commands come from what the node declares on connect after the
gateway's global node command policy (`gateway.nodes.allowCommands` /
`denyCommands`) is applied.
- Per-node `system.run` allow/ask policy lives on the node in
`exec.approvals.node.*`, not in the pairing record.
## Node command gating (2026.3.31+)
<Warning>
**Breaking change:** Starting with `2026.3.31`, node commands are disabled until node pairing is approved. Device pairing alone is no longer enough to expose declared node commands.
</Warning>
When a node connects for the first time, pairing is requested automatically. Until the pairing request is approved, all pending node commands from that node are filtered and will not execute. Once trust is established through pairing approval, the node's declared commands become available subject to the normal command policy.
This means:
- Nodes that were previously relying on device pairing alone to expose commands must now complete node pairing.
- Commands queued before pairing approval are dropped, not deferred.
## Node event trust boundaries (2026.3.31+)
<Warning>
**Breaking change:** Node-originated runs now stay on a reduced trusted surface.
</Warning>
Node-originated summaries and related session events are restricted to the intended trusted surface. Notification-driven or node-triggered flows that previously relied on broader host or session tool access may need adjustment. This hardening ensures that node events cannot escalate into host-level tool access beyond what the node's trust boundary permits.
## Auto-approval (macOS app)
The macOS app can optionally attempt a **silent approval** when:

View File

@@ -116,6 +116,7 @@ These patterns are commonly reported and are usually closed as no-action unless
- Claims that classify normal operator read-path access (for example `sessions.list`/`sessions.preview`/`chat.history`) as IDOR in a shared-gateway setup.
- Localhost-only deployment findings (for example HSTS on loopback-only gateway).
- Discord inbound webhook signature findings for inbound paths that do not exist in this repo.
- Reports that treat node pairing metadata as a hidden second per-command approval layer for `system.run`, when the real execution boundary is still the gateway's global node command policy plus the node's own exec approvals.
- "Missing per-user authorization" findings that treat `sessionKey` as an auth token.
## Researcher preflight checklist
@@ -370,10 +371,18 @@ stronger isolation between agents, run them under separate OS users or separate
If a macOS node is paired, the Gateway can invoke `system.run` on that node. This is **remote code execution** on the Mac:
- Requires node pairing (approval + token).
- Gateway node pairing is not a per-command approval surface. It establishes node identity/trust and token issuance.
- The Gateway applies a coarse global node command policy via `gateway.nodes.allowCommands` / `denyCommands`.
- Controlled on the Mac via **Settings → Exec approvals** (security + ask + allowlist).
- The per-node `system.run` policy is the node's own exec approvals file (`exec.approvals.node.*`), which can be stricter or looser than the gateway's global command-ID policy.
- Approval mode binds exact request context and, when possible, one concrete local script/file operand. If OpenClaw cannot identify exactly one direct local file for an interpreter/runtime command, approval-backed execution is denied rather than promising full semantic coverage.
- If you dont want remote execution, set security to **deny** and remove node pairing for that Mac.
This distinction matters for triage:
- A reconnecting paired node advertising a different command list is not, by itself, a vulnerability if the Gateway global policy and the node's local exec approvals still enforce the actual execution boundary.
- Reports that treat node pairing metadata as a second hidden per-command approval layer are usually policy/UX confusion, not a security boundary bypass.
## Dynamic skills (watcher / remote nodes)
OpenClaw can refresh the skills list mid-session:

View File

@@ -127,7 +127,7 @@ When set, `OPENCLAW_HOME` replaces the system home directory (`$HOME` / `os.home
<key>EnvironmentVariables</key>
<dict>
<key>OPENCLAW_HOME</key>
<string>/Users/kira</string>
<string>/Users/user</string>
</dict>
```

View File

@@ -48,7 +48,7 @@ update **without** changing your persisted channel:
```bash
# Install a specific version
openclaw update --tag 2026.3.31-beta.1
openclaw update --tag 2026.4.1-beta.1
# Install from the beta dist-tag (one-off, does not persist)
openclaw update --tag beta
@@ -57,7 +57,7 @@ openclaw update --tag beta
openclaw update --tag main
# Install a specific npm package spec
openclaw update --tag openclaw@2026.3.31-beta.1
openclaw update --tag openclaw@2026.4.1-beta.1
```
Notes:
@@ -75,7 +75,7 @@ Preview what `openclaw update` would do without making changes:
```bash
openclaw update --dry-run
openclaw update --channel beta --dry-run
openclaw update --tag 2026.3.31-beta.1 --dry-run
openclaw update --tag 2026.4.1-beta.1 --dry-run
openclaw update --dry-run --json
```

View File

@@ -96,6 +96,8 @@ Run a persistent OpenClaw Gateway on Oracle Cloud's **Always Free** ARM tier (up
systemctl --user restart openclaw-gateway
```
`gateway.trustedProxies=["127.0.0.1"]` is for the local Tailscale Serve proxy. Diff viewer routes keep fail-closed behavior in this setup: raw `127.0.0.1` viewer requests without forwarded proxy headers can return `Diff not found`. Use `mode=file` / `mode=both` for attachments, or intentionally enable remote viewers and set `plugins.entries.diffs.config.viewerBaseUrl` (or pass a proxy `baseUrl`) if you need shareable viewer links.
</Step>
<Step title="Lock down VCN security">

View File

@@ -98,73 +98,9 @@ openclaw channels login
```
On macOS, Podman machine may make the browser appear non-local to the gateway.
If the Control UI reports device-auth errors after launch, prefer the SSH
tunnel flow in [macOS Podman SSH tunnel](#macos-podman-ssh-tunnel). For
remote HTTPS access, use the Tailscale guidance in
If the Control UI reports device-auth errors after launch, use the Tailscale guidance in
[Podman + Tailscale](#podman--tailscale).
## macOS Podman SSH tunnel
On macOS, Podman machine can make the browser appear non-local to the gateway even when the published port is only on `127.0.0.1`.
For local browser access, use an SSH tunnel into the Podman VM and open the tunneled localhost port instead.
Recommended local tunnel port:
- `28889` on the Mac host
- forwarded to `127.0.0.1:18789` inside the Podman VM
Start the tunnel in a separate terminal:
```bash
ssh -N \
-i ~/.local/share/containers/podman/machine/machine \
-p <podman-vm-ssh-port> \
-L 28889:127.0.0.1:18789 \
core@127.0.0.1
```
In that command, `<podman-vm-ssh-port>` is the Podman VM's SSH port on the Mac host. Check your current value with:
```bash
podman system connection list
```
Allow the tunneled browser origin once. This is required the first time you use the tunnel because the launcher can auto-seed the Podman-published port, but it cannot infer your chosen browser tunnel port:
```bash
OPENCLAW_CONTAINER=openclaw openclaw config set gateway.controlUi.allowedOrigins \
'["http://127.0.0.1:18789","http://localhost:18789","http://127.0.0.1:28889","http://localhost:28889"]' \
--strict-json
podman restart openclaw
```
That is a one-time step for the default `28889` tunnel.
Then open:
```text
http://127.0.0.1:28889/
```
Notes:
- `18789` is usually already occupied on the Mac host by the Podman-published gateway port, so the tunnel uses `28889` as the local browser port.
- If the UI asks for pairing approval, prefer explicit container-targeted or explicit-URL commands so the host CLI does not fall back to local pairing files:
```bash
openclaw --container openclaw devices list
openclaw --container openclaw devices approve --latest
```
- Equivalent explicit-URL form:
```bash
openclaw devices list \
--url ws://127.0.0.1:28889 \
--token "$(sed -n 's/^OPENCLAW_GATEWAY_TOKEN=//p' ~/.openclaw/.env | head -n1)"
```
<a id="podman--tailscale"></a>
## Podman + Tailscale
@@ -175,7 +111,7 @@ Podman-specific note:
- Keep the Podman publish host at `127.0.0.1`.
- Prefer host-managed `tailscale serve` over `openclaw gateway --tailscale serve`.
- For local macOS browser access without HTTPS, prefer the SSH tunnel section above.
- On macOS, if local browser device-auth context is unreliable, use Tailscale access instead of ad hoc local tunnel workarounds.
See:

View File

@@ -62,7 +62,8 @@ If you see `NODE_BACKGROUND_UNAVAILABLE`, bring the node app to the foreground a
These are different gates:
1. **Device pairing**: can this node connect to the gateway?
2. **Exec approvals**: can this node run a specific shell command?
2. **Gateway node command policy**: is the RPC command ID allowed by `gateway.nodes.allowCommands` / `denyCommands` and platform defaults?
3. **Exec approvals**: can this node run a specific shell command locally?
Quick checks:
@@ -74,7 +75,10 @@ openclaw approvals allowlist add --node <idOrNameOrIp> "/usr/bin/uname"
```
If pairing is missing, approve the node device first.
If pairing is fine but `system.run` fails, fix exec approvals/allowlist.
If `nodes describe` is missing a command, check the gateway node command policy and whether the node actually declared that command on connect.
If pairing is fine but `system.run` fails, fix exec approvals/allowlist on that node.
Node pairing is an identity/trust gate, not a per-command approval surface. For `system.run`, the per-node policy lives in that node's exec approvals file (`openclaw approvals get --node ...`), not in the gateway pairing record.
## Common node error codes

View File

@@ -159,10 +159,44 @@ See [Camera node](/nodes/camera) for parameters and CLI helpers.
- Voice wake/talk-mode toggles are currently removed from Android UX/runtime.
- Additional Android command families (availability depends on device + permissions):
- `device.status`, `device.info`, `device.permissions`, `device.health`
- `notifications.list`, `notifications.actions`
- `notifications.list`, `notifications.actions` (see [Notification forwarding](#notification-forwarding) below)
- `photos.latest`
- `contacts.search`, `contacts.add`
- `calendar.events`, `calendar.add`
- `callLog.search`
- `sms.search`
- `motion.activity`, `motion.pedometer`
## Notification forwarding
Android can forward device notifications to the gateway as events. Several controls let you scope which notifications are forwarded and when.
| Key | Type | Description |
| -------------------------------- | -------------- | ------------------------------------------------------------------------------------------------- |
| `notifications.allowPackages` | string[] | Only forward notifications from these package names. If set, all other packages are ignored. |
| `notifications.denyPackages` | string[] | Never forward notifications from these package names. Applied after `allowPackages`. |
| `notifications.quietHours.start` | string (HH:mm) | Start of quiet hours window (local device time). Notifications are suppressed during this window. |
| `notifications.quietHours.end` | string (HH:mm) | End of quiet hours window. |
| `notifications.rateLimit` | number | Maximum forwarded notifications per package per minute. Excess notifications are dropped. |
The notification picker also uses safer behavior for forwarded notification events, preventing accidental forwarding of sensitive system notifications.
Example configuration:
```json5
{
notifications: {
allowPackages: ["com.slack", "com.whatsapp"],
denyPackages: ["com.android.systemui"],
quietHours: {
start: "22:00",
end: "07:00",
},
rateLimit: 5,
},
}
```
<Note>
Notification forwarding requires the Android Notification Listener permission. The app prompts for this during setup.
</Note>

View File

@@ -126,6 +126,8 @@ openclaw config set gateway.trustedProxies '["127.0.0.1"]'
systemctl --user restart openclaw-gateway
```
`gateway.trustedProxies=["127.0.0.1"]` is for the local Tailscale Serve proxy. Diff viewer routes keep fail-closed behavior in this setup: raw `127.0.0.1` viewer requests without forwarded proxy headers can return `Diff not found`. Use `mode=file` / `mode=both` for attachments, or intentionally enable remote viewers and set `plugins.entries.diffs.config.viewerBaseUrl` (or pass a proxy `baseUrl`) if you need shareable viewer links.
## 7) Verify
```bash

View File

@@ -159,6 +159,8 @@ The current boundary is:
bookkeeping, and execution dispatch
- channel plugins own scoped action discovery, capability discovery, and any
channel-specific schema fragments
- channel plugins own provider-specific session conversation grammar, such as
how conversation ids encode thread ids or inherit from parent conversations
- channel plugins execute the final action through their action adapter
For channel plugins, the SDK surface is
@@ -588,7 +590,7 @@ Provider plugins now have two layers:
runtime load, plus `providerAuthChoices` for cheap onboarding/auth-choice
labels and CLI flag metadata before runtime load
- config-time hooks: `catalog` / legacy `discovery`
- runtime hooks: `resolveDynamicModel`, `prepareDynamicModel`, `normalizeResolvedModel`, `capabilities`, `prepareExtraParams`, `wrapStreamFn`, `formatApiKey`, `refreshOAuth`, `buildAuthDoctorHint`, `isCacheTtlEligible`, `buildMissingAuthMessage`, `suppressBuiltInModel`, `augmentModelCatalog`, `isBinaryThinking`, `supportsXHighThinking`, `resolveDefaultThinkingLevel`, `isModernModelRef`, `prepareRuntimeAuth`, `resolveUsageAuth`, `fetchUsageSnapshot`
- runtime hooks: `resolveDynamicModel`, `prepareDynamicModel`, `normalizeResolvedModel`, `capabilities`, `prepareExtraParams`, `wrapStreamFn`, `formatApiKey`, `refreshOAuth`, `buildAuthDoctorHint`, `isCacheTtlEligible`, `buildMissingAuthMessage`, `suppressBuiltInModel`, `augmentModelCatalog`, `isBinaryThinking`, `supportsXHighThinking`, `resolveDefaultThinkingLevel`, `isModernModelRef`, `prepareRuntimeAuth`, `resolveUsageAuth`, `fetchUsageSnapshot`, `buildReplayPolicy`, `sanitizeReplayHistory`, `validateReplayTurns`
OpenClaw still owns the generic agent loop, failover, transcript handling, and
tool policy. These hooks are the extension surface for provider-specific behavior without
@@ -631,6 +633,9 @@ The "When to use" column is the quick decision guide.
| 19 | `prepareRuntimeAuth` | Exchange a configured credential into the actual runtime token/key just before inference | Provider needs a token exchange or short-lived request credential |
| 20 | `resolveUsageAuth` | Resolve usage/billing credentials for `/usage` and related status surfaces | Provider needs custom usage/quota token parsing or a different usage credential |
| 21 | `fetchUsageSnapshot` | Fetch and normalize provider-specific usage/quota snapshots after auth is resolved | Provider needs a provider-specific usage endpoint or payload parser |
| 22 | `buildReplayPolicy` | Return a replay policy controlling transcript handling for the provider | Provider needs custom transcript policy (for example, thinking-block stripping) |
| 23 | `sanitizeReplayHistory` | Rewrite replay history after generic transcript cleanup | Provider needs provider-specific replay rewrites beyond shared compaction helpers |
| 24 | `validateReplayTurns` | Final replay-turn validation or reshaping before the embedded runner | Provider transport needs stricter turn validation after generic sanitation |
If the provider needs a fully custom wire protocol or custom request executor,
that is a different class of extension. These hooks are for provider behavior
@@ -979,6 +984,7 @@ authoring plugins:
`openclaw/plugin-sdk/allow-from`,
`openclaw/plugin-sdk/channel-config-schema`,
`openclaw/plugin-sdk/channel-policy`,
`openclaw/plugin-sdk/approval-runtime`,
`openclaw/plugin-sdk/config-runtime`,
`openclaw/plugin-sdk/infra-runtime`,
`openclaw/plugin-sdk/agent-runtime`,
@@ -988,6 +994,10 @@ authoring plugins:
`openclaw/plugin-sdk/status-helpers`,
`openclaw/plugin-sdk/runtime-store`, and
`openclaw/plugin-sdk/directory-runtime` for shared runtime/config helpers.
- Approval-specific channel seams should prefer one `approvalCapability`
contract on the plugin. Core then reads approval auth, delivery, render, and
native-routing behavior through that one capability instead of mixing
approval behavior into unrelated plugin fields.
- `openclaw/plugin-sdk/channel-runtime` remains only as a compatibility shim.
New code should import the narrower primitives instead.
- Bundled extension internals remain private. External plugins should use only

View File

@@ -77,18 +77,19 @@ Connect OpenClaw to QQ via the QQ Bot API. Supports private chats, group
mentions, channel messages, and rich media including voice, images, videos,
and files.
- **npm:** `@sliverp/qqbot`
- **repo:** [github.com/sliverp/qqbot](https://github.com/sliverp/qqbot)
- **npm:** `@tencent-connect/openclaw-qqbot`
- **repo:** [github.com/tencent-connect/openclaw-qqbot](https://github.com/tencent-connect/openclaw-qqbot)
```bash
openclaw plugins install @sliverp/qqbot
openclaw plugins install @tencent-connect/openclaw-qqbot
```
### wecom
OpenClaw Enterprise WeCom Channel Plugin.
A bot plugin powered by WeCom AI Bot WebSocket persistent connections,
supports direct messages & group chats, streaming replies, and proactive messaging.
WeCom channel plugin for OpenClaw by the Tencent WeCom team. Powered by
WeCom Bot WebSocket persistent connections, it supports direct messages & group
chats, streaming replies, proactive messaging, image/file processing, Markdown
formatting, built-in access control, and document/meeting/messaging skills.
- **npm:** `@wecom/wecom-openclaw-plugin`
- **repo:** [github.com/WecomTeam/wecom-openclaw-plugin](https://github.com/WecomTeam/wecom-openclaw-plugin)

View File

@@ -28,24 +28,48 @@ shared `message` tool in core. Your plugin owns:
- **Config** — account resolution and setup wizard
- **Security** — DM policy and allowlists
- **Pairing** — DM approval flow
- **Session grammar** — how provider-specific conversation ids map to base chats, thread ids, and parent fallbacks
- **Outbound** — sending text, media, and polls to the platform
- **Threading** — how replies are threaded
Core owns the shared message tool, prompt wiring, session bookkeeping, and
dispatch.
Core owns the shared message tool, prompt wiring, the outer session-key shape,
generic `:thread:` bookkeeping, and dispatch.
If your platform stores extra scope inside conversation ids, keep that parsing
in the plugin with `messaging.resolveSessionConversation(...)`. That is the
canonical hook for mapping `rawId` to the base conversation id, optional thread
id, explicit `baseConversationId`, and any `parentConversationCandidates`.
When you return `parentConversationCandidates`, keep them ordered from the
narrowest parent to the broadest/base conversation.
Bundled plugins that need the same parsing before the channel registry boots
can also expose a top-level `session-key-api.ts` file with a matching
`resolveSessionConversation(...)` export. Core uses that bootstrap-safe surface
only when the runtime plugin registry is not available yet.
`messaging.resolveParentConversationCandidates(...)` remains available as a
legacy compatibility fallback when a plugin only needs parent fallbacks on top
of the generic/raw id. If both hooks exist, core uses
`resolveSessionConversation(...).parentConversationCandidates` first and only
falls back to `resolveParentConversationCandidates(...)` when the canonical hook
omits them.
## Approvals and channel capabilities
Most channel plugins do not need approval-specific code.
- Core owns same-chat `/approve`, shared approval button payloads, and generic fallback delivery.
- Use `auth.authorizeActorAction` or `auth.getActionAvailabilityState` only when approval auth differs from normal chat auth.
- Prefer one `approvalCapability` object on the channel plugin when the channel needs approval-specific behavior.
- `approvalCapability.authorizeActorAction` and `approvalCapability.getActionAvailabilityState` are the canonical approval-auth seam.
- Use `outbound.shouldSuppressLocalPayloadPrompt` or `outbound.beforeDeliverPayload` for channel-specific payload lifecycle behavior such as hiding duplicate local approval prompts or sending typing indicators before delivery.
- Use `approvals.delivery` only for native approval routing or fallback suppression.
- Use `approvals.render` only when a channel truly needs custom approval payloads instead of the shared renderer.
- Use `approvalCapability.delivery` only for native approval routing or fallback suppression.
- Use `approvalCapability.render` only when a channel truly needs custom approval payloads instead of the shared renderer.
- If a channel can infer stable owner-like DM identities from existing config, use `createResolvedApproverActionAuthAdapter` from `openclaw/plugin-sdk/approval-runtime` to restrict same-chat `/approve` without adding approval-specific core logic.
- If a channel needs native approval delivery, keep channel code focused on target normalization and transport hooks. Use `createChannelExecApprovalProfile`, `createChannelNativeOriginTargetResolver`, `createChannelApproverDmTargetResolver`, `createApproverRestrictedNativeApprovalCapability`, and `createChannelNativeApprovalRuntime` from `openclaw/plugin-sdk/approval-runtime` so core owns request filtering, routing, dedupe, expiry, and gateway subscription.
- Native approval channels must route both `accountId` and `approvalKind` through those helpers. `accountId` keeps multi-account approval policy scoped to the right bot account, and `approvalKind` keeps exec vs plugin approval behavior available to the channel without hardcoded branches in core.
- `createApproverRestrictedNativeApprovalAdapter` still exists as a compatibility wrapper, but new code should prefer the capability builder and expose `approvalCapability` on the plugin.
For Slack, Matrix, Microsoft Teams, and similar chat channels, the default path is usually enough: core handles approvals and the plugin just exposes normal outbound and auth capabilities.
Auth-only channels can usually stop at the default path: core handles approvals and the plugin just exposes outbound/auth capabilities. Native approval channels such as Matrix, Slack, Telegram, and custom chat transports should use the shared native helpers instead of rolling their own approval lifecycle.
## Walkthrough

View File

@@ -127,7 +127,7 @@ is a small, self-contained module with a clear purpose and documented contract.
| `plugin-sdk/channel-runtime` | Runtime wiring helpers | Channel runtime utilities |
| `plugin-sdk/channel-send-result` | Send result types | Reply result types |
| `plugin-sdk/runtime-store` | Persistent plugin storage | `createPluginRuntimeStore` |
| `plugin-sdk/approval-runtime` | Approval prompt helpers | Exec/plugin approval payload and reply helpers |
| `plugin-sdk/approval-runtime` | Approval prompt helpers | Exec/plugin approval payload, approval capability/profile helpers, native approval routing/runtime helpers |
| `plugin-sdk/collection-runtime` | Bounded cache helpers | `pruneMapToMaxSize` |
| `plugin-sdk/diagnostic-runtime` | Diagnostic gating helpers | `isDiagnosticFlagEnabled`, `isDiagnosticsEnabled` |
| `plugin-sdk/error-runtime` | Error formatting helpers | `formatUncaughtError`, error graph helpers |

View File

@@ -91,7 +91,7 @@ subpaths is in `scripts/lib/plugin-sdk-entrypoints.json`.
| --- | --- |
| `plugin-sdk/runtime-store` | `createPluginRuntimeStore` |
| `plugin-sdk/config-runtime` | Config load/write helpers |
| `plugin-sdk/approval-runtime` | Exec and plugin approval helpers |
| `plugin-sdk/approval-runtime` | Exec/plugin approval helpers, approval-capability builders, auth/profile helpers, native routing/runtime helpers |
| `plugin-sdk/infra-runtime` | System event/heartbeat helpers |
| `plugin-sdk/collection-runtime` | Small bounded cache helpers |
| `plugin-sdk/diagnostic-runtime` | Diagnostic flag and event helpers |

View File

@@ -312,6 +312,9 @@ API key auth, and dynamic model resolution.
| 20 | `resolveUsageAuth` | Custom usage credential parsing |
| 21 | `fetchUsageSnapshot` | Custom usage endpoint |
| 22 | `onModelSelected` | Post-selection callback (e.g. telemetry) |
| 23 | `buildReplayPolicy` | Custom transcript policy (e.g. thinking-block stripping) |
| 24 | `sanitizeReplayHistory` | Provider-specific replay rewrites after generic cleanup |
| 25 | `validateReplayTurns` | Strict replay-turn validation before the embedded runner |
For detailed descriptions and real-world examples, see
[Internals: Provider Runtime Hooks](/plugins/architecture#provider-runtime-hooks).

View File

@@ -115,6 +115,40 @@ await api.runtime.subagent.deleteSession({
Untrusted plugins can still run subagents, but override requests are rejected.
</Warning>
### `api.runtime.taskFlow`
Bind a TaskFlow runtime to an existing OpenClaw session key or trusted tool
context, then create and manage TaskFlows without passing an owner on every call.
```typescript
const taskFlow = api.runtime.taskFlow.fromToolContext(ctx);
const created = taskFlow.createManaged({
controllerId: "my-plugin/review-batch",
goal: "Review new pull requests",
});
const child = taskFlow.runTask({
flowId: created.flowId,
runtime: "acp",
childSessionKey: "agent:main:subagent:reviewer",
task: "Review PR #123",
status: "running",
startedAt: Date.now(),
});
const waiting = taskFlow.setWaiting({
flowId: created.flowId,
expectedRevision: created.revision,
currentStep: "await-human-reply",
waitJson: { kind: "reply", channel: "telegram" },
});
```
Use `bindSession({ sessionKey, requesterOrigin })` when you already have a
trusted OpenClaw session key from your own binding layer. Do not bind from raw
user input.
### `api.runtime.tts`
Text-to-speech synthesis.

View File

@@ -184,8 +184,10 @@ enabled). Otherwise Anthropic returns:
`HTTP 429: rate_limit_error: Extra usage is required for long context requests`.
Note: Anthropic currently rejects `context-1m-*` beta requests when using
OAuth/subscription tokens (`sk-ant-oat-*`). OpenClaw automatically skips the
context1m beta header for OAuth auth and keeps the required OAuth betas.
subscription setup-tokens (`sk-ant-oat-*`). If you configure `context1m: true`
with subscription auth, OpenClaw logs a warning and falls back to the standard
context window by skipping the context1m beta header while keeping the required
OAuth betas.
## Option B: Claude CLI as the message provider

View File

@@ -174,3 +174,44 @@ openclaw models list
current capabilities.
- If you prefer a managed key flow, you can also place an OpenAIcompatible
proxy in front of Bedrock and configure it as an OpenAI provider instead.
## Guardrails
You can apply [Amazon Bedrock Guardrails](https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html)
to all Bedrock model invocations by adding a `guardrail` object to the
`amazon-bedrock` plugin config. Guardrails let you enforce content filtering,
topic denial, word filters, sensitive information filters, and contextual
grounding checks.
```json5
{
plugins: {
entries: {
"amazon-bedrock": {
config: {
guardrail: {
guardrailIdentifier: "abc123", // guardrail ID or full ARN
guardrailVersion: "1", // version number or "DRAFT"
streamProcessingMode: "sync", // optional: "sync" or "async"
trace: "enabled", // optional: "enabled", "disabled", or "enabled_full"
},
},
},
},
},
}
```
- `guardrailIdentifier` (required) accepts a guardrail ID (e.g. `abc123`) or a
full ARN (e.g. `arn:aws:bedrock:us-east-1:123456789012:guardrail/abc123`).
- `guardrailVersion` (required) specifies which published version to use, or
`"DRAFT"` for the working draft.
- `streamProcessingMode` (optional) controls whether guardrail evaluation runs
synchronously (`"sync"`) or asynchronously (`"async"`) during streaming. If
omitted, Bedrock uses its default behavior.
- `trace` (optional) enables guardrail trace output in the API response. Set to
`"enabled"` or `"enabled_full"` for debugging; omit or set `"disabled"` for
production.
The IAM principal used by the gateway must have the `bedrock:ApplyGuardrail`
permission in addition to the standard invoke permissions.

View File

@@ -39,5 +39,5 @@ openclaw onboard --auth-choice zai-cn
## Notes
- GLM versions and availability can change; check Z.AI's docs for the latest.
- Example model IDs include `glm-5`, `glm-4.7`, and `glm-4.6`.
- Example model IDs include `glm-5.1`, `glm-5`, `glm-5v-turbo`, `glm-4.7`, and `glm-4.6`.
- For provider details, see [/providers/zai](/providers/zai).

View File

@@ -37,8 +37,9 @@ OpenClaw has three public release lanes:
## Release preflight
- Run `pnpm build` before `pnpm release:check` so the expected `dist/*` release
artifacts exist for the pack validation step
- Run `pnpm build && pnpm ui:build` before `pnpm release:check` so the expected
`dist/*` release artifacts and Control UI bundle exist for the pack
validation step
- Run `pnpm release:check` before every tagged release
- Run `RELEASE_TAG=vYYYY.M.D node --import tsx scripts/openclaw-npm-release-check.ts`
(or the matching beta/correction tag) before approval
@@ -46,6 +47,13 @@ OpenClaw has three public release lanes:
`node --import tsx scripts/openclaw-npm-postpublish-verify.ts YYYY.M.D`
(or the matching beta/correction version) to verify the published registry
install path in a fresh temp prefix
- Maintainer release automation now uses preflight-then-promote:
- real npm publish must pass a successful npm `preflight_run_id`
- public `macOS Release` is validation-only
- real private mac publish must pass successful private mac
`preflight_run_id` and `validate_run_id`
- the real publish paths promote prepared artifacts instead of rebuilding
them again
- For stable correction releases like `YYYY.M.D-N`, the post-publish verifier
also checks the same temp-prefix upgrade path from `YYYY.M.D` to `YYYY.M.D-N`
so release corrections cannot silently leave older global installs on the

View File

@@ -20,9 +20,18 @@ For Anthropic pricing details, see:
## Primary knobs
### `cacheRetention` (model and per-agent)
### `cacheRetention` (global default, model, and per-agent)
Set cache retention on model params:
Set cache retention as a global default for all models:
```yaml
agents:
defaults:
params:
cacheRetention: "long" # none | short | long
```
Override per-model:
```yaml
agents:
@@ -45,8 +54,9 @@ agents:
Config merge order:
1. `agents.defaults.models["provider/model"].params`
2. `agents.list[].params` (matching agent id; overrides by key)
1. `agents.defaults.params` (global default — applies to all models)
2. `agents.defaults.models["provider/model"].params` (per-model override)
3. `agents.list[].params` (matching agent id; overrides by key)
### Legacy `cacheControlTtl`

View File

@@ -119,7 +119,7 @@ All fields are optional unless noted:
- `fileScale` (`number`): device scale override (`1`-`4`).
- `fileMaxWidth` (`number`): max render width in CSS pixels (`640`-`2400`).
- `ttlSeconds` (`number`): viewer artifact TTL in seconds. Default 1800, max 21600.
- `baseUrl` (`string`): viewer URL origin override. Must be `http` or `https`, no query/hash.
- `baseUrl` (`string`): viewer URL origin override. Overrides plugin `viewerBaseUrl`. Must be `http` or `https`, no query/hash.
Validation and limits:
@@ -231,6 +231,29 @@ Supported defaults:
Explicit tool parameters override these defaults.
Persistent viewer URL config:
- `viewerBaseUrl` (`string`, optional)
- Plugin-owned fallback for returned viewer links when a tool call does not pass `baseUrl`.
- Must be `http` or `https`, no query/hash.
Example:
```json5
{
plugins: {
entries: {
diffs: {
enabled: true,
config: {
viewerBaseUrl: "https://gateway.example.com/openclaw",
},
},
},
},
}
```
## Security config
- `security.allowRemoteViewer` (`boolean`, default `false`)
@@ -285,8 +308,9 @@ The viewer document resolves those assets relative to the viewer URL, so an opti
URL construction behavior:
- If `baseUrl` is provided, it is used after strict validation.
- Without `baseUrl`, viewer URL defaults to loopback `127.0.0.1`.
- If tool-call `baseUrl` is provided, it is used after strict validation.
- Else if plugin `viewerBaseUrl` is configured, it is used.
- Without either override, viewer URL defaults to loopback `127.0.0.1`.
- If gateway bind mode is `custom` and `gateway.customBindHost` is set, that host is used.
`baseUrl` rules:
@@ -353,8 +377,13 @@ Viewer accessibility issues:
- Viewer URL resolves to `127.0.0.1` by default.
- For remote access scenarios, either:
- set plugin `viewerBaseUrl`, or
- pass `baseUrl` per tool call, or
- use `gateway.bind=custom` and `gateway.customBindHost`
- If `gateway.trustedProxies` includes loopback for a same-host proxy (for example Tailscale Serve), raw loopback viewer requests without forwarded client-IP headers fail closed by design.
- For that proxy topology:
- prefer `mode: "file"` or `mode: "both"` when you only need an attachment, or
- intentionally enable `security.allowRemoteViewer` and set plugin `viewerBaseUrl` or pass a proxy/public `baseUrl` when you need a shareable viewer URL
- Enable `security.allowRemoteViewer` only when you intend external viewer access.
Unmodified-lines row has no expand button:

View File

@@ -14,6 +14,12 @@ commands on a real host (`gateway` or `node`). Think of it like a safety interlo
commands are allowed only when policy + allowlist + (optional) user approval all agree.
Exec approvals are **in addition** to tool policy and elevated gating (unless elevated is set to `full`, which skips approvals).
Effective policy is the **stricter** of `tools.exec.*` and approvals defaults; if an approvals field is omitted, the `tools.exec` value is used.
Host exec also uses the local approvals state on that machine. A host-local
`ask: "always"` in `~/.openclaw/exec-approvals.json` keeps prompting even if
session or config defaults request `ask: "on-miss"`.
Use `openclaw approvals get`, `openclaw approvals get --gateway`, or
`openclaw approvals get --node <id|name|ip>` to inspect the requested policy,
host policy sources, and the effective result.
If the companion app UI is **not available**, any request that requires a prompt is
resolved by the **ask fallback** (default: deny).
@@ -98,6 +104,7 @@ Example schema:
- **off**: never prompt.
- **on-miss**: prompt only when allowlist does not match.
- **always**: prompt on every command.
- `allow-always` durable trust does not suppress prompts when effective ask mode is `always`
### Ask fallback (`askFallback`)
@@ -132,6 +139,7 @@ Allowlists are **per agent**. If multiple agents exist, switch which agent you
editing in the macOS app. Patterns are **case-insensitive glob matches**.
Patterns should resolve to **binary paths** (basename-only entries are ignored).
Legacy `agents.default` entries are migrated to `agents.main` on load.
Shell chains such as `echo ok && pwd` still need every top-level segment to satisfy allowlist rules.
Examples:
@@ -415,9 +423,10 @@ resolved approver list for authorization even when native approval delivery is d
### Native approval delivery
Discord and Telegram can also act as native approval-delivery adapters with channel-specific config.
Discord, Slack, and Telegram can also act as native approval-delivery adapters with channel-specific config.
- Discord: `channels.discord.execApprovals.*`
- Slack: uses shared `approvals.exec.targets` with `channel: "slack"` and renders Block Kit approval buttons when interactivity is enabled
- Telegram: `channels.telegram.execApprovals.*`
These native delivery adapters are opt-in. They add DM routing and channel fanout on top of the

View File

@@ -132,6 +132,8 @@ Manual allowlist enforcement matches **resolved binary paths only** (no basename
allowlisted or a safe bin. Chaining (`;`, `&&`, `||`) and redirections are rejected in
allowlist mode unless every top-level segment satisfies the allowlist (including safe bins).
Redirections remain unsupported.
Durable `allow-always` trust does not bypass that rule: a chained command still requires every
top-level segment to match.
`autoAllowSkills` is a separate convenience path in exec approvals. It is not the same as
manual path allowlist entries. For strict explicit trust, keep `autoAllowSkills` disabled.

View File

@@ -10,7 +10,7 @@ read_when:
Lobster is a workflow shell that lets OpenClaw run multi-step tool sequences as a single, deterministic operation with explicit approval checkpoints.
Lobster is one authoring layer above [ClawFlow](/automation/clawflow). Lobster can decide the step logic, but ClawFlow still owns the job identity, owner context, and how detached work returns to the original conversation.
Lobster is one authoring layer above detached background work. For flow orchestration above individual tasks, see [TaskFlow](/automation/taskflow) (`openclaw flows`). For the task activity ledger, see [`openclaw tasks`](/automation/tasks).
## Hook

View File

@@ -58,6 +58,15 @@ tool with the `react` action. Reaction behavior varies by channel.
</Accordion>
</AccordionGroup>
## Reaction level
Per-channel `reactionLevel` config controls how broadly the agent uses reactions. Values are typically `off`, `ack`, `minimal`, or `extensive`.
- [Telegram reactionLevel](/channels/telegram#reaction-notifications) — `channels.telegram.reactionLevel`
- [WhatsApp reactionLevel](/channels/whatsapp#reactions) — `channels.whatsapp.reactionLevel`
Set `reactionLevel` on individual channels to tune how actively the agent reacts to messages on each platform.
## Related
- [Agent Send](/tools/agent-send) — the `message` tool that includes `react`

View File

@@ -0,0 +1,124 @@
---
summary: "SearXNG web search -- self-hosted, key-free meta-search provider"
read_when:
- You want a self-hosted web search provider
- You want to use SearXNG for web_search
- You need a privacy-focused or air-gapped search option
title: "SearXNG Search"
---
# SearXNG Search
OpenClaw supports [SearXNG](https://docs.searxng.org/) as a **self-hosted,
key-free** `web_search` provider. SearXNG is an open-source meta-search engine
that aggregates results from Google, Bing, DuckDuckGo, and other sources.
Advantages:
- **Free and unlimited** -- no API key or commercial subscription required
- **Privacy / air-gap** -- queries never leave your network
- **Works anywhere** -- no region restrictions on commercial search APIs
## Setup
<Steps>
<Step title="Run a SearXNG instance">
```bash
docker run -d -p 8888:8080 searxng/searxng
```
Or use any existing SearXNG deployment you have access to. See the
[SearXNG documentation](https://docs.searxng.org/) for production setup.
</Step>
<Step title="Configure">
```bash
openclaw configure --section web
# Select "searxng" as the provider
```
Or set the env var and let auto-detection find it:
```bash
export SEARXNG_BASE_URL="http://localhost:8888"
```
</Step>
</Steps>
## Config
```json5
{
tools: {
web: {
search: {
provider: "searxng",
},
},
},
}
```
Plugin-level settings for the SearXNG instance:
```json5
{
plugins: {
entries: {
searxng: {
config: {
webSearch: {
baseUrl: "http://localhost:8888",
categories: "general,news", // optional
language: "en", // optional
},
},
},
},
},
}
```
The `baseUrl` field also accepts SecretRef objects.
## Environment variable
Set `SEARXNG_BASE_URL` as an alternative to config:
```bash
export SEARXNG_BASE_URL="http://localhost:8888"
```
When `SEARXNG_BASE_URL` is set and no explicit provider is configured, auto-detection
picks SearXNG automatically (at the lowest priority -- any API-backed provider with a
key wins first).
## Plugin config reference
| Field | Description |
| ------------ | ------------------------------------------------------------------ |
| `baseUrl` | Base URL of your SearXNG instance (required) |
| `categories` | Comma-separated categories such as `general`, `news`, or `science` |
| `language` | Language code for results such as `en`, `de`, or `fr` |
## Notes
- **JSON API** -- uses SearXNG's native `format=json` endpoint, not HTML scraping
- **No API key** -- works with any SearXNG instance out of the box
- **Auto-detection order** -- SearXNG is checked last (order 200) in auto-detection,
so any API-backed provider with a key takes priority over SearXNG, and SearXNG sits
behind DuckDuckGo (order 100) as well
- **Self-hosted** -- you control the instance, queries, and upstream search engines
- **Categories** default to `general` when not configured
<Tip>
For SearXNG JSON API to work, make sure your SearXNG instance has the `json`
format enabled in its `settings.yml` under `search.formats`.
</Tip>
## Related
- [Web Search overview](/tools/web) -- all providers and auto-detection
- [DuckDuckGo Search](/tools/duckduckgo-search) -- another key-free fallback
- [Brave Search](/tools/brave-search) -- structured results with free tier

View File

@@ -78,8 +78,9 @@ Text + native (when enabled):
- `/tools [compact|verbose]` (show what the current agent can use right now; `verbose` adds descriptions)
- `/skill <name> [input]` (run a skill by name)
- `/status` (show current status; includes provider usage/quota for the current model provider when available)
- `/tasks` (list background tasks for the current session; shows active and recent task details with agent-local fallback counts)
- `/allowlist` (list/add/remove allowlist entries)
- `/approve <id> allow-once|allow-always|deny` (resolve exec approval prompts)
- `/approve <id> <decision>` (resolve exec approval prompts; use the pending approval message for the available decisions)
- `/context [list|detail|json]` (explain “context”; `detail` shows per-file + per-tool + per-skill + system prompt size)
- `/btw <question>` (ask an ephemeral side question about the current session without changing future session context; see [/tools/btw](/tools/btw))
- `/export-session [path]` (alias: `/export`) (export current session to HTML with full system prompt)
@@ -146,6 +147,7 @@ Notes:
- `/fast` is provider-specific: OpenAI/OpenAI Codex map it to `service_tier=priority` on native Responses endpoints, while direct public Anthropic requests, including OAuth-authenticated traffic sent to `api.anthropic.com`, map it to `service_tier=auto` or `standard_only`. See [OpenAI](/providers/openai) and [Anthropic](/providers/anthropic).
- Tool failure summaries are still shown when relevant, but detailed failure text is only included when `/verbose` is `on` or `full`.
- `/reasoning` (and `/verbose`) are risky in group settings: they may reveal internal reasoning or tool output you did not intend to expose. Prefer leaving them off, especially in group chats.
- `/model` persists the new session model immediately, but it does not interrupt a busy run. The current turn finishes first, then queued or future work uses the updated model.
- **Fast path:** command-only messages from allowlisted senders are handled immediately (bypass queue + model).
- **Group mention gating:** command-only messages from allowlisted senders bypass mention requirements.
- **Inline shortcuts (allowlisted senders only):** certain commands also work when embedded in a normal message and are stripped before the model sees the remaining text.

View File

@@ -81,6 +81,9 @@ local while `web_search` and `x_search` can use xAI Responses under the hood.
<Card title="Perplexity" icon="search" href="/tools/perplexity-search">
Structured results with content extraction controls and domain filtering.
</Card>
<Card title="SearXNG" icon="server" href="/tools/searxng-search">
Self-hosted meta-search. No API key needed. Aggregates Google, Bing, DuckDuckGo, and more.
</Card>
<Card title="Tavily" icon="globe" href="/tools/tavily">
Structured results with search depth, topic filtering, and `tavily_extract` for URL extraction.
</Card>
@@ -98,6 +101,7 @@ local while `web_search` and `x_search` can use xAI Responses under the hood.
| [Grok](/tools/grok-search) | AI-synthesized + citations | -- | `XAI_API_KEY` |
| [Kimi](/tools/kimi-search) | AI-synthesized + citations | -- | `KIMI_API_KEY` / `MOONSHOT_API_KEY` |
| [Perplexity](/tools/perplexity-search) | Structured snippets | Country, language, time, domains, content limits | `PERPLEXITY_API_KEY` / `OPENROUTER_API_KEY` |
| [SearXNG](/tools/searxng-search) | Structured snippets | Categories, language | None (self-hosted) |
| [Tavily](/tools/tavily) | Structured snippets | Via `tavily_search` tool | `TAVILY_API_KEY` |
## Auto-detection
@@ -153,8 +157,13 @@ the first one found:
6. **Firecrawl** -- `FIRECRAWL_API_KEY` or `plugins.entries.firecrawl.config.webSearch.apiKey`
7. **Tavily** -- `TAVILY_API_KEY` or `plugins.entries.tavily.config.webSearch.apiKey`
If no keys are found, it falls back to Brave (you will get a missing-key error
prompting you to configure one).
Key-free providers are checked after API-backed providers:
8. **DuckDuckGo** -- no key needed (auto-detect order 100)
9. **SearXNG** -- `SEARXNG_BASE_URL` or `plugins.entries.searxng.config.webSearch.baseUrl` (auto-detect order 200)
If no provider is detected, it falls back to Brave (you will get a missing-key
error prompting you to configure one).
<Note>
All provider key fields support SecretRef objects. In auto-detect mode,

View File

@@ -52,9 +52,9 @@ Status: the macOS/iOS SwiftUI chat UI talks directly to the Gateway WebSocket.
Full configuration: [Configuration](/gateway/configuration)
Channel options:
WebChat options:
- No dedicated `webchat.*` block. WebChat uses the gateway endpoint + auth settings below.
- `gateway.webchat.chatHistoryMaxChars`: maximum character count for text fields in `chat.history` responses. When a transcript entry exceeds this limit, Gateway truncates long text fields and may replace oversized messages with a placeholder. Per-request `maxChars` can also be sent by the client to override this default for a single `chat.history` call.
Related global options:

View File

@@ -1,6 +1,6 @@
{
"name": "@openclaw/acpx",
"version": "2026.3.31-beta.1",
"version": "2026.4.1-beta.1",
"description": "OpenClaw ACP runtime backend via acpx",
"type": "module",
"dependencies": {

View File

@@ -116,6 +116,36 @@ describe("resolveSpawnCommand", () => {
});
});
it("falls back to node on PATH when execPath is unavailable for a node shebang wrapper", async () => {
const dir = await createTempDir();
const binDir = path.join(dir, "bin");
const scriptPath = path.join(binDir, "acpx");
const nodePath = path.join(binDir, "node");
await mkdir(binDir, { recursive: true });
await writeFile(scriptPath, "#!/usr/bin/env node\nconsole.log('ok')\n", "utf8");
await writeFile(nodePath, "#!/bin/sh\nexit 0\n", "utf8");
await chmod(scriptPath, 0o755);
await chmod(nodePath, 0o755);
const resolved = resolveSpawnCommand(
{
command: scriptPath,
args: ["--help"],
},
undefined,
{
platform: "darwin",
env: { PATH: binDir },
execPath: "/missing/node",
},
);
expect(resolved).toEqual({
command: nodePath,
args: [scriptPath, "--help"],
});
});
it("routes .js command execution through node on windows", () => {
const resolved = resolveSpawnCommand(
{

View File

@@ -88,6 +88,13 @@ function resolveExecutableFromPath(command: string, runtime: SpawnRuntime): stri
return undefined;
}
function resolveNodeExecPath(runtime: SpawnRuntime): string {
if (runtime.execPath && isExecutableFile(runtime.execPath, runtime.platform)) {
return runtime.execPath;
}
return resolveExecutableFromPath("node", runtime) ?? runtime.execPath;
}
function resolveNodeShebangScriptPath(command: string, runtime: SpawnRuntime): string | undefined {
const commandPath =
path.isAbsolute(command) || command.includes(path.sep)
@@ -122,7 +129,7 @@ export function resolveSpawnCommand(
resolution: "direct",
});
return {
command: runtime.execPath,
command: resolveNodeExecPath(runtime),
args: [nodeShebangScript, ...params.args],
};
}

View File

@@ -47,6 +47,7 @@ async function expectSessionEnsureFallback(params: {
env?: Record<string, string>;
expectNewAfterStatus: boolean;
expectedRecordId?: string;
expectedResumeSessionId?: string | null;
}) {
const previousEnv = new Map<string, string | undefined>();
for (const [key, value] of Object.entries(params.env ?? {})) {
@@ -70,13 +71,26 @@ async function expectSessionEnsureFallback(params: {
const logs = await readMockRuntimeLogEntries(logPath);
const ensureIndex = logs.findIndex((entry) => entry.kind === "ensure");
const statusIndex = logs.findIndex((entry) => entry.kind === "status");
const newIndex = logs.findIndex((entry) => entry.kind === "new");
const newEntries = logs.filter((entry) => entry.kind === "new");
const newEntry = newEntries[0] ?? null;
const newIndex = newEntry ? logs.indexOf(newEntry) : -1;
expect(ensureIndex).toBeGreaterThanOrEqual(0);
expect(statusIndex).toBeGreaterThan(ensureIndex);
if (params.expectNewAfterStatus) {
expect(newEntries).toHaveLength(1);
expect(newIndex).toBeGreaterThan(statusIndex);
} else {
expect(newIndex).toBe(-1);
expect(newEntries).toHaveLength(0);
}
const newArgs = ((newEntry?.args as string[]) ?? []).slice();
const resumeFlagIndex = newArgs.indexOf("--resume-session");
if (params.expectedResumeSessionId === undefined) {
// No assertion requested for resume behavior.
} else if (params.expectedResumeSessionId === null) {
expect(resumeFlagIndex).toBe(-1);
} else {
expect(resumeFlagIndex).toBeGreaterThanOrEqual(0);
expect(newArgs[resumeFlagIndex + 1]).toBe(params.expectedResumeSessionId);
}
} finally {
for (const [key, value] of previousEnv.entries()) {
@@ -241,14 +255,15 @@ describe("AcpxRuntime", () => {
expect(resumeArgs[resumeFlagIndex + 1]).toBe(resumeSessionId);
});
it("retains dead named sessions when status only reports queue owner unavailable", async () => {
it("repairs dead named sessions when status only reports queue owner unavailable", async () => {
await expectSessionEnsureFallback({
sessionKey: "agent:codex:acp:dead-session",
env: {
MOCK_ACPX_STATUS_STATUS: "dead",
MOCK_ACPX_STATUS_SUMMARY: "queue owner unavailable",
},
expectNewAfterStatus: false,
expectNewAfterStatus: true,
expectedResumeSessionId: "sid-agent:codex:acp:dead-session",
});
});
@@ -275,7 +290,7 @@ describe("AcpxRuntime", () => {
});
});
it("retains the named session after ensure failure when status only reports queue owner unavailable", async () => {
it("repairs the named session after ensure failure when status only reports queue owner unavailable", async () => {
await expectSessionEnsureFallback({
sessionKey: "agent:codex:acp:ensure-fallback-dead",
env: {
@@ -283,11 +298,73 @@ describe("AcpxRuntime", () => {
MOCK_ACPX_STATUS_STATUS: "dead",
MOCK_ACPX_STATUS_SUMMARY: "queue owner unavailable",
},
expectNewAfterStatus: false,
expectNewAfterStatus: true,
expectedRecordId: "rec-agent:codex:acp:ensure-fallback-dead",
expectedResumeSessionId: "sid-agent:codex:acp:ensure-fallback-dead",
});
});
it("falls back to a fresh named session when queue owner recovery has no resumable id", async () => {
await expectSessionEnsureFallback({
sessionKey: "agent:codex:acp:dead-session-no-ids",
env: {
MOCK_ACPX_STATUS_STATUS: "dead",
MOCK_ACPX_STATUS_SUMMARY: "queue owner unavailable",
MOCK_ACPX_STATUS_NO_IDS: "1",
},
expectNewAfterStatus: true,
expectedResumeSessionId: null,
});
});
it("falls back to a fresh named session when queue owner resume repair uses a stale session id", async () => {
const previousResumeFailure = process.env.MOCK_ACPX_NEW_FAIL_ON_RESUME;
const previousStatus = process.env.MOCK_ACPX_STATUS_STATUS;
const previousSummary = process.env.MOCK_ACPX_STATUS_SUMMARY;
process.env.MOCK_ACPX_NEW_FAIL_ON_RESUME = "1";
process.env.MOCK_ACPX_STATUS_STATUS = "dead";
process.env.MOCK_ACPX_STATUS_SUMMARY = "queue owner unavailable";
try {
const { runtime, logPath } = await createMockRuntimeFixture();
const handle = await runtime.ensureSession({
sessionKey: "agent:codex:acp:dead-session-stale-resume",
agent: "codex",
mode: "persistent",
});
expect(handle.backend).toBe("acpx");
const logs = await readMockRuntimeLogEntries(logPath);
const newEntries = logs.filter((entry) => entry.kind === "new");
expect(newEntries).toHaveLength(2);
const firstArgs = ((newEntries[0]?.args as string[]) ?? []).slice();
const secondArgs = ((newEntries[1]?.args as string[]) ?? []).slice();
const firstResumeFlagIndex = firstArgs.indexOf("--resume-session");
expect(firstResumeFlagIndex).toBeGreaterThanOrEqual(0);
expect(firstArgs[firstResumeFlagIndex + 1]).toBe(
"sid-agent:codex:acp:dead-session-stale-resume",
);
expect(secondArgs.indexOf("--resume-session")).toBe(-1);
} finally {
if (previousResumeFailure === undefined) {
delete process.env.MOCK_ACPX_NEW_FAIL_ON_RESUME;
} else {
process.env.MOCK_ACPX_NEW_FAIL_ON_RESUME = previousResumeFailure;
}
if (previousStatus === undefined) {
delete process.env.MOCK_ACPX_STATUS_STATUS;
} else {
process.env.MOCK_ACPX_STATUS_STATUS = previousStatus;
}
if (previousSummary === undefined) {
delete process.env.MOCK_ACPX_STATUS_SUMMARY;
} else {
process.env.MOCK_ACPX_STATUS_SUMMARY = previousSummary;
}
}
});
it("creates a fresh named session after ensure failure when status indicates an unrecoverable failure", async () => {
await expectSessionEnsureFallback({
sessionKey: "agent:codex:acp:ensure-fallback-dead-unrecoverable",
@@ -300,6 +377,84 @@ describe("AcpxRuntime", () => {
});
});
it("surfaces structured control-command errors from sessions ensure", async () => {
const previousEnsureExit = process.env.MOCK_ACPX_ENSURE_EXIT_1;
const previousStatusSignal = process.env.MOCK_ACPX_STATUS_SIGNAL;
process.env.MOCK_ACPX_ENSURE_EXIT_1 = "1";
process.env.MOCK_ACPX_STATUS_SIGNAL = "SIGTERM";
try {
const { runtime } = await createMockRuntimeFixture();
await expect(
runtime.ensureSession({
sessionKey: "agent:codex:acp:ensure-structured-error",
agent: "codex",
mode: "persistent",
}),
).rejects.toMatchObject({
code: "ACP_SESSION_INIT_FAILED",
message: "-32603: mock ensure failure",
});
} finally {
if (previousEnsureExit === undefined) {
delete process.env.MOCK_ACPX_ENSURE_EXIT_1;
} else {
process.env.MOCK_ACPX_ENSURE_EXIT_1 = previousEnsureExit;
}
if (previousStatusSignal === undefined) {
delete process.env.MOCK_ACPX_STATUS_SIGNAL;
} else {
process.env.MOCK_ACPX_STATUS_SIGNAL = previousStatusSignal;
}
}
});
it("appends stderr details when control-command errors are generic", async () => {
const previousEnsureExit = process.env.MOCK_ACPX_ENSURE_EXIT_1;
const previousEnsureMessage = process.env.MOCK_ACPX_ENSURE_ERROR_MESSAGE;
const previousEnsureStderr = process.env.MOCK_ACPX_ENSURE_STDERR;
const previousStatusSignal = process.env.MOCK_ACPX_STATUS_SIGNAL;
process.env.MOCK_ACPX_ENSURE_EXIT_1 = "1";
process.env.MOCK_ACPX_ENSURE_ERROR_MESSAGE = "Internal error";
process.env.MOCK_ACPX_ENSURE_STDERR = "usage limit exceeded";
process.env.MOCK_ACPX_STATUS_SIGNAL = "SIGTERM";
try {
const { runtime } = await createMockRuntimeFixture();
await expect(
runtime.ensureSession({
sessionKey: "agent:codex:acp:ensure-generic-error",
agent: "codex",
mode: "persistent",
}),
).rejects.toMatchObject({
code: "ACP_SESSION_INIT_FAILED",
message: "-32603: Internal error | usage limit exceeded",
});
} finally {
if (previousEnsureExit === undefined) {
delete process.env.MOCK_ACPX_ENSURE_EXIT_1;
} else {
process.env.MOCK_ACPX_ENSURE_EXIT_1 = previousEnsureExit;
}
if (previousEnsureMessage === undefined) {
delete process.env.MOCK_ACPX_ENSURE_ERROR_MESSAGE;
} else {
process.env.MOCK_ACPX_ENSURE_ERROR_MESSAGE = previousEnsureMessage;
}
if (previousEnsureStderr === undefined) {
delete process.env.MOCK_ACPX_ENSURE_STDERR;
} else {
process.env.MOCK_ACPX_ENSURE_STDERR = previousEnsureStderr;
}
if (previousStatusSignal === undefined) {
delete process.env.MOCK_ACPX_STATUS_SIGNAL;
} else {
process.env.MOCK_ACPX_STATUS_SIGNAL = previousStatusSignal;
}
}
});
it("serializes text plus image attachments into ACP prompt blocks", async () => {
const { runtime, logPath } = await createMockRuntimeFixture();

View File

@@ -14,6 +14,7 @@ import type {
import { AcpRuntimeError } from "../runtime-api.js";
import { toAcpMcpServers, type ResolvedAcpxPluginConfig } from "./config.js";
import { checkAcpxVersion, type AcpxVersionCheckResult } from "./ensure.js";
import { parseControlJsonError } from "./runtime-internals/control-errors.js";
import {
parseJsonLines,
parsePromptEventLine,
@@ -73,6 +74,11 @@ type AcpxHealthCheckResult =
};
};
type EnsureFailureRecoveryResult = {
events: AcpxJsonObject[];
skipPostEnsureReplacement: boolean;
};
function formatPermissionModeGuidance(): string {
return "Configure plugins.entries.acpx.config.permissionMode to one of: approve-reads, approve-all, deny-all.";
}
@@ -128,6 +134,29 @@ function shouldRetainNamedSessionForDeadStatus(detail: AcpxJsonObject | undefine
return summary?.includes("queue owner unavailable") ?? false;
}
function resolveResumeSessionIdFromDetail(detail: AcpxJsonObject | undefined): string | undefined {
return asOptionalString(detail?.acpxSessionId) ?? asOptionalString(detail?.agentSessionId);
}
function formatAcpxControlErrorMessage(params: {
code?: string;
message: string;
stderr: string;
}): string {
const baseMessage = params.code ? `${params.code}: ${params.message}` : params.message;
const stderrSummary = summarizeLogText(params.stderr);
if (!stderrSummary) {
return baseMessage;
}
if (
/^(?:internal error|acpx reported an error)$/i.test(params.message) &&
!baseMessage.includes(stderrSummary)
) {
return `${baseMessage} | ${stderrSummary}`;
}
return baseMessage;
}
function findSessionIdentifierEvent(events: AcpxJsonObject[]): AcpxJsonObject | undefined {
return events.find(
(event) =>
@@ -330,11 +359,54 @@ export class AcpxRuntime implements AcpRuntime {
});
}
private async replaceDeadNamedSession(params: {
detail: AcpxJsonObject | undefined;
sessionName: string;
agent: string;
cwd: string;
logContext: string;
}): Promise<AcpxJsonObject[]> {
const resumeSessionId = resolveResumeSessionIdFromDetail(params.detail);
if (!resumeSessionId) {
this.logger?.warn?.(
`acpx ensureSession repairing dead named session with fresh session owner: session=${params.sessionName} cwd=${params.cwd} ${params.logContext}`,
);
return await this.createNamedSession({
agent: params.agent,
cwd: params.cwd,
sessionName: params.sessionName,
});
}
this.logger?.warn?.(
`acpx ensureSession repairing dead named session by resuming backend session: session=${params.sessionName} cwd=${params.cwd} resumeSessionId=${resumeSessionId} ${params.logContext}`,
);
try {
return await this.createNamedSession({
agent: params.agent,
cwd: params.cwd,
sessionName: params.sessionName,
resumeSessionId,
});
} catch (error) {
if (!(error instanceof AcpRuntimeError) || error.code !== "ACP_SESSION_INIT_FAILED") {
throw error;
}
this.logger?.warn?.(
`acpx ensureSession dead-session resume repair failed; retrying with fresh session owner: session=${params.sessionName} cwd=${params.cwd} resumeSessionId=${resumeSessionId} error=${summarizeLogText(error.message) || "<empty>"} ${params.logContext}`,
);
return await this.createNamedSession({
agent: params.agent,
cwd: params.cwd,
sessionName: params.sessionName,
});
}
}
private async shouldReplaceEnsuredSession(params: {
sessionName: string;
agent: string;
cwd: string;
}): Promise<boolean> {
}): Promise<{ replace: boolean; replacementEvents?: AcpxJsonObject[] }> {
const args = await this.buildVerbArgs({
agent: params.agent,
cwd: params.cwd,
@@ -352,7 +424,7 @@ export class AcpxRuntime implements AcpRuntime {
this.logger?.warn?.(
`acpx ensureSession status probe failed: session=${params.sessionName} cwd=${params.cwd} error=${summarizeLogText(error instanceof Error ? error.message : String(error)) || "<empty>"}`,
);
return false;
return { replace: false };
}
const noSession = events.some((event) => toAcpxErrorEvent(event)?.code === "NO_SESSION");
@@ -360,7 +432,7 @@ export class AcpxRuntime implements AcpRuntime {
this.logger?.warn?.(
`acpx ensureSession replacing missing named session: session=${params.sessionName} cwd=${params.cwd}`,
);
return true;
return { replace: true };
}
const detail = events.find((event) => !toAcpxErrorEvent(event));
@@ -368,18 +440,24 @@ export class AcpxRuntime implements AcpRuntime {
if (status === "dead") {
const summary = summarizeLogText(asOptionalString(detail?.summary) ?? "");
if (shouldRetainNamedSessionForDeadStatus(detail)) {
this.logger?.warn?.(
`acpx ensureSession retaining dead named session with recoverable status: session=${params.sessionName} cwd=${params.cwd} status=${status} summary=${summary || "<empty>"}`,
);
return false;
return {
replace: true,
replacementEvents: await this.replaceDeadNamedSession({
detail,
sessionName: params.sessionName,
agent: params.agent,
cwd: params.cwd,
logContext: `status=${status} summary=${summary || "<empty>"}`,
}),
};
}
this.logger?.warn?.(
`acpx ensureSession replacing dead named session: session=${params.sessionName} cwd=${params.cwd} status=${status} summary=${summary || "<empty>"}`,
);
return true;
return { replace: true };
}
return false;
return { replace: false };
}
private async recoverEnsureFailure(params: {
@@ -387,7 +465,7 @@ export class AcpxRuntime implements AcpRuntime {
agent: string;
cwd: string;
error: unknown;
}): Promise<AcpxJsonObject[] | null> {
}): Promise<EnsureFailureRecoveryResult | null> {
const errorMessage = summarizeLogText(
params.error instanceof Error ? params.error.message : String(params.error),
);
@@ -419,11 +497,14 @@ export class AcpxRuntime implements AcpRuntime {
this.logger?.warn?.(
`acpx ensureSession creating named session after ensure failure and missing status: session=${params.sessionName} cwd=${params.cwd}`,
);
return await this.createNamedSession({
agent: params.agent,
cwd: params.cwd,
sessionName: params.sessionName,
});
return {
events: await this.createNamedSession({
agent: params.agent,
cwd: params.cwd,
sessionName: params.sessionName,
}),
skipPostEnsureReplacement: true,
};
}
const detail = events.find((event) => !toAcpxErrorEvent(event));
@@ -431,26 +512,38 @@ export class AcpxRuntime implements AcpRuntime {
if (status === "dead") {
const summary = summarizeLogText(asOptionalString(detail?.summary) ?? "");
if (shouldRetainNamedSessionForDeadStatus(detail)) {
this.logger?.warn?.(
`acpx ensureSession retaining dead named session after ensure failure with recoverable status: session=${params.sessionName} cwd=${params.cwd} status=${status} summary=${summary || "<empty>"}`,
);
return events;
return {
events: await this.replaceDeadNamedSession({
detail,
sessionName: params.sessionName,
agent: params.agent,
cwd: params.cwd,
logContext: `status=${status} summary=${summary || "<empty>"}`,
}),
skipPostEnsureReplacement: true,
};
}
this.logger?.warn?.(
`acpx ensureSession replacing dead named session after ensure failure: session=${params.sessionName} cwd=${params.cwd}`,
);
return await this.createNamedSession({
agent: params.agent,
cwd: params.cwd,
sessionName: params.sessionName,
});
return {
events: await this.createNamedSession({
agent: params.agent,
cwd: params.cwd,
sessionName: params.sessionName,
}),
skipPostEnsureReplacement: true,
};
}
if (status === "alive" || findSessionIdentifierEvent(events)) {
this.logger?.warn?.(
`acpx ensureSession reusing live named session after ensure failure: session=${params.sessionName} cwd=${params.cwd} status=${status || "unknown"}`,
);
return events;
return {
events,
skipPostEnsureReplacement: false,
};
}
return null;
@@ -469,6 +562,7 @@ export class AcpxRuntime implements AcpRuntime {
const mode = input.mode;
const resumeSessionId = asTrimmedString(input.resumeSessionId);
let events: AcpxJsonObject[];
let skipPostEnsureReplacement = false;
if (resumeSessionId) {
events = await this.createNamedSession({
agent,
@@ -497,7 +591,8 @@ export class AcpxRuntime implements AcpRuntime {
if (!recovered) {
throw error;
}
events = recovered;
events = recovered.events;
skipPostEnsureReplacement = recovered.skipPostEnsureReplacement;
}
}
if (events.length === 0) {
@@ -507,26 +602,27 @@ export class AcpxRuntime implements AcpRuntime {
}
let ensuredEvent = findSessionIdentifierEvent(events);
if (
ensuredEvent &&
!resumeSessionId &&
(await this.shouldReplaceEnsuredSession({
if (ensuredEvent && !resumeSessionId && !skipPostEnsureReplacement) {
const replacement = await this.shouldReplaceEnsuredSession({
sessionName,
agent,
cwd,
}))
) {
events = await this.createNamedSession({
agent,
cwd,
sessionName,
});
if (events.length === 0) {
this.logger?.warn?.(
`acpx ensureSession returned no events after replacing dead session: session=${sessionName} agent=${agent} cwd=${cwd}`,
);
if (replacement.replace) {
events =
replacement.replacementEvents ??
(await this.createNamedSession({
agent,
cwd,
sessionName,
}));
if (events.length === 0) {
this.logger?.warn?.(
`acpx ensureSession returned no events after replacing dead session: session=${sessionName} agent=${agent} cwd=${cwd}`,
);
}
ensuredEvent = findSessionIdentifierEvent(events);
}
ensuredEvent = findSessionIdentifierEvent(events);
}
if (!ensuredEvent && !resumeSessionId) {
@@ -1037,14 +1133,21 @@ export class AcpxRuntime implements AcpRuntime {
}
const events = parseJsonLines(result.stdout);
const errorEvent = events.map((event) => toAcpxErrorEvent(event)).find(Boolean) ?? null;
const errorEvent =
events
.map((event) => toAcpxErrorEvent(event) ?? parseControlJsonError(event))
.find(Boolean) ?? null;
if (errorEvent) {
if (params.ignoreNoSession && errorEvent.code === "NO_SESSION") {
return events;
}
throw new AcpRuntimeError(
params.fallbackCode,
errorEvent.code ? `${errorEvent.code}: ${errorEvent.message}` : errorEvent.message,
formatAcpxControlErrorMessage({
code: errorEvent.code,
message: errorEvent.message,
stderr: result.stderr,
}),
);
}

View File

@@ -1,3 +1,6 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { AcpRuntimeError } from "openclaw/plugin-sdk/acp-runtime";
import {
__testing,
@@ -20,6 +23,11 @@ vi.mock("./ensure.js", () => ({
type RuntimeStub = AcpRuntime & {
probeAvailability(): Promise<void>;
isHealthy(): boolean;
doctor?(): Promise<{
ok: boolean;
message: string;
details?: string[];
}>;
};
function createRuntimeStub(healthy: boolean): {
@@ -53,6 +61,56 @@ function createRuntimeStub(healthy: boolean): {
};
}
function createRetryingRuntimeStub(
healthSequence: boolean[],
doctorReport: { ok: boolean; message: string; details?: string[] } = {
ok: false,
message: "acpx help check failed",
details: ["stderr=temporary startup race"],
},
): {
runtime: RuntimeStub;
probeAvailabilitySpy: ReturnType<typeof vi.fn>;
isHealthySpy: ReturnType<typeof vi.fn>;
doctorSpy: ReturnType<typeof vi.fn>;
} {
let probeCount = 0;
const probeAvailabilitySpy = vi.fn(async () => {
probeCount += 1;
});
const isHealthySpy = vi.fn(() => {
const index = Math.max(0, probeCount - 1);
return healthSequence[Math.min(index, healthSequence.length - 1)] ?? false;
});
const doctorSpy = vi.fn(async () => doctorReport);
return {
runtime: {
ensureSession: vi.fn(async (input) => ({
sessionKey: input.sessionKey,
backend: "acpx",
runtimeSessionName: input.sessionKey,
})),
runTurn: vi.fn(async function* () {
yield { type: "done" as const };
}),
cancel: vi.fn(async () => {}),
close: vi.fn(async () => {}),
async probeAvailability() {
await probeAvailabilitySpy();
},
isHealthy() {
return isHealthySpy();
},
async doctor() {
return await doctorSpy();
},
},
probeAvailabilitySpy,
isHealthySpy,
doctorSpy,
};
}
function createServiceContext(
overrides: Partial<OpenClawPluginServiceContext> = {},
): OpenClawPluginServiceContext {
@@ -105,6 +163,7 @@ describe("createAcpxRuntimeService", () => {
const { runtime } = createRuntimeStub(false);
const service = createAcpxRuntimeService({
runtimeFactory: () => runtime,
healthProbeRetryDelaysMs: [],
});
const context = createServiceContext();
@@ -177,4 +236,79 @@ describe("createAcpxRuntimeService", () => {
expect(startResult).toBe("started");
expect(getAcpRuntimeBackend("acpx")?.runtime).toBe(runtime);
});
it("creates the workspace dir before probing acpx", async () => {
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "acpx-service-workspace-"));
const workspaceDir = path.join(tempRoot, "workspace");
const { runtime, probeAvailabilitySpy } = createRuntimeStub(true);
const service = createAcpxRuntimeService({
runtimeFactory: ({ pluginConfig }) => {
expect(pluginConfig.cwd).toBe(workspaceDir);
return runtime;
},
});
const context = createServiceContext({ workspaceDir });
try {
await service.start(context);
expect(fs.existsSync(workspaceDir)).toBe(true);
await vi.waitFor(() => {
expect(probeAvailabilitySpy).toHaveBeenCalledOnce();
});
} finally {
await service.stop?.(context);
fs.rmSync(tempRoot, { recursive: true, force: true });
}
});
it("retries health probes until the runtime becomes healthy", async () => {
const { runtime, probeAvailabilitySpy, doctorSpy } = createRetryingRuntimeStub([
false,
false,
true,
]);
const service = createAcpxRuntimeService({
runtimeFactory: () => runtime,
healthProbeRetryDelaysMs: [0, 0],
});
const context = createServiceContext();
await service.start(context);
await vi.waitFor(() => {
expect(probeAvailabilitySpy).toHaveBeenCalledTimes(3);
});
expect(doctorSpy).toHaveBeenCalledTimes(2);
expect(context.logger.warn).toHaveBeenCalledWith(
expect.stringContaining("probe attempt 1 failed"),
);
expect(context.logger.info).toHaveBeenCalledWith(
"acpx runtime backend ready after 3 probe attempts",
);
});
it("does not treat doctor ok as healthy when the runtime still reports unhealthy", async () => {
const { runtime, probeAvailabilitySpy, doctorSpy } = createRetryingRuntimeStub([false], {
ok: true,
message: "acpx help check passed",
});
const service = createAcpxRuntimeService({
runtimeFactory: () => runtime,
healthProbeRetryDelaysMs: [],
});
const context = createServiceContext();
await service.start(context);
await vi.waitFor(() => {
expect(probeAvailabilitySpy).toHaveBeenCalledOnce();
expect(doctorSpy).toHaveBeenCalledOnce();
expect(context.logger.warn).toHaveBeenCalledWith(
"acpx runtime backend probe failed: acpx help check passed",
);
});
expect(context.logger.info).not.toHaveBeenCalledWith("acpx runtime backend ready");
expect(() => requireAcpRuntimeBackend("acpx")).toThrowError(AcpRuntimeError);
});
});

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