Bug type
Bug (CLI scope defaults to "all", loads every plugin manifest just to send one message)
Beta release blocker
No
Summary
Sending a message via openclaw message send ends up loading every plugin shipped with openclaw before doing the send. With ~88 bundled plugins on this install that is 2-3 minutes of CPU on a Pi 500, even when you just want to deliver one Discord message. The command only needs the channel it is sending to.
Steps to reproduce
- Run openclaw 2026.4.25
- Time a single CLI message send:
time openclaw message send --channel discord --target <id> --dry-run -m "x"
Expected behaviour
A CLI invocation that knows its target channel ahead of time should load only that channel's plugin (or at most the configured channels), not every plugin in the install.
Actual behaviour
The function that handles message-send (runMessageAction in dist/register.message-*.js) calls the registry loader without telling it which plugin it actually needs. The loader's default behaviour is to scan every plugin directory under dist/extensions/, open each openclaw.plugin.json, and parse the contents. The send itself only needs the channel plugin's manifest.
The loader does support narrower modes - "only configured channels", "only one specific plugin id" - but the message-send code path does not pass any of them, so it always gets the full scan.
OpenClaw version
2026.4.25
Environment
Raspberry Pi 500 (Debian Trixie, aarch64). Gateway runs as a systemd user service. Many side-of-house scripts use openclaw message send (boot-check posts two reports per gateway restart, cron jobs deliver to Discord).
Logs, screenshots, and evidence
Standalone timing on a healthy gateway:
time openclaw message send --channel discord --target <id> --dry-run -m "x"
| Scope passed |
Wall time |
(default "all") |
~2m30s |
{ scope: "configured-channels" } (2 channels here) |
1m9s |
{ onlyPluginIds: [opts.channel] } |
10.7s |
CPU is almost entirely on the V8 main thread. V8 --prof capture during a separate gateway boot showed ~52% of all JS CPU time inside node_modules/json5/lib/parse.js - that is the manifest parse path, hit once per plugin during the registry load. So the cost is real per-call work, not stale gateway state.
Code pointers on this install:
dist/register.message-CaRx3OC0.js line 113 - runMessageAction calls ensurePluginRegistryLoaded() with no args
dist/runtime-registry-loader-fxcQDWv8.js line 40 - const scope = options?.scope ?? "all"
Bundle filenames will rotate per release.
Impact and severity
Affected: anything that shells out to openclaw message send. On this install:
boot-check posts two reports to Discord per gateway restart, costing ~5 minutes of CPU between them
- Family cron jobs (chore reports, football updates) each pay 2-3 min when they fire
- Manual
openclaw message send from the shell takes 2-3 min before the message even leaves
Severity: high on slow hardware, medium elsewhere. CPU is taken from whatever else is running, so on a Pi 500 this competes with the gateway's own startup work after a restart and stretches channel startup out further than necessary.
Frequency: every CLI invocation.
Additional information
I worked around this on my box with a one-line dist patch in register.message-*.js:
ensurePluginRegistryLoaded(opts.channel ? { onlyPluginIds: [opts.channel] } : { scope: "configured-channels" });
CLI message send dropped from 2m30s to ~10s.
Bug type
Bug (CLI scope defaults to "all", loads every plugin manifest just to send one message)
Beta release blocker
No
Summary
Sending a message via
openclaw message sendends up loading every plugin shipped with openclaw before doing the send. With ~88 bundled plugins on this install that is 2-3 minutes of CPU on a Pi 500, even when you just want to deliver one Discord message. The command only needs the channel it is sending to.Steps to reproduce
Expected behaviour
A CLI invocation that knows its target channel ahead of time should load only that channel's plugin (or at most the configured channels), not every plugin in the install.
Actual behaviour
The function that handles message-send (
runMessageActionindist/register.message-*.js) calls the registry loader without telling it which plugin it actually needs. The loader's default behaviour is to scan every plugin directory underdist/extensions/, open eachopenclaw.plugin.json, and parse the contents. The send itself only needs the channel plugin's manifest.The loader does support narrower modes - "only configured channels", "only one specific plugin id" - but the message-send code path does not pass any of them, so it always gets the full scan.
OpenClaw version
2026.4.25
Environment
Raspberry Pi 500 (Debian Trixie, aarch64). Gateway runs as a systemd user service. Many side-of-house scripts use
openclaw message send(boot-check posts two reports per gateway restart, cron jobs deliver to Discord).Logs, screenshots, and evidence
Standalone timing on a healthy gateway:
"all"){ scope: "configured-channels" }(2 channels here){ onlyPluginIds: [opts.channel] }CPU is almost entirely on the V8 main thread. V8
--profcapture during a separate gateway boot showed~52%of all JS CPU time insidenode_modules/json5/lib/parse.js- that is the manifest parse path, hit once per plugin during the registry load. So the cost is real per-call work, not stale gateway state.Code pointers on this install:
dist/register.message-CaRx3OC0.jsline 113 -runMessageActioncallsensurePluginRegistryLoaded()with no argsdist/runtime-registry-loader-fxcQDWv8.jsline 40 -const scope = options?.scope ?? "all"Bundle filenames will rotate per release.
Impact and severity
Affected: anything that shells out to
openclaw message send. On this install:boot-checkposts two reports to Discord per gateway restart, costing ~5 minutes of CPU between themopenclaw message sendfrom the shell takes 2-3 min before the message even leavesSeverity: high on slow hardware, medium elsewhere. CPU is taken from whatever else is running, so on a Pi 500 this competes with the gateway's own startup work after a restart and stretches channel startup out further than necessary.
Frequency: every CLI invocation.
Additional information
I worked around this on my box with a one-line dist patch in
register.message-*.js:CLI message send dropped from 2m30s to ~10s.