mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-12 17:23:20 +08:00
Compare commits
441 Commits
codex/doct
...
fix/codeql
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16a367787c | ||
|
|
a07aaee3ec | ||
|
|
42ec7a868f | ||
|
|
0970507078 | ||
|
|
56de930628 | ||
|
|
453789914b | ||
|
|
d4a9b28d0c | ||
|
|
32dd1ffc5a | ||
|
|
52ea8eadcb | ||
|
|
e68b2269b9 | ||
|
|
a9c46d5b1a | ||
|
|
d1386ada5a | ||
|
|
ead8be96fd | ||
|
|
835c4e053c | ||
|
|
3a7ee209c9 | ||
|
|
41f9768cd8 | ||
|
|
a9a308becd | ||
|
|
50d3bd638a | ||
|
|
f86f8400f5 | ||
|
|
0d3a5c3101 | ||
|
|
2cacd2097b | ||
|
|
52cc1ebac7 | ||
|
|
d9bd010e5e | ||
|
|
0bd8d0bba0 | ||
|
|
ea168c22ce | ||
|
|
c018e73475 | ||
|
|
e2ade56952 | ||
|
|
8262735354 | ||
|
|
cc0f3067a0 | ||
|
|
f3330f5db6 | ||
|
|
019ef71fe8 | ||
|
|
9ca1f1a64e | ||
|
|
fde4bf7fc1 | ||
|
|
d42b0e043c | ||
|
|
2d2402cee8 | ||
|
|
3a14a95085 | ||
|
|
b33eb93aac | ||
|
|
c9b9d33451 | ||
|
|
5086069c94 | ||
|
|
b86a04262d | ||
|
|
d8ae63e7a2 | ||
|
|
61250e2bea | ||
|
|
718dffd2f2 | ||
|
|
25a02825a5 | ||
|
|
5a202f6f90 | ||
|
|
6d49681a62 | ||
|
|
d610e2cc6c | ||
|
|
5ea0ded5a5 | ||
|
|
664b9fe7eb | ||
|
|
867b4c2a32 | ||
|
|
f9207e5d39 | ||
|
|
63dc5089b2 | ||
|
|
8a0cb03300 | ||
|
|
ae57a7998e | ||
|
|
7c0549bd9f | ||
|
|
d12987d725 | ||
|
|
26bc5e47ee | ||
|
|
df5abf9a98 | ||
|
|
554f93a999 | ||
|
|
377e254f6a | ||
|
|
8a490f4509 | ||
|
|
4e42a4cfe8 | ||
|
|
da773175f2 | ||
|
|
d399ac74f7 | ||
|
|
b7c8c53af2 | ||
|
|
de8a00d922 | ||
|
|
30aa1f890a | ||
|
|
b5a5b59742 | ||
|
|
e3cba98f39 | ||
|
|
915931aa38 | ||
|
|
b69e3b633b | ||
|
|
492dfdc7f2 | ||
|
|
61ee67aecc | ||
|
|
107d2b7a09 | ||
|
|
5f81147c4d | ||
|
|
59f8a2c3fa | ||
|
|
db958463f6 | ||
|
|
f4add8047b | ||
|
|
a580db58ca | ||
|
|
8ca66cad68 | ||
|
|
ea74e01ed6 | ||
|
|
e625651de8 | ||
|
|
fb80405693 | ||
|
|
829ace53d3 | ||
|
|
ddedcac54a | ||
|
|
741d5d3231 | ||
|
|
45730f6117 | ||
|
|
14e0a8c2bc | ||
|
|
4e9c83d4d8 | ||
|
|
aa27e27f36 | ||
|
|
60e7b692cc | ||
|
|
1d4859dc53 | ||
|
|
d1cc54866d | ||
|
|
cc2b4cf125 | ||
|
|
b9b97f2653 | ||
|
|
a1087ea7a6 | ||
|
|
c12af80b5b | ||
|
|
a57fbc8026 | ||
|
|
d4d4a8c14e | ||
|
|
fbf8b216c6 | ||
|
|
e40d7abda9 | ||
|
|
82020bd787 | ||
|
|
acb10cd21c | ||
|
|
f6504ceb1d | ||
|
|
b3db7c6987 | ||
|
|
5dab0dae56 | ||
|
|
0376987691 | ||
|
|
2b5c719a62 | ||
|
|
dea05aae6b | ||
|
|
45e2a15e29 | ||
|
|
86856b88e3 | ||
|
|
3dba3d8b35 | ||
|
|
4693d20cad | ||
|
|
989193b4b4 | ||
|
|
0270428645 | ||
|
|
c735b59043 | ||
|
|
5d9941c36d | ||
|
|
beefcda68f | ||
|
|
1787ae0f5d | ||
|
|
50e484b22e | ||
|
|
272a72b716 | ||
|
|
2a4fa8ffe8 | ||
|
|
893a18ff5c | ||
|
|
3a6d50deb3 | ||
|
|
21162233d5 | ||
|
|
84571e45ce | ||
|
|
0c46e8000e | ||
|
|
9eeceaca43 | ||
|
|
a35c166348 | ||
|
|
2d53ad5cb6 | ||
|
|
0c54254231 | ||
|
|
719d6df156 | ||
|
|
304126ad79 | ||
|
|
a7696b496a | ||
|
|
99cfa50451 | ||
|
|
137f5c3a8b | ||
|
|
5d1568963b | ||
|
|
adccd0d75e | ||
|
|
9d3c56d236 | ||
|
|
9613a0759c | ||
|
|
5c445f7842 | ||
|
|
5009c588d9 | ||
|
|
ee3bb1f36b | ||
|
|
5394efe71f | ||
|
|
d4a8fdb6ce | ||
|
|
4de80807b9 | ||
|
|
e2f13959d4 | ||
|
|
900ba7cf33 | ||
|
|
8a7d67f305 | ||
|
|
535a1d699e | ||
|
|
2f23b84dc4 | ||
|
|
72731a37d2 | ||
|
|
0cce4cf8f6 | ||
|
|
4cca309657 | ||
|
|
bad38150cb | ||
|
|
139dfd97bb | ||
|
|
150053bc86 | ||
|
|
b0c9810b0f | ||
|
|
cabdf5bbc4 | ||
|
|
95a2b0d799 | ||
|
|
55318df83f | ||
|
|
11804a484d | ||
|
|
5adf9d2619 | ||
|
|
78b9890ae1 | ||
|
|
8a9d02dd82 | ||
|
|
5b8bd6371c | ||
|
|
6e985a421d | ||
|
|
b20208fa4c | ||
|
|
86f8c826e2 | ||
|
|
af46830927 | ||
|
|
245451b6a9 | ||
|
|
86099ec62a | ||
|
|
f102ddad0c | ||
|
|
b885aa7cd3 | ||
|
|
4b1395b251 | ||
|
|
a7f48b6c6c | ||
|
|
58a2bfeb7a | ||
|
|
e228c92e84 | ||
|
|
105aeac48e | ||
|
|
5e14663ed9 | ||
|
|
db551c4274 | ||
|
|
967c6bd785 | ||
|
|
ffd76d6aee | ||
|
|
bcd915dab1 | ||
|
|
913f4e61a9 | ||
|
|
7bd74758c5 | ||
|
|
272313877d | ||
|
|
f896c3935e | ||
|
|
cf858258c7 | ||
|
|
8154337cb6 | ||
|
|
7a168150e6 | ||
|
|
ff8b7145d7 | ||
|
|
c997a9f978 | ||
|
|
7536993397 | ||
|
|
b4d756c746 | ||
|
|
037d12974c | ||
|
|
0e23107ffb | ||
|
|
02112803b5 | ||
|
|
7425cb0549 | ||
|
|
25ad66520b | ||
|
|
ecac696643 | ||
|
|
588e59db26 | ||
|
|
c3f4c75d39 | ||
|
|
d43b3b3b70 | ||
|
|
56e299cbca | ||
|
|
def392ad7d | ||
|
|
2c516fe516 | ||
|
|
37d5c34749 | ||
|
|
8226a3f8fe | ||
|
|
0f689d22f4 | ||
|
|
88c91675e2 | ||
|
|
47f6a98909 | ||
|
|
e471d40942 | ||
|
|
c2a353a3bd | ||
|
|
51dd4f288f | ||
|
|
ef9ca09b8e | ||
|
|
b9cc293167 | ||
|
|
14934f0b7c | ||
|
|
5c8a5fa8fa | ||
|
|
e6d04682d3 | ||
|
|
8b76392e3e | ||
|
|
8cae2ed645 | ||
|
|
0e50fee996 | ||
|
|
0651e5dc97 | ||
|
|
65c9cb852e | ||
|
|
ed7ea75fc0 | ||
|
|
c9998af44d | ||
|
|
7b5307acfc | ||
|
|
d12b523611 | ||
|
|
8d57d745cf | ||
|
|
d795000377 | ||
|
|
07f33b2909 | ||
|
|
59523e66da | ||
|
|
70f5c26a71 | ||
|
|
bc0f54bd04 | ||
|
|
dcf01ce72f | ||
|
|
3bd2ee78b6 | ||
|
|
a43c1f8807 | ||
|
|
b1016c39fd | ||
|
|
e54c04f495 | ||
|
|
6bc0dc8fb6 | ||
|
|
3ffd944e6b | ||
|
|
926068b14f | ||
|
|
5d7d5ca2a9 | ||
|
|
7418adf875 | ||
|
|
a16f8dff15 | ||
|
|
7a63dd3f12 | ||
|
|
f07b00de66 | ||
|
|
3bc99bc70e | ||
|
|
6fea42fc2d | ||
|
|
9439d633ef | ||
|
|
c2bffc6033 | ||
|
|
94275f13fb | ||
|
|
1042b893f6 | ||
|
|
a155b84cda | ||
|
|
8207567cba | ||
|
|
62adf6349d | ||
|
|
d7e2939791 | ||
|
|
2495886287 | ||
|
|
67a2b187b7 | ||
|
|
80608ae26c | ||
|
|
1cfebfe0e1 | ||
|
|
860dad268d | ||
|
|
ec3dbd22a4 | ||
|
|
0c70cb3b9c | ||
|
|
cba92f893d | ||
|
|
129f548c44 | ||
|
|
95db5966a0 | ||
|
|
7330a0c7e0 | ||
|
|
342583348d | ||
|
|
5738201b22 | ||
|
|
712b7c6637 | ||
|
|
6b4f6ca20c | ||
|
|
bbef1c5557 | ||
|
|
da36c1967f | ||
|
|
042c031c5c | ||
|
|
f191dd3d53 | ||
|
|
5b0ee04c0d | ||
|
|
3eb7605318 | ||
|
|
59e2825274 | ||
|
|
e35e6e1d15 | ||
|
|
78a431ed22 | ||
|
|
a08a2e381f | ||
|
|
1981622b92 | ||
|
|
560b04d4c6 | ||
|
|
cc57d56b92 | ||
|
|
c9f2403547 | ||
|
|
660cea680a | ||
|
|
11cffb2300 | ||
|
|
afc0c32bd0 | ||
|
|
b2352c3e24 | ||
|
|
51c11cfd90 | ||
|
|
769ab4a91c | ||
|
|
c15edc3641 | ||
|
|
f6dcf968ca | ||
|
|
3de44fe593 | ||
|
|
11ad1919ed | ||
|
|
5deef28b7a | ||
|
|
11abe5ec49 | ||
|
|
f8573fe9c2 | ||
|
|
0340321c12 | ||
|
|
2fe7c6fed4 | ||
|
|
f738b73107 | ||
|
|
4d1ee3a73e | ||
|
|
90877e0d42 | ||
|
|
3df9fd4354 | ||
|
|
06d46869f8 | ||
|
|
f4ffed8482 | ||
|
|
27b348b3e5 | ||
|
|
1cf79803d7 | ||
|
|
c1ad8076a3 | ||
|
|
32163e0e98 | ||
|
|
16c7de085c | ||
|
|
d9c5479029 | ||
|
|
12f7de3ef3 | ||
|
|
7e49cc87f9 | ||
|
|
d3e66e36f6 | ||
|
|
d5880ae6a5 | ||
|
|
23c7a7d557 | ||
|
|
cbfc21badb | ||
|
|
58f54801b7 | ||
|
|
c05791f619 | ||
|
|
f7a426d516 | ||
|
|
7ba13fbc2b | ||
|
|
bda391e4c2 | ||
|
|
bbe0234720 | ||
|
|
5dfc1b90e1 | ||
|
|
1b997bebd0 | ||
|
|
27c61ed0d4 | ||
|
|
7a958d920c | ||
|
|
3a64aa49a9 | ||
|
|
aef0bb4915 | ||
|
|
6b618f0635 | ||
|
|
f3bcea8732 | ||
|
|
2b45a112cb | ||
|
|
2c701ab296 | ||
|
|
7d1891e6e6 | ||
|
|
4f4288e3b5 | ||
|
|
50667db297 | ||
|
|
1ff07245f3 | ||
|
|
7130e56f87 | ||
|
|
a3ae336c51 | ||
|
|
d3d9b5738f | ||
|
|
5ca6b3568c | ||
|
|
34896839ba | ||
|
|
a6aa151653 | ||
|
|
8f64cd3e4d | ||
|
|
8866544ffe | ||
|
|
60f7a59f5e | ||
|
|
aa3a5f9ff7 | ||
|
|
55c45307d0 | ||
|
|
577ff767fa | ||
|
|
608c08fc54 | ||
|
|
0783090da0 | ||
|
|
04a54cf54e | ||
|
|
6944d7025d | ||
|
|
68b9ad4205 | ||
|
|
ebd7f19a3b | ||
|
|
11fa1d2dc7 | ||
|
|
9faa9d33e6 | ||
|
|
9b7f6250f4 | ||
|
|
2e2a134489 | ||
|
|
4514691300 | ||
|
|
fcaf6a23dd | ||
|
|
9ece33c505 | ||
|
|
320d52a23e | ||
|
|
3814dc860b | ||
|
|
f3c37a946c | ||
|
|
daed93dd30 | ||
|
|
a8edf29bd0 | ||
|
|
01bc49c88c | ||
|
|
4013c65853 | ||
|
|
ed51963c47 | ||
|
|
b453293349 | ||
|
|
83370f0021 | ||
|
|
d38ed0831d | ||
|
|
934dd5b3a7 | ||
|
|
0e7250f37b | ||
|
|
e5f55dd024 | ||
|
|
6831579267 | ||
|
|
b7b66a6047 | ||
|
|
56fe2aab9c | ||
|
|
b5e5f2cede | ||
|
|
c138368040 | ||
|
|
d85dc46e37 | ||
|
|
a79c40a789 | ||
|
|
f03252aaf9 | ||
|
|
cead2ea4b1 | ||
|
|
447105a278 | ||
|
|
028b6c9b13 | ||
|
|
40be5ad581 | ||
|
|
4630ce3d9e | ||
|
|
cc92699ff7 | ||
|
|
6a61cb73c5 | ||
|
|
a52b50ef3c | ||
|
|
0a3da5cd8a | ||
|
|
38caa6832d | ||
|
|
665cc3d537 | ||
|
|
c1b9aa7d96 | ||
|
|
a437666a37 | ||
|
|
aa21d4ea7e | ||
|
|
1e8dc2389e | ||
|
|
69196670b7 | ||
|
|
661f11b947 | ||
|
|
bcdacfa1b3 | ||
|
|
33c0cd1378 | ||
|
|
81666e586a | ||
|
|
4e4aeacae4 | ||
|
|
50e36983bb | ||
|
|
f353a61bab | ||
|
|
e30837910b | ||
|
|
512d3d2287 | ||
|
|
28fc03c386 | ||
|
|
9f8b400630 | ||
|
|
a02a54ff13 | ||
|
|
5b3952e857 | ||
|
|
8ba22ca0dc | ||
|
|
41c5ffc5d5 | ||
|
|
925d11d890 | ||
|
|
8fade9df27 | ||
|
|
48b9452c07 | ||
|
|
bc195b8f53 | ||
|
|
972c7112a2 | ||
|
|
02d7215005 | ||
|
|
ed6b487e20 | ||
|
|
5dd3c37fce | ||
|
|
3d8e6a3aa3 | ||
|
|
0baa8c1763 | ||
|
|
bd1b8448a5 | ||
|
|
b7fba2100f | ||
|
|
f85806b6d7 | ||
|
|
cb4fc58547 | ||
|
|
564f820efa | ||
|
|
fa139b4fca | ||
|
|
ad0fcf9143 | ||
|
|
37c37eecfb | ||
|
|
b588b5a230 | ||
|
|
d29eaeafc1 | ||
|
|
7d9172d5e0 | ||
|
|
bcea5e75eb | ||
|
|
7ac35b4f69 |
@@ -279,8 +279,20 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
|
||||
- `node --import tsx scripts/openclaw-npm-postpublish-verify.ts <beta-version>`
|
||||
- install/update smoke against the published beta channel
|
||||
- Docker install/update coverage that exercises the published beta package
|
||||
- published npm Telegram proof: dispatch Actions > `NPM Telegram Beta E2E`
|
||||
from `main` with `package_spec=openclaw@<beta-version>` and
|
||||
`provider_mode=mock-openai`, approve `npm-release`, and require success.
|
||||
This is the default button path for installed-package onboarding,
|
||||
Telegram setup, and real Telegram E2E against the published npm package.
|
||||
Use the local `pnpm test:docker:npm-telegram-live` lane with the matching
|
||||
`OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC` and Convex CI env only as a fallback
|
||||
or debugging path.
|
||||
- Parallels published beta install/update coverage with both OpenAI and
|
||||
Anthropic provider keys available
|
||||
- Parallels install/update proof must keep plugin installs enabled unless the
|
||||
operator explicitly scopes a harness-only isolation check; a lane that
|
||||
disables bundled plugin installs is not valid plugin/dependency release
|
||||
evidence.
|
||||
- targeted QA reruns only for areas touched by fixes after the full pre-npm
|
||||
roster, unless the operator requests the full QA roster again. If the fix
|
||||
touches live channel QA, credential plumbing, Matrix, Telegram, or the QA
|
||||
@@ -329,10 +341,17 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
|
||||
`openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml`
|
||||
workflow because `npm dist-tag` management needs `NPM_TOKEN`, while the
|
||||
public npm release workflow stays OIDC-only.
|
||||
- Prefer fixing the private workflow token path over any local 1Password
|
||||
fallback. The desired setup is a granular npm token stored as the private
|
||||
repo's `NPM_TOKEN` secret, scoped to the `openclaw` package with read/write
|
||||
and 2FA bypass for automation.
|
||||
- If the private dist-tag workflow cannot promote because `NPM_TOKEN` is absent
|
||||
or stale, use the local tmux + 1Password fallback:
|
||||
- Start or reuse a tmux session so interactive `npm login` and OTP prompts
|
||||
are observable and recoverable.
|
||||
- Hard rule: never run `op` directly in the main agent shell during release
|
||||
work. Any 1Password CLI use must happen inside that tmux session so prompts
|
||||
and alerts are contained and observable.
|
||||
- Use the 1Password item `op://Private/Npmjs` for npm credentials and OTP.
|
||||
Do not print passwords, tokens, or OTPs to the transcript; send them through
|
||||
tmux buffers, env vars scoped to the tmux command, or `expect` with
|
||||
@@ -502,9 +521,11 @@ node --import tsx scripts/openclaw-npm-postpublish-verify.ts <published-version>
|
||||
23. Run the post-published beta verification roster. If any lane fails after
|
||||
the beta tag/package is pushed or published, fix, commit/push/pull,
|
||||
increment to the next beta tag, and restart at the full pre-npm beta test
|
||||
roster for the new beta. If a pre-npm lane fails before any tag/package
|
||||
leaves the machine, fix and rerun the same intended beta attempt. Repeat up
|
||||
to the operator's authorized beta-attempt limit, normally 4.
|
||||
roster for the new beta. The roster includes the manual Actions >
|
||||
`NPM Telegram Beta E2E` workflow against the exact published beta package.
|
||||
If a pre-npm lane fails before any tag/package leaves the machine, fix and
|
||||
rerun the same intended beta attempt. Repeat up to the operator's
|
||||
authorized beta-attempt limit, normally 4.
|
||||
24. Announce the beta/stable release on Discord best-effort using Peter's bot
|
||||
token from `.profile`.
|
||||
25. If the operator requested beta only, stop after beta verification and the
|
||||
|
||||
@@ -8,6 +8,14 @@
|
||||
|
||||
.bun-cache
|
||||
.bun
|
||||
.artifacts
|
||||
**/.artifacts
|
||||
.local
|
||||
**/.local
|
||||
.pi
|
||||
**/.pi
|
||||
__openclaw_vitest__
|
||||
**/__openclaw_vitest__
|
||||
.tmp
|
||||
**/.tmp
|
||||
.DS_Store
|
||||
@@ -38,6 +46,9 @@ docs/.generated
|
||||
*.log
|
||||
tmp
|
||||
**/tmp
|
||||
dist-runtime
|
||||
**/dist-runtime
|
||||
openclaw-path-alias-*
|
||||
|
||||
# build artifacts
|
||||
dist
|
||||
|
||||
@@ -12,6 +12,9 @@ paths-ignore:
|
||||
- docs
|
||||
- "**/node_modules"
|
||||
- "**/coverage"
|
||||
- "**/*.generated.ts"
|
||||
- "**/*.bundle.js"
|
||||
- "**/*-runtime.js"
|
||||
- "**/*.test.ts"
|
||||
- "**/*.test.tsx"
|
||||
- "**/*.e2e.test.ts"
|
||||
|
||||
9
.github/labeler.yml
vendored
9
.github/labeler.yml
vendored
@@ -29,6 +29,11 @@
|
||||
- any-glob-to-any-file:
|
||||
- "extensions/google-meet/**"
|
||||
- "docs/plugins/google-meet.md"
|
||||
"plugin: bonjour":
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "extensions/bonjour/**"
|
||||
- "docs/gateway/bonjour.md"
|
||||
"channel: imessage":
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
@@ -382,3 +387,7 @@
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "extensions/fal/**"
|
||||
"extensions: gradium":
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "extensions/gradium/**"
|
||||
|
||||
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
@@ -3,6 +3,9 @@ name: CI
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths-ignore:
|
||||
- "**/*.md"
|
||||
- "docs/**"
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize, ready_for_review, converted_to_draft]
|
||||
|
||||
@@ -194,6 +197,11 @@ jobs:
|
||||
}).map((shard) => ({
|
||||
check_name: shard.checkName,
|
||||
extensions_csv: shard.extensionIds.join(","),
|
||||
runner: isCanonicalRepository && [0, 3, 4].includes(shard.index)
|
||||
? "blacksmith-8vcpu-ubuntu-2404"
|
||||
: isCanonicalRepository
|
||||
? "blacksmith-4vcpu-ubuntu-2404"
|
||||
: "ubuntu-24.04",
|
||||
shard_index: shard.index + 1,
|
||||
task: "extensions-batch",
|
||||
}))
|
||||
@@ -208,6 +216,7 @@ jobs:
|
||||
configs: shard.configs,
|
||||
includePatterns: shard.includePatterns,
|
||||
requires_dist: shard.requiresDist,
|
||||
runner: shard.runner,
|
||||
}))
|
||||
: [];
|
||||
const nodeTestNonDistShards = nodeTestShards.filter((shard) => !shard.requires_dist);
|
||||
@@ -654,7 +663,7 @@ jobs:
|
||||
name: ${{ matrix.check_name }}
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_checks_fast == 'true'
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ${{ github.repository == 'openclaw/openclaw' && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04' }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -913,7 +922,7 @@ jobs:
|
||||
name: ${{ matrix.check_name }}
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_checks_fast == 'true'
|
||||
runs-on: ${{ github.repository == 'openclaw/openclaw' && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04' }}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -975,7 +984,7 @@ jobs:
|
||||
- name: Run extension shard
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=6144
|
||||
OPENCLAW_EXTENSION_BATCH_PARALLEL: 1
|
||||
OPENCLAW_EXTENSION_BATCH_PARALLEL: 2
|
||||
OPENCLAW_VITEST_MAX_WORKERS: 1
|
||||
OPENCLAW_EXTENSION_BATCH: ${{ matrix.extensions_csv }}
|
||||
run: pnpm test:extensions:batch -- "$OPENCLAW_EXTENSION_BATCH"
|
||||
@@ -1036,7 +1045,7 @@ jobs:
|
||||
name: checks-node-compat-node22
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_node == 'true' && github.event_name == 'push'
|
||||
runs-on: ${{ github.repository == 'openclaw/openclaw' && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-24.04' }}
|
||||
runs-on: ${{ github.repository == 'openclaw/openclaw' && 'blacksmith-4vcpu-ubuntu-2404' || 'ubuntu-24.04' }}
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -1113,10 +1122,7 @@ jobs:
|
||||
name: ${{ matrix.check_name }}
|
||||
needs: [preflight]
|
||||
if: needs.preflight.outputs.run_checks_node_core_nondist == 'true'
|
||||
# Keep core shards on GitHub-hosted runners. The Blacksmith pool is already
|
||||
# occupied by build and extension shards; queueing these shards there hides
|
||||
# actual test-speed improvements behind runner wait time.
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ${{ github.repository == 'openclaw/openclaw' && (matrix.runner || 'ubuntu-24.04') || 'ubuntu-24.04' }}
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -1372,16 +1378,16 @@ jobs:
|
||||
runner: ubuntu-24.04
|
||||
- check_name: check-prod-types
|
||||
task: prod-types
|
||||
runner: ubuntu-24.04
|
||||
runner: blacksmith-4vcpu-ubuntu-2404
|
||||
- check_name: check-lint
|
||||
task: lint
|
||||
runner: ubuntu-24.04
|
||||
runner: blacksmith-16vcpu-ubuntu-2404
|
||||
- check_name: check-policy-guards
|
||||
task: policy-guards
|
||||
runner: ubuntu-24.04
|
||||
- check_name: check-test-types
|
||||
task: test-types
|
||||
runner: ubuntu-24.04
|
||||
runner: blacksmith-4vcpu-ubuntu-2404
|
||||
- check_name: check-strict-smoke
|
||||
task: strict-smoke
|
||||
runner: ubuntu-24.04
|
||||
@@ -1456,7 +1462,7 @@ jobs:
|
||||
pnpm tsgo:prod
|
||||
;;
|
||||
lint)
|
||||
pnpm lint
|
||||
pnpm lint --threads=8
|
||||
;;
|
||||
policy-guards)
|
||||
pnpm lint:webhook:no-low-level-body-read
|
||||
|
||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- language: javascript-typescript
|
||||
runs_on: blacksmith-16vcpu-ubuntu-2404
|
||||
runs_on: blacksmith-32vcpu-ubuntu-2404
|
||||
needs_node: true
|
||||
needs_python: false
|
||||
needs_java: false
|
||||
|
||||
@@ -137,7 +137,7 @@ jobs:
|
||||
env:
|
||||
OPENAI_API_KEY: ${{ secrets.OPENCLAW_DOCS_I18N_OPENAI_API_KEY || secrets.OPENAI_API_KEY }}
|
||||
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
OPENCLAW_CONTROL_UI_I18N_MODEL: gpt-5.4
|
||||
OPENCLAW_CONTROL_UI_I18N_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL_BARE }}
|
||||
OPENCLAW_CONTROL_UI_I18N_THINKING: low
|
||||
LOCALE: ${{ matrix.locale }}
|
||||
run: node --import tsx scripts/control-ui-i18n.ts sync --locale "${LOCALE}" --write
|
||||
|
||||
2
.github/workflows/docs-agent.yml
vendored
2
.github/workflows/docs-agent.yml
vendored
@@ -156,7 +156,7 @@ jobs:
|
||||
with:
|
||||
openai-api-key: ${{ secrets.OPENCLAW_DOCS_AGENT_OPENAI_API_KEY || secrets.OPENAI_API_KEY }}
|
||||
prompt-file: .github/codex/prompts/docs-agent.md
|
||||
model: gpt-5.4
|
||||
model: ${{ vars.OPENCLAW_CI_OPENAI_MODEL_BARE }}
|
||||
effort: medium
|
||||
sandbox: workspace-write
|
||||
safety-strategy: drop-sudo
|
||||
|
||||
29
.github/workflows/docs-sync-publish.yml
vendored
29
.github/workflows/docs-sync-publish.yml
vendored
@@ -63,18 +63,43 @@ jobs:
|
||||
working-directory: publish
|
||||
run: |
|
||||
set -euo pipefail
|
||||
remote_source_sha() {
|
||||
git show refs/remotes/origin/main:.openclaw-sync/source.json 2>/dev/null \
|
||||
| node -e 'const fs = require("node:fs"); try { const data = JSON.parse(fs.readFileSync(0, "utf8")); if (data.sha) process.stdout.write(data.sha); } catch {}' \
|
||||
|| true
|
||||
}
|
||||
|
||||
skip_stale_source() {
|
||||
current_source_sha="$(remote_source_sha)"
|
||||
if [ -z "$current_source_sha" ] || [ "$current_source_sha" = "$GITHUB_SHA" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if git -C "$GITHUB_WORKSPACE" merge-base --is-ancestor "$GITHUB_SHA" "$current_source_sha"; then
|
||||
echo "Skipping stale publish sync for $GITHUB_SHA; origin/main already mirrors $current_source_sha."
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
if git diff --quiet -- docs .openclaw-sync; then
|
||||
echo "No publish-repo changes."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if git fetch origin main:refs/remotes/origin/main; then
|
||||
skip_stale_source
|
||||
fi
|
||||
|
||||
git config user.name "openclaw-docs-sync[bot]"
|
||||
git config user.email "openclaw-docs-sync[bot]@users.noreply.github.com"
|
||||
git add docs .openclaw-sync
|
||||
git commit -m "chore(sync): mirror docs from $GITHUB_REPOSITORY@$GITHUB_SHA"
|
||||
for attempt in 1 2 3 4 5; do
|
||||
if git fetch origin main && git rebase origin/main && git push origin HEAD:main; then
|
||||
exit 0
|
||||
if git fetch origin main:refs/remotes/origin/main; then
|
||||
skip_stale_source
|
||||
if git rebase -X theirs origin/main && git push origin HEAD:main; then
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
git rebase --abort >/dev/null 2>&1 || true
|
||||
echo "Publish sync attempt ${attempt} failed; retrying."
|
||||
|
||||
39
.github/workflows/docs.yml
vendored
Normal file
39
.github/workflows/docs.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
name: Docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "**/*.md"
|
||||
- "docs/**"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ format('{0}-{1}', github.workflow, github.ref) }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
|
||||
jobs:
|
||||
docs:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 1
|
||||
fetch-tags: false
|
||||
persist-credentials: false
|
||||
submodules: false
|
||||
|
||||
- name: Setup Node environment
|
||||
uses: ./.github/actions/setup-node-env
|
||||
with:
|
||||
install-bun: "false"
|
||||
|
||||
- name: Check docs
|
||||
run: pnpm check:docs
|
||||
12
.github/workflows/install-smoke.yml
vendored
12
.github/workflows/install-smoke.yml
vendored
@@ -116,6 +116,12 @@ jobs:
|
||||
run: |
|
||||
docker run --rm --entrypoint sh openclaw-dockerfile-smoke:local -lc 'which openclaw && openclaw --version'
|
||||
|
||||
- name: Run agents delete shared workspace Docker CLI smoke
|
||||
env:
|
||||
OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE: openclaw-dockerfile-smoke:local
|
||||
OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD: "1"
|
||||
run: bash scripts/e2e/agents-delete-shared-workspace-docker.sh
|
||||
|
||||
- name: Run Docker gateway network e2e
|
||||
env:
|
||||
OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE: openclaw-dockerfile-smoke:local
|
||||
@@ -211,6 +217,12 @@ jobs:
|
||||
run: |
|
||||
docker run --rm --entrypoint sh openclaw-dockerfile-smoke:local -lc 'which openclaw && openclaw --version'
|
||||
|
||||
- name: Run agents delete shared workspace Docker CLI smoke
|
||||
env:
|
||||
OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE: openclaw-dockerfile-smoke:local
|
||||
OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD: "1"
|
||||
run: bash scripts/e2e/agents-delete-shared-workspace-docker.sh
|
||||
|
||||
- name: Run Docker gateway network e2e
|
||||
env:
|
||||
OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE: openclaw-dockerfile-smoke:local
|
||||
|
||||
210
.github/workflows/npm-telegram-beta-e2e.yml
vendored
Normal file
210
.github/workflows/npm-telegram-beta-e2e.yml
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
name: NPM Telegram Beta E2E
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
package_spec:
|
||||
description: Published OpenClaw package spec to test
|
||||
required: true
|
||||
default: openclaw@beta
|
||||
type: string
|
||||
provider_mode:
|
||||
description: QA provider mode
|
||||
required: true
|
||||
default: mock-openai
|
||||
type: choice
|
||||
options:
|
||||
- mock-openai
|
||||
- live-frontier
|
||||
scenario:
|
||||
description: Optional comma-separated Telegram scenario ids
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: npm-telegram-beta-e2e-${{ github.run_id }}
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
NODE_VERSION: "24.x"
|
||||
PNPM_VERSION: "10.33.0"
|
||||
|
||||
jobs:
|
||||
validate_dispatch_ref:
|
||||
name: Validate dispatch ref
|
||||
runs-on: blacksmith-8vcpu-ubuntu-2404
|
||||
steps:
|
||||
- name: Require main workflow ref
|
||||
env:
|
||||
WORKFLOW_REF: ${{ github.ref }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ "${WORKFLOW_REF}" != "refs/heads/main" ]]; then
|
||||
echo "NPM Telegram beta E2E must be dispatched from main so workflow logic stays controlled." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
approve_release_manager:
|
||||
name: Approve npm Telegram beta E2E
|
||||
needs: validate_dispatch_ref
|
||||
runs-on: ubuntu-latest
|
||||
environment: npm-release
|
||||
steps:
|
||||
- name: Record approval
|
||||
env:
|
||||
PACKAGE_SPEC: ${{ inputs.package_spec }}
|
||||
run: echo "Approved npm Telegram beta E2E for ${PACKAGE_SPEC}"
|
||||
|
||||
prepare_docker_e2e_image:
|
||||
name: Prepare Docker E2E image
|
||||
needs: validate_dispatch_ref
|
||||
runs-on: blacksmith-32vcpu-ubuntu-2404
|
||||
timeout-minutes: 90
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
outputs:
|
||||
image: ${{ steps.image.outputs.image }}
|
||||
env:
|
||||
DOCKER_BUILD_SUMMARY: "false"
|
||||
DOCKER_BUILD_RECORD_UPLOAD: "false"
|
||||
steps:
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ github.sha }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Resolve Docker E2E image tag
|
||||
id: image
|
||||
shell: bash
|
||||
env:
|
||||
SELECTED_SHA: ${{ github.sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
repository="${GITHUB_REPOSITORY,,}"
|
||||
image="ghcr.io/${repository}-docker-e2e:${SELECTED_SHA}"
|
||||
echo "image=$image" >> "$GITHUB_OUTPUT"
|
||||
echo "Docker E2E image: \`$image\`" >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
- name: Set up Blacksmith Docker Builder
|
||||
uses: useblacksmith/setup-docker-builder@ac083cc84672d01c60d5e8561d0a939b697de542 # v1
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ github.token }}
|
||||
|
||||
- name: Build and push Docker E2E image
|
||||
uses: useblacksmith/build-push-action@cbd1f60d194a98cb3be5523b15134501eaf0fbf3 # v2
|
||||
with:
|
||||
context: .
|
||||
file: ./scripts/e2e/Dockerfile
|
||||
target: build
|
||||
platforms: linux/amd64
|
||||
tags: ${{ steps.image.outputs.image }}
|
||||
provenance: false
|
||||
push: true
|
||||
|
||||
run_npm_telegram_beta_e2e:
|
||||
name: Run published npm Telegram E2E
|
||||
needs: [approve_release_manager, prepare_docker_e2e_image]
|
||||
runs-on: blacksmith-32vcpu-ubuntu-2404
|
||||
timeout-minutes: 60
|
||||
environment: qa-live-shared
|
||||
permissions:
|
||||
contents: read
|
||||
packages: read
|
||||
steps:
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ github.sha }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ github.token }}
|
||||
|
||||
- name: Setup Node environment
|
||||
uses: ./.github/actions/setup-node-env
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
pnpm-version: ${{ env.PNPM_VERSION }}
|
||||
install-bun: "true"
|
||||
|
||||
- name: Validate inputs and secrets
|
||||
env:
|
||||
PACKAGE_SPEC: ${{ inputs.package_spec }}
|
||||
PROVIDER_MODE: ${{ inputs.provider_mode }}
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
|
||||
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [[ ! "${PACKAGE_SPEC}" =~ ^openclaw@(beta|latest|[0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*(-[1-9][0-9]*|-beta\.[1-9][0-9]*)?)$ ]]; then
|
||||
echo "package_spec must be openclaw@beta, openclaw@latest, or an exact OpenClaw release version; got: ${PACKAGE_SPEC}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
require_var() {
|
||||
local key="$1"
|
||||
if [[ -z "${!key:-}" ]]; then
|
||||
echo "Missing required ${key}." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_var OPENCLAW_QA_CONVEX_SITE_URL
|
||||
require_var OPENCLAW_QA_CONVEX_SECRET_CI
|
||||
if [[ "${PROVIDER_MODE}" == "live-frontier" ]]; then
|
||||
require_var OPENAI_API_KEY
|
||||
fi
|
||||
|
||||
- name: Run npm Telegram beta E2E
|
||||
id: run_lane
|
||||
shell: bash
|
||||
env:
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
OPENCLAW_SKIP_DOCKER_BUILD: "1"
|
||||
OPENCLAW_DOCKER_E2E_IMAGE: ${{ needs.prepare_docker_e2e_image.outputs.image }}
|
||||
OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC: ${{ inputs.package_spec }}
|
||||
OPENCLAW_NPM_TELEGRAM_PROVIDER_MODE: ${{ inputs.provider_mode }}
|
||||
OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE: convex
|
||||
OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE: ci
|
||||
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
|
||||
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
|
||||
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
|
||||
INPUT_SCENARIO: ${{ inputs.scenario }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
output_dir=".artifacts/qa-e2e/npm-telegram-beta-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
|
||||
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
|
||||
export OPENCLAW_NPM_TELEGRAM_OUTPUT_DIR="${output_dir}"
|
||||
|
||||
if [[ -n "${INPUT_SCENARIO// }" ]]; then
|
||||
export OPENCLAW_NPM_TELEGRAM_SCENARIOS="${INPUT_SCENARIO}"
|
||||
fi
|
||||
|
||||
pnpm test:docker:npm-telegram-live
|
||||
|
||||
- name: Upload npm Telegram E2E artifacts
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: npm-telegram-beta-e2e-${{ github.run_id }}-${{ github.run_attempt }}
|
||||
path: ${{ steps.run_lane.outputs.output_dir }}
|
||||
retention-days: 14
|
||||
if-no-files-found: warn
|
||||
@@ -623,6 +623,9 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ github.token }}
|
||||
|
||||
- name: Setup Docker builder
|
||||
uses: useblacksmith/setup-docker-builder@ac083cc84672d01c60d5e8561d0a939b697de542 # v1
|
||||
|
||||
- name: Build and push shared Docker E2E image
|
||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
||||
with:
|
||||
|
||||
15
.github/workflows/openclaw-release-checks.yml
vendored
15
.github/workflows/openclaw-release-checks.yml
vendored
@@ -34,6 +34,7 @@ env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
NODE_VERSION: "24.x"
|
||||
PNPM_VERSION: "10.33.0"
|
||||
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL }}
|
||||
|
||||
jobs:
|
||||
resolve_target:
|
||||
@@ -245,13 +246,13 @@ jobs:
|
||||
- name: Build private QA runtime
|
||||
run: pnpm build
|
||||
|
||||
- name: Run GPT-5.4 lane
|
||||
- name: Run OpenAI candidate lane
|
||||
run: |
|
||||
pnpm openclaw qa suite \
|
||||
--provider-mode mock-openai \
|
||||
--parity-pack agentic \
|
||||
--concurrency "${QA_PARITY_CONCURRENCY}" \
|
||||
--model openai/gpt-5.4 \
|
||||
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--alt-model openai/gpt-5.4-alt \
|
||||
--output-dir .artifacts/qa-e2e/gpt54
|
||||
|
||||
@@ -271,7 +272,7 @@ jobs:
|
||||
--repo-root . \
|
||||
--candidate-summary .artifacts/qa-e2e/gpt54/qa-suite-summary.json \
|
||||
--baseline-summary .artifacts/qa-e2e/opus46/qa-suite-summary.json \
|
||||
--candidate-label openai/gpt-5.4 \
|
||||
--candidate-label "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--baseline-label anthropic/claude-opus-4-6 \
|
||||
--output-dir .artifacts/qa-e2e/parity
|
||||
|
||||
@@ -341,8 +342,8 @@ jobs:
|
||||
--repo-root . \
|
||||
--output-dir "${output_dir}" \
|
||||
--provider-mode live-frontier \
|
||||
--model openai/gpt-5.4 \
|
||||
--alt-model openai/gpt-5.4 \
|
||||
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--alt-model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--fast
|
||||
|
||||
- name: Upload Matrix QA artifacts
|
||||
@@ -423,8 +424,8 @@ jobs:
|
||||
--repo-root . \
|
||||
--output-dir "${output_dir}" \
|
||||
--provider-mode live-frontier \
|
||||
--model openai/gpt-5.4 \
|
||||
--alt-model openai/gpt-5.4 \
|
||||
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--alt-model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--fast \
|
||||
--credential-source convex \
|
||||
--credential-role ci
|
||||
|
||||
9
.github/workflows/parity-gate.yml
vendored
9
.github/workflows/parity-gate.yml
vendored
@@ -24,7 +24,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
parity-gate:
|
||||
name: Run the GPT-5.4 / Opus 4.6 parity gate against the qa-lab mock
|
||||
name: Run the OpenAI / Opus 4.6 parity gate against the qa-lab mock
|
||||
if: ${{ github.event.pull_request.draft != true }}
|
||||
runs-on: blacksmith-32vcpu-ubuntu-2404
|
||||
timeout-minutes: 30
|
||||
@@ -42,6 +42,7 @@ jobs:
|
||||
# followthrough gate that expects a fast post-approval read within a 30s
|
||||
# agent.wait timeout.
|
||||
QA_PARITY_CONCURRENCY: "1"
|
||||
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL }}
|
||||
OPENCLAW_QA_TRANSPORT_READY_TIMEOUT_MS: "180000"
|
||||
OPENAI_API_KEY: ""
|
||||
ANTHROPIC_API_KEY: ""
|
||||
@@ -75,13 +76,13 @@ jobs:
|
||||
# The approval-turn sentinel still runs inside the full parity pack below.
|
||||
# Keep the exact mock read-plan contract in deterministic unit tests instead
|
||||
# of paying for a separate full-runtime preflight that has been flaky in CI.
|
||||
- name: Run GPT-5.4 lane
|
||||
- name: Run OpenAI candidate lane
|
||||
run: |
|
||||
pnpm openclaw qa suite \
|
||||
--provider-mode mock-openai \
|
||||
--parity-pack agentic \
|
||||
--concurrency "${QA_PARITY_CONCURRENCY}" \
|
||||
--model openai/gpt-5.4 \
|
||||
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--alt-model openai/gpt-5.4-alt \
|
||||
--output-dir .artifacts/qa-e2e/gpt54
|
||||
|
||||
@@ -101,7 +102,7 @@ jobs:
|
||||
--repo-root . \
|
||||
--candidate-summary .artifacts/qa-e2e/gpt54/qa-suite-summary.json \
|
||||
--baseline-summary .artifacts/qa-e2e/opus46/qa-suite-summary.json \
|
||||
--candidate-label openai/gpt-5.4 \
|
||||
--candidate-label "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--baseline-label anthropic/claude-opus-4-6 \
|
||||
--output-dir .artifacts/qa-e2e/parity
|
||||
|
||||
|
||||
15
.github/workflows/qa-live-transports-convex.yml
vendored
15
.github/workflows/qa-live-transports-convex.yml
vendored
@@ -31,6 +31,7 @@ env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
NODE_VERSION: "24.x"
|
||||
PNPM_VERSION: "10.33.0"
|
||||
OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL }}
|
||||
OPENCLAW_BUILD_PRIVATE_QA: "1"
|
||||
OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
|
||||
|
||||
@@ -156,13 +157,13 @@ jobs:
|
||||
- name: Build private QA runtime
|
||||
run: pnpm build
|
||||
|
||||
- name: Run GPT-5.4 lane
|
||||
- name: Run OpenAI candidate lane
|
||||
run: |
|
||||
pnpm openclaw qa suite \
|
||||
--provider-mode mock-openai \
|
||||
--parity-pack agentic \
|
||||
--concurrency "${QA_PARITY_CONCURRENCY}" \
|
||||
--model openai/gpt-5.4 \
|
||||
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--alt-model openai/gpt-5.4-alt \
|
||||
--output-dir .artifacts/qa-e2e/gpt54
|
||||
|
||||
@@ -182,7 +183,7 @@ jobs:
|
||||
--repo-root . \
|
||||
--candidate-summary .artifacts/qa-e2e/gpt54/qa-suite-summary.json \
|
||||
--baseline-summary .artifacts/qa-e2e/opus46/qa-suite-summary.json \
|
||||
--candidate-label openai/gpt-5.4 \
|
||||
--candidate-label "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--baseline-label anthropic/claude-opus-4-6 \
|
||||
--output-dir .artifacts/qa-e2e/parity
|
||||
|
||||
@@ -246,8 +247,8 @@ jobs:
|
||||
--repo-root . \
|
||||
--output-dir "${output_dir}" \
|
||||
--provider-mode live-frontier \
|
||||
--model openai/gpt-5.4 \
|
||||
--alt-model openai/gpt-5.4 \
|
||||
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--alt-model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--fast
|
||||
|
||||
- name: Upload Matrix QA artifacts
|
||||
@@ -335,8 +336,8 @@ jobs:
|
||||
--repo-root . \
|
||||
--output-dir "${output_dir}" \
|
||||
--provider-mode live-frontier \
|
||||
--model openai/gpt-5.4 \
|
||||
--alt-model openai/gpt-5.4 \
|
||||
--model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--alt-model "${OPENCLAW_CI_OPENAI_MODEL}" \
|
||||
--fast \
|
||||
--credential-source convex \
|
||||
--credential-role ci \
|
||||
|
||||
2
.github/workflows/test-performance-agent.yml
vendored
2
.github/workflows/test-performance-agent.yml
vendored
@@ -133,7 +133,7 @@ jobs:
|
||||
with:
|
||||
openai-api-key: ${{ secrets.OPENCLAW_TEST_PERF_AGENT_OPENAI_API_KEY || secrets.OPENAI_API_KEY }}
|
||||
prompt-file: .github/codex/prompts/test-performance-agent.md
|
||||
model: gpt-5.4
|
||||
model: ${{ vars.OPENCLAW_CI_OPENAI_MODEL_BARE }}
|
||||
effort: high
|
||||
sandbox: workspace-write
|
||||
safety-strategy: drop-sudo
|
||||
|
||||
283
AGENTS.md
283
AGENTS.md
@@ -1,214 +1,165 @@
|
||||
# AGENTS.MD
|
||||
|
||||
Telegraph style. Root rules only. Read scoped `AGENTS.md` before touching a subtree.
|
||||
Telegraph style. Root rules only. Read scoped `AGENTS.md` before subtree work.
|
||||
|
||||
## Start
|
||||
|
||||
- Repo: `https://github.com/openclaw/openclaw`
|
||||
- Replies: repo-root file refs only, e.g. `extensions/telegram/src/index.ts:80`. No absolute paths, no `~/`.
|
||||
- CODEOWNERS: maintenance/refactors/tests are ok. For larger behavior, product, security, or ownership-sensitive changes, get a listed owner request/review first.
|
||||
- First pass: run docs list (`pnpm docs:list`; ignore if unavailable), then read only relevant docs/guides.
|
||||
- Missing deps: run `pnpm install`, rerun once, then report first actionable error.
|
||||
- Use "plugin/plugins" in docs/UI/changelog. `extensions/` remains internal workspace layout.
|
||||
- Add channel/plugin/app/doc surface: update `.github/labeler.yml` and matching GitHub labels.
|
||||
- New `AGENTS.md`: add sibling `CLAUDE.md` symlink to it.
|
||||
- Replies: repo-root refs only: `extensions/telegram/src/index.ts:80`. No absolute paths, no `~/`.
|
||||
- Run docs list first: `pnpm docs:list` if available; read relevant docs only.
|
||||
- High-confidence answers only when fixing/triaging: verify source, tests, shipped/current behavior, and dependency contracts before deciding.
|
||||
- Dependency-backed behavior: read upstream dependency docs/source/types first. Do not assume APIs, defaults, errors, timing, or runtime behavior.
|
||||
- Missing deps: `pnpm install`, retry once, then report first actionable error.
|
||||
- CODEOWNERS: maint/refactor/tests ok. Larger behavior/product/security/ownership: owner ask/review.
|
||||
- Wording: product/docs/UI/changelog say "plugin/plugins"; `extensions/` is internal.
|
||||
- New channel/plugin/app/doc surface: update `.github/labeler.yml` + GH labels.
|
||||
- New `AGENTS.md`: add sibling `CLAUDE.md` symlink.
|
||||
|
||||
## Repo Map
|
||||
## Map
|
||||
|
||||
- Core TS: `src/`, `ui/`, `packages/`
|
||||
- Bundled plugins: `extensions/`
|
||||
- Plugin SDK/public contract: `src/plugin-sdk/*`
|
||||
- Core channel internals: `src/channels/*`
|
||||
- Plugin loader/registry/contracts: `src/plugins/*`
|
||||
- Gateway protocol: `src/gateway/protocol/*`
|
||||
- Docs: `docs/`
|
||||
- Apps: `apps/`, `Swabble/`
|
||||
- Installers served from `openclaw.ai`: sibling `../openclaw.ai`
|
||||
|
||||
Scoped guides:
|
||||
|
||||
- `extensions/AGENTS.md`: bundled plugin rules
|
||||
- `src/plugin-sdk/AGENTS.md`: public SDK rules
|
||||
- `src/channels/AGENTS.md`: channel core rules
|
||||
- `src/plugins/AGENTS.md`: plugin loader/registry rules
|
||||
- `src/gateway/AGENTS.md`, `src/gateway/protocol/AGENTS.md`: gateway/protocol rules
|
||||
- `src/agents/AGENTS.md`: agent import/test perf rules
|
||||
- `test/helpers/AGENTS.md`, `test/helpers/channels/AGENTS.md`: shared test helpers
|
||||
- `docs/AGENTS.md`, `ui/AGENTS.md`, `scripts/AGENTS.md`: docs/UI/scripts
|
||||
- Core TS: `src/`, `ui/`, `packages/`; plugins: `extensions/`; SDK: `src/plugin-sdk/*`; channels: `src/channels/*`; loader: `src/plugins/*`; protocol: `src/gateway/protocol/*`; docs/apps: `docs/`, `apps/`, `Swabble/`.
|
||||
- Installers: sibling `../openclaw.ai`.
|
||||
- Scoped guides exist in: `extensions/`, `src/{plugin-sdk,channels,plugins,gateway,gateway/protocol,agents}/`, `test/helpers*/`, `docs/`, `ui/`, `scripts/`.
|
||||
|
||||
## Architecture
|
||||
|
||||
- Core must stay extension-agnostic. No core special cases for bundled plugin/provider/channel ids when manifest/registry/capability contracts can express it.
|
||||
- Extensions cross into core only via `openclaw/plugin-sdk/*`, manifest metadata, injected runtime helpers, and documented local barrels (`api.ts`, `runtime-api.ts`).
|
||||
- Extension production code must not import core `src/**`, `src/plugin-sdk-internal/**`, another extension's `src/**`, or relative paths outside its package.
|
||||
- Core code/tests must not deep-import plugin internals (`extensions/*/src/**`, `onboard.js`). Use plugin `api.ts` / public SDK facade / generic contract.
|
||||
- Extension-owned behavior stays in the extension: legacy repair, detection, onboarding, auth/provider defaults, provider tools/settings.
|
||||
- Legacy config repair: prefer doctor/fix paths over startup/load-time core migrations.
|
||||
- If a core test asserts extension-specific behavior, move it to the owning extension or a generic contract test.
|
||||
- Core stays extension-agnostic. No bundled ids in core when manifest/registry/capability contracts work.
|
||||
- Extensions cross into core only via `openclaw/plugin-sdk/*`, manifest metadata, injected runtime helpers, documented barrels (`api.ts`, `runtime-api.ts`).
|
||||
- Extension prod code: no core `src/**`, `src/plugin-sdk-internal/**`, other extension `src/**`, or relative outside package.
|
||||
- Core/tests: no deep plugin internals (`extensions/*/src/**`, `onboard.js`). Use `api.ts`, SDK facade, generic contracts.
|
||||
- Extension-owned behavior stays extension-owned: repair, detection, onboarding, auth/provider defaults, provider tools/settings.
|
||||
- Legacy config repair: doctor/fix paths, not startup/load-time core migrations.
|
||||
- Core test asserting extension-specific behavior: move to owner extension or generic contract test.
|
||||
- New seams: backwards-compatible, documented, versioned. Third-party plugins exist.
|
||||
- Channels: `src/channels/**` is implementation. Plugin authors get SDK seams, not channel internals.
|
||||
- Providers: core owns generic inference loop; provider plugins own provider-specific auth/catalog/runtime hooks.
|
||||
- Gateway protocol changes are contract changes: additive first; incompatible needs versioning/docs/client follow-through.
|
||||
- Config contract: keep exported types, schema/help, generated metadata, baselines, docs aligned. Retired public keys stay retired; compatibility belongs in raw migration/doctor paths.
|
||||
- Plugin architecture direction: manifest-first control plane; targeted runtime loaders; no hidden paths around declared contracts; broad mutable registries are transitional.
|
||||
- Prompt-cache rule: deterministic ordering for maps/sets/registries/plugin lists/files/network results before model/tool payloads. Preserve old transcript bytes when possible.
|
||||
- Channels: `src/channels/**` is implementation; plugin authors get SDK seams.
|
||||
- Providers: core owns generic loop; provider plugins own auth/catalog/runtime hooks.
|
||||
- Gateway protocol changes: additive first; incompatible needs versioning/docs/client follow-through.
|
||||
- Config contract: exported types, schema/help, metadata, baselines, docs aligned. Retired public keys stay retired; compat in raw migration/doctor.
|
||||
- Direction: manifest-first control plane; targeted runtime loaders; no hidden contract bypasses; broad mutable registries transitional.
|
||||
- Prompt cache: deterministic ordering for maps/sets/registries/plugin lists/files/network results before model/tool payloads. Preserve old transcript bytes when possible.
|
||||
|
||||
## Commands
|
||||
|
||||
- Runtime: Node 22+. Keep Node and Bun paths working.
|
||||
- Install: `pnpm install` (Bun supported; keep lockfiles/patches aligned if touched).
|
||||
- Dev CLI: `pnpm openclaw ...` or `pnpm dev`.
|
||||
- Build: `pnpm build`
|
||||
- Smart local gate: `pnpm check:changed` (scoped typecheck/lint/guards + relevant tests)
|
||||
- Explain smart gate: `pnpm changed:lanes --json`
|
||||
- Staged gate preview: `pnpm check:changed --staged`
|
||||
- Normal full prod sweep: `pnpm check` (prod typecheck/lint/guards, no tests)
|
||||
- Full tests: `pnpm test`
|
||||
- Changed tests only: `pnpm test:changed`
|
||||
- Local serial loop: `pnpm test:serial`
|
||||
- Extension tests: `pnpm test:extensions` or `pnpm test extensions` = all extension shards; `pnpm test extensions/<id>` = one extension lane. Heavy channels/OpenAI have dedicated shards.
|
||||
- Shard timing artifact: `.artifacts/vitest-shard-timings.json`; auto-used for balanced shard ordering. Disable with `OPENCLAW_TEST_PROJECTS_TIMINGS=0`.
|
||||
- Targeted tests: `pnpm test <path-or-filter> [vitest args...]`; do not call raw `vitest`.
|
||||
- Coverage: `pnpm test:coverage`
|
||||
- Format check/fix: `pnpm format:check` / `pnpm format`
|
||||
- Typecheck:
|
||||
- `pnpm tsgo`: fastest core prod graph
|
||||
- `pnpm tsgo:prod`: core + extensions prod graphs; used by `pnpm check`
|
||||
- `pnpm check:test-types` / `pnpm tsgo:test`: all test graphs
|
||||
- `pnpm tsgo:all`: all prod + test project refs
|
||||
- Debug slices exist; do not present as normal user flow.
|
||||
- Profile: `pnpm tsgo:profile [core-test|extensions-test|--all]`
|
||||
- Type policy: use `tsgo`; do not add `tsc --noEmit`, `typecheck`, or `check:types` lanes. `tsc` only for declaration/package-boundary emit gaps.
|
||||
- Lint:
|
||||
- `pnpm lint`: core/extensions/scripts shards
|
||||
- `pnpm lint:core`, `pnpm lint:extensions`, `pnpm lint:scripts`
|
||||
- `pnpm lint:apps`: Swift/app surface, separate from TS lint
|
||||
- `pnpm lint:all`: legacy comparison lane
|
||||
- Local heavy-check behavior: `OPENCLAW_LOCAL_CHECK=1` default; `OPENCLAW_LOCAL_CHECK_MODE=throttled|full`; `OPENCLAW_LOCAL_CHECK=0` for CI/shared runs.
|
||||
- Local validation is local-first. Do not default to Blacksmith/Testbox for routine OpenClaw iteration; it burns warm caches and startup time. Use repo `pnpm` lanes first, then reach for remote CI/Testbox only for parity-only failures, secrets/services, or when explicitly requested.
|
||||
- Runtime: Node 22+. Keep Node + Bun paths working.
|
||||
- Install: `pnpm install` (keep Bun lock/patches aligned if touched).
|
||||
- CLI: `pnpm openclaw ...` or `pnpm dev`; build: `pnpm build`.
|
||||
- Smart gate: `pnpm check:changed`; explain `pnpm changed:lanes --json`; staged preview `pnpm check:changed --staged`.
|
||||
- Prod sweep: `pnpm check`; tests: `pnpm test`, `pnpm test:changed`, `pnpm test:serial`, `pnpm test:coverage`.
|
||||
- Extension tests: `pnpm test:extensions`, `pnpm test extensions`, `pnpm test extensions/<id>`.
|
||||
- Targeted tests: `pnpm test <path-or-filter> [vitest args...]`; never raw `vitest`.
|
||||
- Typecheck: `tsgo` lanes only (`pnpm tsgo*`, `pnpm check:test-types`); do not add `tsc --noEmit`, `typecheck`, `check:types`.
|
||||
- Format/lint: `pnpm format:check`/`pnpm format`; `pnpm lint*` lanes.
|
||||
- Heavy checks: `OPENCLAW_LOCAL_CHECK=1`, mode `OPENCLAW_LOCAL_CHECK_MODE=throttled|full`; CI/shared use `OPENCLAW_LOCAL_CHECK=0`.
|
||||
- Local first. Use repo `pnpm` lanes before Blacksmith/Testbox. Remote only for parity-only failures, secrets/services, or explicit ask.
|
||||
|
||||
## GitHub API
|
||||
## GitHub / CI
|
||||
|
||||
- Issue/PR triage: list first, hydrate few. Use bounded fields + `--jq`, e.g. `gh issue list --state open --limit 80 --json number,title,labels,updatedAt,comments --jq '.[]|[.number,.updatedAt,.comments,.title]|@tsv'`; then `gh issue view <n> --json title,body,comments,labels,createdAt,updatedAt,url --jq '{title,labels,createdAt,updatedAt,url,body,comments:[.comments[]|{author:.author.login,createdAt,body}]}'` only for shortlisted items.
|
||||
- Search/dedupe: prefer `gh search issues 'repo:openclaw/openclaw is:open <terms>' --json number,title,state,updatedAt --limit 20 --jq '.[]|[.number,.updatedAt,.title]|@tsv'`; avoid repeated full `--comments` scans.
|
||||
- After landing a PR: search for duplicate open issues/PRs that can be closed.
|
||||
- Before closing an issue/PR: add a comment explaining why, usually duplicate/invalid, with the canonical issue/PR when relevant.
|
||||
- PR links: `gh pr list --state open --search '<issue-or-terms>' --json number,title,updatedAt,headRefName --limit 20`; use `gh pr view <n> --json number,title,body,closingIssuesReferences,files,statusCheckRollup,reviewDecision` only after shortlist.
|
||||
- CI polling: keep full `gh` capability, but request only needed fields. Known run status: `gh api repos/<owner>/<repo>/actions/runs/<id> --jq '{status,conclusion,head_sha,updated_at,name,path}'`.
|
||||
- Non-blocking background workflows: `Auto response`, `Docs Sync Publish Repo`, `Docs Agent`, and `Test Performance Agent` are service/agent work. Do not wait on, rerun, or fix them during normal push/PR verification unless the user explicitly asks or the task is about those workflows. Report them as background if mentioned.
|
||||
- `/landpr` CI wait scope: do not idle on pending `auto-response`/`Auto response` or `check-docs`. Treat docs as local proof unless `check-docs` already failed with a relevant, actionable error. If required product/code gates and touched-surface local gates are green, proceed without waiting for docs-only or auto-response automation.
|
||||
- Waiting: poll lightly, usually 30-60s backoff. Fetch jobs/logs/artifacts only after completion/failure or when job detail is needed; avoid repeated workflow + run + jobs loops.
|
||||
- Triage: list first, hydrate few. Use bounded `gh --json --jq`; avoid repeated full comment scans.
|
||||
- Search/dedupe: prefer `gh search issues 'repo:openclaw/openclaw is:open <terms>' --json number,title,state,updatedAt --limit 20`.
|
||||
- PR shortlist: `gh pr list ...`; then `gh pr view <n> --json number,title,body,closingIssuesReferences,files,statusCheckRollup,reviewDecision`.
|
||||
- After landing PR: search duplicate open issues/PRs. Before closing: comment why + canonical link.
|
||||
- GH comments with markdown backticks, `$`, or shell snippets: avoid inline double-quoted `--body`; use single quotes or `--body-file`.
|
||||
- PR review answer must explicitly cover: what bug/behavior we are trying to fix; PR/issue URL(s) and affected endpoint/surface; whether this is the best possible fix, with high-certainty evidence from code, tests, CI, and shipped/current behavior.
|
||||
- CI polling: exact SHA, needed fields only. Example: `gh api repos/<owner>/<repo>/actions/runs/<id> --jq '{status,conclusion,head_sha,updated_at,name,path}'`.
|
||||
- Post-land wait: minimal. Exact landed SHA only. If superseded on `main`, same-branch `cancel-in-progress` cancellations are expected; stop once local touched-surface proof exists. Never wait for newer unrelated `main` unless asked.
|
||||
- Wait matrix:
|
||||
- never: `Auto response`, `Labeler`, `Docs Sync Publish Repo`, `Docs Agent`, `Test Performance Agent`, `Stale`.
|
||||
- conditional: `CI` exact SHA only; `Docs` only docs task/no local docs proof; `Workflow Sanity` only workflow/composite/CI-policy edits; `Plugin NPM Release` only plugin package/release metadata.
|
||||
- release/manual only: `Docker Release`, `OpenClaw NPM Release`, `macOS Release`, `OpenClaw Release Checks`, `Cross-OS Release Checks`, `NPM Telegram Beta E2E`.
|
||||
- explicit/surface only: `QA-Lab - All Lanes`, `Scheduled Live And E2E`, `Install Smoke`, `CodeQL`, `Sandbox Common Smoke`, `Parity gate`, `Blacksmith Testbox`, `Control UI Locale Refresh`.
|
||||
- `/landpr`: do not idle on `auto-response` or `check-docs`. Treat docs as local proof unless `check-docs` already failed with actionable relevant error.
|
||||
- Poll 30-60s. Fetch jobs/logs/artifacts only after failure/completion or concrete need.
|
||||
|
||||
## Gates
|
||||
|
||||
- Pre-commit hook: staged formatting only. It does not run lint, typecheck, or tests.
|
||||
- Pre-commit hook: staged formatting only. Validation explicit.
|
||||
- Changed lanes:
|
||||
- core prod => core prod typecheck + core tests
|
||||
- core tests => core test typecheck/tests only
|
||||
- extension prod => extension prod typecheck + extension tests
|
||||
- extension tests => extension test typecheck/tests only
|
||||
- public SDK/plugin contract => extension prod/test validation too
|
||||
- unknown root/config => all lanes
|
||||
- Local loop: run `pnpm check:changed` explicitly before handoff/push; use `pnpm test:changed` for tests only; use `pnpm check` for full prod TS/lint sweep without tests.
|
||||
- Landing on `main`: verify touched surface near landing; default bar is `pnpm check` + `pnpm test` when feasible.
|
||||
- Hard build gate: run/pass `pnpm build` before push if build output, packaging, lazy/module boundaries, or published surfaces can change.
|
||||
- Do not land related failing format/lint/type/build/tests. If failures are unrelated on latest `origin/main`, say so and give scoped proof.
|
||||
- Commit helper is formatting-only; validation gates are explicit commands, not commit side effects.
|
||||
- CI architecture gate: `check-additional`; local equivalent `pnpm check:architecture`.
|
||||
- Config docs drift: `pnpm config:docs:gen/check`
|
||||
- Plugin SDK API drift: `pnpm plugin-sdk:api:gen/check`
|
||||
- Generated docs baselines: tracked `docs/.generated/*.sha256`; full JSON ignored.
|
||||
- core prod: core prod typecheck + core tests
|
||||
- core tests: core test typecheck/tests
|
||||
- extension prod: extension prod typecheck + extension tests
|
||||
- extension tests: extension test typecheck/tests
|
||||
- public SDK/plugin contract: extension prod/test too
|
||||
- unknown root/config: all lanes
|
||||
- Before handoff/push: `pnpm check:changed`. Tests-only: `pnpm test:changed`. Full prod sweep: `pnpm check`.
|
||||
- Landing on `main`: verify touched surface near landing. Default feasible bar: `pnpm check` + `pnpm test`.
|
||||
- Hard build gate: `pnpm build` before push if build output, packaging, lazy/module boundaries, or published surfaces can change.
|
||||
- Do not land related failing format/lint/type/build/tests. If unrelated on latest `origin/main`, say so with scoped proof.
|
||||
- Generated/API drift: `pnpm check:architecture`, `pnpm config:docs:gen/check`, `pnpm plugin-sdk:api:gen/check`. Track `docs/.generated/*.sha256`; full JSON ignored.
|
||||
|
||||
## Code Style
|
||||
## Code
|
||||
|
||||
- TypeScript ESM. Strict types. Avoid `any`; prefer real types/`unknown`/narrow adapters.
|
||||
- No `@ts-nocheck`. No lint suppressions unless intentional and explained.
|
||||
- TS ESM, strict. Avoid `any`; prefer real types, `unknown`, narrow adapters.
|
||||
- No `@ts-nocheck`. Lint suppressions only intentional + explained.
|
||||
- External boundaries: prefer `zod` or existing schema helpers.
|
||||
- Runtime branching: prefer discriminated unions / closed codes over freeform strings.
|
||||
- Avoid magic sentinels like `?? 0`, empty object/string when semantics change.
|
||||
- Dynamic import: do not mix static and dynamic import for same module in prod path. Use dedicated `*.runtime.ts` lazy boundary. After lazy-boundary edits, run `pnpm build` and check `[INEFFECTIVE_DYNAMIC_IMPORT]`.
|
||||
- Cycles: keep `pnpm check:import-cycles` and architecture/madge cycle checks green.
|
||||
- Classes: no prototype mixins/mutations. Use explicit inheritance/composition. Tests prefer per-instance stubs.
|
||||
- Comments: brief only for non-obvious logic.
|
||||
- File size: split around ~700 LOC when it improves clarity/testability.
|
||||
- Product naming: **OpenClaw** product/docs; `openclaw` CLI/package/path/config.
|
||||
- Written English: American spelling.
|
||||
- Runtime branching: discriminated unions/closed codes over freeform strings.
|
||||
- Avoid semantic sentinels: `?? 0`, empty object/string, etc.
|
||||
- Dynamic import: no static+dynamic import for same prod module. Use `*.runtime.ts` lazy boundary. After edits: `pnpm build`; check `[INEFFECTIVE_DYNAMIC_IMPORT]`.
|
||||
- Cycles: keep `pnpm check:import-cycles` + architecture/madge green.
|
||||
- Classes: no prototype mixins/mutations. Prefer inheritance/composition. Tests prefer per-instance stubs.
|
||||
- Comments: brief, only non-obvious logic.
|
||||
- Split files around ~700 LOC when clarity/testability improves.
|
||||
- Naming: **OpenClaw** product/docs; `openclaw` CLI/package/path/config.
|
||||
- English: American spelling.
|
||||
|
||||
## Tests
|
||||
|
||||
- Vitest. Tests colocated `*.test.ts`; e2e `*.e2e.test.ts`.
|
||||
- Example models in tests: `sonnet-4.6`, `gpt-5.4`.
|
||||
- Clean up timers/env/globals/mocks/sockets/temp dirs/module state; `--isolate=false` must stay safe.
|
||||
- Hot tests: avoid per-test `vi.resetModules()` + fresh heavy imports; prefer static or `beforeAll` imports and reset state directly.
|
||||
- Measure first: `pnpm test:perf:imports <file>` for import drag; `pnpm test:perf:hotspots --limit N` for suite targets.
|
||||
- Keep tests at seam depth: unit-test pure helpers/contracts; one integration smoke per boundary, not per branch.
|
||||
- Mock expensive runtime seams directly: scanners, manifests, package registries, filesystem crawls, provider SDKs, network/process launch.
|
||||
- Prefer injected deps over module mocks; if mocking modules, mock narrow local `*.runtime.ts` seams, not broad barrels.
|
||||
- Share fixtures/builders; do not recreate temp dirs, package manifests, or plugin workspaces in every case unless state isolation needs it.
|
||||
- Delete duplicate assertions when another test owns the boundary; assert only the behavior that can regress here.
|
||||
- Avoid broad `importOriginal()` / broad `openclaw/plugin-sdk/*` partial mocks in hot tests. Add narrow local `*.runtime.ts` seam and mock it.
|
||||
- Use existing deps/callback/runtime injection seams before module mocks.
|
||||
- Import-dominated test time is a boundary smell; shrink import surface before adding cases.
|
||||
- Replacing slow integration coverage: extract production composition into a named helper and test that helper.
|
||||
- Do not modify baseline/inventory/ignore/snapshot/expected-failure files to silence checks without explicit approval.
|
||||
- Do not set test workers above 16. For memory pressure: `OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test`.
|
||||
- Live: `OPENCLAW_LIVE_TEST=1 pnpm test:live`; full logs `OPENCLAW_LIVE_TEST_QUIET=0`.
|
||||
- Full testing guide: `docs/help/testing.md`.
|
||||
- Vitest. Colocated `*.test.ts`; e2e `*.e2e.test.ts`; example models `sonnet-4.6`, `gpt-5.4`.
|
||||
- Clean timers/env/globals/mocks/sockets/temp dirs/module state; `--isolate=false` safe.
|
||||
- Hot tests: avoid per-test `vi.resetModules()` + heavy imports. Measure with `pnpm test:perf:imports <file>` / `pnpm test:perf:hotspots --limit N`.
|
||||
- Seam depth: pure helper/contract unit tests; one integration smoke per boundary.
|
||||
- Mock expensive seams directly: scanners, manifests, registries, fs crawls, provider SDKs, network/process launch.
|
||||
- Prefer injection; if module mocking, mock narrow local `*.runtime.ts`, not broad barrels or `openclaw/plugin-sdk/*`.
|
||||
- Share fixtures/builders; delete duplicate assertions; assert behavior that can regress here.
|
||||
- Do not edit baseline/inventory/ignore/snapshot/expected-failure files to silence checks without explicit approval.
|
||||
- Test workers max 16. Memory pressure: `OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test`.
|
||||
- Live: `OPENCLAW_LIVE_TEST=1 pnpm test:live`; verbose `OPENCLAW_LIVE_TEST_QUIET=0`.
|
||||
- Guide: `docs/help/testing.md`.
|
||||
|
||||
## Docs / Changelog
|
||||
|
||||
- Update docs when behavior/API changes. Use docs list/read_when hints.
|
||||
- Docs links: see `docs/AGENTS.md`.
|
||||
- Changelog: user-facing only. Pure test/internal changes usually no entry.
|
||||
- Changelog placement: append to active version `### Changes`/`### Fixes`; at most one contributor mention, prefer `Thanks @user`.
|
||||
- Docs change with behavior/API. Use docs list/read_when hints; docs links per `docs/AGENTS.md`.
|
||||
- Changelog user-facing only; pure test/internal usually no entry.
|
||||
- Changelog placement: active version `### Changes`/`### Fixes`; at most one contributor mention, prefer `Thanks @user`.
|
||||
|
||||
## Git
|
||||
|
||||
- Use `scripts/committer "<msg>" <file...>`; stage only intended files. It formats staged files only; run validation separately.
|
||||
- Commits: conventional-ish, concise/action-oriented. Group related changes.
|
||||
- No manual stash/autostash unless explicitly requested. No branch/worktree changes unless requested.
|
||||
- No merge commits on `main`; rebase on latest `origin/main` before push.
|
||||
- User says "commit": commit your changes only. "commit all": commit everything in grouped chunks. "push": may `git pull --rebase` first.
|
||||
- Do not delete/rename unexpected files; ask if it blocks. Otherwise ignore unrelated WIP.
|
||||
- If bulk PR close/reopen affects >5 PRs, ask with exact count/scope.
|
||||
- PR/issue workflows: use `$openclaw-pr-maintainer`.
|
||||
- `/landpr`: use `~/.codex/prompts/landpr.md`.
|
||||
- Commit via `scripts/committer "<msg>" <file...>`; stage intended files only. It formats staged files; still run gates.
|
||||
- Commits: conventional-ish, concise, grouped.
|
||||
- No manual stash/autostash unless explicit. No branch/worktree changes unless requested.
|
||||
- `main`: no merge commits; rebase on latest `origin/main` before push.
|
||||
- User says `commit`: your changes only. `commit all`: all changes in grouped chunks. `push`: may `git pull --rebase` first.
|
||||
- Do not delete/rename unexpected files; ask if blocking, else ignore.
|
||||
- Bulk PR close/reopen >5: ask with count/scope.
|
||||
- PR/issue workflows: `$openclaw-pr-maintainer`. `/landpr`: `~/.codex/prompts/landpr.md`.
|
||||
|
||||
## Security / Release
|
||||
|
||||
- Never commit real phone numbers, videos, credentials, live config.
|
||||
- Secrets: channel/provider credentials under `~/.openclaw/credentials/`; model auth profiles under `~/.openclaw/agents/<agentId>/agent/auth-profiles.json`.
|
||||
- Secrets: channel/provider creds in `~/.openclaw/credentials/`; model auth profiles in `~/.openclaw/agents/<agentId>/agent/auth-profiles.json`.
|
||||
- Env keys: check `~/.profile`.
|
||||
- Dependency patches/overrides/vendor changes require explicit approval. `pnpm.patchedDependencies` must use exact versions.
|
||||
- Carbon pins owner-only: do not change `@buape/carbon` versions unless Shadow (`@thewilloftheshadow`, verified by `gh`) asks.
|
||||
- Releases/publish/version bumps require explicit approval.
|
||||
- Release docs: `docs/reference/RELEASING.md`; use `$openclaw-release-maintainer`.
|
||||
- GHSA/advisories: use `$openclaw-ghsa-maintainer`.
|
||||
- Beta tag/version must match, e.g. `vYYYY.M.D-beta.N` => npm `YYYY.M.D-beta.N --tag beta`.
|
||||
- Dependency patches/overrides/vendor changes need explicit approval. `pnpm.patchedDependencies` exact versions only.
|
||||
- Carbon pins owner-only: do not change `@buape/carbon` unless Shadow (`@thewilloftheshadow`, verified by `gh`) asks.
|
||||
- Releases/publish/version bumps need explicit approval. Release docs: `docs/reference/RELEASING.md`; use `$openclaw-release-maintainer`.
|
||||
- GHSA/advisories: `$openclaw-ghsa-maintainer`.
|
||||
- Beta tag/version match: `vYYYY.M.D-beta.N` -> npm `YYYY.M.D-beta.N --tag beta`.
|
||||
|
||||
## Apps / Platform
|
||||
|
||||
- Before simulator/emulator testing, check connected real iOS/Android devices first.
|
||||
- Before simulator/emulator testing, check real iOS/Android devices.
|
||||
- "restart iOS/Android apps" = rebuild/reinstall/relaunch, not kill/launch.
|
||||
- SwiftUI: prefer Observation (`@Observable`, `@Bindable`) over new `ObservableObject`.
|
||||
- mac gateway: use app or `openclaw gateway restart/status --deep`; avoid ad-hoc tmux gateway sessions. Rebuild mac app locally, not over SSH.
|
||||
- mac logs: `./scripts/clawlog.sh`.
|
||||
- Version bump touches: `package.json`, `apps/android/app/build.gradle.kts`, `apps/ios/version.json` then `pnpm ios:version:sync`, `apps/macos/.../Info.plist`, `docs/install/updating.md`. Appcast only for Sparkle release.
|
||||
- iOS Team ID: `security find-identity -p codesigning -v`; fallback `defaults read com.apple.dt.Xcode IDEProvisioningTeamIdentifiers`.
|
||||
- Mobile LAN pairing: plaintext `ws://` is loopback-only by default. Trusted private-network `ws://` needs `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`; Tailscale/public use `wss://` or a tunnel.
|
||||
- SwiftUI: Observation (`@Observable`, `@Bindable`) over new `ObservableObject`.
|
||||
- Mac gateway: use app or `openclaw gateway restart/status --deep`; no ad-hoc tmux gateway. Logs: `./scripts/clawlog.sh`.
|
||||
- Version bump touches: `package.json`, `apps/android/app/build.gradle.kts`, `apps/ios/version.json` + `pnpm ios:version:sync`, macOS `Info.plist`, `docs/install/updating.md`. Appcast only for Sparkle release.
|
||||
- Mobile LAN pairing: plaintext `ws://` loopback-only. Private-network `ws://` needs `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`; Tailscale/public use `wss://` or tunnel.
|
||||
- A2UI hash `src/canvas-host/a2ui/.bundle.hash`: generated; ignore unless running `pnpm canvas:a2ui:bundle`; commit separately.
|
||||
|
||||
## External Ops
|
||||
|
||||
- Remote install docs: `docs/install/exe-dev.md`, `docs/install/fly.md`, `docs/install/hetzner.md`.
|
||||
- Parallels smoke: `$openclaw-parallels-smoke`; Discord roundtrip: `parallels-discord-roundtrip`.
|
||||
|
||||
## Misc Footguns
|
||||
## Ops / Footguns
|
||||
|
||||
- Remote install docs: `docs/install/{exe-dev,fly,hetzner}.md`. Parallels smoke: `$openclaw-parallels-smoke`; Discord roundtrip: `parallels-discord-roundtrip`.
|
||||
- Rebrand/migration/config warnings: run `openclaw doctor`.
|
||||
- Never edit `node_modules`.
|
||||
- Local-only `.agents` ignores: use `.git/info/exclude`, not repo `.gitignore`.
|
||||
- CLI progress: use `src/cli/progress.ts`; status tables: `src/terminal/table.ts`.
|
||||
- Local-only `.agents` ignores: `.git/info/exclude`, not repo `.gitignore`.
|
||||
- CLI progress: `src/cli/progress.ts`; status tables: `src/terminal/table.ts`.
|
||||
- Connection/provider additions: update all UI surfaces + docs + status/config forms.
|
||||
- Provider-facing tool schemas: prefer flat string enum helpers over `Type.Union([Type.Literal(...)])`; some providers reject generated `anyOf`. Do not treat this as a repo-wide protocol/schema ban.
|
||||
- External messaging surfaces: no token-delta channel messages. Follow `docs/concepts/streaming.md`; preview/block streaming uses message edits/chunks and must preserve final/fallback delivery.
|
||||
- Provider tool schemas: prefer flat string enum helpers over `Type.Union([Type.Literal(...)])`; some providers reject `anyOf`. Not a repo-wide protocol/schema ban.
|
||||
- External messaging: no token-delta channel messages. Follow `docs/concepts/streaming.md`; preview/block streaming uses edits/chunks and preserves final/fallback delivery.
|
||||
|
||||
3371
CHANGELOG.md
3371
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -29,9 +29,9 @@ ARG OPENCLAW_NODE_BOOKWORM_SLIM_DIGEST="sha256:e8e2e91b1378f83c5b2dd15f0247f3411
|
||||
FROM ${OPENCLAW_NODE_BOOKWORM_IMAGE} AS ext-deps
|
||||
ARG OPENCLAW_EXTENSIONS
|
||||
ARG OPENCLAW_BUNDLED_PLUGIN_DIR
|
||||
COPY ${OPENCLAW_BUNDLED_PLUGIN_DIR} /tmp/${OPENCLAW_BUNDLED_PLUGIN_DIR}
|
||||
# Copy package.json for opted-in extensions so pnpm resolves their deps.
|
||||
RUN mkdir -p /out && \
|
||||
RUN --mount=type=bind,source=${OPENCLAW_BUNDLED_PLUGIN_DIR},target=/tmp/${OPENCLAW_BUNDLED_PLUGIN_DIR},readonly \
|
||||
mkdir -p /out && \
|
||||
for ext in $OPENCLAW_EXTENSIONS; do \
|
||||
if [ -f "/tmp/${OPENCLAW_BUNDLED_PLUGIN_DIR}/$ext/package.json" ]; then \
|
||||
mkdir -p "/out/$ext" && \
|
||||
|
||||
35
VISION.md
35
VISION.md
@@ -53,12 +53,24 @@ We prioritize secure defaults, but also expose clear knobs for trusted high-powe
|
||||
|
||||
OpenClaw has an extensive plugin API.
|
||||
Core stays lean; optional capability should usually ship as plugins.
|
||||
We are generally slimming down core while expanding what plugins can do.
|
||||
If a useful feature cannot be built as a plugin yet, we welcome PRs and design discussions that extend the plugin API instead of adding one-off core behavior.
|
||||
|
||||
There are two broad plugin styles:
|
||||
|
||||
- Code plugins run OpenClaw plugin code and are appropriate for deeper runtime extension.
|
||||
- Bundle-style plugins package stable external surfaces such as skills, MCP servers, and related configuration.
|
||||
|
||||
Prefer bundle-style plugins when they can express the capability.
|
||||
They have a smaller, more stable interface and better security boundaries.
|
||||
Use code plugins when the capability needs runtime hooks, providers, channels, tools, or other in-process extension points.
|
||||
|
||||
Preferred plugin path is npm package distribution plus local extension loading for development.
|
||||
If you build a plugin, host and maintain it in your own repository.
|
||||
The bar for adding optional plugins to core is intentionally high.
|
||||
Plugin docs: [`docs/tools/plugin.md`](docs/tools/plugin.md)
|
||||
Community plugin listing + PR bar: https://docs.openclaw.ai/plugins/community
|
||||
Plugin discovery, official publisher status, provenance, and security review live in [ClawHub](https://clawhub.ai/).
|
||||
OpenClaw docs should document core extension points; plugin promotion belongs in ClawHub, preferably under vetted org publishers for official plugins.
|
||||
|
||||
Memory is a special plugin slot where only one memory plugin can be active at a time.
|
||||
Today we ship multiple memory options; over time we plan to converge on one recommended default path.
|
||||
@@ -66,21 +78,16 @@ Today we ship multiple memory options; over time we plan to converge on one reco
|
||||
### Skills
|
||||
|
||||
We still ship some bundled skills for baseline UX.
|
||||
New skills should be published to ClawHub first (`clawhub.ai`), not added to core by default.
|
||||
Core skill additions should be rare and require a strong product or security reason.
|
||||
New skills should be published through [ClawHub](https://clawhub.ai/) first, not added to core by default.
|
||||
Official or bundled promotion should require a clear product, security, or maintainer-ownership reason.
|
||||
|
||||
### MCP Support
|
||||
|
||||
OpenClaw supports MCP through `mcporter`: https://github.com/steipete/mcporter
|
||||
OpenClaw supports MCP as both a server and a runtime integration surface.
|
||||
MCP details live in [`docs/cli/mcp.md`](docs/cli/mcp.md).
|
||||
|
||||
This keeps MCP integration flexible and decoupled from core runtime:
|
||||
|
||||
- add or change MCP servers without restarting the gateway
|
||||
- keep core tool/context surface lean
|
||||
- reduce MCP churn impact on core stability and security
|
||||
|
||||
For now, we prefer this bridge model over building first-class MCP runtime into core.
|
||||
If there is an MCP server or feature `mcporter` does not support yet, please open an issue there.
|
||||
The project goal is pragmatic MCP support without duplicating existing agent,
|
||||
tool, ACPX, plugin, or ClawHub paths.
|
||||
|
||||
### Setup
|
||||
|
||||
@@ -98,11 +105,11 @@ It is widely known, fast to iterate in, and easy to read, modify, and extend.
|
||||
|
||||
## What We Will Not Merge (For Now)
|
||||
|
||||
- New core skills when they can live on ClawHub
|
||||
- New core skills when they can live on [ClawHub](https://clawhub.ai/)
|
||||
- Full-doc translation sets for all docs (deferred; we plan AI-generated translations later)
|
||||
- Commercial service integrations that do not clearly fit the model-provider category
|
||||
- Wrapper channels around already supported channels without a clear capability or security gap
|
||||
- First-class MCP runtime in core when `mcporter` already provides the integration path
|
||||
- MCP work that duplicates existing MCP, ACPX, plugin, or ClawHub paths without a clear product or security gap
|
||||
- Agent-hierarchy frameworks (manager-of-managers / nested planner trees) as a default architecture
|
||||
- Heavy orchestration layers that duplicate existing agent and tool infrastructure
|
||||
|
||||
|
||||
@@ -1,6 +1,24 @@
|
||||
import Foundation
|
||||
import OpenClawProtocol
|
||||
|
||||
func whatsappLoginWaitRequestTimeoutMs(
|
||||
startedAt: Date,
|
||||
timeoutMs: Int,
|
||||
didRunFinalWait: inout Bool,
|
||||
now: Date = Date()) -> Int?
|
||||
{
|
||||
let elapsedMs = Int(now.timeIntervalSince(startedAt) * 1000)
|
||||
let remainingMs = max(timeoutMs - elapsedMs, 0)
|
||||
if remainingMs > 0 {
|
||||
return remainingMs
|
||||
}
|
||||
if didRunFinalWait {
|
||||
return nil
|
||||
}
|
||||
didRunFinalWait = true
|
||||
return 1
|
||||
}
|
||||
|
||||
extension ChannelsStore {
|
||||
func start() {
|
||||
guard !self.isPreview else { return }
|
||||
@@ -77,18 +95,28 @@ extension ChannelsStore {
|
||||
guard !self.whatsappBusy else { return }
|
||||
self.whatsappBusy = true
|
||||
defer { self.whatsappBusy = false }
|
||||
let startedAt = Date()
|
||||
var didRunFinalWait = false
|
||||
do {
|
||||
let params: [String: AnyCodable] = [
|
||||
"timeoutMs": AnyCodable(timeoutMs),
|
||||
]
|
||||
let result: WhatsAppLoginWaitResult = try await GatewayConnection.shared.requestDecoded(
|
||||
method: .webLoginWait,
|
||||
params: params,
|
||||
timeoutMs: Double(timeoutMs) + 5000)
|
||||
self.whatsappLoginMessage = result.message
|
||||
self.whatsappLoginConnected = result.connected
|
||||
if result.connected {
|
||||
self.whatsappLoginQrDataUrl = nil
|
||||
while let remainingMs = whatsappLoginWaitRequestTimeoutMs(
|
||||
startedAt: startedAt,
|
||||
timeoutMs: timeoutMs,
|
||||
didRunFinalWait: &didRunFinalWait)
|
||||
{
|
||||
var params: [String: AnyCodable] = [
|
||||
"timeoutMs": AnyCodable(remainingMs),
|
||||
]
|
||||
if let currentQrDataUrl = self.whatsappLoginQrDataUrl {
|
||||
params["currentQrDataUrl"] = AnyCodable(currentQrDataUrl)
|
||||
}
|
||||
let result: WhatsAppLoginWaitResult = try await GatewayConnection.shared.requestDecoded(
|
||||
method: .webLoginWait,
|
||||
params: params,
|
||||
timeoutMs: Double(remainingMs) + 5000)
|
||||
self.applyWhatsAppLoginWaitResult(result)
|
||||
if result.connected || result.qrDataUrl == nil || didRunFinalWait {
|
||||
break
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
self.whatsappLoginMessage = error.localizedDescription
|
||||
@@ -151,9 +179,10 @@ private struct WhatsAppLoginStartResult: Codable {
|
||||
let connected: Bool?
|
||||
}
|
||||
|
||||
private struct WhatsAppLoginWaitResult: Codable {
|
||||
struct WhatsAppLoginWaitResult: Codable {
|
||||
let connected: Bool
|
||||
let message: String
|
||||
let qrDataUrl: String?
|
||||
}
|
||||
|
||||
private struct ChannelLogoutResult: Codable {
|
||||
|
||||
@@ -290,6 +290,16 @@ final class ChannelsStore {
|
||||
return self.snapshot?.channelOrder ?? []
|
||||
}
|
||||
|
||||
func applyWhatsAppLoginWaitResult(_ result: WhatsAppLoginWaitResult) {
|
||||
self.whatsappLoginMessage = result.message
|
||||
self.whatsappLoginConnected = result.connected
|
||||
if let qrDataUrl = result.qrDataUrl {
|
||||
self.whatsappLoginQrDataUrl = qrDataUrl
|
||||
} else if result.connected {
|
||||
self.whatsappLoginQrDataUrl = nil
|
||||
}
|
||||
}
|
||||
|
||||
init(isPreview: Bool = ProcessInfo.processInfo.isPreview) {
|
||||
self.isPreview = isPreview
|
||||
}
|
||||
|
||||
@@ -2610,18 +2610,22 @@ public struct WebLoginStartParams: Codable, Sendable {
|
||||
public struct WebLoginWaitParams: Codable, Sendable {
|
||||
public let timeoutms: Int?
|
||||
public let accountid: String?
|
||||
public let currentqrdataurl: String?
|
||||
|
||||
public init(
|
||||
timeoutms: Int?,
|
||||
accountid: String?)
|
||||
accountid: String?,
|
||||
currentqrdataurl: String?)
|
||||
{
|
||||
self.timeoutms = timeoutms
|
||||
self.accountid = accountid
|
||||
self.currentqrdataurl = currentqrdataurl
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case timeoutms = "timeoutMs"
|
||||
case accountid = "accountId"
|
||||
case currentqrdataurl = "currentQrDataUrl"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -156,4 +156,63 @@ struct ChannelsSettingsSmokeTests {
|
||||
let view = ChannelsSettings(store: store)
|
||||
_ = view.body
|
||||
}
|
||||
|
||||
@Test func `whatsapp login wait result keeps latest qr until connected`() {
|
||||
let store = makeChannelsStore(channels: [:])
|
||||
store.whatsappLoginQrDataUrl = "data:image/png;base64,initial"
|
||||
|
||||
store.applyWhatsAppLoginWaitResult(
|
||||
WhatsAppLoginWaitResult(
|
||||
connected: false,
|
||||
message: "QR refreshed. Scan the latest code in WhatsApp → Linked Devices.",
|
||||
qrDataUrl: "data:image/png;base64,rotated"))
|
||||
|
||||
#expect(store.whatsappLoginQrDataUrl == "data:image/png;base64,rotated")
|
||||
#expect(store.whatsappLoginConnected == false)
|
||||
|
||||
store.applyWhatsAppLoginWaitResult(
|
||||
WhatsAppLoginWaitResult(
|
||||
connected: false,
|
||||
message: "Still waiting for the QR scan. Let me know when you’ve scanned it.",
|
||||
qrDataUrl: nil))
|
||||
|
||||
#expect(store.whatsappLoginQrDataUrl == "data:image/png;base64,rotated")
|
||||
|
||||
store.applyWhatsAppLoginWaitResult(
|
||||
WhatsAppLoginWaitResult(
|
||||
connected: true,
|
||||
message: "✅ Linked! WhatsApp is ready.",
|
||||
qrDataUrl: nil))
|
||||
|
||||
#expect(store.whatsappLoginQrDataUrl == nil)
|
||||
#expect(store.whatsappLoginConnected == true)
|
||||
}
|
||||
|
||||
@Test func `whatsapp login wait budget allows one final poll`() {
|
||||
let startedAt = Date(timeIntervalSince1970: 1_700_000_000)
|
||||
var didRunFinalWait = false
|
||||
|
||||
#expect(
|
||||
whatsappLoginWaitRequestTimeoutMs(
|
||||
startedAt: startedAt,
|
||||
timeoutMs: 1_000,
|
||||
didRunFinalWait: &didRunFinalWait,
|
||||
now: Date(timeInterval: 0.25, since: startedAt)) == 750)
|
||||
#expect(didRunFinalWait == false)
|
||||
|
||||
#expect(
|
||||
whatsappLoginWaitRequestTimeoutMs(
|
||||
startedAt: startedAt,
|
||||
timeoutMs: 1_000,
|
||||
didRunFinalWait: &didRunFinalWait,
|
||||
now: Date(timeInterval: 1.25, since: startedAt)) == 1)
|
||||
#expect(didRunFinalWait == true)
|
||||
|
||||
#expect(
|
||||
whatsappLoginWaitRequestTimeoutMs(
|
||||
startedAt: startedAt,
|
||||
timeoutMs: 1_000,
|
||||
didRunFinalWait: &didRunFinalWait,
|
||||
now: Date(timeInterval: 1.5, since: startedAt)) == nil)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2610,18 +2610,22 @@ public struct WebLoginStartParams: Codable, Sendable {
|
||||
public struct WebLoginWaitParams: Codable, Sendable {
|
||||
public let timeoutms: Int?
|
||||
public let accountid: String?
|
||||
public let currentqrdataurl: String?
|
||||
|
||||
public init(
|
||||
timeoutms: Int?,
|
||||
accountid: String?)
|
||||
accountid: String?,
|
||||
currentqrdataurl: String?)
|
||||
{
|
||||
self.timeoutms = timeoutms
|
||||
self.accountid = accountid
|
||||
self.currentqrdataurl = currentqrdataurl
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case timeoutms = "timeoutMs"
|
||||
case accountid = "accountId"
|
||||
case currentqrdataurl = "currentQrDataUrl"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
f0421335bfd388b7ebe1b8d478036ece4bf5eb8fd7b1de81b8cdc4ec6522ce20 config-baseline.json
|
||||
bf00f7910d8f0d8e12592e8a1c6bd0397f8e62fef2c11eb0cbd3b3a3e2a78ffe config-baseline.core.json
|
||||
8f23e853ccde6cd021b84b32fe205f456f8516667683d16c9b56d6598f608989 config-baseline.json
|
||||
037bf4a873587adb8349f531c0ad79cd4f90e01712f5aa5d8b4387be73538a7f config-baseline.core.json
|
||||
22d7cd6d8279146b2d79c9531a55b80b52a2c99c81338c508104729154fdd02d config-baseline.channel.json
|
||||
c6f99aed28b98e5914585956ec303b615a8ef975abf5cec186a61781c20b9106 config-baseline.plugin.json
|
||||
86f615b7d267b03888af0af7ccb3f8232a6b636f8a741d522ff425e46729ba81 config-baseline.plugin.json
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
3ce0dadfe0cac406051ff95ee8201a508d588e634b98ac22659e6b010c3641f6 plugin-sdk-api-baseline.json
|
||||
69c9058277b146196a3a3ef49fe193e42987a3642a233732370c9ddae60ddf62 plugin-sdk-api-baseline.jsonl
|
||||
56ccee3ef8ff3b0ba7e2e765ae631b59254464585d5fef9db7e905f2c4c34ded plugin-sdk-api-baseline.json
|
||||
39184cf8afaec691f0352d1a113e30a7099b87c0748237a3c7307e903ba24eee plugin-sdk-api-baseline.jsonl
|
||||
|
||||
@@ -11,6 +11,30 @@
|
||||
"source": "Pi",
|
||||
"target": "Pi"
|
||||
},
|
||||
{
|
||||
"source": "Agent runtimes",
|
||||
"target": "Agent Runtimes"
|
||||
},
|
||||
{
|
||||
"source": "Agent Runtimes",
|
||||
"target": "Agent Runtimes"
|
||||
},
|
||||
{
|
||||
"source": "Codex harness",
|
||||
"target": "Codex harness"
|
||||
},
|
||||
{
|
||||
"source": "Agent harness plugins",
|
||||
"target": "Agent harness plugins"
|
||||
},
|
||||
{
|
||||
"source": "Agent loop",
|
||||
"target": "Agent loop"
|
||||
},
|
||||
{
|
||||
"source": "Models",
|
||||
"target": "Models"
|
||||
},
|
||||
{
|
||||
"source": "Skills",
|
||||
"target": "Skills"
|
||||
@@ -331,10 +355,18 @@
|
||||
"source": "Plugin SDK",
|
||||
"target": "插件 SDK"
|
||||
},
|
||||
{
|
||||
"source": "Building plugins",
|
||||
"target": "构建插件"
|
||||
},
|
||||
{
|
||||
"source": "Plugin SDK Overview",
|
||||
"target": "插件 SDK 概览"
|
||||
},
|
||||
{
|
||||
"source": "Plugin SDK overview",
|
||||
"target": "插件 SDK 概览"
|
||||
},
|
||||
{
|
||||
"source": "SDK Overview",
|
||||
"target": "SDK 概览"
|
||||
@@ -343,6 +375,22 @@
|
||||
"source": "Plugin Entry Points",
|
||||
"target": "插件入口点"
|
||||
},
|
||||
{
|
||||
"source": "Plugin entry points",
|
||||
"target": "插件入口点"
|
||||
},
|
||||
{
|
||||
"source": "Plugin hooks",
|
||||
"target": "插件钩子"
|
||||
},
|
||||
{
|
||||
"source": "Internal hooks",
|
||||
"target": "内部钩子"
|
||||
},
|
||||
{
|
||||
"source": "Plugin architecture internals",
|
||||
"target": "插件架构内部机制"
|
||||
},
|
||||
{
|
||||
"source": "Entry Points",
|
||||
"target": "入口点"
|
||||
|
||||
@@ -7,8 +7,6 @@ read_when:
|
||||
title: "Scheduled tasks"
|
||||
---
|
||||
|
||||
# Scheduled Tasks (Cron)
|
||||
|
||||
Cron is the Gateway's built-in scheduler. It persists jobs, wakes the agent at the right time, and can deliver output back to a chat channel or webhook endpoint.
|
||||
|
||||
## Quick start
|
||||
|
||||
@@ -106,7 +106,7 @@ const handler = async (event) => {
|
||||
export default handler;
|
||||
```
|
||||
|
||||
Each event includes: `type`, `action`, `sessionKey`, `timestamp`, `messages` (push to send to user), and `context` (event-specific data).
|
||||
Each event includes: `type`, `action`, `sessionKey`, `timestamp`, `messages` (push to send to user), and `context` (event-specific data). Agent and tool plugin hook contexts can also include `trace`, a read-only W3C-compatible diagnostic trace context that plugins may pass into structured logs for OTEL correlation.
|
||||
|
||||
### Event context highlights
|
||||
|
||||
@@ -205,9 +205,12 @@ Runs `BOOT.md` from the active workspace when the gateway starts.
|
||||
|
||||
## Plugin hooks
|
||||
|
||||
Plugins can register hooks through the Plugin SDK for deeper integration: intercepting tool calls, modifying prompts, controlling message flow, and more. The Plugin SDK exposes 28 hooks covering model resolution, agent lifecycle, message flow, tool execution, subagent coordination, and gateway lifecycle.
|
||||
Plugins can register typed hooks through the Plugin SDK for deeper integration:
|
||||
intercepting tool calls, modifying prompts, controlling message flow, and more.
|
||||
Use plugin hooks when you need `before_tool_call`, `before_agent_reply`,
|
||||
`before_install`, or other in-process lifecycle hooks.
|
||||
|
||||
For the complete plugin hook reference including `before_tool_call`, `before_agent_reply`, `before_install`, and all other plugin hooks, see [Plugin Architecture](/plugins/architecture-internals#provider-runtime-hooks).
|
||||
For the complete plugin hook reference, see [Plugin hooks](/plugins/hooks).
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -315,5 +318,5 @@ Check for missing binaries (PATH), environment variables, config values, or OS c
|
||||
|
||||
- [CLI Reference: hooks](/cli/hooks)
|
||||
- [Webhooks](/automation/cron-jobs#webhooks)
|
||||
- [Plugin Architecture](/plugins/architecture-internals#provider-runtime-hooks) — full plugin hook reference
|
||||
- [Plugin hooks](/plugins/hooks) — in-process plugin lifecycle hooks
|
||||
- [Configuration](/gateway/configuration-reference#hooks)
|
||||
|
||||
@@ -40,7 +40,7 @@ flowchart TD
|
||||
| Audit what ran and when | Background Tasks | `openclaw tasks list` and `openclaw tasks audit` |
|
||||
| Multi-step research then summarize | Task Flow | Durable orchestration with revision tracking |
|
||||
| Run a script on session reset | Hooks | Event-driven, fires on lifecycle events |
|
||||
| Execute code on every tool call | Hooks | Hooks can filter by event type |
|
||||
| Execute code on every tool call | Plugin hooks | In-process hooks can intercept tool calls |
|
||||
| Always check compliance before replying | Standing Orders | Injected into every session automatically |
|
||||
|
||||
### Scheduled Tasks (Cron) vs Heartbeat
|
||||
@@ -83,7 +83,11 @@ See [Standing Orders](/automation/standing-orders).
|
||||
|
||||
### Hooks
|
||||
|
||||
Hooks are event-driven scripts triggered by agent lifecycle events (`/new`, `/reset`, `/stop`), session compaction, gateway startup, message flow, and tool calls. Hooks are automatically discovered from directories and can be managed with `openclaw hooks`.
|
||||
Internal hooks are event-driven scripts triggered by agent lifecycle events
|
||||
(`/new`, `/reset`, `/stop`), session compaction, gateway startup, and message
|
||||
flow. They are automatically discovered from directories and can be managed
|
||||
with `openclaw hooks`. For in-process tool-call interception, use
|
||||
[Plugin hooks](/plugins/hooks).
|
||||
|
||||
See [Hooks](/automation/hooks).
|
||||
|
||||
@@ -97,7 +101,7 @@ See [Heartbeat](/gateway/heartbeat).
|
||||
|
||||
- **Cron** handles precise schedules (daily reports, weekly reviews) and one-shot reminders. All cron executions create task records.
|
||||
- **Heartbeat** handles routine monitoring (inbox, calendar, notifications) in one batched turn every 30 minutes.
|
||||
- **Hooks** react to specific events (tool calls, session resets, compaction) with custom scripts.
|
||||
- **Hooks** react to specific events (session resets, compaction, message flow) with custom scripts. Plugin hooks cover tool calls.
|
||||
- **Standing orders** give the agent persistent context and authority boundaries.
|
||||
- **Task Flow** coordinates multi-step flows above individual tasks.
|
||||
- **Tasks** automatically track all detached work so you can inspect and audit it.
|
||||
@@ -108,6 +112,7 @@ See [Heartbeat](/gateway/heartbeat).
|
||||
- [Background Tasks](/automation/tasks) — task ledger for all detached work
|
||||
- [Task Flow](/automation/taskflow) — durable multi-step flow orchestration
|
||||
- [Hooks](/automation/hooks) — event-driven lifecycle scripts
|
||||
- [Plugin hooks](/plugins/hooks) — in-process tool, prompt, message, and lifecycle hooks
|
||||
- [Standing Orders](/automation/standing-orders) — persistent agent instructions
|
||||
- [Heartbeat](/gateway/heartbeat) — periodic main-session turns
|
||||
- [Configuration Reference](/gateway/configuration-reference) — all config keys
|
||||
|
||||
@@ -27,7 +27,7 @@ This is the difference between telling your assistant "send the weekly report" e
|
||||
- You only get involved for exceptions and approvals
|
||||
- The agent fills idle time productively
|
||||
|
||||
## How They Work
|
||||
## How they work
|
||||
|
||||
Standing orders are defined in your [agent workspace](/concepts/agent-workspace) files. The recommended approach is to include them directly in `AGENTS.md` (which is auto-injected every session) so the agent always has them in context. For larger configurations, you can also place them in a dedicated file like `standing-orders.md` and reference it from `AGENTS.md`.
|
||||
|
||||
@@ -198,8 +198,6 @@ This pattern prevents the most common agent failure mode: acknowledging a task w
|
||||
For agents managing multiple concerns, organize standing orders as separate programs with clear boundaries:
|
||||
|
||||
```markdown
|
||||
# Standing Orders
|
||||
|
||||
## Program 1: [Domain A] (Weekly)
|
||||
|
||||
...
|
||||
|
||||
@@ -20,6 +20,78 @@ Use Task Flow when work spans multiple sequential or branching steps and you nee
|
||||
| Observe externally created tasks | Task Flow (mirrored) |
|
||||
| One-shot reminder | Cron job |
|
||||
|
||||
## Reliable scheduled workflow pattern
|
||||
|
||||
For recurring workflows such as market intelligence briefings, treat the schedule, orchestration, and reliability checks as separate layers:
|
||||
|
||||
1. Use [Scheduled Tasks](/automation/cron-jobs) for timing.
|
||||
2. Use a persistent cron session when the workflow should build on prior context.
|
||||
3. Use [Lobster](/tools/lobster) for deterministic steps, approval gates, and resume tokens.
|
||||
4. Use Task Flow to track the multi-step run across child tasks, waits, retries, and gateway restarts.
|
||||
|
||||
Example cron shape:
|
||||
|
||||
```bash
|
||||
openclaw cron add \
|
||||
--name "Market intelligence brief" \
|
||||
--cron "0 7 * * 1-5" \
|
||||
--tz "America/New_York" \
|
||||
--session session:market-intel \
|
||||
--message "Run the market-intel Lobster workflow. Verify source freshness before summarizing." \
|
||||
--announce \
|
||||
--channel slack \
|
||||
--to "channel:C1234567890"
|
||||
```
|
||||
|
||||
Use `session:<id>` instead of `isolated` when the recurring workflow needs deliberate history, previous run summaries, or standing context. Use `isolated` when each run should start fresh and all required state is explicit in the workflow.
|
||||
|
||||
Inside the workflow, put reliability checks before the LLM summary step:
|
||||
|
||||
```yaml
|
||||
name: market-intel-brief
|
||||
steps:
|
||||
- id: preflight
|
||||
command: market-intel check --json
|
||||
- id: collect
|
||||
command: market-intel collect --json
|
||||
stdin: $preflight.json
|
||||
- id: summarize
|
||||
command: market-intel summarize --json
|
||||
stdin: $collect.json
|
||||
- id: approve
|
||||
command: market-intel deliver --preview
|
||||
stdin: $summarize.json
|
||||
approval: required
|
||||
- id: deliver
|
||||
command: market-intel deliver --execute
|
||||
stdin: $summarize.json
|
||||
condition: $approve.approved
|
||||
```
|
||||
|
||||
Recommended preflight checks:
|
||||
|
||||
- Browser availability and profile choice, for example `openclaw` for managed state or `user` when a signed-in Chrome session is required. See [Browser](/tools/browser).
|
||||
- API credentials and quota for each source.
|
||||
- Network reachability for required endpoints.
|
||||
- Required tools enabled for the agent, such as `lobster`, `browser`, and `llm-task`.
|
||||
- Failure destination configured for cron so preflight failures are visible. See [Scheduled Tasks](/automation/cron-jobs#delivery-and-output).
|
||||
|
||||
Recommended data provenance fields for every collected item:
|
||||
|
||||
```json
|
||||
{
|
||||
"sourceUrl": "https://example.com/report",
|
||||
"retrievedAt": "2026-04-24T12:00:00Z",
|
||||
"asOf": "2026-04-24",
|
||||
"title": "Example report",
|
||||
"content": "..."
|
||||
}
|
||||
```
|
||||
|
||||
Have the workflow reject or mark stale items before summarization. The LLM step should receive only structured JSON and should be asked to preserve `sourceUrl`, `retrievedAt`, and `asOf` in its output. Use [LLM Task](/tools/llm-task) when you need a schema-validated model step inside the workflow.
|
||||
|
||||
For reusable team or community workflows, package the CLI, `.lobster` files, and any setup notes as a skill or plugin and publish it through [ClawHub](/tools/clawhub). Keep workflow-specific guardrails in that package unless the plugin API is missing a needed generic capability.
|
||||
|
||||
## Sync modes
|
||||
|
||||
### Managed mode
|
||||
|
||||
@@ -7,8 +7,6 @@ read_when:
|
||||
title: "BlueBubbles"
|
||||
---
|
||||
|
||||
# BlueBubbles (macOS REST)
|
||||
|
||||
Status: bundled plugin that talks to the BlueBubbles macOS server over HTTP. **Recommended for iMessage integration** due to its richer API and easier setup compared to the legacy imsg channel.
|
||||
|
||||
## Bundled plugin
|
||||
|
||||
@@ -305,7 +305,7 @@ By default, components are single use. Set `components.reusable=true` to allow b
|
||||
|
||||
To restrict who can click a button, set `allowedUsers` on that button (Discord user IDs, tags, or `*`). When configured, unmatched users receive an ephemeral denial.
|
||||
|
||||
The `/model` and `/models` slash commands open an interactive model picker with provider and model dropdowns plus a Submit step. Unless `commands.modelsWrite=false`, `/models add` also supports adding a new provider/model entry from chat, and newly added models show up without restarting the gateway. The picker reply is ephemeral and only the invoking user can use it.
|
||||
The `/model` and `/models` slash commands open an interactive model picker with provider, model, and compatible runtime dropdowns plus a Submit step. `/models add` is deprecated and now returns a deprecation message instead of registering models from chat. The picker reply is ephemeral and only the invoking user can use it.
|
||||
|
||||
File attachments:
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@ read_when:
|
||||
title: "Group messages"
|
||||
---
|
||||
|
||||
# Group messages (WhatsApp web channel)
|
||||
|
||||
Goal: let Clawd sit in WhatsApp groups, wake up only when pinged, and keep that thread separate from the personal DM session.
|
||||
|
||||
Note: `agents.list[].groupChat.mentionPatterns` is now used by Telegram/Discord/Slack/iMessage as well; this doc focuses on WhatsApp-specific behavior. For multi-agent setups, set `agents.list[].groupChat.mentionPatterns` per agent (or use `messages.groupChat.mentionPatterns` as a global fallback).
|
||||
|
||||
@@ -6,8 +6,6 @@ read_when:
|
||||
title: "iMessage"
|
||||
---
|
||||
|
||||
# iMessage (legacy: imsg)
|
||||
|
||||
<Warning>
|
||||
For new iMessage deployments, use <a href="/channels/bluebubbles">BlueBubbles</a>.
|
||||
|
||||
|
||||
@@ -9,6 +9,16 @@ title: "Chat channels"
|
||||
OpenClaw can talk to you on any chat app you already use. Each channel connects via the Gateway.
|
||||
Text is supported everywhere; media and reactions vary by channel.
|
||||
|
||||
## Delivery notes
|
||||
|
||||
- Telegram replies that contain markdown image syntax, such as ``,
|
||||
are converted into media replies on the final outbound path when possible.
|
||||
- Slack multi-person DMs route as group chats, so group policy, mention
|
||||
behavior, and group-session rules apply to MPIM conversations.
|
||||
- WhatsApp setup is install-on-demand: onboarding can show the setup flow before
|
||||
Baileys runtime dependencies are staged, and the Gateway loads the WhatsApp
|
||||
runtime only when the channel is actually active.
|
||||
|
||||
## Supported channels
|
||||
|
||||
- [BlueBubbles](/channels/bluebubbles) — **Recommended for iMessage**; uses the BlueBubbles macOS server REST API with full feature support (bundled plugin; edit, unsend, effects, reactions, group management — edit currently broken on macOS 26 Tahoe).
|
||||
|
||||
@@ -310,16 +310,127 @@ Enable encryption:
|
||||
|
||||
Verification commands (all take `--verbose` for diagnostics and `--json` for machine-readable output):
|
||||
|
||||
| Command | Purpose |
|
||||
| -------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
|
||||
| `openclaw matrix verify status` | Check cross-signing and device verification state |
|
||||
| `openclaw matrix verify status --include-recovery-key --json` | Include the stored recovery key |
|
||||
| `openclaw matrix verify bootstrap` | Bootstrap cross-signing and verification (see below) |
|
||||
| `openclaw matrix verify bootstrap --force-reset-cross-signing` | Discard the current cross-signing identity and create a new one |
|
||||
| `openclaw matrix verify device "<recovery-key>"` | Verify this device with a recovery key |
|
||||
| `openclaw matrix verify backup status` | Check room-key backup health |
|
||||
| `openclaw matrix verify backup restore` | Restore room keys from server backup |
|
||||
| `openclaw matrix verify backup reset --yes` | Delete the current backup and create a fresh baseline (may recreate secret storage) |
|
||||
```bash
|
||||
openclaw matrix verify status
|
||||
```
|
||||
|
||||
Verbose status (full diagnostics):
|
||||
|
||||
```bash
|
||||
openclaw matrix verify status --verbose
|
||||
```
|
||||
|
||||
Include the stored recovery key in machine-readable output:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify status --include-recovery-key --json
|
||||
```
|
||||
|
||||
Bootstrap cross-signing and verification state:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify bootstrap
|
||||
```
|
||||
|
||||
Verbose bootstrap diagnostics:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify bootstrap --verbose
|
||||
```
|
||||
|
||||
Force a fresh cross-signing identity reset before bootstrapping:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify bootstrap --force-reset-cross-signing
|
||||
```
|
||||
|
||||
Verify this device with a recovery key:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify device "<your-recovery-key>"
|
||||
```
|
||||
|
||||
This command reports three separate states:
|
||||
|
||||
- `Recovery key accepted`: Matrix accepted the recovery key for secret storage or device trust.
|
||||
- `Backup usable`: room-key backup can be loaded with trusted recovery material.
|
||||
- `Device verified by owner`: the current OpenClaw device has full Matrix cross-signing identity trust.
|
||||
|
||||
`Signed by owner` in verbose or JSON output is diagnostic only. OpenClaw does not
|
||||
treat that as sufficient unless `Cross-signing verified` is also `yes`.
|
||||
|
||||
The command still exits non-zero when full Matrix identity trust is incomplete,
|
||||
even if the recovery key can unlock backup material. In that case, complete
|
||||
self-verification from another Matrix client:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify self
|
||||
```
|
||||
|
||||
Accept the request in another Matrix client, compare the SAS emoji or decimals,
|
||||
and type `yes` only when they match. The command waits for Matrix to report
|
||||
`Cross-signing verified: yes` before it exits successfully.
|
||||
|
||||
Use `verify bootstrap --force-reset-cross-signing` only when you intentionally
|
||||
want to replace the current cross-signing identity.
|
||||
|
||||
Verbose device verification details:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify device "<your-recovery-key>" --verbose
|
||||
```
|
||||
|
||||
Check room-key backup health:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify backup status
|
||||
```
|
||||
|
||||
Verbose backup health diagnostics:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify backup status --verbose
|
||||
```
|
||||
|
||||
Restore room keys from server backup:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify backup restore
|
||||
```
|
||||
|
||||
Interactive self-verification flow:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify self
|
||||
```
|
||||
|
||||
For lower-level or inbound verification requests, use:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify accept <id>
|
||||
openclaw matrix verify start <id>
|
||||
openclaw matrix verify sas <id>
|
||||
openclaw matrix verify confirm-sas <id>
|
||||
```
|
||||
|
||||
Use `openclaw matrix verify cancel <id>` to cancel a request.
|
||||
|
||||
Verbose restore diagnostics:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify backup restore --verbose
|
||||
```
|
||||
|
||||
Delete the current server backup and create a fresh backup baseline. If the stored
|
||||
backup key cannot be loaded cleanly, this reset can also recreate secret storage so
|
||||
future cold starts can load the new backup key:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify backup reset --yes
|
||||
```
|
||||
|
||||
All `verify` commands are concise by default (including quiet internal SDK logging) and show detailed diagnostics only with `--verbose`.
|
||||
Use `--json` for full machine-readable output when scripting.
|
||||
|
||||
In multi-account setups, Matrix CLI commands use the implicit Matrix default account unless you pass `--account <id>`.
|
||||
If you configure multiple named accounts, set `channels.matrix.defaultAccount` first or those implicit CLI operations will stop and ask you to choose an account explicitly.
|
||||
@@ -341,7 +452,9 @@ When encryption is disabled or unavailable for a named account, Matrix warnings
|
||||
- `Cross-signing verified`: the SDK reports verification via cross-signing
|
||||
- `Signed by owner`: signed by your own self-signing key
|
||||
|
||||
`Verified by owner` becomes `yes` only when cross-signing or owner-signing is present. Local trust alone is not enough.
|
||||
`Verified by owner` becomes `yes` only when cross-signing verification is present.
|
||||
Local trust or an owner signature by itself is not enough for OpenClaw to treat
|
||||
the device as fully verified.
|
||||
|
||||
</Accordion>
|
||||
|
||||
|
||||
@@ -44,6 +44,31 @@ Details: [Plugins](/tools/plugin)
|
||||
4. Configure OpenClaw:
|
||||
- Config: `channels.nextcloud-talk.baseUrl` + `channels.nextcloud-talk.botSecret`
|
||||
- Or env: `NEXTCLOUD_TALK_BOT_SECRET` (default account only)
|
||||
|
||||
CLI setup:
|
||||
|
||||
```bash
|
||||
openclaw channels add --channel nextcloud-talk \
|
||||
--url https://cloud.example.com \
|
||||
--token "<shared-secret>"
|
||||
```
|
||||
|
||||
Equivalent explicit fields:
|
||||
|
||||
```bash
|
||||
openclaw channels add --channel nextcloud-talk \
|
||||
--base-url https://cloud.example.com \
|
||||
--secret "<shared-secret>"
|
||||
```
|
||||
|
||||
File-backed secret:
|
||||
|
||||
```bash
|
||||
openclaw channels add --channel nextcloud-talk \
|
||||
--base-url https://cloud.example.com \
|
||||
--secret-file /path/to/nextcloud-talk-secret
|
||||
```
|
||||
|
||||
5. Restart the gateway (or finish setup).
|
||||
|
||||
Minimal config:
|
||||
|
||||
@@ -6,8 +6,6 @@ read_when:
|
||||
title: "Signal"
|
||||
---
|
||||
|
||||
# Signal (signal-cli)
|
||||
|
||||
Status: external CLI integration. Gateway talks to `signal-cli` over HTTP JSON-RPC + SSE.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -301,8 +301,8 @@ Surface different features that extend the above defaults.
|
||||
},
|
||||
{
|
||||
"command": "/models",
|
||||
"description": "List providers/models or add a model",
|
||||
"usage_hint": "[provider] [page] [limit=<n>|size=<n>|all] | add <provider> <modelId>"
|
||||
"description": "List providers/models",
|
||||
"usage_hint": "[provider] [page] [limit=<n>|size=<n>|all]"
|
||||
},
|
||||
{
|
||||
"command": "/help",
|
||||
@@ -436,7 +436,7 @@ Available action groups in current Slack tooling:
|
||||
| memberInfo | enabled |
|
||||
| emojiList | enabled |
|
||||
|
||||
Current Slack message actions include `send`, `upload-file`, `download-file`, `read`, `edit`, `delete`, `pin`, `unpin`, `list-pins`, `member-info`, and `emoji-list`.
|
||||
Current Slack message actions include `send`, `upload-file`, `download-file`, `read`, `edit`, `delete`, `pin`, `unpin`, `list-pins`, `member-info`, and `emoji-list`. `download-file` accepts Slack file IDs shown in inbound file placeholders and returns image previews for images or local file metadata for other file types.
|
||||
|
||||
## Access control and routing
|
||||
|
||||
@@ -606,7 +606,7 @@ Notes:
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Inbound attachments">
|
||||
Slack file attachments are downloaded from Slack-hosted private URLs (token-authenticated request flow) and written to the media store when fetch succeeds and size limits permit.
|
||||
Slack file attachments are downloaded from Slack-hosted private URLs (token-authenticated request flow) and written to the media store when fetch succeeds and size limits permit. File placeholders include the Slack `fileId` so agents can fetch the original file with `download-file`.
|
||||
|
||||
Runtime inbound size cap defaults to `20MB` unless overridden by `channels.slack.mediaMaxMb`.
|
||||
|
||||
@@ -773,7 +773,8 @@ Same-chat `/approve` also works in Slack channels and DMs that already support c
|
||||
|
||||
## Events and operational behavior
|
||||
|
||||
- Message edits/deletes/thread broadcasts are mapped into system events.
|
||||
- Message edits/deletes are mapped into system events.
|
||||
- Thread broadcasts ("Also send to channel" thread replies) are processed as normal user messages.
|
||||
- Reaction add/remove events are mapped into system events.
|
||||
- Member join/leave, channel created/renamed, and pin add/remove events are mapped into system events.
|
||||
- `channel_id_changed` can migrate channel config keys when `configWrites` is enabled.
|
||||
@@ -826,6 +827,9 @@ openclaw doctor
|
||||
- `channels.slack.dm.enabled`
|
||||
- `channels.slack.dmPolicy` (or legacy `channels.slack.dm.policy`)
|
||||
- pairing approvals / allowlist entries
|
||||
- Slack Assistant DM events: verbose logs mentioning `drop message_changed`
|
||||
usually mean Slack sent an edited Assistant-thread event without a
|
||||
recoverable human sender in message metadata
|
||||
|
||||
```bash
|
||||
openclaw pairing list slack
|
||||
|
||||
@@ -64,6 +64,13 @@ openclaw channels login --channel whatsapp
|
||||
|
||||
```bash
|
||||
openclaw channels login --channel whatsapp --account work
|
||||
```
|
||||
|
||||
To attach an existing/custom WhatsApp Web auth directory before login:
|
||||
|
||||
```bash
|
||||
openclaw channels add --channel whatsapp --account work --auth-dir /path/to/wa-auth
|
||||
openclaw channels login --channel whatsapp --account work
|
||||
```
|
||||
|
||||
</Step>
|
||||
@@ -145,6 +152,46 @@ OpenClaw recommends running WhatsApp on a separate number when possible. (The ch
|
||||
- Group sessions are isolated (`agent:<agentId>:whatsapp:group:<jid>`).
|
||||
- WhatsApp Web transport honors standard proxy environment variables on the gateway host (`HTTPS_PROXY`, `HTTP_PROXY`, `NO_PROXY` / lowercase variants). Prefer host-level proxy config over channel-specific WhatsApp proxy settings.
|
||||
|
||||
## Plugin hooks and privacy
|
||||
|
||||
WhatsApp inbound messages can contain personal message content, phone numbers,
|
||||
group identifiers, sender names, and session correlation fields. For that reason,
|
||||
WhatsApp does not broadcast inbound `message_received` hook payloads to plugins
|
||||
unless you explicitly opt in:
|
||||
|
||||
```json5
|
||||
{
|
||||
channels: {
|
||||
whatsapp: {
|
||||
pluginHooks: {
|
||||
messageReceived: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
You can scope the opt-in to one account:
|
||||
|
||||
```json5
|
||||
{
|
||||
channels: {
|
||||
whatsapp: {
|
||||
accounts: {
|
||||
work: {
|
||||
pluginHooks: {
|
||||
messageReceived: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Only enable this for plugins you trust to receive inbound WhatsApp message
|
||||
content and identifiers.
|
||||
|
||||
## Access control and activation
|
||||
|
||||
<Tabs>
|
||||
@@ -333,19 +380,20 @@ When the linked self number is also present in `allowFrom`, WhatsApp self-chat s
|
||||
|
||||
WhatsApp supports native reply quoting, where outbound replies visibly quote the inbound message. Control it with `channels.whatsapp.replyToMode`.
|
||||
|
||||
| Value | Behavior |
|
||||
| -------- | ---------------------------------------------------------------------------------- |
|
||||
| `"auto"` | Quote the inbound message when the provider supports it; skip quoting otherwise |
|
||||
| `"on"` | Always quote the inbound message; fall back to a plain send if quoting is rejected |
|
||||
| `"off"` | Never quote; send as a plain message |
|
||||
| Value | Behavior |
|
||||
| ----------- | --------------------------------------------------------------------- |
|
||||
| `"off"` | Never quote; send as a plain message |
|
||||
| `"first"` | Quote only the first outbound reply chunk |
|
||||
| `"all"` | Quote every outbound reply chunk |
|
||||
| `"batched"` | Quote queued batched replies while leaving immediate replies unquoted |
|
||||
|
||||
Default is `"auto"`. Per-account overrides use `channels.whatsapp.accounts.<id>.replyToMode`.
|
||||
Default is `"off"`. Per-account overrides use `channels.whatsapp.accounts.<id>.replyToMode`.
|
||||
|
||||
```json5
|
||||
{
|
||||
channels: {
|
||||
whatsapp: {
|
||||
replyToMode: "on",
|
||||
replyToMode: "first",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -493,15 +541,15 @@ Resolution hierarchy for group messages:
|
||||
|
||||
The effective `groups` map is determined first: if the account defines its own `groups`, it fully replaces the root `groups` map (no deep merge). Prompt lookup then runs on the resulting single map:
|
||||
|
||||
1. **Group-specific system prompt** (`groups["<groupId>"].systemPrompt`): used if the specific group entry defines a `systemPrompt`.
|
||||
2. **Group wildcard system prompt** (`groups["*"].systemPrompt`): used when the specific group entry is absent or defines no `systemPrompt`.
|
||||
1. **Group-specific system prompt** (`groups["<groupId>"].systemPrompt`): used when the specific group entry exists in the map **and** its `systemPrompt` key is defined. If `systemPrompt` is an empty string (`""`), the wildcard is suppressed and no system prompt is applied.
|
||||
2. **Group wildcard system prompt** (`groups["*"].systemPrompt`): used when the specific group entry is absent from the map entirely, or when it exists but defines no `systemPrompt` key.
|
||||
|
||||
Resolution hierarchy for direct messages:
|
||||
|
||||
The effective `direct` map is determined first: if the account defines its own `direct`, it fully replaces the root `direct` map (no deep merge). Prompt lookup then runs on the resulting single map:
|
||||
|
||||
1. **Direct-specific system prompt** (`direct["<peerId>"].systemPrompt`): used if the specific peer entry defines a `systemPrompt`.
|
||||
2. **Direct wildcard system prompt** (`direct["*"].systemPrompt`): used when the specific peer entry is absent or defines no `systemPrompt`.
|
||||
1. **Direct-specific system prompt** (`direct["<peerId>"].systemPrompt`): used when the specific peer entry exists in the map **and** its `systemPrompt` key is defined. If `systemPrompt` is an empty string (`""`), the wildcard is suppressed and no system prompt is applied.
|
||||
2. **Direct wildcard system prompt** (`direct["*"].systemPrompt`): used when the specific peer entry is absent from the map entirely, or when it exists but defines no `systemPrompt` key.
|
||||
|
||||
Note: `dms` remains the lightweight per-DM history override bucket (`dms.<id>.historyLimit`); prompt overrides live under `direct`.
|
||||
|
||||
|
||||
@@ -5,8 +5,6 @@ read_when:
|
||||
title: "Zalo"
|
||||
---
|
||||
|
||||
# Zalo (Bot API)
|
||||
|
||||
Status: experimental. DMs are supported. The [Capabilities](#capabilities) section below reflects current Marketplace-bot behavior.
|
||||
|
||||
## Bundled plugin
|
||||
|
||||
@@ -6,8 +6,6 @@ read_when:
|
||||
title: "Zalo personal"
|
||||
---
|
||||
|
||||
# Zalo Personal (unofficial)
|
||||
|
||||
Status: experimental. This integration automates a **personal Zalo account** via native `zca-js` inside OpenClaw.
|
||||
|
||||
> **Warning:** This is an unofficial integration and may result in account suspension/ban. Use at your own risk.
|
||||
|
||||
@@ -91,13 +91,13 @@ Jobs are ordered so cheap checks fail before expensive ones run:
|
||||
Scope logic lives in `scripts/ci-changed-scope.mjs` and is covered by unit tests in `src/scripts/ci-changed-scope.test.ts`.
|
||||
CI workflow edits validate the Node CI graph plus workflow linting, but do not force Windows, Android, or macOS native builds by themselves; those platform lanes stay scoped to platform source changes.
|
||||
Windows Node checks are scoped to Windows-specific process/path wrappers, npm/pnpm/UI runner helpers, package manager config, and the CI workflow surfaces that execute that lane; unrelated source, plugin, install-smoke, and test-only changes stay on the Linux Node lanes so they do not reserve a 16-vCPU Windows worker for coverage that is already exercised by the normal test shards.
|
||||
The separate `install-smoke` workflow reuses the same scope script through its own `preflight` job. It splits smoke coverage into `run_fast_install_smoke` and `run_full_install_smoke`. Pull requests run the fast path for Docker/package surfaces, bundled plugin package/manifest changes, and core plugin/channel/gateway/Plugin SDK surfaces that the Docker smoke jobs exercise. Source-only bundled plugin changes, test-only edits, and docs-only edits do not reserve Docker workers. The fast path builds the root Dockerfile image once, checks the CLI, runs the container gateway-network e2e, verifies a bundled extension build arg, and runs the bounded bundled-plugin Docker profile under a 120-second command timeout. The full path keeps QR package install and installer Docker/update coverage for nightly scheduled runs, manual dispatches, workflow-call release checks, and pull requests that truly touch installer/package/Docker surfaces. `main` pushes, including merge commits, do not force the full path; when changed-scope logic would request full coverage on a push, the workflow keeps the fast Docker smoke and leaves the full install smoke to nightly or release validation. The slow Bun global install image-provider smoke is separately gated by `run_bun_global_install_smoke`; it runs on the nightly schedule and from the release checks workflow, and manual `install-smoke` dispatches can opt into it, but pull requests and `main` pushes do not run it. QR and installer Docker tests keep their own install-focused Dockerfiles. Local `test:docker:all` prebuilds one shared live-test image and one shared `scripts/e2e/Dockerfile` built-app image, then runs the live/E2E smoke lanes in parallel with `OPENCLAW_SKIP_DOCKER_BUILD=1`; tune the default main-pool concurrency of 8 with `OPENCLAW_DOCKER_ALL_PARALLELISM` and the provider-sensitive tail-pool concurrency of 8 with `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM`. The local aggregate stops scheduling new pooled lanes after the first failure by default, and each lane has a 120-minute timeout overrideable with `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS`. The reusable live/E2E workflow mirrors the shared-image pattern by building and pushing one SHA-tagged GHCR Docker E2E image before the Docker matrix, then running the matrix with `OPENCLAW_SKIP_DOCKER_BUILD=1`. The scheduled live/E2E workflow runs the full release-path Docker suite daily. The full bundled update/channel matrix remains manual/full-suite because it performs repeated real npm update and doctor repair passes.
|
||||
The separate `install-smoke` workflow reuses the same scope script through its own `preflight` job. It splits smoke coverage into `run_fast_install_smoke` and `run_full_install_smoke`. Pull requests run the fast path for Docker/package surfaces, bundled plugin package/manifest changes, and core plugin/channel/gateway/Plugin SDK surfaces that the Docker smoke jobs exercise. Source-only bundled plugin changes, test-only edits, and docs-only edits do not reserve Docker workers. The fast path builds the root Dockerfile image once, checks the CLI, runs the agents delete shared-workspace CLI smoke, runs the container gateway-network e2e, verifies a bundled extension build arg, and runs the bounded bundled-plugin Docker profile under a 120-second command timeout. The full path keeps QR package install and installer Docker/update coverage for nightly scheduled runs, manual dispatches, workflow-call release checks, and pull requests that truly touch installer/package/Docker surfaces. `main` pushes, including merge commits, do not force the full path; when changed-scope logic would request full coverage on a push, the workflow keeps the fast Docker smoke and leaves the full install smoke to nightly or release validation. The slow Bun global install image-provider smoke is separately gated by `run_bun_global_install_smoke`; it runs on the nightly schedule and from the release checks workflow, and manual `install-smoke` dispatches can opt into it, but pull requests and `main` pushes do not run it. QR and installer Docker tests keep their own install-focused Dockerfiles. Local `test:docker:all` prebuilds one shared live-test image and one shared `scripts/e2e/Dockerfile` built-app image, then runs the live/E2E smoke lanes with a weighted scheduler and `OPENCLAW_SKIP_DOCKER_BUILD=1`; tune the default main-pool slot count of 10 with `OPENCLAW_DOCKER_ALL_PARALLELISM` and the provider-sensitive tail-pool slot count of 10 with `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM`. Heavy lane caps default to `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=6`, `OPENCLAW_DOCKER_ALL_NPM_LIMIT=8`, and `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7` so npm install and multi-service lanes do not overcommit Docker while lighter lanes still fill available slots. Lane starts are staggered by 2 seconds by default to avoid local Docker daemon create storms; override with `OPENCLAW_DOCKER_ALL_START_STAGGER_MS=0` or another millisecond value. The local aggregate preflights Docker, removes stale OpenClaw E2E containers, emits active-lane status, persists lane timings for longest-first ordering, and supports `OPENCLAW_DOCKER_ALL_DRY_RUN=1` for scheduler inspection. It stops scheduling new pooled lanes after the first failure by default, and each lane has a 120-minute fallback timeout overrideable with `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS`; selected live/tail lanes use tighter per-lane caps. The reusable live/E2E workflow mirrors the shared-image pattern by building and pushing one SHA-tagged GHCR Docker E2E image before the Docker matrix, then running the matrix with `OPENCLAW_SKIP_DOCKER_BUILD=1`. The scheduled live/E2E workflow runs the full release-path Docker suite daily. The bundled update matrix is split by update target so repeated npm update and doctor repair passes can shard with other bundled checks.
|
||||
|
||||
Local changed-lane logic lives in `scripts/changed-lanes.mjs` and is executed by `scripts/check-changed.mjs`. That local gate is stricter about architecture boundaries than the broad CI platform scope: core production changes run core prod typecheck plus core tests, core test-only changes run only core test typecheck/tests, extension production changes run extension prod typecheck plus extension tests, and extension test-only changes run only extension test typecheck/tests. Public Plugin SDK or plugin-contract changes expand to extension validation because extensions depend on those core contracts. Release metadata-only version bumps run targeted version/config/root-dependency checks. Unknown root/config changes fail safe to all lanes.
|
||||
|
||||
On pushes, the `checks` matrix adds the push-only `compat-node22` lane. On pull requests, that lane is skipped and the matrix stays focused on the normal test/channel lanes.
|
||||
|
||||
The slowest Node test families are split or balanced so each job stays small without over-reserving runners: channel contracts run as three weighted shards, bundled plugin tests balance across six extension workers, small core unit lanes are paired, auto-reply runs as three balanced workers instead of six tiny workers, and agentic gateway/plugin configs are spread across the existing source-only agentic Node jobs instead of waiting on built artifacts. Broad browser, QA, media, and miscellaneous plugin tests use their dedicated Vitest configs instead of the shared plugin catch-all. Extension shard jobs run plugin config groups serially with one Vitest worker and a larger Node heap so import-heavy plugin batches do not overcommit small CI runners. The broad agents lane uses the shared Vitest file-parallel scheduler because it is import/scheduling dominated rather than owned by a single slow test file. `runtime-config` runs with the infra core-runtime shard to keep the shared runtime shard from owning the tail. `check-additional` keeps package-boundary compile/canary work together and separates runtime topology architecture from gateway watch coverage; the boundary guard shard runs its small independent guards concurrently inside one job. Gateway watch, channel tests, and the core support-boundary shard run concurrently inside `build-artifacts` after `dist/` and `dist-runtime/` are already built, keeping their old check names as lightweight verifier jobs while avoiding two extra Blacksmith workers and a second artifact-consumer queue.
|
||||
The slowest Node test families are split or balanced so each job stays small without over-reserving runners: channel contracts run as three weighted shards, bundled plugin tests balance across six extension workers, small core unit lanes are paired, auto-reply runs as three balanced workers instead of six tiny workers, and agentic gateway/plugin configs are spread across the existing source-only agentic Node jobs instead of waiting on built artifacts. Broad browser, QA, media, and miscellaneous plugin tests use their dedicated Vitest configs instead of the shared plugin catch-all. Extension shard jobs run up to two plugin config groups at a time with one Vitest worker per group and a larger Node heap so import-heavy plugin batches do not create extra CI jobs. The broad agents lane uses the shared Vitest file-parallel scheduler because it is import/scheduling dominated rather than owned by a single slow test file. `runtime-config` runs with the infra core-runtime shard to keep the shared runtime shard from owning the tail. `check-additional` keeps package-boundary compile/canary work together and separates runtime topology architecture from gateway watch coverage; the boundary guard shard runs its small independent guards concurrently inside one job. Gateway watch, channel tests, and the core support-boundary shard run concurrently inside `build-artifacts` after `dist/` and `dist-runtime/` are already built, keeping their old check names as lightweight verifier jobs while avoiding two extra Blacksmith workers and a second artifact-consumer queue.
|
||||
Android CI runs both `testPlayDebugUnitTest` and `testThirdPartyDebugUnitTest`, then builds the Play debug APK. The third-party flavor has no separate source set or manifest; its unit-test lane still compiles that flavor with the SMS/call-log BuildConfig flags, while avoiding a duplicate debug APK packaging job on every Android-relevant push.
|
||||
`extension-fast` is PR-only because push runs already execute the full bundled plugin shards. That keeps changed-plugin feedback for reviews without reserving an extra Blacksmith worker on `main` for coverage already present in `checks-node-extensions`.
|
||||
|
||||
|
||||
@@ -150,6 +150,9 @@ Notes:
|
||||
- `main` cannot be deleted.
|
||||
- Without `--force`, interactive confirmation is required.
|
||||
- Workspace, agent state, and session transcript directories are moved to Trash, not hard-deleted.
|
||||
- If another agent's workspace is the same path, inside this workspace, or contains this workspace,
|
||||
the workspace is retained and `--json` reports `workspaceRetained`,
|
||||
`workspaceRetainedReason`, and `workspaceSharedWith`.
|
||||
|
||||
## Identity files
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ openclaw browser --browser-profile openclaw open https://example.com
|
||||
openclaw browser --browser-profile openclaw snapshot
|
||||
```
|
||||
|
||||
Agents can run the same readiness check with `browser({ action: "doctor" })`.
|
||||
|
||||
## Quick troubleshooting
|
||||
|
||||
If `start` fails with `not reachable after start`, troubleshoot CDP readiness first. If `start` and `tabs` succeed but `open` or `navigate` fails, the browser control plane is healthy and the failure is usually navigation SSRF policy.
|
||||
@@ -40,6 +42,7 @@ If `start` fails with `not reachable after start`, troubleshoot CDP readiness fi
|
||||
Minimal sequence:
|
||||
|
||||
```bash
|
||||
openclaw browser --browser-profile openclaw doctor
|
||||
openclaw browser --browser-profile openclaw start
|
||||
openclaw browser --browser-profile openclaw tabs
|
||||
openclaw browser --browser-profile openclaw open https://example.com
|
||||
@@ -51,6 +54,7 @@ Detailed guidance: [Browser troubleshooting](/tools/browser#cdp-startup-failure-
|
||||
|
||||
```bash
|
||||
openclaw browser status
|
||||
openclaw browser doctor
|
||||
openclaw browser start
|
||||
openclaw browser stop
|
||||
openclaw browser --browser-profile openclaw reset-profile
|
||||
@@ -111,20 +115,28 @@ openclaw browser --browser-profile work tabs
|
||||
|
||||
```bash
|
||||
openclaw browser tabs
|
||||
openclaw browser tab new
|
||||
openclaw browser tab new --label docs
|
||||
openclaw browser tab label t1 docs
|
||||
openclaw browser tab select 2
|
||||
openclaw browser tab close 2
|
||||
openclaw browser open https://docs.openclaw.ai
|
||||
openclaw browser focus <targetId>
|
||||
openclaw browser close <targetId>
|
||||
openclaw browser open https://docs.openclaw.ai --label docs
|
||||
openclaw browser focus docs
|
||||
openclaw browser close t1
|
||||
```
|
||||
|
||||
`tabs` returns `suggestedTargetId` first, then the stable `tabId` such as `t1`,
|
||||
the optional label, and the raw `targetId`. Agents should pass
|
||||
`suggestedTargetId` back into `focus`, `close`, snapshots, and actions. You can
|
||||
assign a label with `open --label`, `tab new --label`, or `tab label`; labels,
|
||||
tab ids, raw target ids, and unique target-id prefixes are all accepted.
|
||||
|
||||
## Snapshot / screenshot / actions
|
||||
|
||||
Snapshot:
|
||||
|
||||
```bash
|
||||
openclaw browser snapshot
|
||||
openclaw browser snapshot --urls
|
||||
```
|
||||
|
||||
Screenshot:
|
||||
@@ -133,6 +145,7 @@ Screenshot:
|
||||
openclaw browser screenshot
|
||||
openclaw browser screenshot --full-page
|
||||
openclaw browser screenshot --ref e12
|
||||
openclaw browser screenshot --labels
|
||||
```
|
||||
|
||||
Notes:
|
||||
@@ -141,6 +154,10 @@ Notes:
|
||||
or `--element`.
|
||||
- `existing-session` / `user` profiles support page screenshots and `--ref`
|
||||
screenshots from snapshot output, but not CSS `--element` screenshots.
|
||||
- `--labels` overlays current snapshot refs on the screenshot.
|
||||
- `snapshot --urls` appends discovered link destinations to AI snapshots so
|
||||
agents can choose direct navigation targets instead of guessing from link
|
||||
text alone.
|
||||
|
||||
Navigate/click/type (ref-based UI automation):
|
||||
|
||||
|
||||
@@ -13,6 +13,9 @@ Note: The **Model** section now includes a multi-select for the
|
||||
`agents.defaults.models` allowlist (what shows up in `/model` and the model picker).
|
||||
Provider-scoped setup choices merge their selected models into the existing
|
||||
allowlist instead of replacing unrelated providers already in the config.
|
||||
Re-running provider auth from configure preserves an existing
|
||||
`agents.defaults.model.primary`; use `openclaw models auth login --provider <id> --set-default`
|
||||
or `openclaw models set <model>` when you intentionally want to change the default model.
|
||||
|
||||
When configure starts from a provider auth choice, the default-model and
|
||||
allowlist pickers prefer that provider automatically. For paired providers such
|
||||
|
||||
@@ -43,7 +43,7 @@ Notes:
|
||||
- `--fix` (alias for `--repair`) writes a backup to `~/.openclaw/openclaw.json.bak` and drops unknown config keys, listing each removal.
|
||||
- State integrity checks now detect orphan transcript files in the sessions directory and can archive them as `.deleted.<timestamp>` to reclaim space safely.
|
||||
- Doctor also scans `~/.openclaw/cron/jobs.json` (or `cron.store`) for legacy cron job shapes and can rewrite them in place before the scheduler has to auto-normalize them at runtime.
|
||||
- Doctor repairs missing bundled plugin runtime dependencies without requiring write access to the installed OpenClaw package. For root-owned npm installs or hardened systemd units, set `OPENCLAW_PLUGIN_STAGE_DIR` to a writable directory such as `/var/lib/openclaw/plugin-runtime-deps`.
|
||||
- Doctor repairs missing bundled plugin runtime dependencies without writing into packaged global installs. For root-owned npm installs or hardened systemd units, set `OPENCLAW_PLUGIN_STAGE_DIR` to a writable directory such as `/var/lib/openclaw/plugin-runtime-deps`.
|
||||
- Doctor auto-migrates legacy flat Talk config (`talk.voiceId`, `talk.modelId`, and friends) into `talk.provider` + `talk.providers.<provider>`.
|
||||
- Repeat `doctor --fix` runs no longer report/apply Talk normalization when the only difference is object key order.
|
||||
- Doctor includes a memory-search readiness check and can recommend `openclaw configure --section model` when embedding credentials are missing.
|
||||
|
||||
@@ -15,7 +15,7 @@ Running `openclaw hooks` with no subcommand is equivalent to `openclaw hooks lis
|
||||
Related:
|
||||
|
||||
- Hooks: [Hooks](/automation/hooks)
|
||||
- Plugin hooks: [Plugin hooks](/plugins/architecture-internals#provider-runtime-hooks)
|
||||
- Plugin hooks: [Plugin hooks](/plugins/hooks)
|
||||
|
||||
## List All Hooks
|
||||
|
||||
|
||||
@@ -47,6 +47,11 @@ Benefits:
|
||||
- Prefer a first-party OpenClaw surface when the task is fundamentally "run inference."
|
||||
- Use the normal local path without requiring the gateway for most infer commands.
|
||||
|
||||
For end-to-end provider checks, prefer `openclaw infer ...` once lower-level
|
||||
provider tests are green. It exercises the shipped CLI, config loading,
|
||||
default-agent resolution, bundled plugin activation, runtime-dependency repair,
|
||||
and the shared capability runtime before the provider request is made.
|
||||
|
||||
## Command tree
|
||||
|
||||
```text
|
||||
@@ -157,6 +162,25 @@ openclaw infer image describe --file ./photo.jpg --model ollama/qwen2.5vl:7b --j
|
||||
Notes:
|
||||
|
||||
- Use `image edit` when starting from existing input files.
|
||||
- Use `image providers --json` to verify which bundled image providers are
|
||||
discoverable, configured, selected, and which generation/edit capabilities
|
||||
each provider exposes.
|
||||
- Use `image generate --model <provider/model> --json` as the narrowest live
|
||||
CLI smoke for image generation changes. Example:
|
||||
|
||||
```bash
|
||||
openclaw infer image providers --json
|
||||
openclaw infer image generate \
|
||||
--model google/gemini-3.1-flash-image-preview \
|
||||
--prompt "Minimal flat test image: one blue square on a white background, no text." \
|
||||
--output ./openclaw-infer-image-smoke.png \
|
||||
--json
|
||||
```
|
||||
|
||||
The JSON response reports `ok`, `provider`, `model`, `attempts`, and written
|
||||
output paths. When `--output` is set, the final extension may follow the
|
||||
provider's returned MIME type.
|
||||
|
||||
- For `image describe`, `--model` must be an image-capable `<provider/model>`.
|
||||
- For local Ollama vision models, pull the model first and set `OLLAMA_API_KEY` to any placeholder value, for example `ollama-local`. See [Ollama](/providers/ollama#vision-and-image-description).
|
||||
|
||||
@@ -258,6 +282,10 @@ Top-level fields are stable:
|
||||
- `outputs`
|
||||
- `error`
|
||||
|
||||
For generated media commands, `outputs` contains files written by OpenClaw. Use
|
||||
the `path`, `mimeType`, `size`, and any media-specific dimensions in that array
|
||||
for automation instead of parsing human-readable stdout.
|
||||
|
||||
## Common pitfalls
|
||||
|
||||
```bash
|
||||
|
||||
@@ -77,7 +77,9 @@ Options:
|
||||
For a node connecting to a non-loopback `ws://` Gateway on a trusted private
|
||||
network, set `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`. Without it, node startup
|
||||
fails closed and asks you to use `wss://`, an SSH tunnel, or Tailscale.
|
||||
`openclaw node install` persists this opt-in into the supervised node service.
|
||||
This is a process-environment opt-in, not an `openclaw.json` config key.
|
||||
`openclaw node install` persists it into the supervised node service when it is
|
||||
present in the install command environment.
|
||||
|
||||
## Service (background)
|
||||
|
||||
|
||||
@@ -23,11 +23,14 @@ Interactive onboarding for local or remote Gateway setup.
|
||||
openclaw onboard
|
||||
openclaw onboard --flow quickstart
|
||||
openclaw onboard --flow manual
|
||||
openclaw onboard --skip-bootstrap
|
||||
openclaw onboard --mode remote --remote-url wss://gateway-host:18789
|
||||
```
|
||||
|
||||
For plaintext private-network `ws://` targets (trusted networks only), set
|
||||
`OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` in the onboarding process environment.
|
||||
There is no `openclaw.json` equivalent for this client-side transport
|
||||
break-glass.
|
||||
|
||||
Non-interactive custom provider:
|
||||
|
||||
@@ -113,6 +116,7 @@ Non-interactive local gateway health:
|
||||
- Unless you pass `--skip-health`, onboarding waits for a reachable local gateway before it exits successfully.
|
||||
- `--install-daemon` starts the managed gateway install path first. Without it, you must already have a local gateway running, for example `openclaw gateway run`.
|
||||
- If you only want config/workspace/bootstrap writes in automation, use `--skip-health`.
|
||||
- If you manage workspace files yourself, pass `--skip-bootstrap` to set `agents.defaults.skipBootstrap: true` and skip creating `AGENTS.md`, `SOUL.md`, `TOOLS.md`, `IDENTITY.md`, `USER.md`, `HEARTBEAT.md`, and `BOOTSTRAP.md`.
|
||||
- On native Windows, `--install-daemon` tries Scheduled Tasks first and falls back to a per-user Startup-folder login item if task creation is denied.
|
||||
|
||||
Interactive onboarding behavior with reference mode:
|
||||
|
||||
@@ -200,6 +200,23 @@ table view to per-plugin detail lines with source/origin/version/activation
|
||||
metadata. Use `--json` for machine-readable inventory plus registry
|
||||
diagnostics.
|
||||
|
||||
`plugins list` runs discovery from the current CLI environment and config. It is
|
||||
useful for checking whether a plugin is enabled/loadable, but it is not a live
|
||||
runtime probe of an already-running Gateway process. After changing plugin code,
|
||||
enablement, hook policy, or `plugins.load.paths`, restart the Gateway that
|
||||
serves the channel before expecting new `register(api)` code or hooks to run.
|
||||
For remote/container deployments, verify you are restarting the actual
|
||||
`openclaw gateway run` child, not only a wrapper process.
|
||||
|
||||
For runtime hook debugging:
|
||||
|
||||
- `openclaw plugins inspect <id> --json` shows registered hooks and diagnostics
|
||||
from a module-loaded inspection pass.
|
||||
- `openclaw gateway status --deep --require-rpc` confirms the reachable Gateway,
|
||||
service/process hints, config path, and RPC health.
|
||||
- Non-bundled conversation hooks (`llm_input`, `llm_output`, `agent_end`) require
|
||||
`plugins.entries.<id>.hooks.allowConversationAccess=true`.
|
||||
|
||||
Use `--link` to avoid copying a local directory (adds to `plugins.load.paths`):
|
||||
|
||||
```bash
|
||||
|
||||
@@ -21,7 +21,7 @@ Notes:
|
||||
|
||||
- `--deep` runs live probes (WhatsApp Web + Telegram + Discord + Slack + Signal).
|
||||
- `--usage` prints normalized provider usage windows as `X% left`.
|
||||
- Session status output now separates `Runtime:` from `Runner:`. `Runtime` is the execution path and sandbox state (`direct`, `docker/*`), while `Runner` tells you whether the session is using embedded Pi, a CLI-backed provider, or an ACP harness backend such as `codex (acp/acpx)`.
|
||||
- Session status output separates `Execution:` from `Runtime:`. `Execution` is the sandbox path (`direct`, `docker/*`), while `Runtime` tells you whether the session is using `OpenClaw Pi Default`, `OpenAI Codex`, a CLI backend, or an ACP backend such as `codex (acp/acpx)`. See [Agent runtimes](/concepts/agent-runtimes) for the provider/model/runtime distinction.
|
||||
- MiniMax's raw `usage_percent` / `usagePercent` fields are remaining quota, so OpenClaw inverts them before display; count-based fields win when present. `model_remains` responses prefer the chat-model entry, derive the window label from timestamps when needed, and include the model name in the plan label.
|
||||
- When the current session snapshot is sparse, `/status` can backfill token and cache counters from the most recent transcript usage log. Existing nonzero live values still win over transcript fallback values.
|
||||
- Transcript fallback can also recover the active runtime model label when the live session entry is missing it. If that transcript model differs from the selected model, status resolves the context window against the recovered runtime model instead of the selected one.
|
||||
|
||||
@@ -6,8 +6,6 @@ read_when:
|
||||
title: "Agent loop"
|
||||
---
|
||||
|
||||
# Agent Loop (OpenClaw)
|
||||
|
||||
An agentic loop is the full “real” run of an agent: intake → context assembly → model inference →
|
||||
tool execution → streaming replies → persistence. It’s the authoritative path that turns a message
|
||||
into actions and a final reply, while keeping session state consistent.
|
||||
@@ -112,7 +110,7 @@ Hook decision rules for outbound/tool guards:
|
||||
- `message_sending`: `{ cancel: true }` is terminal and stops lower-priority handlers.
|
||||
- `message_sending`: `{ cancel: false }` is a no-op and does not clear a prior cancel.
|
||||
|
||||
See [Plugin hooks](/plugins/architecture-internals#provider-runtime-hooks) for the hook API and registration details.
|
||||
See [Plugin hooks](/plugins/hooks) for the hook API and registration details.
|
||||
|
||||
Harnesses may adapt these hooks differently. The Codex app-server harness keeps
|
||||
OpenClaw plugin hooks as the compatibility contract for documented mirrored
|
||||
|
||||
127
docs/concepts/agent-runtimes.md
Normal file
127
docs/concepts/agent-runtimes.md
Normal file
@@ -0,0 +1,127 @@
|
||||
---
|
||||
summary: "How OpenClaw separates model providers, models, channels, and agent runtimes"
|
||||
title: "Agent runtimes"
|
||||
read_when:
|
||||
- You are choosing between PI, Codex, ACP, or another native agent runtime
|
||||
- You are confused by provider/model/runtime labels in status or config
|
||||
- You are documenting support parity for a native harness
|
||||
---
|
||||
|
||||
An **agent runtime** is the component that owns one prepared model loop: it
|
||||
receives the prompt, drives model output, handles native tool calls, and returns
|
||||
the finished turn to OpenClaw.
|
||||
|
||||
Runtimes are easy to confuse with providers because both show up near model
|
||||
configuration. They are different layers:
|
||||
|
||||
| Layer | Examples | What It Means |
|
||||
| ------------- | ------------------------------------- | ------------------------------------------------------------------- |
|
||||
| Provider | `openai`, `anthropic`, `openai-codex` | How OpenClaw authenticates, discovers models, and names model refs. |
|
||||
| Model | `gpt-5.5`, `claude-opus-4-6` | The model selected for the agent turn. |
|
||||
| Agent runtime | `pi`, `codex`, ACP-backed runtimes | The low level loop that executes the prepared turn. |
|
||||
| Channel | Telegram, Discord, Slack, WhatsApp | Where messages enter and leave OpenClaw. |
|
||||
|
||||
You will also see the word **harness** in code and config. A harness is the
|
||||
implementation that provides an agent runtime. For example, the bundled Codex
|
||||
harness implements the `codex` runtime. The config key is still named
|
||||
`embeddedHarness` for compatibility, but user-facing docs and status output
|
||||
should generally say runtime.
|
||||
|
||||
The common Codex setup uses the `openai` provider with the `codex` runtime:
|
||||
|
||||
```json5
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
model: "openai/gpt-5.5",
|
||||
embeddedHarness: {
|
||||
runtime: "codex",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
That means OpenClaw selects an OpenAI model ref, then asks the Codex app-server
|
||||
runtime to run the embedded agent turn. It does not mean the channel, model
|
||||
provider catalog, or OpenClaw session store becomes Codex.
|
||||
|
||||
## Runtime ownership
|
||||
|
||||
Different runtimes own different amounts of the loop.
|
||||
|
||||
| Surface | OpenClaw PI embedded | Codex app-server |
|
||||
| --------------------------- | --------------------------------------- | --------------------------------------------------------------------------- |
|
||||
| Model loop owner | OpenClaw through the PI embedded runner | Codex app-server |
|
||||
| Canonical thread state | OpenClaw transcript | Codex thread, plus OpenClaw transcript mirror |
|
||||
| OpenClaw dynamic tools | Native OpenClaw tool loop | Bridged through the Codex adapter |
|
||||
| Native shell and file tools | PI/OpenClaw path | Codex-native tools, bridged through native hooks where supported |
|
||||
| Context engine | Native OpenClaw context assembly | OpenClaw projects assembled context into the Codex turn |
|
||||
| Compaction | OpenClaw or selected context engine | Codex-native compaction, with OpenClaw notifications and mirror maintenance |
|
||||
| Channel delivery | OpenClaw | OpenClaw |
|
||||
|
||||
This ownership split is the main design rule:
|
||||
|
||||
- If OpenClaw owns the surface, OpenClaw can provide normal plugin hook behavior.
|
||||
- If the native runtime owns the surface, OpenClaw needs runtime events or native hooks.
|
||||
- If the native runtime owns canonical thread state, OpenClaw should mirror and project context, not rewrite unsupported internals.
|
||||
|
||||
## Runtime selection
|
||||
|
||||
OpenClaw chooses an embedded runtime after provider and model resolution:
|
||||
|
||||
1. A session's recorded runtime wins. Config changes do not hot-switch an
|
||||
existing transcript to a different native thread system.
|
||||
2. `OPENCLAW_AGENT_RUNTIME=<id>` forces that runtime for new or reset sessions.
|
||||
3. `agents.defaults.embeddedHarness.runtime` or
|
||||
`agents.list[].embeddedHarness.runtime` can set `auto`, `pi`, or a registered
|
||||
runtime id such as `codex`.
|
||||
4. In `auto` mode, registered plugin runtimes can claim supported provider/model
|
||||
pairs.
|
||||
5. If no runtime claims a turn in `auto` mode and `fallback: "pi"` is set
|
||||
(the default), OpenClaw uses PI as the compatibility fallback. Set
|
||||
`fallback: "none"` to make unmatched `auto`-mode selection fail instead.
|
||||
|
||||
Explicit plugin runtimes fail closed by default. For example,
|
||||
`runtime: "codex"` means Codex or a clear selection error unless you set
|
||||
`fallback: "pi"` in the same override scope.
|
||||
|
||||
## Compatibility contract
|
||||
|
||||
When a runtime is not PI, it should document what OpenClaw surfaces it supports.
|
||||
Use this shape for runtime docs:
|
||||
|
||||
| Question | Why It Matters |
|
||||
| -------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| Who owns the model loop? | Determines where retries, tool continuation, and final answer decisions happen. |
|
||||
| Who owns canonical thread history? | Determines whether OpenClaw can edit history or only mirror it. |
|
||||
| Do OpenClaw dynamic tools work? | Messaging, sessions, cron, and OpenClaw-owned tools rely on this. |
|
||||
| Do dynamic tool hooks work? | Plugins expect `before_tool_call`, `after_tool_call`, and middleware around OpenClaw-owned tools. |
|
||||
| Do native tool hooks work? | Shell, patch, and runtime-owned tools need native hook support for policy and observation. |
|
||||
| Does the context engine lifecycle run? | Memory and context plugins depend on assemble, ingest, after-turn, and compaction lifecycle. |
|
||||
| What compaction data is exposed? | Some plugins only need notifications, while others need kept/dropped metadata. |
|
||||
| What is intentionally unsupported? | Users should not assume PI equivalence where the native runtime owns more state. |
|
||||
|
||||
The Codex runtime support contract is documented in
|
||||
[Codex harness](/plugins/codex-harness#v1-support-contract).
|
||||
|
||||
## Status labels
|
||||
|
||||
Status output may show both `Execution` and `Runtime` labels. Read them as
|
||||
diagnostics, not as provider names.
|
||||
|
||||
- A model ref such as `openai/gpt-5.5` tells you the selected provider/model.
|
||||
- A runtime id such as `codex` tells you which loop is executing the turn.
|
||||
- A channel label such as Telegram or Discord tells you where the conversation is happening.
|
||||
|
||||
If a session still shows PI after changing runtime config, start a new session
|
||||
with `/new` or clear the current one with `/reset`. Existing sessions keep their
|
||||
recorded runtime so a transcript is not replayed through two incompatible native
|
||||
session systems.
|
||||
|
||||
## Related
|
||||
|
||||
- [Codex harness](/plugins/codex-harness)
|
||||
- [Agent harness plugins](/plugins/sdk-agent-harness)
|
||||
- [Agent loop](/concepts/agent-loop)
|
||||
- [Models](/concepts/models)
|
||||
@@ -28,8 +28,10 @@ inside a sandbox workspace under `~/.openclaw/sandboxes`, not your host workspac
|
||||
|
||||
```json5
|
||||
{
|
||||
agent: {
|
||||
workspace: "~/.openclaw/workspace",
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: "~/.openclaw/workspace",
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
@@ -43,7 +45,7 @@ If you already manage the workspace files yourself, you can disable bootstrap
|
||||
file creation:
|
||||
|
||||
```json5
|
||||
{ agent: { skipBootstrap: true } }
|
||||
{ agents: { defaults: { skipBootstrap: true } } }
|
||||
```
|
||||
|
||||
## Extra workspace folders
|
||||
|
||||
@@ -44,7 +44,7 @@ If a file is missing, OpenClaw injects a single “missing file” marker line (
|
||||
To disable bootstrap file creation entirely (for pre-seeded workspaces), set:
|
||||
|
||||
```json5
|
||||
{ agent: { skipBootstrap: true } }
|
||||
{ agents: { defaults: { skipBootstrap: true } } }
|
||||
```
|
||||
|
||||
## Built-in tools
|
||||
|
||||
@@ -210,7 +210,10 @@ enabled for the run:
|
||||
- `true` — the engine owns compaction behavior. OpenClaw disables Pi's built-in
|
||||
auto-compaction for that run, and the engine's `compact()` implementation is
|
||||
responsible for `/compact`, overflow recovery compaction, and any proactive
|
||||
compaction it wants to do in `afterTurn()`.
|
||||
compaction it wants to do in `afterTurn()`. OpenClaw may still run the
|
||||
pre-prompt overflow safeguard; when it predicts the full transcript will
|
||||
overflow, the recovery path calls the active engine's `compact()` before
|
||||
submitting another prompt.
|
||||
- `false` or unset — Pi's built-in auto-compaction may still run during prompt
|
||||
execution, but the active engine's `compact()` method is still called for
|
||||
`/compact` and overflow recovery.
|
||||
|
||||
@@ -24,6 +24,12 @@ For model selection rules, see [/concepts/models](/concepts/models).
|
||||
- Plugin auto-enable follows that same boundary: `openai-codex/<model>` belongs
|
||||
to the OpenAI plugin, while the Codex plugin is enabled by
|
||||
`embeddedHarness.runtime: "codex"` or legacy `codex/<model>` refs.
|
||||
- CLI runtimes use the same split: choose canonical model refs such as
|
||||
`anthropic/claude-*`, `google/gemini-*`, or `openai/gpt-*`, then set
|
||||
`agents.defaults.embeddedHarness.runtime` to `claude-cli`,
|
||||
`google-gemini-cli`, or `codex-cli` when you want a local CLI backend.
|
||||
Legacy `claude-cli/*`, `google-gemini-cli/*`, and `codex-cli/*` refs migrate
|
||||
back to canonical provider refs with the runtime recorded separately.
|
||||
- GPT-5.5 is currently available through subscription/OAuth routes:
|
||||
`openai-codex/gpt-5.5` in PI or `openai/gpt-5.5` with the Codex app-server
|
||||
harness. The direct API-key route for `openai/gpt-5.5` is supported once
|
||||
@@ -174,6 +180,8 @@ OpenClaw ships with the pi‑ai catalog. These providers require **no**
|
||||
- Example models: `google/gemini-3.1-pro-preview`, `google/gemini-3-flash-preview`
|
||||
- Compatibility: legacy OpenClaw config using `google/gemini-3.1-flash-preview` is normalized to `google/gemini-3-flash-preview`
|
||||
- CLI: `openclaw onboard --auth-choice gemini-api-key`
|
||||
- Thinking: `/think adaptive` uses Google dynamic thinking. Gemini 3/3.1 omit a fixed
|
||||
`thinkingLevel`; Gemini 2.5 sends `thinkingBudget: -1`.
|
||||
- Direct Gemini runs also accept `agents.defaults.models["google/<model>"].params.cachedContent`
|
||||
(or legacy `cached_content`) to forward a provider-native
|
||||
`cachedContents/...` handle; Gemini cache hits surface as OpenClaw `cacheRead`
|
||||
@@ -235,6 +243,7 @@ See [/providers/kilocode](/providers/kilocode) for setup details.
|
||||
| BytePlus | `byteplus` / `byteplus-plan` | `BYTEPLUS_API_KEY` | `byteplus-plan/ark-code-latest` |
|
||||
| Cerebras | `cerebras` | `CEREBRAS_API_KEY` | `cerebras/zai-glm-4.7` |
|
||||
| Cloudflare AI Gateway | `cloudflare-ai-gateway` | `CLOUDFLARE_AI_GATEWAY_API_KEY` | — |
|
||||
| DeepSeek | `deepseek` | `DEEPSEEK_API_KEY` | `deepseek/deepseek-v4-flash` |
|
||||
| GitHub Copilot | `github-copilot` | `COPILOT_GITHUB_TOKEN` / `GH_TOKEN` / `GITHUB_TOKEN` | — |
|
||||
| Groq | `groq` | `GROQ_API_KEY` | — |
|
||||
| Hugging Face Inference | `huggingface` | `HUGGINGFACE_HUB_TOKEN` or `HF_TOKEN` | `huggingface/deepseek-ai/DeepSeek-R1` |
|
||||
@@ -259,7 +268,7 @@ Quirks worth knowing:
|
||||
|
||||
- **OpenRouter** applies its app-attribution headers and Anthropic `cache_control` markers only on verified `openrouter.ai` routes. As a proxy-style OpenAI-compatible path, it skips native-OpenAI-only shaping (`serviceTier`, Responses `store`, prompt-cache hints, OpenAI reasoning-compat). Gemini-backed refs keep proxy-Gemini thought-signature sanitation only.
|
||||
- **Kilo Gateway** Gemini-backed refs follow the same proxy-Gemini sanitation path; `kilocode/kilo/auto` and other proxy-reasoning-unsupported refs skip proxy reasoning injection.
|
||||
- **MiniMax** API-key onboarding writes explicit M2.7 model definitions with `input: ["text", "image"]`; the bundled catalog keeps chat refs text-only until that config is materialized.
|
||||
- **MiniMax** API-key onboarding writes explicit text-only M2.7 chat model definitions; image understanding stays on the plugin-owned `MiniMax-VL-01` media provider.
|
||||
- **xAI** uses the xAI Responses path. `/fast` or `params.fastMode: true` rewrites `grok-3`, `grok-3-mini`, `grok-4`, and `grok-4-0709` to their `*-fast` variants. `tool_stream` defaults on; disable via `agents.defaults.models["xai/<model>"].params.tool_stream=false`.
|
||||
- **Cerebras** GLM models use `zai-glm-4.7` / `zai-glm-4.6`; OpenAI-compatible base URL is `https://api.cerebras.ai/v1`.
|
||||
|
||||
|
||||
@@ -10,6 +10,11 @@ title: "Models CLI"
|
||||
See [/concepts/model-failover](/concepts/model-failover) for auth profile
|
||||
rotation, cooldowns, and how that interacts with fallbacks.
|
||||
Quick provider overview + examples: [/concepts/model-providers](/concepts/model-providers).
|
||||
Model refs choose a provider and model. They do not usually choose the
|
||||
low-level agent runtime. For example, `openai/gpt-5.5` can run through the
|
||||
normal OpenAI provider path or through the Codex app-server runtime, depending
|
||||
on `agents.defaults.embeddedHarness.runtime`. See
|
||||
[/concepts/agent-runtimes](/concepts/agent-runtimes).
|
||||
|
||||
## How model selection works
|
||||
|
||||
@@ -82,6 +87,10 @@ provided value should become the complete target value.
|
||||
Interactive provider setup and `openclaw configure --section model` also merge
|
||||
provider-scoped selections into the existing allowlist, so adding Codex,
|
||||
Ollama, or another provider does not drop unrelated model entries.
|
||||
Configure preserves an existing `agents.defaults.model.primary` when provider
|
||||
auth is re-applied. Explicit default-setting commands such as
|
||||
`openclaw models auth login --provider <id> --set-default` and
|
||||
`openclaw models set <model>` still replace `agents.defaults.model.primary`.
|
||||
|
||||
## "Model is not allowed" (and why replies stop)
|
||||
|
||||
@@ -130,9 +139,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.
|
||||
- `/models add` is available by default and can be disabled with `commands.modelsWrite=false`.
|
||||
- When enabled, `/models add <provider> <modelId>` is the fastest path; bare `/models add` starts a provider-first guided flow where supported.
|
||||
- After `/models add`, the new model becomes available in `/models` and `/model` without restarting the gateway.
|
||||
- `/models add` is deprecated and now returns a deprecation message instead of registering models from chat.
|
||||
- `/model <#>` selects from that picker.
|
||||
- `/model` persists the new session selection immediately.
|
||||
- If the agent is idle, the next run uses the new model right away.
|
||||
@@ -151,14 +158,6 @@ Notes:
|
||||
|
||||
Full command behavior/config: [Slash commands](/tools/slash-commands).
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
/models add
|
||||
/models add ollama glm-5.1:cloud
|
||||
/models add lmstudio qwen/qwen3.5-9b
|
||||
```
|
||||
|
||||
## CLI commands
|
||||
|
||||
```bash
|
||||
@@ -284,6 +283,7 @@ This applies whenever OpenClaw regenerates `models.json`, including command-driv
|
||||
## Related
|
||||
|
||||
- [Model Providers](/concepts/model-providers) — provider routing and auth
|
||||
- [Agent Runtimes](/concepts/agent-runtimes) — PI, Codex, and other agent loop runtimes
|
||||
- [Model Failover](/concepts/model-failover) — fallback chains
|
||||
- [Image Generation](/tools/image-generation) — image model configuration
|
||||
- [Music Generation](/tools/music-generation) — music model configuration
|
||||
|
||||
@@ -44,9 +44,10 @@ To reduce that, OpenClaw treats `auth-profiles.json` as a **token sink**:
|
||||
|
||||
- the runtime reads credentials from **one place**
|
||||
- we can keep multiple profiles and route them deterministically
|
||||
- when credentials are reused from an external CLI like Codex CLI, OpenClaw
|
||||
mirrors them with provenance and re-reads that external source instead of
|
||||
rotating the refresh token itself
|
||||
- external CLI reuse is provider-specific: Codex CLI can bootstrap an empty
|
||||
`openai-codex:default` profile, but once OpenClaw has a local OAuth profile,
|
||||
the local refresh token is canonical; other integrations can remain
|
||||
externally managed and re-read their CLI auth store
|
||||
|
||||
## Storage (where tokens live)
|
||||
|
||||
@@ -128,8 +129,11 @@ At runtime:
|
||||
|
||||
- if `expires` is in the future → use the stored access token
|
||||
- if expired → refresh (under a file lock) and overwrite the stored credentials
|
||||
- exception: reused external CLI credentials stay externally managed; OpenClaw
|
||||
re-reads the CLI auth store and never spends the copied refresh token itself
|
||||
- exception: some external CLI credentials stay externally managed; OpenClaw
|
||||
re-reads those CLI auth stores instead of spending copied refresh tokens.
|
||||
Codex CLI bootstrap is intentionally narrower: it seeds an empty
|
||||
`openai-codex:default` profile, then OpenClaw-owned refreshes keep the local
|
||||
profile canonical.
|
||||
|
||||
The refresh flow is automatic; you generally don't need to manage tokens manually.
|
||||
|
||||
|
||||
@@ -64,6 +64,9 @@ the child config scoped to the transport under test, so Matrix runs without
|
||||
a combined stdout/stderr log into the selected Matrix QA output directory. To
|
||||
capture the outer `scripts/run-node.mjs` build/launcher output too, set
|
||||
`OPENCLAW_RUN_NODE_OUTPUT_LOG=<path>` to a repo-local log file.
|
||||
Matrix progress is printed by default. `OPENCLAW_QA_MATRIX_TIMEOUT_MS` bounds
|
||||
the full run, and `OPENCLAW_QA_MATRIX_CLEANUP_TIMEOUT_MS` bounds cleanup so a
|
||||
stuck Docker teardown reports the exact recovery command instead of hanging.
|
||||
|
||||
For a transport-real Telegram smoke lane, run:
|
||||
|
||||
@@ -83,6 +86,16 @@ you want artifacts without a failing exit code.
|
||||
The Telegram report and summary include per-reply RTT from the driver message
|
||||
send request to the observed SUT reply, starting with the canary.
|
||||
|
||||
Before using pooled live credentials, run:
|
||||
|
||||
```bash
|
||||
pnpm openclaw qa credentials doctor
|
||||
```
|
||||
|
||||
The doctor checks Convex broker env, validates endpoint settings, and verifies
|
||||
admin/list reachability when the maintainer secret is present. It reports only
|
||||
set/missing status for secrets.
|
||||
|
||||
For a transport-real Discord smoke lane, run:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -5,8 +5,6 @@ read_when:
|
||||
title: "Command queue"
|
||||
---
|
||||
|
||||
# Command Queue (2026-01-16)
|
||||
|
||||
We serialize inbound auto-reply runs (all channels) through a tiny in-process queue to prevent multiple agent runs from colliding, while still allowing safe parallelism across sessions.
|
||||
|
||||
## Why
|
||||
|
||||
@@ -156,6 +156,7 @@ Slack:
|
||||
- `partial` can use Slack native streaming (`chat.startStream`/`append`/`stop`) when available.
|
||||
- `block` uses append-style draft previews.
|
||||
- `progress` uses status preview text, then final answer.
|
||||
- Native and draft preview streaming suppress block replies for that turn, so a Slack reply is streamed by one delivery path only.
|
||||
- Final media/error payloads and progress finals do not create throwaway draft messages; only text/block finals that can edit the preview flush pending draft text.
|
||||
|
||||
Mattermost:
|
||||
|
||||
@@ -171,6 +171,10 @@ Eligibility includes skill metadata gates, runtime environment/config checks,
|
||||
and the effective agent skill allowlist when `agents.defaults.skills` or
|
||||
`agents.list[].skills` is configured.
|
||||
|
||||
Plugin-bundled skills are eligible only when their owning plugin is enabled.
|
||||
This lets tool plugins expose deeper operating guides without embedding all of
|
||||
that guidance directly in every tool description.
|
||||
|
||||
```
|
||||
<available_skills>
|
||||
<skill>
|
||||
|
||||
@@ -1085,6 +1085,7 @@
|
||||
"concepts/architecture",
|
||||
"concepts/agent",
|
||||
"concepts/agent-loop",
|
||||
"concepts/agent-runtimes",
|
||||
"concepts/system-prompt",
|
||||
"concepts/context",
|
||||
"concepts/context-engine",
|
||||
@@ -1092,7 +1093,8 @@
|
||||
"concepts/soul",
|
||||
"concepts/oauth",
|
||||
"start/bootstrapping",
|
||||
"concepts/experimental-features"
|
||||
"concepts/experimental-features",
|
||||
"concepts/qa-e2e-automation"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1153,11 +1155,14 @@
|
||||
"plugins/webhooks",
|
||||
"plugins/voice-call",
|
||||
"plugins/memory-wiki",
|
||||
"plugins/message-presentation",
|
||||
"plugins/skill-workshop",
|
||||
"plugins/zalouser",
|
||||
{
|
||||
"group": "Building plugins",
|
||||
"pages": [
|
||||
"plugins/building-plugins",
|
||||
"plugins/hooks",
|
||||
"plugins/sdk-channel-plugins",
|
||||
"plugins/sdk-provider-plugins",
|
||||
"plugins/sdk-migration"
|
||||
@@ -1299,6 +1304,7 @@
|
||||
"providers/github-copilot",
|
||||
"providers/glm",
|
||||
"providers/google",
|
||||
"providers/gradium",
|
||||
"providers/groq",
|
||||
"providers/huggingface",
|
||||
"providers/inferrs",
|
||||
@@ -1594,6 +1600,7 @@
|
||||
"cli/dns",
|
||||
"cli/docs",
|
||||
"cli/mcp",
|
||||
"cli/proxy",
|
||||
"cli/wiki"
|
||||
]
|
||||
}
|
||||
@@ -1640,7 +1647,9 @@
|
||||
"concepts/markdown-formatting",
|
||||
"concepts/typing-indicators",
|
||||
"concepts/usage-tracking",
|
||||
"concepts/timezone"
|
||||
"concepts/timezone",
|
||||
"help/gpt54-codex-agentic-parity",
|
||||
"help/gpt54-codex-agentic-parity-maintainers"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -6,8 +6,6 @@ read_when:
|
||||
title: "Authentication"
|
||||
---
|
||||
|
||||
# Authentication (Model Providers)
|
||||
|
||||
<Note>
|
||||
This page covers **model provider** authentication (API keys, OAuth, Claude CLI reuse, and Anthropic setup-token). For **gateway connection** authentication (token, password, trusted-proxy), see [Configuration](/gateway/configuration) and [Trusted Proxy Auth](/gateway/trusted-proxy-auth).
|
||||
</Note>
|
||||
|
||||
@@ -9,9 +9,10 @@ title: "Bonjour discovery"
|
||||
# Bonjour / mDNS discovery
|
||||
|
||||
OpenClaw uses Bonjour (mDNS / DNS‑SD) to discover an active Gateway (WebSocket endpoint).
|
||||
Multicast `local.` browsing is a **LAN-only convenience**. For cross-network discovery, the
|
||||
same beacon can also be published through a configured wide-area DNS-SD domain. Discovery is
|
||||
still best-effort and does **not** replace SSH or Tailnet-based connectivity.
|
||||
Multicast `local.` browsing is a **LAN-only convenience**. The bundled `bonjour`
|
||||
plugin owns LAN advertising and is enabled by default. For cross-network discovery,
|
||||
the same beacon can also be published through a configured wide-area DNS-SD domain.
|
||||
Discovery is still best-effort and does **not** replace SSH or Tailnet-based connectivity.
|
||||
|
||||
## Wide-area Bonjour (Unicast DNS-SD) over Tailscale
|
||||
|
||||
@@ -79,7 +80,9 @@ For tailnet‑only setups:
|
||||
|
||||
## What advertises
|
||||
|
||||
Only the Gateway advertises `_openclaw-gw._tcp`.
|
||||
Only the Gateway advertises `_openclaw-gw._tcp`. LAN multicast advertising is
|
||||
provided by the bundled `bonjour` plugin; wide-area DNS-SD publishing remains
|
||||
Gateway-owned.
|
||||
|
||||
## Service types
|
||||
|
||||
@@ -97,7 +100,7 @@ The Gateway advertises small non‑secret hints to make UI flows convenient:
|
||||
- `gatewayTlsSha256=<sha256>` (only when TLS is enabled and fingerprint is available)
|
||||
- `canvasPort=<port>` (only when the canvas host is enabled; currently the same as `gatewayPort`)
|
||||
- `transport=gateway`
|
||||
- `tailnetDns=<magicdns>` (optional hint when Tailnet is available)
|
||||
- `tailnetDns=<magicdns>` (mDNS full mode only, optional hint when Tailnet is available)
|
||||
- `sshPort=<port>` (mDNS full mode only; wide-area DNS-SD may omit it)
|
||||
- `cliPath=<path>` (mDNS full mode only; wide-area DNS-SD still writes it as a remote-install hint)
|
||||
|
||||
@@ -167,10 +170,12 @@ sequences (e.g. spaces become `\032`).
|
||||
|
||||
## Disabling / configuration
|
||||
|
||||
- `OPENCLAW_DISABLE_BONJOUR=1` disables advertising (legacy: `OPENCLAW_DISABLE_BONJOUR`).
|
||||
- `openclaw plugins disable bonjour` disables LAN multicast advertising by disabling the bundled plugin.
|
||||
- `openclaw plugins enable bonjour` restores the default LAN discovery plugin.
|
||||
- `OPENCLAW_DISABLE_BONJOUR=1` disables LAN multicast advertising without changing plugin config; accepted truthy values are `1`, `true`, `yes`, and `on` (legacy: `OPENCLAW_DISABLE_BONJOUR`).
|
||||
- `gateway.bind` in `~/.openclaw/openclaw.json` controls the Gateway bind mode.
|
||||
- `OPENCLAW_SSH_PORT` overrides the SSH port when `sshPort` is advertised (legacy: `OPENCLAW_SSH_PORT`).
|
||||
- `OPENCLAW_TAILNET_DNS` publishes a MagicDNS hint in TXT (legacy: `OPENCLAW_TAILNET_DNS`).
|
||||
- `OPENCLAW_TAILNET_DNS` publishes a MagicDNS hint in TXT when mDNS full mode is enabled (legacy: `OPENCLAW_TAILNET_DNS`).
|
||||
- `OPENCLAW_CLI_PATH` overrides the advertised CLI path (legacy: `OPENCLAW_CLI_PATH`).
|
||||
|
||||
## Related docs
|
||||
|
||||
@@ -7,8 +7,6 @@ read_when:
|
||||
title: "Bridge protocol"
|
||||
---
|
||||
|
||||
# Bridge protocol (legacy node transport)
|
||||
|
||||
<Warning>
|
||||
The TCP bridge has been **removed**. Current OpenClaw builds do not ship the bridge listener and `bridge.*` config keys are no longer in the schema. This page is kept for historical reference only. Use the [Gateway Protocol](/gateway/protocol) for all node/operator clients.
|
||||
</Warning>
|
||||
|
||||
@@ -7,8 +7,6 @@ read_when:
|
||||
title: "CLI backends"
|
||||
---
|
||||
|
||||
# CLI backends (fallback runtime)
|
||||
|
||||
OpenClaw can run **local AI CLIs** as a **text-only fallback** when API providers are down,
|
||||
rate-limited, or temporarily misbehaving. This is intentionally conservative:
|
||||
|
||||
|
||||
@@ -316,7 +316,7 @@ Time format in system prompt. Default: `auto` (OS preference).
|
||||
},
|
||||
params: { cacheRetention: "long" }, // global default provider params
|
||||
embeddedHarness: {
|
||||
runtime: "auto", // auto | pi | registered harness id, e.g. codex
|
||||
runtime: "pi", // pi | auto | registered harness id, e.g. codex
|
||||
fallback: "pi", // pi | none
|
||||
},
|
||||
pdfMaxBytesMb: 10,
|
||||
@@ -369,16 +369,17 @@ Time format in system prompt. Default: `auto` (OS preference).
|
||||
- For direct OpenAI Responses models, server-side compaction is enabled automatically. Use `params.responsesServerCompaction: false` to stop injecting `context_management`, or `params.responsesCompactThreshold` to override the threshold. See [OpenAI server-side compaction](/providers/openai#server-side-compaction-responses-api).
|
||||
- `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.
|
||||
- `embeddedHarness`: default low-level embedded agent runtime policy. Use `runtime: "auto"` to let registered plugin harnesses claim supported models, `runtime: "pi"` to force the built-in PI harness, or a registered harness id such as `runtime: "codex"`. Set `fallback: "none"` to disable automatic PI fallback.
|
||||
- `embeddedHarness`: default low-level embedded agent runtime policy. Omitted runtime defaults to OpenClaw Pi. Use `runtime: "pi"` to force the built-in PI harness, `runtime: "auto"` to let registered plugin harnesses claim supported models, or a registered harness id such as `runtime: "codex"`. Set `fallback: "none"` to disable automatic PI fallback. Explicit plugin runtimes such as `codex` fail closed by default unless you set `fallback: "pi"` in the same override scope. Keep model refs canonical as `provider/model`; select Codex, Claude CLI, Gemini CLI, and other execution backends through runtime config instead of legacy runtime provider prefixes. See [Agent runtimes](/concepts/agent-runtimes) for how this differs from provider/model selection.
|
||||
- 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.
|
||||
|
||||
### `agents.defaults.embeddedHarness`
|
||||
|
||||
`embeddedHarness` controls which low-level executor runs embedded agent turns.
|
||||
Most deployments should keep the default `{ runtime: "auto", fallback: "pi" }`.
|
||||
Most deployments should keep the default OpenClaw Pi runtime.
|
||||
Use it when a trusted plugin provides a native harness, such as the bundled
|
||||
Codex app-server harness.
|
||||
Codex app-server harness. For the mental model, see
|
||||
[Agent runtimes](/concepts/agent-runtimes).
|
||||
|
||||
```json5
|
||||
{
|
||||
@@ -395,9 +396,9 @@ Codex app-server harness.
|
||||
```
|
||||
|
||||
- `runtime`: `"auto"`, `"pi"`, or a registered plugin harness id. The bundled Codex plugin registers `codex`.
|
||||
- `fallback`: `"pi"` or `"none"`. `"pi"` keeps the built-in PI harness as the compatibility fallback when no plugin harness is selected. `"none"` makes missing or unsupported plugin harness selection fail instead of silently using PI. Selected plugin harness failures always surface directly.
|
||||
- Environment overrides: `OPENCLAW_AGENT_RUNTIME=<id|auto|pi>` overrides `runtime`; `OPENCLAW_AGENT_HARNESS_FALLBACK=none` disables PI fallback for that process.
|
||||
- For Codex-only deployments, set `model: "openai/gpt-5.5"`, `embeddedHarness.runtime: "codex"`, and `embeddedHarness.fallback: "none"`.
|
||||
- `fallback`: `"pi"` or `"none"`. In `runtime: "auto"`, omitted fallback defaults to `"pi"` so old configs can keep using PI when no plugin harness claims a run. In explicit plugin runtime mode, such as `runtime: "codex"`, omitted fallback defaults to `"none"` so a missing harness fails instead of silently using PI. Runtime overrides do not inherit fallback from a broader scope; set `fallback: "pi"` alongside the explicit runtime when you intentionally want that compatibility fallback. Selected plugin harness failures always surface directly.
|
||||
- Environment overrides: `OPENCLAW_AGENT_RUNTIME=<id|auto|pi>` overrides `runtime`; `OPENCLAW_AGENT_HARNESS_FALLBACK=pi|none` overrides fallback for that process.
|
||||
- For Codex-only deployments, set `model: "openai/gpt-5.5"` and `embeddedHarness.runtime: "codex"`. You may also set `embeddedHarness.fallback: "none"` explicitly for readability; it is the default for explicit plugin runtimes.
|
||||
- Harness choice is pinned per session id after the first embedded run. Config/env changes affect new or reset sessions, not an existing transcript. Legacy sessions with transcript history but no recorded pin are treated as PI-pinned. `/status` shows non-PI harness ids such as `codex` next to `Fast`.
|
||||
- This only controls the embedded chat harness. Media generation, vision, PDF, music, video, and TTS still use their provider/model settings.
|
||||
|
||||
@@ -943,10 +944,10 @@ scripts/sandbox-browser-setup.sh # optional browser image
|
||||
- `model`: string form overrides `primary` only; object form `{ primary, fallbacks }` overrides both (`[]` disables global fallbacks). Cron jobs that only override `primary` still inherit default fallbacks unless you set `fallbacks: []`.
|
||||
- `params`: per-agent stream params merged over the selected model entry in `agents.defaults.models`. Use this for agent-specific overrides like `cacheRetention`, `temperature`, or `maxTokens` without duplicating the whole model catalog.
|
||||
- `skills`: optional per-agent skill allowlist. If omitted, the agent inherits `agents.defaults.skills` when set; an explicit list replaces defaults instead of merging, and `[]` means no skills.
|
||||
- `thinkingDefault`: optional per-agent default thinking level (`off | minimal | low | medium | high | xhigh | adaptive | max`). Overrides `agents.defaults.thinkingDefault` for this agent when no per-message or session override is set.
|
||||
- `thinkingDefault`: optional per-agent default thinking level (`off | minimal | low | medium | high | xhigh | adaptive | max`). Overrides `agents.defaults.thinkingDefault` for this agent when no per-message or session override is set. The selected provider/model profile controls which values are valid; for Google Gemini, `adaptive` keeps provider-owned dynamic thinking (`thinkingLevel` omitted on Gemini 3/3.1, `thinkingBudget: -1` on Gemini 2.5).
|
||||
- `reasoningDefault`: optional per-agent default reasoning visibility (`on | off | stream`). Applies when no per-message or session reasoning override is set.
|
||||
- `fastModeDefault`: optional per-agent default for fast mode (`true | false`). Applies when no per-message or session fast-mode override is set.
|
||||
- `embeddedHarness`: optional per-agent low-level harness policy override. Use `{ runtime: "codex", fallback: "none" }` to make one agent Codex-only while other agents keep the default PI fallback.
|
||||
- `embeddedHarness`: optional per-agent low-level harness policy override. Use `{ runtime: "codex" }` to make one agent Codex-only while other agents keep the default PI fallback in `auto` mode.
|
||||
- `runtime`: optional per-agent runtime descriptor. Use `type: "acp"` with `runtime.acp` defaults (`agent`, `backend`, `mode`, `cwd`) when the agent should default to ACP harness sessions.
|
||||
- `identity.avatar`: workspace-relative path, `http(s)` URL, or `data:` URI.
|
||||
- `identity` derives defaults: `ackReaction` from `emoji`, `mentionPatterns` from `name`/`emoji`.
|
||||
|
||||
@@ -628,7 +628,7 @@ Base URL should omit `/v1` (Anthropic client appends it). Shortcut: `openclaw on
|
||||
id: "MiniMax-M2.7",
|
||||
name: "MiniMax M2.7",
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
input: ["text"],
|
||||
cost: { input: 0.3, output: 1.2, cacheRead: 0.06, cacheWrite: 0.375 },
|
||||
contextWindow: 204800,
|
||||
maxTokens: 131072,
|
||||
|
||||
@@ -118,9 +118,11 @@ provider / base-URL setup moved to a dedicated page — see
|
||||
- `plugins.entries.<id>.apiKey`: plugin-level API key convenience field (when supported by the plugin).
|
||||
- `plugins.entries.<id>.env`: plugin-scoped env var map.
|
||||
- `plugins.entries.<id>.hooks.allowPromptInjection`: when `false`, core blocks `before_prompt_build` and ignores prompt-mutating fields from legacy `before_agent_start`, while preserving legacy `modelOverride` and `providerOverride`. Applies to native plugin hooks and supported bundle-provided hook directories.
|
||||
- `plugins.entries.<id>.hooks.allowConversationAccess`: when `true`, trusted non-bundled plugins may read raw conversation content from typed hooks such as `llm_input`, `llm_output`, and `agent_end`.
|
||||
- `plugins.entries.<id>.subagent.allowModelOverride`: explicitly trust this plugin to request per-run `provider` and `model` overrides for background subagent runs.
|
||||
- `plugins.entries.<id>.subagent.allowedModels`: optional allowlist of canonical `provider/model` targets for trusted subagent overrides. Use `"*"` only when you intentionally want to allow any model.
|
||||
- `plugins.entries.<id>.config`: plugin-defined config object (validated by native OpenClaw plugin schema when available).
|
||||
- Channel plugin account/runtime settings live under `channels.<id>` and should be described by the owning plugin's manifest `channelConfigs` metadata, not by a central OpenClaw option registry.
|
||||
- `plugins.entries.firecrawl.config.webFetch`: Firecrawl web-fetch provider settings.
|
||||
- `apiKey`: Firecrawl API key (accepts SecretRef). Falls back to `plugins.entries.firecrawl.config.webSearch.apiKey`, legacy `tools.web.fetch.firecrawl.apiKey`, or `FIRECRAWL_API_KEY` env var.
|
||||
- `baseUrl`: Firecrawl API base URL (default: `https://api.firecrawl.dev`).
|
||||
@@ -319,7 +321,12 @@ See [Plugins](/tools/plugin).
|
||||
- `controlUi.allowedOrigins`: explicit browser-origin allowlist for Gateway WebSocket connects. Required when browser clients are expected from non-loopback origins.
|
||||
- `controlUi.dangerouslyAllowHostHeaderOriginFallback`: dangerous mode that enables Host-header origin fallback for deployments that intentionally rely on Host-header origin policy.
|
||||
- `remote.transport`: `ssh` (default) or `direct` (ws/wss). For `direct`, `remote.url` must be `ws://` or `wss://`.
|
||||
- `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`: client-side break-glass override that allows plaintext `ws://` to trusted private-network IPs; default remains loopback-only for plaintext.
|
||||
- `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1`: client-side process-environment
|
||||
break-glass override that allows plaintext `ws://` to trusted private-network
|
||||
IPs; default remains loopback-only for plaintext. There is no `openclaw.json`
|
||||
equivalent, and browser private-network config such as
|
||||
`browser.ssrfPolicy.dangerouslyAllowPrivateNetwork` does not affect Gateway
|
||||
WebSocket clients.
|
||||
- `gateway.remote.token` / `.password` are remote-client credential fields. They do not configure gateway auth by themselves.
|
||||
- `gateway.push.apns.relay.baseUrl`: base HTTPS URL for the external APNs relay used by official/TestFlight iOS builds after they publish relay-backed registrations to the gateway. This URL must match the relay URL compiled into the iOS build.
|
||||
- `gateway.push.apns.relay.timeoutMs`: gateway-to-relay send timeout in milliseconds. Defaults to `10000`.
|
||||
@@ -791,6 +798,14 @@ Notes:
|
||||
logs: false,
|
||||
sampleRate: 1.0,
|
||||
flushIntervalMs: 5000,
|
||||
captureContent: {
|
||||
enabled: false,
|
||||
inputMessages: false,
|
||||
outputMessages: false,
|
||||
toolInputs: false,
|
||||
toolOutputs: false,
|
||||
systemPrompt: false,
|
||||
},
|
||||
},
|
||||
|
||||
cacheTrace: {
|
||||
@@ -815,6 +830,7 @@ Notes:
|
||||
- `otel.traces` / `otel.metrics` / `otel.logs`: enable trace, metrics, or log export.
|
||||
- `otel.sampleRate`: trace sampling rate `0`–`1`.
|
||||
- `otel.flushIntervalMs`: periodic telemetry flush interval in ms.
|
||||
- `otel.captureContent`: opt-in raw content capture for OTEL span attributes. Defaults to off. Boolean `true` captures non-system message/tool content; the object form lets you enable `inputMessages`, `outputMessages`, `toolInputs`, `toolOutputs`, and `systemPrompt` explicitly.
|
||||
- `cacheTrace.enabled`: log cache trace snapshots for embedded runs (default: `false`).
|
||||
- `cacheTrace.filePath`: output path for cache trace JSONL (default: `$OPENCLAW_STATE_DIR/logs/cache-trace.jsonl`).
|
||||
- `cacheTrace.includeMessages` / `includePrompt` / `includeSystem`: control what is included in cache trace output (all default: `true`).
|
||||
|
||||
@@ -387,6 +387,12 @@ are missing, doctor reports the packages and installs them in
|
||||
use `openclaw plugins install` / `openclaw plugins update`; doctor does not
|
||||
install dependencies for arbitrary plugin paths.
|
||||
|
||||
The Gateway and local CLI can also repair active bundled plugin runtime
|
||||
dependencies on demand before importing a bundled plugin. These installs are
|
||||
scoped to the plugin runtime install root, run with scripts disabled, do not
|
||||
write a package lock, and are guarded by an install-root lock so concurrent CLI
|
||||
or Gateway starts do not mutate the same `node_modules` tree at the same time.
|
||||
|
||||
### 8) Gateway service migrations and cleanup hints
|
||||
|
||||
Doctor detects legacy gateway services (launchd/systemd/schtasks) and
|
||||
|
||||
@@ -6,8 +6,6 @@ read_when:
|
||||
title: "Health checks"
|
||||
---
|
||||
|
||||
# Health Checks (CLI)
|
||||
|
||||
Short guide to verify channel connectivity without guessing.
|
||||
|
||||
## Quick checks
|
||||
|
||||
@@ -6,8 +6,6 @@ read_when:
|
||||
title: "Heartbeat"
|
||||
---
|
||||
|
||||
# Heartbeat (Gateway)
|
||||
|
||||
> **Heartbeat vs Cron?** See [Automation & Tasks](/automation) for guidance on when to use each.
|
||||
|
||||
Heartbeat runs **periodic agent turns** in the main session so the model can
|
||||
|
||||
@@ -176,6 +176,42 @@ OPENCLAW_CONFIG_PATH=~/.openclaw/b.json OPENCLAW_STATE_DIR=~/.openclaw-b opencla
|
||||
|
||||
Detailed setup: [/gateway/multiple-gateways](/gateway/multiple-gateways).
|
||||
|
||||
## VoiceClaw real-time brain endpoint
|
||||
|
||||
OpenClaw exposes a VoiceClaw-compatible real-time WebSocket endpoint at
|
||||
`/voiceclaw/realtime`. Use it when a VoiceClaw desktop client should talk
|
||||
directly to a real-time OpenClaw brain instead of going through a separate relay
|
||||
process.
|
||||
|
||||
The endpoint uses Gemini Live for real-time audio and calls OpenClaw as the
|
||||
brain by exposing OpenClaw tools directly to Gemini Live. Tool calls return an
|
||||
immediate `working` result to keep the voice turn responsive, then OpenClaw
|
||||
executes the actual tool asynchronously and injects the result back into the
|
||||
live session. Set `GEMINI_API_KEY` in the gateway process environment. If
|
||||
gateway auth is enabled, the desktop client sends the gateway token or password
|
||||
in its first `session.config` message.
|
||||
|
||||
Real-time brain access runs owner-authorized OpenClaw agent commands. Keep
|
||||
`gateway.auth.mode: "none"` limited to loopback-only test instances. Non-local
|
||||
real-time brain connections require gateway auth.
|
||||
|
||||
For an isolated test gateway, run a separate instance with its own port, config,
|
||||
and state:
|
||||
|
||||
```bash
|
||||
OPENCLAW_CONFIG_PATH=/path/to/openclaw-realtime/openclaw.json \
|
||||
OPENCLAW_STATE_DIR=/path/to/openclaw-realtime/state \
|
||||
OPENCLAW_SKIP_CHANNELS=1 \
|
||||
GEMINI_API_KEY=... \
|
||||
openclaw gateway --port 19789
|
||||
```
|
||||
|
||||
Then configure VoiceClaw to use:
|
||||
|
||||
```text
|
||||
ws://127.0.0.1:19789/voiceclaw/realtime
|
||||
```
|
||||
|
||||
## Remote access
|
||||
|
||||
Preferred: Tailscale/VPN.
|
||||
|
||||
@@ -6,8 +6,6 @@ read_when:
|
||||
title: "Multiple gateways"
|
||||
---
|
||||
|
||||
# Multiple Gateways (same host)
|
||||
|
||||
Most setups should use one Gateway because a single Gateway can handle multiple messaging connections and agents. If you need stronger isolation or redundancy (e.g., a rescue bot), run separate Gateways with isolated profiles/ports.
|
||||
|
||||
## Best Recommended Setup
|
||||
|
||||
@@ -5,8 +5,6 @@ read_when:
|
||||
title: "OpenAI chat completions"
|
||||
---
|
||||
|
||||
# OpenAI Chat Completions (HTTP)
|
||||
|
||||
OpenClaw’s Gateway can serve a small OpenAI-compatible Chat Completions endpoint.
|
||||
|
||||
This endpoint is **disabled by default**. Enable it in config first.
|
||||
|
||||
@@ -6,8 +6,6 @@ read_when:
|
||||
title: "OpenResponses API"
|
||||
---
|
||||
|
||||
# OpenResponses API (HTTP)
|
||||
|
||||
OpenClaw’s Gateway can serve an OpenResponses-compatible `POST /v1/responses` endpoint.
|
||||
|
||||
This endpoint is **disabled by default**. Enable it in config first.
|
||||
@@ -174,8 +172,9 @@ Current behavior:
|
||||
rasterized into images and passed to the model, and the injected file block uses
|
||||
the placeholder `[PDF content rendered to images]`.
|
||||
|
||||
PDF parsing uses the Node-friendly `pdfjs-dist` legacy build (no worker). The modern
|
||||
PDF.js build expects browser workers/DOM globals, so it is not used in the Gateway.
|
||||
PDF parsing is provided by the bundled `document-extract` plugin, which uses the
|
||||
Node-friendly `pdfjs-dist` legacy build (no worker). The modern PDF.js build
|
||||
expects browser workers/DOM globals, so it is not used in the Gateway.
|
||||
|
||||
URL fetch defaults:
|
||||
|
||||
|
||||
@@ -7,8 +7,6 @@ read_when:
|
||||
title: "Gateway-owned pairing"
|
||||
---
|
||||
|
||||
# Gateway-owned pairing (Option B)
|
||||
|
||||
In Gateway-owned pairing, the **Gateway** is the source of truth for which nodes
|
||||
are allowed to join. UIs (macOS app, future clients) are just frontends that
|
||||
approve or reject pending requests.
|
||||
|
||||
@@ -7,8 +7,6 @@ read_when:
|
||||
title: "Gateway protocol"
|
||||
---
|
||||
|
||||
# Gateway protocol (WebSocket)
|
||||
|
||||
The Gateway WS protocol is the **single control plane + node transport** for
|
||||
OpenClaw. All clients (CLI, web UI, macOS app, iOS/Android nodes, headless
|
||||
nodes) connect over WebSocket and declare their **role** + **scope** at
|
||||
|
||||
@@ -5,8 +5,6 @@ read_when:
|
||||
title: "Remote access"
|
||||
---
|
||||
|
||||
# Remote access (SSH, tunnels, and tailnets)
|
||||
|
||||
This repo supports “remote over SSH” by keeping a single Gateway (the master) running on a dedicated host (desktop/server) and connecting clients to it.
|
||||
|
||||
- For **operators (you / the macOS app)**: SSH tunneling is the universal fallback.
|
||||
@@ -138,7 +136,9 @@ Short version: **keep the Gateway loopback-only** unless you’re sure you need
|
||||
|
||||
- **Loopback + SSH/Tailscale Serve** is the safest default (no public exposure).
|
||||
- Plaintext `ws://` is loopback-only by default. For trusted private networks,
|
||||
set `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` on the client process as break-glass.
|
||||
set `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` on the client process as
|
||||
break-glass. There is no `openclaw.json` equivalent; this must be process
|
||||
environment for the client making the WebSocket connection.
|
||||
- **Non-loopback binds** (`lan`/`tailnet`/`custom`, or `auto` when loopback is unavailable) must use gateway auth: token, password, or an identity-aware reverse proxy with `gateway.auth.mode: "trusted-proxy"`.
|
||||
- `gateway.remote.token` / `.password` are client credential sources. They do **not** configure server auth by themselves.
|
||||
- Local call paths can use `gateway.remote.*` as fallback only when `gateway.auth.*` is unset.
|
||||
|
||||
@@ -115,8 +115,9 @@ Use this as the quick model when triaging risk:
|
||||
## Not vulnerabilities by design
|
||||
|
||||
<Accordion title="Common findings that are out of scope">
|
||||
These patterns get reported often and are usually closed as no-action unless
|
||||
a real boundary bypass is demonstrated:
|
||||
|
||||
These patterns get reported often and are usually closed as no-action unless
|
||||
a real boundary bypass is demonstrated:
|
||||
|
||||
- Prompt-injection-only chains without a policy, auth, or sandbox bypass.
|
||||
- Claims that assume hostile multi-tenant operation on one shared host or
|
||||
@@ -134,7 +135,8 @@ Use this as the quick model when triaging risk:
|
||||
approvals.
|
||||
- "Missing per-user authorization" findings that treat `sessionKey` as an
|
||||
auth token.
|
||||
</Accordion>
|
||||
|
||||
</Accordion>
|
||||
|
||||
## Hardened baseline in 60 seconds
|
||||
|
||||
@@ -461,6 +463,10 @@ Two built-in tools can make persistent control-plane changes:
|
||||
The owner-only `gateway` runtime tool still refuses to rewrite
|
||||
`tools.exec.ask` or `tools.exec.security`; legacy `tools.bash.*` aliases are
|
||||
normalized to the same protected exec paths before the write.
|
||||
Agent-driven `gateway config.apply` and `gateway config.patch` edits are
|
||||
fail-closed by default: only a narrow set of prompt, model, and mention-gating
|
||||
paths are agent-tunable. New sensitive config trees are therefore protected
|
||||
unless they are deliberately added to the allowlist.
|
||||
|
||||
For any agent/surface that handles untrusted content, deny these by default:
|
||||
|
||||
@@ -840,7 +846,13 @@ If `gateway.auth.token` / `gateway.auth.password` is explicitly configured via
|
||||
SecretRef and unresolved, resolution fails closed (no remote fallback masking).
|
||||
Optional: pin remote TLS with `gateway.remote.tlsFingerprint` when using `wss://`.
|
||||
Plaintext `ws://` is loopback-only by default. For trusted private-network
|
||||
paths, set `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` on the client process as break-glass.
|
||||
paths, set `OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1` on the client process as
|
||||
break-glass. This is intentionally process environment only, not an
|
||||
`openclaw.json` config key.
|
||||
Mobile pairing and Android manual or scanned gateway routes are stricter:
|
||||
cleartext is accepted for loopback, but private-LAN, link-local, `.local`, and
|
||||
dotless hostnames must use TLS unless you explicitly opt into the trusted
|
||||
private-network cleartext path.
|
||||
|
||||
Local device pairing:
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@ read_when:
|
||||
title: "Tailscale"
|
||||
---
|
||||
|
||||
# Tailscale (Gateway dashboard)
|
||||
|
||||
OpenClaw can auto-configure Tailscale **Serve** (tailnet) or **Funnel** (public) for the
|
||||
Gateway dashboard and WebSocket port. This keeps the Gateway bound to loopback while
|
||||
Tailscale provides HTTPS, routing, and (for Serve) identity headers.
|
||||
|
||||
@@ -482,6 +482,8 @@ Common signatures:
|
||||
- `existing-session file uploads do not support element selectors; use ref/inputRef.` → Chrome MCP upload hooks need snapshot refs, not CSS selectors.
|
||||
- `existing-session file uploads currently support one file at a time.` → send one upload per call on Chrome MCP profiles.
|
||||
- `existing-session dialog handling does not support timeoutMs.` → dialog hooks on Chrome MCP profiles do not support timeout overrides.
|
||||
- `existing-session type does not support timeoutMs overrides.` → omit `timeoutMs` for `act:type` on `profile="user"` / Chrome MCP existing-session profiles, or use a managed/CDP browser profile when a custom timeout is required.
|
||||
- `existing-session evaluate does not support timeoutMs overrides.` → omit `timeoutMs` for `act:evaluate` on `profile="user"` / Chrome MCP existing-session profiles, or use a managed/CDP browser profile when a custom timeout is required.
|
||||
- `response body is not supported for existing-session profiles yet.` → `responsebody` still requires a managed browser or raw CDP profile.
|
||||
- stale viewport / dark-mode / locale / offline overrides on attach-only or remote CDP profiles → run `openclaw browser stop --browser-profile <name>` to close the active control session and release Playwright/CDP emulation state without restarting the whole gateway.
|
||||
|
||||
|
||||
@@ -76,9 +76,8 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS,
|
||||
|
||||
## Quick start and first-run setup
|
||||
|
||||
First-run setup Q&A — install, onboard, auth routes, subscriptions, initial
|
||||
failures — moved to a dedicated page:
|
||||
[FAQ — quick start and first-run setup](/help/faq-first-run).
|
||||
First-run Q&A — install, onboard, auth routes, subscriptions, initial failures —
|
||||
lives on the [First-run FAQ](/help/faq-first-run).
|
||||
|
||||
## What is OpenClaw?
|
||||
|
||||
@@ -1380,8 +1379,7 @@ failures — moved to a dedicated page:
|
||||
## Models, failover, and auth profiles
|
||||
|
||||
Model Q&A — defaults, selection, aliases, switching, failover, auth profiles —
|
||||
moved to a dedicated page:
|
||||
[FAQ — models and auth profiles](/help/faq-models).
|
||||
lives on the [Models FAQ](/help/faq-models).
|
||||
|
||||
## Gateway: ports, "already running", and remote mode
|
||||
|
||||
@@ -1970,6 +1968,6 @@ Still stuck? Ask in [Discord](https://discord.com/invite/clawd) or open a [GitHu
|
||||
|
||||
## Related
|
||||
|
||||
- [FAQ — quick start and first-run setup](/help/faq-first-run)
|
||||
- [FAQ — models and auth profiles](/help/faq-models)
|
||||
- [Troubleshooting](/help/troubleshooting)
|
||||
- [First-run FAQ](/help/faq-first-run) — install, onboard, auth, subscriptions, early failures
|
||||
- [Models FAQ](/help/faq-models) — model selection, failover, auth profiles
|
||||
- [Troubleshooting](/help/troubleshooting) — symptom-first triage
|
||||
|
||||
@@ -1,26 +1,38 @@
|
||||
---
|
||||
summary: "Help hub: common fixes, install sanity, and where to look when something breaks"
|
||||
read_when:
|
||||
- You’re new and want the “what do I click/run” guide
|
||||
- You are new and want a "what do I click/run" guide
|
||||
- Something broke and you want the fastest path to a fix
|
||||
title: "Help"
|
||||
---
|
||||
|
||||
If you want a quick “get unstuck” flow, start here:
|
||||
Quick "get unstuck" path for the most common problems:
|
||||
|
||||
- **Troubleshooting:** [Start here](/help/troubleshooting)
|
||||
- **Install sanity (Node/npm/PATH):** [Install](/install/node#troubleshooting)
|
||||
- **Gateway issues:** [Gateway troubleshooting](/gateway/troubleshooting)
|
||||
- **Logs:** [Logging](/logging) and [Gateway logging](/gateway/logging)
|
||||
- **Repairs:** [Doctor](/gateway/doctor)
|
||||
- [Troubleshooting](/help/troubleshooting) — symptom-first decision tree
|
||||
- [Debugging](/help/debugging) — watch mode, raw streams, dev profile
|
||||
- [Install sanity](/install/node#troubleshooting) — Node / npm / PATH checks
|
||||
- [Gateway troubleshooting](/gateway/troubleshooting) — gateway-specific issues
|
||||
- [Doctor](/gateway/doctor) — automated repair + diagnostic bundle
|
||||
|
||||
If you’re looking for conceptual questions (not “something broke”):
|
||||
## FAQ
|
||||
|
||||
- [FAQ (concepts)](/help/faq)
|
||||
- [FAQ](/help/faq) — day-to-day concepts and operational questions
|
||||
- [First-run FAQ](/help/faq-first-run) — install, onboard, auth, subscriptions, early failures
|
||||
- [Models FAQ](/help/faq-models) — model selection, failover, auth profiles
|
||||
|
||||
## Environment and debugging
|
||||
## Diagnostics
|
||||
|
||||
- **Environment variables:** [Where OpenClaw loads env vars and precedence](/help/environment)
|
||||
- **Debugging:** [Watch mode, raw streams, and dev profile](/help/debugging)
|
||||
- **Testing:** [Test suites, live tests, and Docker runners](/help/testing)
|
||||
- **Scripts:** [Repository helper scripts](/help/scripts)
|
||||
- [Environment variables](/help/environment) — where OpenClaw loads env vars and precedence
|
||||
- [Diagnostics flags](/diagnostics/flags) — runtime diagnostics and verbose modes
|
||||
- [Node + tsx crash](/debug/node-issue) — specific Node / tsx runtime crash scenarios
|
||||
|
||||
## Testing
|
||||
|
||||
- [Testing](/help/testing) — test suites and Docker runners
|
||||
- [Live tests](/help/testing-live) — network-touching provider and CLI smokes
|
||||
|
||||
## Community and meta
|
||||
|
||||
- [OpenClaw lore](/start/lore) — the story
|
||||
- [Docs hubs](/start/hubs) — how this documentation is organized
|
||||
- [Docs directory](/start/docs-directory) — full file map
|
||||
|
||||
@@ -48,7 +48,7 @@ Live tests are split into two layers so we can isolate failures:
|
||||
- `pnpm test:live` (or `OPENCLAW_LIVE_TEST=1` if invoking Vitest directly)
|
||||
- Set `OPENCLAW_LIVE_MODELS=modern` (or `all`, alias for modern) to actually run this suite; otherwise it skips to keep `pnpm test:live` focused on gateway smoke
|
||||
- How to select models:
|
||||
- `OPENCLAW_LIVE_MODELS=modern` to run the modern allowlist (Opus/Sonnet 4.6+, GPT-5.2 + Codex, Gemini 3, GLM 4.7, MiniMax M2.7, Grok 4)
|
||||
- `OPENCLAW_LIVE_MODELS=modern` to run the modern allowlist (Opus/Sonnet 4.6+, GPT-5.2 + Codex, Gemini 3, DeepSeek V4, GLM 4.7, MiniMax M2.7, Grok 4)
|
||||
- `OPENCLAW_LIVE_MODELS=all` is an alias for the modern allowlist
|
||||
- or `OPENCLAW_LIVE_MODELS="openai/gpt-5.2,openai-codex/gpt-5.2,anthropic/claude-opus-4-6,..."` (comma allowlist)
|
||||
- Modern/all sweeps default to a curated high-signal cap; set `OPENCLAW_LIVE_MAX_MODELS=0` for an exhaustive modern sweep or a positive number for a smaller cap.
|
||||
@@ -82,7 +82,7 @@ Live tests are split into two layers so we can isolate failures:
|
||||
- How to enable:
|
||||
- `pnpm test:live` (or `OPENCLAW_LIVE_TEST=1` if invoking Vitest directly)
|
||||
- How to select models:
|
||||
- Default: modern allowlist (Opus/Sonnet 4.6+, GPT-5.2 + Codex, Gemini 3, GLM 4.7, MiniMax M2.7, Grok 4)
|
||||
- Default: modern allowlist (Opus/Sonnet 4.6+, GPT-5.2 + Codex, Gemini 3, DeepSeek V4, GLM 4.7, MiniMax M2.7, Grok 4)
|
||||
- `OPENCLAW_LIVE_GATEWAY_MODELS=all` is an alias for the modern allowlist
|
||||
- Or set `OPENCLAW_LIVE_GATEWAY_MODELS="provider/model"` (or comma list) to narrow
|
||||
- Modern/all gateway sweeps default to a curated high-signal cap; set `OPENCLAW_LIVE_GATEWAY_MAX_MODELS=0` for an exhaustive modern sweep or a positive number for a smaller cap.
|
||||
@@ -124,7 +124,8 @@ openclaw models list --json
|
||||
- `OPENCLAW_LIVE_CLI_BACKEND_IMAGE_ARG="--image"` to pass image file paths as CLI args instead of prompt injection.
|
||||
- `OPENCLAW_LIVE_CLI_BACKEND_IMAGE_MODE="repeat"` (or `"list"`) to control how image args are passed when `IMAGE_ARG` is set.
|
||||
- `OPENCLAW_LIVE_CLI_BACKEND_RESUME_PROBE=1` to send a second turn and validate resume flow.
|
||||
- `OPENCLAW_LIVE_CLI_BACKEND_MODEL_SWITCH_PROBE=0` to disable the default Claude Sonnet -> Opus same-session continuity probe (set to `1` to force it on when the selected model supports a switch target).
|
||||
- `OPENCLAW_LIVE_CLI_BACKEND_MODEL_SWITCH_PROBE=1` to opt into the Claude Sonnet -> Opus same-session continuity probe when the selected model supports a switch target. Docker recipes default this off for aggregate reliability.
|
||||
- `OPENCLAW_LIVE_CLI_BACKEND_MCP_PROBE=1` to opt into the MCP/tool loopback probe. Docker recipes default this off unless explicitly requested.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -287,12 +288,17 @@ Narrow, explicit allowlists are fastest and least flaky:
|
||||
- `OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.2" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts`
|
||||
|
||||
- Tool calling across several providers:
|
||||
- `OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.2,openai-codex/gpt-5.2,anthropic/claude-opus-4-6,google/gemini-3-flash-preview,zai/glm-4.7,minimax/MiniMax-M2.7" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts`
|
||||
- `OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.2,openai-codex/gpt-5.2,anthropic/claude-opus-4-6,google/gemini-3-flash-preview,deepseek/deepseek-v4-flash,zai/glm-4.7,minimax/MiniMax-M2.7" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts`
|
||||
|
||||
- Google focus (Gemini API key + Antigravity):
|
||||
- Gemini (API key): `OPENCLAW_LIVE_GATEWAY_MODELS="google/gemini-3-flash-preview" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts`
|
||||
- Antigravity (OAuth): `OPENCLAW_LIVE_GATEWAY_MODELS="google-antigravity/claude-opus-4-6-thinking,google-antigravity/gemini-3-pro-high" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts`
|
||||
|
||||
- Google adaptive thinking smoke:
|
||||
- If local keys live in shell profile: `source ~/.profile`
|
||||
- Gemini 3 dynamic default: `pnpm openclaw qa manual --provider-mode live-frontier --model google/gemini-3.1-pro-preview --alt-model google/gemini-3.1-pro-preview --message '/think adaptive Reply exactly: GEMINI_ADAPTIVE_OK' --timeout-ms 180000`
|
||||
- Gemini 2.5 dynamic budget: `pnpm openclaw qa manual --provider-mode live-frontier --model google/gemini-2.5-flash --alt-model google/gemini-2.5-flash --message '/think adaptive Reply exactly: GEMINI25_ADAPTIVE_OK' --timeout-ms 180000`
|
||||
|
||||
Notes:
|
||||
|
||||
- `google/...` uses the Gemini API (API key).
|
||||
@@ -315,11 +321,12 @@ This is the “common models” run we expect to keep working:
|
||||
- Anthropic: `anthropic/claude-opus-4-6` (or `anthropic/claude-sonnet-4-6`)
|
||||
- Google (Gemini API): `google/gemini-3.1-pro-preview` and `google/gemini-3-flash-preview` (avoid older Gemini 2.x models)
|
||||
- Google (Antigravity): `google-antigravity/claude-opus-4-6-thinking` and `google-antigravity/gemini-3-flash`
|
||||
- DeepSeek: `deepseek/deepseek-v4-flash` and `deepseek/deepseek-v4-pro`
|
||||
- Z.AI (GLM): `zai/glm-4.7`
|
||||
- MiniMax: `minimax/MiniMax-M2.7`
|
||||
|
||||
Run gateway smoke with tools + image:
|
||||
`OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.2,openai-codex/gpt-5.2,anthropic/claude-opus-4-6,google/gemini-3.1-pro-preview,google/gemini-3-flash-preview,google-antigravity/claude-opus-4-6-thinking,google-antigravity/gemini-3-flash,zai/glm-4.7,minimax/MiniMax-M2.7" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts`
|
||||
`OPENCLAW_LIVE_GATEWAY_MODELS="openai/gpt-5.2,openai-codex/gpt-5.2,anthropic/claude-opus-4-6,google/gemini-3.1-pro-preview,google/gemini-3-flash-preview,google-antigravity/claude-opus-4-6-thinking,google-antigravity/gemini-3-flash,deepseek/deepseek-v4-flash,zai/glm-4.7,minimax/MiniMax-M2.7" pnpm test:live src/gateway/gateway-models.profiles.live.test.ts`
|
||||
|
||||
### Baseline: tool calling (Read + optional Exec)
|
||||
|
||||
@@ -328,6 +335,7 @@ Pick at least one per provider family:
|
||||
- OpenAI: `openai/gpt-5.2`
|
||||
- Anthropic: `anthropic/claude-opus-4-6` (or `anthropic/claude-sonnet-4-6`)
|
||||
- Google: `google/gemini-3-flash-preview` (or `google/gemini-3.1-pro-preview`)
|
||||
- DeepSeek: `deepseek/deepseek-v4-flash`
|
||||
- Z.AI (GLM): `zai/glm-4.7`
|
||||
- MiniMax: `minimax/MiniMax-M2.7`
|
||||
|
||||
@@ -387,7 +395,7 @@ If you want to rely on env keys (e.g. exported in your `~/.profile`), run local
|
||||
- Enable: `OPENCLAW_LIVE_TEST=1 COMFY_LIVE_TEST=1 pnpm test:live -- extensions/comfy/comfy.live.test.ts`
|
||||
- Scope:
|
||||
- Exercises the bundled comfy image, video, and `music_generate` paths
|
||||
- Skips each capability unless `models.providers.comfy.<capability>` is configured
|
||||
- Skips each capability unless `plugins.entries.comfy.config.<capability>` is configured
|
||||
- Useful after changing comfy workflow submission, polling, downloads, or plugin registration
|
||||
|
||||
## Image generation live
|
||||
@@ -400,11 +408,9 @@ If you want to rely on env keys (e.g. exported in your `~/.profile`), run local
|
||||
- Loads missing provider env vars from your login shell (`~/.profile`) before probing
|
||||
- Uses live/env API keys ahead of stored auth profiles by default, so stale test keys in `auth-profiles.json` do not mask real shell credentials
|
||||
- Skips providers with no usable auth/profile/model
|
||||
- Runs the stock image-generation variants through the shared runtime capability:
|
||||
- `google:flash-generate`
|
||||
- `google:pro-generate`
|
||||
- `google:pro-edit`
|
||||
- `openai:default-generate`
|
||||
- Runs each configured provider through the shared image-generation runtime:
|
||||
- `<provider>:generate`
|
||||
- `<provider>:edit` when the provider declares edit support
|
||||
- Current bundled providers covered:
|
||||
- `fal`
|
||||
- `google`
|
||||
@@ -420,6 +426,23 @@ If you want to rely on env keys (e.g. exported in your `~/.profile`), run local
|
||||
- Optional auth behavior:
|
||||
- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` to force profile-store auth and ignore env-only overrides
|
||||
|
||||
For the shipped CLI path, add an `infer` smoke after the provider/runtime live
|
||||
test passes:
|
||||
|
||||
```bash
|
||||
OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_INFER_CLI_TEST=1 pnpm test:live -- test/image-generation.infer-cli.live.test.ts
|
||||
openclaw infer image providers --json
|
||||
openclaw infer image generate \
|
||||
--model google/gemini-3.1-flash-image-preview \
|
||||
--prompt "Minimal flat test image: one blue square on a white background, no text." \
|
||||
--output ./openclaw-infer-image-smoke.png \
|
||||
--json
|
||||
```
|
||||
|
||||
This covers CLI argument parsing, config/default-agent resolution, bundled
|
||||
plugin activation, on-demand bundled runtime-dependency repair, the shared
|
||||
image-generation runtime, and the live provider request.
|
||||
|
||||
## Music generation live
|
||||
|
||||
- Test: `extensions/music-generation-providers.live.test.ts`
|
||||
|
||||
@@ -112,7 +112,16 @@ runs the same lanes before release approval.
|
||||
live Telegram QA lane with that installed package as the SUT Gateway.
|
||||
- Defaults to `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@beta`.
|
||||
- Uses the same Telegram env credentials or Convex credential source as
|
||||
`pnpm openclaw qa telegram`.
|
||||
`pnpm openclaw qa telegram`. For CI/release automation, set
|
||||
`OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex` plus
|
||||
`OPENCLAW_QA_CONVEX_SITE_URL` and the role secret. If
|
||||
`OPENCLAW_QA_CONVEX_SITE_URL` and a Convex role secret are present in CI,
|
||||
the Docker wrapper selects Convex automatically.
|
||||
- `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci|maintainer` overrides the shared
|
||||
`OPENCLAW_QA_CREDENTIAL_ROLE` for this lane only.
|
||||
- GitHub Actions exposes this lane as the manual maintainer workflow
|
||||
`NPM Telegram Beta E2E`. It does not run on merge. The workflow uses the
|
||||
`qa-live-shared` environment and Convex CI credential leases.
|
||||
- `pnpm test:docker:bundled-channel-deps`
|
||||
- Packs and installs the current OpenClaw build in Docker, starts the Gateway
|
||||
with OpenAI configured, then enables bundled channel/plugins via config
|
||||
@@ -125,6 +134,37 @@ runs the same lanes before release approval.
|
||||
`openclaw update --tag <candidate>`, and verifies the candidate's
|
||||
post-update doctor repairs bundled channel runtime dependencies without a
|
||||
harness-side postinstall repair.
|
||||
- `pnpm test:parallels:npm-update`
|
||||
- Runs the native packaged-install update smoke across Parallels guests. Each
|
||||
selected platform first installs the requested baseline package, then runs
|
||||
the installed `openclaw update` command in the same guest and verifies the
|
||||
installed version, update status, gateway readiness, and one local agent
|
||||
turn.
|
||||
- Use `--platform macos`, `--platform windows`, or `--platform linux` while
|
||||
iterating on one guest. Use `--json` for the summary artifact path and
|
||||
per-lane status.
|
||||
- Wrap long local runs in a host timeout so Parallels transport stalls cannot
|
||||
consume the rest of the testing window:
|
||||
|
||||
```bash
|
||||
timeout --foreground 150m pnpm test:parallels:npm-update -- --json
|
||||
timeout --foreground 90m pnpm test:parallels:npm-update -- --platform windows --json
|
||||
```
|
||||
|
||||
- The script writes nested lane logs under `/tmp/openclaw-parallels-npm-update.*`.
|
||||
Inspect `windows-update.log`, `macos-update.log`, or `linux-update.log`
|
||||
before assuming the outer wrapper is hung.
|
||||
- Windows update can spend 10 to 15 minutes in post-update doctor/runtime
|
||||
dependency repair on a cold guest; that is still healthy when the nested
|
||||
npm debug log is advancing.
|
||||
- Do not run this aggregate wrapper in parallel with individual Parallels
|
||||
macOS, Windows, or Linux smoke lanes. They share VM state and can collide on
|
||||
snapshot restore, package serving, or guest gateway state.
|
||||
- The post-update proof runs the normal bundled plugin surface because
|
||||
capability facades such as speech, image generation, and media
|
||||
understanding are loaded through bundled runtime APIs even when the agent
|
||||
turn itself only checks a simple text response.
|
||||
|
||||
- `pnpm openclaw qa aimock`
|
||||
- Starts only the local AIMock provider server for direct protocol smoke
|
||||
testing.
|
||||
@@ -138,6 +178,7 @@ runs the same lanes before release approval.
|
||||
- Uses the pinned stable Tuwunel image `ghcr.io/matrix-construct/tuwunel:v1.5.1` by default. Override with `OPENCLAW_QA_MATRIX_TUWUNEL_IMAGE` when you need to test a different image.
|
||||
- Matrix does not expose shared credential-source flags because the lane provisions disposable users locally.
|
||||
- Writes a Matrix QA report, summary, observed-events artifact, and combined stdout/stderr output log under `.artifacts/qa-e2e/...`.
|
||||
- Emits progress by default and enforces a hard run timeout with `OPENCLAW_QA_MATRIX_TIMEOUT_MS` (default 30 minutes). Cleanup is bounded by `OPENCLAW_QA_MATRIX_CLEANUP_TIMEOUT_MS` and failures include the recovery `docker compose ... down --remove-orphans` command.
|
||||
- `pnpm openclaw qa telegram`
|
||||
- Runs the Telegram live QA lane against a real private group using the driver and SUT bot tokens from env.
|
||||
- Requires `OPENCLAW_QA_TELEGRAM_GROUP_ID`, `OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN`, and `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN`. The group id must be the numeric Telegram chat id.
|
||||
@@ -196,12 +237,16 @@ Maintainer admin commands (pool add/remove/list) require
|
||||
CLI helpers for maintainers:
|
||||
|
||||
```bash
|
||||
pnpm openclaw qa credentials doctor
|
||||
pnpm openclaw qa credentials add --kind telegram --payload-file qa/telegram-credential.json
|
||||
pnpm openclaw qa credentials list --kind telegram
|
||||
pnpm openclaw qa credentials remove --credential-id <credential-id>
|
||||
```
|
||||
|
||||
Use `--json` for machine-readable output in scripts and CI utilities.
|
||||
Use `doctor` before live runs to check the Convex site URL, broker secrets,
|
||||
endpoint prefix, HTTP timeout, and admin/list reachability without printing
|
||||
secret values. Use `--json` for machine-readable output in scripts and CI
|
||||
utilities.
|
||||
|
||||
Default endpoint contract (`OPENCLAW_QA_CONVEX_SITE_URL` + `/qa-credentials/v1`):
|
||||
|
||||
@@ -326,81 +371,100 @@ Think of the suites as “increasing realism” (and increasing flakiness/cost):
|
||||
- Runs in CI
|
||||
- No real keys required
|
||||
- Should be fast and stable
|
||||
<AccordionGroup>
|
||||
<Accordion title="Projects, shards, and scoped lanes"> - Untargeted `pnpm test` runs twelve smaller shard configs (`core-unit-fast`, `core-unit-src`, `core-unit-security`, `core-unit-ui`, `core-unit-support`, `core-support-boundary`, `core-contracts`, `core-bundled`, `core-runtime`, `agentic`, `auto-reply`, `extensions`) instead of one giant native root-project process. This cuts peak RSS on loaded machines and avoids auto-reply/extension work starving unrelated suites. - `pnpm test --watch` still uses the native root `vitest.config.ts` project graph, because a multi-shard watch loop is not practical. - `pnpm test`, `pnpm test:watch`, and `pnpm test:perf:imports` route explicit file/directory targets through scoped lanes first, so `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` avoids paying the full root project startup tax. - `pnpm test:changed` expands changed git paths into the same scoped lanes when the diff only touches routable source/test files; config/setup edits still fall back to the broad root-project rerun. - `pnpm check:changed` is the normal smart local gate for narrow work. It classifies the diff into core, core tests, extensions, extension tests, apps, docs, release metadata, and tooling, then runs the matching typecheck/lint/test lanes. Public Plugin SDK and plugin-contract changes include one extension validation pass because extensions depend on those core contracts. Release metadata-only version bumps run targeted version/config/root-dependency checks instead of the full suite, with a guard that rejects package changes outside the top-level version field. - Import-light unit tests from agents, commands, plugins, auto-reply helpers, `plugin-sdk`, and similar pure utility areas route through the `unit-fast` lane, which skips `test/setup-openclaw-runtime.ts`; stateful/runtime-heavy files stay on the existing lanes. - Selected `plugin-sdk` and `commands` helper source files also map changed-mode runs to explicit sibling tests in those light lanes, so helper edits avoid rerunning the full heavy suite for that directory. - `auto-reply` has three dedicated buckets: top-level core helpers, top-level `reply.*` integration tests, and the `src/auto-reply/reply/**` subtree. This keeps the heaviest reply harness work off the cheap status/chunk/token tests.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Embedded runner coverage">
|
||||
- When you change message-tool discovery inputs or compaction runtime
|
||||
context, keep both levels of coverage.
|
||||
- Add focused helper regressions for pure routing and normalization
|
||||
boundaries.
|
||||
- Keep the embedded runner integration suites healthy:
|
||||
`src/agents/pi-embedded-runner/compact.hooks.test.ts`,
|
||||
`src/agents/pi-embedded-runner/run.overflow-compaction.test.ts`, and
|
||||
`src/agents/pi-embedded-runner/run.overflow-compaction.loop.test.ts`.
|
||||
- Those suites verify that scoped ids and compaction behavior still flow
|
||||
through the real `run.ts` / `compact.ts` paths; helper-only tests are
|
||||
not a sufficient substitute for those integration paths.
|
||||
</Accordion>
|
||||
<AccordionGroup>
|
||||
<Accordion title="Projects, shards, and scoped lanes">
|
||||
|
||||
<Accordion title="Vitest pool and isolation defaults">
|
||||
- Base Vitest config defaults to `threads`.
|
||||
- The shared Vitest config fixes `isolate: false` and uses the
|
||||
non-isolated runner across the root projects, e2e, and live configs.
|
||||
- The root UI lane keeps its `jsdom` setup and optimizer, but runs on the
|
||||
shared non-isolated runner too.
|
||||
- Each `pnpm test` shard inherits the same `threads` + `isolate: false`
|
||||
defaults from the shared Vitest config.
|
||||
- `scripts/run-vitest.mjs` adds `--no-maglev` for Vitest child Node
|
||||
processes by default to reduce V8 compile churn during big local runs.
|
||||
Set `OPENCLAW_VITEST_ENABLE_MAGLEV=1` to compare against stock V8
|
||||
behavior.
|
||||
</Accordion>
|
||||
- Untargeted `pnpm test` runs twelve smaller shard configs (`core-unit-fast`, `core-unit-src`, `core-unit-security`, `core-unit-ui`, `core-unit-support`, `core-support-boundary`, `core-contracts`, `core-bundled`, `core-runtime`, `agentic`, `auto-reply`, `extensions`) instead of one giant native root-project process. This cuts peak RSS on loaded machines and avoids auto-reply/extension work starving unrelated suites.
|
||||
- `pnpm test --watch` still uses the native root `vitest.config.ts` project graph, because a multi-shard watch loop is not practical.
|
||||
- `pnpm test`, `pnpm test:watch`, and `pnpm test:perf:imports` route explicit file/directory targets through scoped lanes first, so `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` avoids paying the full root project startup tax.
|
||||
- `pnpm test:changed` expands changed git paths into the same scoped lanes when the diff only touches routable source/test files; config/setup edits still fall back to the broad root-project rerun.
|
||||
- `pnpm check:changed` is the normal smart local gate for narrow work. It classifies the diff into core, core tests, extensions, extension tests, apps, docs, release metadata, and tooling, then runs the matching typecheck/lint/test lanes. Public Plugin SDK and plugin-contract changes include one extension validation pass because extensions depend on those core contracts. Release metadata-only version bumps run targeted version/config/root-dependency checks instead of the full suite, with a guard that rejects package changes outside the top-level version field.
|
||||
- Import-light unit tests from agents, commands, plugins, auto-reply helpers, `plugin-sdk`, and similar pure utility areas route through the `unit-fast` lane, which skips `test/setup-openclaw-runtime.ts`; stateful/runtime-heavy files stay on the existing lanes.
|
||||
- Selected `plugin-sdk` and `commands` helper source files also map changed-mode runs to explicit sibling tests in those light lanes, so helper edits avoid rerunning the full heavy suite for that directory.
|
||||
- `auto-reply` has three dedicated buckets: top-level core helpers, top-level `reply.*` integration tests, and the `src/auto-reply/reply/**` subtree. This keeps the heaviest reply harness work off the cheap status/chunk/token tests.
|
||||
|
||||
<Accordion title="Fast local iteration">
|
||||
- `pnpm changed:lanes` shows which architectural lanes a diff triggers.
|
||||
- The pre-commit hook is formatting-only. It restages formatted files and
|
||||
does not run lint, typecheck, or tests.
|
||||
- Run `pnpm check:changed` explicitly before handoff or push when you
|
||||
need the smart local gate. Public Plugin SDK and plugin-contract
|
||||
changes include one extension validation pass.
|
||||
- `pnpm test:changed` routes through scoped lanes when the changed paths
|
||||
map cleanly to a smaller suite.
|
||||
- `pnpm test:max` and `pnpm test:changed:max` keep the same routing
|
||||
behavior, just with a higher worker cap.
|
||||
- Local worker auto-scaling is intentionally conservative and backs off
|
||||
when the host load average is already high, so multiple concurrent
|
||||
Vitest runs do less damage by default.
|
||||
- The base Vitest config marks the projects/config files as
|
||||
`forceRerunTriggers` so changed-mode reruns stay correct when test
|
||||
wiring changes.
|
||||
- The config keeps `OPENCLAW_VITEST_FS_MODULE_CACHE` enabled on supported
|
||||
hosts; set `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path` if you want
|
||||
one explicit cache location for direct profiling.
|
||||
</Accordion>
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Perf debugging">
|
||||
- `pnpm test:perf:imports` enables Vitest import-duration reporting plus
|
||||
import-breakdown output.
|
||||
- `pnpm test:perf:imports:changed` scopes the same profiling view to
|
||||
files changed since `origin/main`.
|
||||
- When one hot test still spends most of its time in startup imports,
|
||||
keep heavy dependencies behind a narrow local `*.runtime.ts` seam and
|
||||
mock that seam directly instead of deep-importing runtime helpers just
|
||||
to pass them through `vi.mock(...)`.
|
||||
- `pnpm test:perf:changed:bench -- --ref <git-ref>` compares routed
|
||||
`test:changed` against the native root-project path for that committed
|
||||
diff and prints wall time plus macOS max RSS.
|
||||
- `pnpm test:perf:changed:bench -- --worktree` benchmarks the current
|
||||
dirty tree by routing the changed file list through
|
||||
`scripts/test-projects.mjs` and the root Vitest config.
|
||||
- `pnpm test:perf:profile:main` writes a main-thread CPU profile for
|
||||
Vitest/Vite startup and transform overhead.
|
||||
- `pnpm test:perf:profile:runner` writes runner CPU+heap profiles for the
|
||||
unit suite with file parallelism disabled.
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
<Accordion title="Embedded runner coverage">
|
||||
|
||||
- When you change message-tool discovery inputs or compaction runtime
|
||||
context, keep both levels of coverage.
|
||||
- Add focused helper regressions for pure routing and normalization
|
||||
boundaries.
|
||||
- Keep the embedded runner integration suites healthy:
|
||||
`src/agents/pi-embedded-runner/compact.hooks.test.ts`,
|
||||
`src/agents/pi-embedded-runner/run.overflow-compaction.test.ts`, and
|
||||
`src/agents/pi-embedded-runner/run.overflow-compaction.loop.test.ts`.
|
||||
- Those suites verify that scoped ids and compaction behavior still flow
|
||||
through the real `run.ts` / `compact.ts` paths; helper-only tests are
|
||||
not a sufficient substitute for those integration paths.
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Vitest pool and isolation defaults">
|
||||
|
||||
- Base Vitest config defaults to `threads`.
|
||||
- The shared Vitest config fixes `isolate: false` and uses the
|
||||
non-isolated runner across the root projects, e2e, and live configs.
|
||||
- The root UI lane keeps its `jsdom` setup and optimizer, but runs on the
|
||||
shared non-isolated runner too.
|
||||
- Each `pnpm test` shard inherits the same `threads` + `isolate: false`
|
||||
defaults from the shared Vitest config.
|
||||
- `scripts/run-vitest.mjs` adds `--no-maglev` for Vitest child Node
|
||||
processes by default to reduce V8 compile churn during big local runs.
|
||||
Set `OPENCLAW_VITEST_ENABLE_MAGLEV=1` to compare against stock V8
|
||||
behavior.
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Fast local iteration">
|
||||
|
||||
- `pnpm changed:lanes` shows which architectural lanes a diff triggers.
|
||||
- The pre-commit hook is formatting-only. It restages formatted files and
|
||||
does not run lint, typecheck, or tests.
|
||||
- Run `pnpm check:changed` explicitly before handoff or push when you
|
||||
need the smart local gate. Public Plugin SDK and plugin-contract
|
||||
changes include one extension validation pass.
|
||||
- `pnpm test:changed` routes through scoped lanes when the changed paths
|
||||
map cleanly to a smaller suite.
|
||||
- `pnpm test:max` and `pnpm test:changed:max` keep the same routing
|
||||
behavior, just with a higher worker cap.
|
||||
- Local worker auto-scaling is intentionally conservative and backs off
|
||||
when the host load average is already high, so multiple concurrent
|
||||
Vitest runs do less damage by default.
|
||||
- The base Vitest config marks the projects/config files as
|
||||
`forceRerunTriggers` so changed-mode reruns stay correct when test
|
||||
wiring changes.
|
||||
- The config keeps `OPENCLAW_VITEST_FS_MODULE_CACHE` enabled on supported
|
||||
hosts; set `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path` if you want
|
||||
one explicit cache location for direct profiling.
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Perf debugging">
|
||||
|
||||
- `pnpm test:perf:imports` enables Vitest import-duration reporting plus
|
||||
import-breakdown output.
|
||||
- `pnpm test:perf:imports:changed` scopes the same profiling view to
|
||||
files changed since `origin/main`.
|
||||
- When one hot test still spends most of its time in startup imports,
|
||||
keep heavy dependencies behind a narrow local `*.runtime.ts` seam and
|
||||
mock that seam directly instead of deep-importing runtime helpers just
|
||||
to pass them through `vi.mock(...)`.
|
||||
- `pnpm test:perf:changed:bench -- --ref <git-ref>` compares routed
|
||||
`test:changed` against the native root-project path for that committed
|
||||
diff and prints wall time plus macOS max RSS.
|
||||
- `pnpm test:perf:changed:bench -- --worktree` benchmarks the current
|
||||
dirty tree by routing the changed file list through
|
||||
`scripts/test-projects.mjs` and the root Vitest config.
|
||||
- `pnpm test:perf:profile:main` writes a main-thread CPU profile for
|
||||
Vitest/Vite startup and transform overhead.
|
||||
- `pnpm test:perf:profile:runner` writes runner CPU+heap profiles for the
|
||||
unit suite with file parallelism disabled.
|
||||
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
### Stability (gateway)
|
||||
|
||||
@@ -504,8 +568,8 @@ These Docker runners split into two buckets:
|
||||
`OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=45000`, and
|
||||
`OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`. Override those env vars when you
|
||||
explicitly want the larger exhaustive scan.
|
||||
- `test:docker:all` builds the live Docker image once via `test:docker:live-build`, then reuses it for the two live Docker lanes. It also builds one shared `scripts/e2e/Dockerfile` image via `test:docker:e2e-build` and reuses it for the E2E container smoke runners that exercise the built app.
|
||||
- Container smoke runners: `test:docker:openwebui`, `test:docker:onboard`, `test:docker:npm-onboard-channel-agent`, `test:docker:gateway-network`, `test:docker:mcp-channels`, `test:docker:pi-bundle-mcp-tools`, `test:docker:cron-mcp-cleanup`, `test:docker:plugins`, `test:docker:plugin-update`, and `test:docker:config-reload` boot one or more real containers and verify higher-level integration paths.
|
||||
- `test:docker:all` builds the live Docker image once via `test:docker:live-build`, then reuses it for the live Docker lanes. It also builds one shared `scripts/e2e/Dockerfile` image via `test:docker:e2e-build` and reuses it for the E2E container smoke runners that exercise the built app. The aggregate uses a weighted local scheduler: `OPENCLAW_DOCKER_ALL_PARALLELISM` controls process slots, while resource caps keep heavy live, npm-install, and multi-service lanes from all starting at once. Defaults are 10 slots, `OPENCLAW_DOCKER_ALL_LIVE_LIMIT=6`, `OPENCLAW_DOCKER_ALL_NPM_LIMIT=8`, and `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`; tune `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` or `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT` only when the Docker host has more headroom. The runner performs a Docker preflight by default, removes stale OpenClaw E2E containers, prints status every 30 seconds, stores successful lane timings in `.artifacts/docker-tests/lane-timings.json`, and uses those timings to start longer lanes first on later runs. Use `OPENCLAW_DOCKER_ALL_DRY_RUN=1` to print the weighted lane manifest without building or running Docker.
|
||||
- Container smoke runners: `test:docker:openwebui`, `test:docker:onboard`, `test:docker:npm-onboard-channel-agent`, `test:docker:agents-delete-shared-workspace`, `test:docker:gateway-network`, `test:docker:mcp-channels`, `test:docker:pi-bundle-mcp-tools`, `test:docker:cron-mcp-cleanup`, `test:docker:plugins`, `test:docker:plugin-update`, and `test:docker:config-reload` boot one or more real containers and verify higher-level integration paths.
|
||||
|
||||
The live-model Docker runners also bind-mount only the needed CLI auth homes (or all supported ones when the run is not narrowed), then copy them into the container home before the run so external-CLI OAuth can refresh tokens without mutating the host auth store:
|
||||
|
||||
@@ -516,10 +580,11 @@ The live-model Docker runners also bind-mount only the needed CLI auth homes (or
|
||||
- Gateway + dev agent: `pnpm test:docker:live-gateway` (script: `scripts/test-live-gateway-models-docker.sh`)
|
||||
- Open WebUI live smoke: `pnpm test:docker:openwebui` (script: `scripts/e2e/openwebui-docker.sh`)
|
||||
- Onboarding wizard (TTY, full scaffolding): `pnpm test:docker:onboard` (script: `scripts/e2e/onboard-docker.sh`)
|
||||
- Npm tarball onboarding/channel/agent smoke: `pnpm test:docker:npm-onboard-channel-agent` installs the packed OpenClaw tarball globally in Docker, configures OpenAI via env-ref onboarding plus Telegram by default, verifies enabling the plugin installs its runtime deps on demand, runs doctor, and runs one mocked OpenAI agent turn. Reuse a prebuilt tarball with `OPENCLAW_NPM_ONBOARD_PACKAGE_TGZ=/path/to/openclaw-*.tgz`, skip the host rebuild with `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0`, or switch channel with `OPENCLAW_NPM_ONBOARD_CHANNEL=discord`.
|
||||
- Npm tarball onboarding/channel/agent smoke: `pnpm test:docker:npm-onboard-channel-agent` installs the packed OpenClaw tarball globally in Docker, configures OpenAI via env-ref onboarding plus Telegram by default, verifies doctor repairs activated plugin runtime deps, and runs one mocked OpenAI agent turn. Reuse a prebuilt tarball with `OPENCLAW_NPM_ONBOARD_PACKAGE_TGZ=/path/to/openclaw-*.tgz`, skip the host rebuild with `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0`, or switch channel with `OPENCLAW_NPM_ONBOARD_CHANNEL=discord`.
|
||||
- Bun global install smoke: `bash scripts/e2e/bun-global-install-smoke.sh` packs the current tree, installs it with `bun install -g` in an isolated home, and verifies `openclaw infer image providers --json` returns bundled image providers instead of hanging. Reuse a prebuilt tarball with `OPENCLAW_BUN_GLOBAL_SMOKE_PACKAGE_TGZ=/path/to/openclaw-*.tgz`, skip the host build with `OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD=0`, or copy `dist/` from a built Docker image with `OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE=openclaw-dockerfile-smoke:local`.
|
||||
- Installer Docker smoke: `bash scripts/test-install-sh-docker.sh` shares one npm cache across its root, update, and direct-npm containers. Update smoke defaults to npm `latest` as the stable baseline before upgrading to the candidate tarball. Non-root installer checks keep an isolated npm cache so root-owned cache entries do not mask user-local install behavior. Set `OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR=/path/to/cache` to reuse the root/update/direct-npm cache across local reruns.
|
||||
- Install Smoke CI skips the duplicate direct-npm global update with `OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL=1`; run the script locally without that env when direct `npm install -g` coverage is needed.
|
||||
- Agents delete shared workspace CLI smoke: `pnpm test:docker:agents-delete-shared-workspace` (script: `scripts/e2e/agents-delete-shared-workspace-docker.sh`) builds the root Dockerfile image by default, seeds two agents with one workspace in an isolated container home, runs `agents delete --json`, and verifies valid JSON plus retained workspace behavior. Reuse the install-smoke image with `OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE=openclaw-dockerfile-smoke:local OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD=1`.
|
||||
- Gateway networking (two containers, WS auth + health): `pnpm test:docker:gateway-network` (script: `scripts/e2e/gateway-network-docker.sh`)
|
||||
- OpenAI Responses web_search minimal reasoning regression: `pnpm test:docker:openai-web-search-minimal` (script: `scripts/e2e/openai-web-search-minimal-docker.sh`) runs a mocked OpenAI server through Gateway, verifies `web_search` raises `reasoning.effort` from `minimal` to `low`, then forces the provider schema reject and checks the raw detail appears in Gateway logs.
|
||||
- MCP channel bridge (seeded Gateway + stdio bridge + raw Claude notification-frame smoke): `pnpm test:docker:mcp-channels` (script: `scripts/e2e/mcp-channels-docker.sh`)
|
||||
@@ -528,7 +593,7 @@ The live-model Docker runners also bind-mount only the needed CLI auth homes (or
|
||||
- Plugins (install smoke + `/plugin` alias + Claude-bundle restart semantics): `pnpm test:docker:plugins` (script: `scripts/e2e/plugins-docker.sh`)
|
||||
- Plugin update unchanged smoke: `pnpm test:docker:plugin-update` (script: `scripts/e2e/plugin-update-unchanged-docker.sh`)
|
||||
- Config reload metadata smoke: `pnpm test:docker:config-reload` (script: `scripts/e2e/config-reload-source-docker.sh`)
|
||||
- Bundled plugin runtime deps: `pnpm test:docker:bundled-channel-deps` builds a small Docker runner image by default, builds and packs OpenClaw once on the host, then mounts that tarball into each Linux install scenario. Reuse the image with `OPENCLAW_SKIP_DOCKER_BUILD=1`, skip the host rebuild after a fresh local build with `OPENCLAW_BUNDLED_CHANNEL_HOST_BUILD=0`, or point at an existing tarball with `OPENCLAW_BUNDLED_CHANNEL_PACKAGE_TGZ=/path/to/openclaw-*.tgz`.
|
||||
- Bundled plugin runtime deps: `pnpm test:docker:bundled-channel-deps` builds a small Docker runner image by default, builds and packs OpenClaw once on the host, then mounts that tarball into each Linux install scenario. Reuse the image with `OPENCLAW_SKIP_DOCKER_BUILD=1`, skip the host rebuild after a fresh local build with `OPENCLAW_BUNDLED_CHANNEL_HOST_BUILD=0`, or point at an existing tarball with `OPENCLAW_BUNDLED_CHANNEL_PACKAGE_TGZ=/path/to/openclaw-*.tgz`. The full Docker aggregate pre-packs this tarball once, then shards bundled channel checks into independent lanes, including separate update lanes for Telegram, Discord, Slack, Feishu, memory-lancedb, and ACPX. Use `OPENCLAW_BUNDLED_CHANNELS=telegram,slack` to narrow the channel matrix when running the bundled lane directly, or `OPENCLAW_BUNDLED_CHANNEL_UPDATE_TARGETS=telegram,acpx` to narrow the update scenario. The lane also verifies that `channels.<id>.enabled=false` and `plugins.entries.<id>.enabled=false` suppress doctor/runtime-dependency repair.
|
||||
- Narrow bundled plugin runtime deps while iterating by disabling unrelated scenarios, for example:
|
||||
`OPENCLAW_BUNDLED_CHANNEL_SCENARIOS=0 OPENCLAW_BUNDLED_CHANNEL_UPDATE_SCENARIO=0 OPENCLAW_BUNDLED_CHANNEL_ROOT_OWNED_SCENARIO=0 OPENCLAW_BUNDLED_CHANNEL_SETUP_ENTRY_SCENARIO=0 pnpm test:docker:bundled-channel-deps`.
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@ read_when:
|
||||
title: "General troubleshooting"
|
||||
---
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
If you only have 2 minutes, use this page as a triage front door.
|
||||
|
||||
## First 60 seconds
|
||||
|
||||
@@ -105,6 +105,17 @@ If your old installation had local-only encrypted history that was never backed
|
||||
openclaw matrix verify device "<your-recovery-key>"
|
||||
```
|
||||
|
||||
If the recovery key is accepted and backup is usable, but `Cross-signing verified`
|
||||
is still `no`, complete self-verification from another Matrix client:
|
||||
|
||||
```bash
|
||||
openclaw matrix verify self
|
||||
```
|
||||
|
||||
Accept the request in another Matrix client, compare the emoji or decimals,
|
||||
and type `yes` only when they match. The command exits successfully only
|
||||
after `Cross-signing verified` becomes `yes`.
|
||||
|
||||
7. If you are intentionally abandoning unrecoverable old history and want a fresh backup baseline for future messages, run:
|
||||
|
||||
```bash
|
||||
@@ -293,10 +304,17 @@ new backup key can load correctly after restart.
|
||||
- Meaning: the provided key could not be parsed or did not match the expected format.
|
||||
- What to do: retry with the exact recovery key from your Matrix client or recovery-key file.
|
||||
|
||||
`Matrix device is still unverified after applying recovery key. Verify your recovery key and ensure cross-signing is available.`
|
||||
`Matrix recovery key was applied, but this device still lacks full Matrix identity trust.`
|
||||
|
||||
- Meaning: the key was applied, but the device still could not complete verification.
|
||||
- What to do: confirm you used the correct key and that cross-signing is available on the account, then retry.
|
||||
- Meaning: OpenClaw could apply the recovery key, but Matrix still has not
|
||||
established full cross-signing identity trust for this device. Check the
|
||||
command output for `Recovery key accepted`, `Backup usable`,
|
||||
`Cross-signing verified`, and `Device verified by owner`.
|
||||
- What to do: run `openclaw matrix verify self`, accept the request in another
|
||||
Matrix client, compare the SAS, and type `yes` only when it matches. The
|
||||
command waits for full Matrix identity trust before reporting success. Use
|
||||
`openclaw matrix verify bootstrap --recovery-key "<your-recovery-key>" --force-reset-cross-signing`
|
||||
only when you intentionally want to replace the current cross-signing identity.
|
||||
|
||||
`Matrix key backup is not active on this device after loading from secret storage.`
|
||||
|
||||
|
||||
@@ -52,13 +52,17 @@ pnpm add -g openclaw@latest
|
||||
bun add -g openclaw@latest
|
||||
```
|
||||
|
||||
### Root-owned global npm installs
|
||||
### Global npm installs and runtime dependencies
|
||||
|
||||
Some Linux npm setups install global packages under root-owned directories such as
|
||||
`/usr/lib/node_modules/openclaw`. OpenClaw supports that layout: the installed
|
||||
package is treated as read-only at runtime, and bundled plugin runtime
|
||||
OpenClaw treats packaged global installs as read-only at runtime, even when the
|
||||
global package directory is writable by the current user. Bundled plugin runtime
|
||||
dependencies are staged into a writable runtime directory instead of mutating the
|
||||
package tree.
|
||||
package tree. This keeps `openclaw update` from racing with a running gateway or
|
||||
local agent that is repairing plugin dependencies during the same install.
|
||||
|
||||
Some Linux npm setups install global packages under root-owned directories such
|
||||
as `/usr/lib/node_modules/openclaw`. OpenClaw supports that layout through the
|
||||
same external staging path.
|
||||
|
||||
For hardened systemd units, set a writable stage directory that is included in
|
||||
`ReadWritePaths`:
|
||||
@@ -71,6 +75,18 @@ ReadWritePaths=/var/lib/openclaw /home/openclaw/.openclaw /tmp
|
||||
If `OPENCLAW_PLUGIN_STAGE_DIR` is not set, OpenClaw uses `$STATE_DIRECTORY` when
|
||||
systemd provides it, then falls back to `~/.openclaw/plugin-runtime-deps`.
|
||||
|
||||
### Bundled plugin runtime dependencies
|
||||
|
||||
Packaged installs keep bundled plugin runtime dependencies out of the read-only
|
||||
package tree. On startup and during `openclaw doctor --fix`, OpenClaw repairs
|
||||
runtime dependencies only for bundled plugins that are active in config, active
|
||||
through legacy channel config, or enabled by their bundled manifest default.
|
||||
|
||||
Explicit disablement wins. A disabled plugin or channel does not get its
|
||||
runtime dependencies repaired just because it exists in the package. External
|
||||
plugins and custom load paths still use `openclaw plugins install` or
|
||||
`openclaw plugins update`.
|
||||
|
||||
## Auto-updater
|
||||
|
||||
The auto-updater is off by default. Enable it in `~/.openclaw/openclaw.json`:
|
||||
|
||||
@@ -279,7 +279,15 @@ works with any OpenTelemetry collector/backend that accepts OTLP/HTTP.
|
||||
"metrics": true,
|
||||
"logs": true,
|
||||
"sampleRate": 0.2,
|
||||
"flushIntervalMs": 60000
|
||||
"flushIntervalMs": 60000,
|
||||
"captureContent": {
|
||||
"enabled": false,
|
||||
"inputMessages": false,
|
||||
"outputMessages": false,
|
||||
"toolInputs": false,
|
||||
"toolOutputs": false,
|
||||
"systemPrompt": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -293,6 +301,9 @@ Notes:
|
||||
counters/histograms (webhooks, queueing, session state, queue depth/wait).
|
||||
- Traces/metrics can be toggled with `traces` / `metrics` (default: on). Traces
|
||||
include model usage spans plus webhook/message processing spans when enabled.
|
||||
- Raw model/tool content is not exported by default. Use
|
||||
`diagnostics.otel.captureContent` only when your collector and retention policy
|
||||
are approved for prompt, response, tool, or system prompt text.
|
||||
- Set `headers` when your collector requires auth.
|
||||
- Environment variables supported: `OTEL_EXPORTER_OTLP_ENDPOINT`,
|
||||
`OTEL_SERVICE_NAME`, `OTEL_EXPORTER_OTLP_PROTOCOL`.
|
||||
@@ -341,8 +352,17 @@ Queues + sessions:
|
||||
|
||||
- `openclaw.model.usage`
|
||||
- `openclaw.channel`, `openclaw.provider`, `openclaw.model`
|
||||
- `openclaw.sessionKey`, `openclaw.sessionId`
|
||||
- `openclaw.tokens.*` (input/output/cache_read/cache_write/total)
|
||||
- `openclaw.run`
|
||||
- `openclaw.outcome`, `openclaw.channel`, `openclaw.provider`,
|
||||
`openclaw.model`, `openclaw.errorCategory`
|
||||
- `openclaw.model.call`
|
||||
- `gen_ai.system`, `gen_ai.request.model`, `gen_ai.operation.name`,
|
||||
`openclaw.provider`, `openclaw.model`, `openclaw.api`,
|
||||
`openclaw.transport`
|
||||
- `openclaw.tool.execution`
|
||||
- `gen_ai.tool.name`, `openclaw.toolName`, `openclaw.errorCategory`,
|
||||
`openclaw.tool.params.*`
|
||||
- `openclaw.webhook.processed`
|
||||
- `openclaw.channel`, `openclaw.webhook`, `openclaw.chatId`
|
||||
- `openclaw.webhook.error`
|
||||
@@ -350,11 +370,13 @@ Queues + sessions:
|
||||
`openclaw.error`
|
||||
- `openclaw.message.processed`
|
||||
- `openclaw.channel`, `openclaw.outcome`, `openclaw.chatId`,
|
||||
`openclaw.messageId`, `openclaw.sessionKey`, `openclaw.sessionId`,
|
||||
`openclaw.reason`
|
||||
`openclaw.messageId`, `openclaw.reason`
|
||||
- `openclaw.session.stuck`
|
||||
- `openclaw.state`, `openclaw.ageMs`, `openclaw.queueDepth`,
|
||||
`openclaw.sessionKey`, `openclaw.sessionId`
|
||||
- `openclaw.state`, `openclaw.ageMs`, `openclaw.queueDepth`
|
||||
|
||||
When content capture is explicitly enabled, model/tool spans can also include
|
||||
bounded, redacted `openclaw.content.*` attributes for the specific content
|
||||
classes you opted into.
|
||||
|
||||
### Sampling + flushing
|
||||
|
||||
|
||||
@@ -137,8 +137,8 @@ Rules:
|
||||
skips the `[Image]` summary block and passes the original image into the
|
||||
model instead.
|
||||
- If a Gateway/WebChat primary model is text-only, image attachments are
|
||||
preserved as offloaded `media://inbound/*` refs so the image tool or configured
|
||||
image model can still inspect them instead of losing the attachment.
|
||||
preserved as offloaded `media://inbound/*` refs so the image/PDF tools or
|
||||
configured image model can still inspect them instead of losing the attachment.
|
||||
- Explicit `openclaw infer image describe --model <provider/model>` requests
|
||||
are different: they run that image-capable provider/model directly, including
|
||||
Ollama refs such as `ollama/qwen2.5vl:7b`.
|
||||
|
||||
12
docs/pi.md
12
docs/pi.md
@@ -23,10 +23,10 @@ OpenClaw uses the pi SDK to embed an AI coding agent into its messaging gateway
|
||||
|
||||
```json
|
||||
{
|
||||
"@mariozechner/pi-agent-core": "0.68.1",
|
||||
"@mariozechner/pi-ai": "0.68.1",
|
||||
"@mariozechner/pi-coding-agent": "0.68.1",
|
||||
"@mariozechner/pi-tui": "0.68.1"
|
||||
"@mariozechner/pi-agent-core": "0.70.2",
|
||||
"@mariozechner/pi-ai": "0.70.2",
|
||||
"@mariozechner/pi-coding-agent": "0.70.2",
|
||||
"@mariozechner/pi-tui": "0.70.2"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -135,7 +135,7 @@ directories instead of under `src/agents/tools`, for example:
|
||||
- the Telegram plugin action runtime file
|
||||
- the WhatsApp plugin action runtime file
|
||||
|
||||
## Core Integration Flow
|
||||
## Core integration flow
|
||||
|
||||
### 1. Running an Embedded Agent
|
||||
|
||||
@@ -285,7 +285,7 @@ export function splitSdkTools(options: { tools: AnyAgentTool[]; sandboxEnabled:
|
||||
|
||||
This ensures OpenClaw's policy filtering, sandbox integration, and extended toolset remain consistent across providers.
|
||||
|
||||
## System Prompt Construction
|
||||
## System prompt construction
|
||||
|
||||
The system prompt is built in `buildAgentSystemPrompt()` (`system-prompt.ts`). It assembles a full prompt with sections including Tooling, Tool Call Style, Safety guardrails, OpenClaw CLI reference, Skills, Docs, Workspace, Sandbox, Messaging, Reply Tags, Voice, Silent Replies, Heartbeats, Runtime metadata, plus Memory and Reactions when enabled, and optional context files and extra system prompt content. Sections are trimmed for minimal prompt mode used by subagents.
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user