You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When a user invokes openclaw <tool-name> where <tool-name> is a registered agent tool owned by an enabled, loaded plugin (not a plugin id and not a bundled CLI surface), the CLI router emits a misleading error that suggests adding the tool name to plugins.allow. The suggestion does nothing — plugins.allow accepts plugin ids, not tool names — and routes the user toward editing config that gets rejected by the protected-paths guard anyway.
Reproduction
A loaded lossless-claw plugin (kind: context-engine) registers five agent tools at runtime via api.registerTool(factory, { name: "lcm_recent" }) etc. The manifest correctly declares them in contracts.tools. The agent attempts:
openclaw lcm_recent
Result:
[openclaw] Failed to start CLI: Error: The `openclaw lcm_recent` command is unavailable
because `plugins.allow` excludes "lcm_recent". Add "lcm_recent" to `plugins.allow`
if you want that bundled plugin CLI surface.
at runCli (file:///.../dist/cli/run-main.js:412:46)
at async runMainOrRootHelp (file:///.../dist/entry.js:356:3)
The user (or agent) then follows the suggestion, attempting:
— at which point the user thinks the plugin is broken when in fact the plugin works correctly and the tool just isn't a CLI subcommand.
Why the message is wrong
plugins.allow is a list of plugin ids (e.g. lossless-claw, cortex, telegram). It is not a list of tool names. The suggestion to add "lcm_recent" to plugins.allow would produce:
A plugin not found: lcm_recent warning at next config load (visible in openclaw doctor)
No effect on the actual tool's availability
The CLI router has the information needed to give a much better error. The plugin manifest declares contracts.tools = ["lcm_recent", ...], and the runtime registry knows which plugin owns each tool name. The suggestion should be one of:
"lcm_recent is an agent tool registered by the lossless-claw plugin, not a CLI subcommand. Use it from an agent turn (model tool-use), not the CLI." — accurate when the name maps to a registered tool of an enabled plugin.
"lcm_recent is not a known plugin id or CLI subcommand. Did you mean lossless-claw? (Loaded plugins: ...)" — when the name doesn't match any registered tool either.
The current message conflates "this name is unknown" with "this is a known plugin disabled in plugins.allow" — which is the only case the suggestion to edit plugins.allow would actually help.
Why this is operationally bad
In our case (separate report at #76940 / PR #76950), an agent that hit this error spent 3+ restart cycles attempting to "fix" the perceived configuration problem:
Agent ran openclaw lcm_recent <args>
Hit the misleading error
Tried to add "lcm_recent", "lossless", "lcm" aliases to plugins.allow via config.patch
Hit the protected-paths guard
Concluded the plugin was broken and edited the LCM source to "add explicit tool registration names" (which were already present)
Restarted the gateway twice to "reload"
None of this was needed — the plugin works correctly and the tools are registered. The agent was misled by the CLI error suggestion.
Proposed fix
In src/cli/run-main.ts (or wherever the unknown-subcommand handler lives), before emitting the plugins.allow suggestion:
Look up the input name against the running plugin tool registry (the same lookup the agent's tool-dispatch uses).
If it matches a registered tool: emit the "this is a model tool, not a CLI subcommand" message instead.
If it matches a known plugin id that's currently disabled in plugins.allow: keep the existing suggestion (this is the only case where it's correct).
Otherwise: emit the "did you mean" suggestion against loaded plugin ids and bundled CLI surface ids, NOT against tool names.
The fix should be small (one branch in the unknown-subcommand error handler) and is a strict improvement — the only case where the current suggestion is correct is case (3), which the new logic preserves.
Adjacent
This bites users on plugins that register agent tools at runtime (lossless-claw, possibly cortex's tools depending on how they're registered, anything using api.registerTool). It does NOT bite users whose tools are declared statically in the manifest's top-level tools: [...] field — those have a separate code path.
Summary
When a user invokes
openclaw <tool-name>where<tool-name>is a registered agent tool owned by an enabled, loaded plugin (not a plugin id and not a bundled CLI surface), the CLI router emits a misleading error that suggests adding the tool name toplugins.allow. The suggestion does nothing —plugins.allowaccepts plugin ids, not tool names — and routes the user toward editing config that gets rejected by the protected-paths guard anyway.Reproduction
A loaded
lossless-clawplugin (kind:context-engine) registers five agent tools at runtime viaapi.registerTool(factory, { name: "lcm_recent" })etc. The manifest correctly declares them incontracts.tools. The agent attempts:Result:
The user (or agent) then follows the suggestion, attempting:
Which fails with the protected-config-paths guard:
— at which point the user thinks the plugin is broken when in fact the plugin works correctly and the tool just isn't a CLI subcommand.
Why the message is wrong
plugins.allowis a list of plugin ids (e.g.lossless-claw,cortex,telegram). It is not a list of tool names. The suggestion to add"lcm_recent"toplugins.allowwould produce:plugin not found: lcm_recentwarning at next config load (visible inopenclaw doctor)The CLI router has the information needed to give a much better error. The plugin manifest declares
contracts.tools = ["lcm_recent", ...], and the runtime registry knows which plugin owns each tool name. The suggestion should be one of:"
lcm_recentis an agent tool registered by thelossless-clawplugin, not a CLI subcommand. Use it from an agent turn (model tool-use), not the CLI." — accurate when the name maps to a registered tool of an enabled plugin."
lcm_recentis not a known plugin id or CLI subcommand. Did you meanlossless-claw? (Loaded plugins: ...)" — when the name doesn't match any registered tool either.The current message conflates "this name is unknown" with "this is a known plugin disabled in
plugins.allow" — which is the only case the suggestion to editplugins.allowwould actually help.Why this is operationally bad
In our case (separate report at #76940 / PR #76950), an agent that hit this error spent 3+ restart cycles attempting to "fix" the perceived configuration problem:
openclaw lcm_recent <args>"lcm_recent","lossless","lcm"aliases toplugins.allowviaconfig.patchNone of this was needed — the plugin works correctly and the tools are registered. The agent was misled by the CLI error suggestion.
Proposed fix
In
src/cli/run-main.ts(or wherever the unknown-subcommand handler lives), before emitting theplugins.allowsuggestion:plugins.allow: keep the existing suggestion (this is the only case where it's correct).The fix should be small (one branch in the unknown-subcommand error handler) and is a strict improvement — the only case where the current suggestion is correct is case (3), which the new logic preserves.
Adjacent
api.registerTool). It does NOT bite users whose tools are declared statically in the manifest's top-leveltools: [...]field — those have a separate code path.fix(sessions): context-engine fallback session-size guard) where this behavior was observed in the wild during operator troubleshooting.