Skip to content

Optional plugin tools allowed with alsoAllow are not discovered #76616

@richardmqq

Description

@richardmqq

Summary

In OpenClaw 2026.5.2, optional plugin tools can appear in tools.catalog but remain unavailable to the live agent/tool execution paths (tools.effective, tools.invoke, and native agent tool surface). This affected @openclaw/lobster and the bundled llm-task plugin.

Observed result before hotfix:

  • openclaw plugins list shows both plugins loaded/enabled.
  • openclaw gateway call tools.catalog --params '{"agentId":"main","includePlugins":true}' lists llm-task and lobster as optional plugin tools.
  • openclaw gateway call tools.effective ... does not include them.
  • openclaw gateway call tools.invoke --params '{"name":"llm-task",...}' returns Tool not available: llm-task.
  • Native agent tool surface does not include either tool.

Environment

  • OpenClaw: 2026.5.2 (8b2a6e5)
  • macOS: 26.4.1
  • Plugins:
    • llm-task: bundled, enabled, version 2026.5.2
    • lobster: installed from npm as @openclaw/lobster@2026.5.2, enabled

Root cause found locally

There are two related issues:

1. Optional plugin runtime registry is preloaded for tools.catalog, but not for execution/effective paths

tools.catalog explicitly calls ensureStandalonePluginToolRegistryLoaded(...) before resolvePluginTools(...).

But createOpenClawTools(...) / resolveGatewayScopedTools(...) / tools.effective ultimately call plugin tool resolution without that preload. In local reproduction:

resolvePluginTools({ toolAllowlist: ['lobster', 'llm-task'], ... }) // []

ensureStandalonePluginToolRegistryLoaded({ toolAllowlist: ['lobster', 'llm-task'], ... })
resolvePluginTools({ toolAllowlist: ['lobster', 'llm-task'], ... }) // ['llm-task', 'lobster']

This explains why catalog can see the tools while effective/invoke/agent cannot.

2. Docs/config semantics are confusing for optional plugin tools

docs/tools/lobster.md recommends:

{ "tools": { "alsoAllow": ["lobster"] } }

But source behavior in 2026.5.2 is:

  • collectExplicitAllowlist() reads only allow, not alsoAllow, for plugin discovery.
  • mergeAlsoAllowPolicy() only merges alsoAllow when there is already a policy.allow list.
  • tools.profile="full" resolves to {} / no allow list, so alsoAllow alone does not widen the full profile.
  • Config validation rejects setting allow and alsoAllow in the same scope.

So the documented tools.alsoAllow path is insufficient for tools.profile="full" and optional plugin discovery.

Local hotfix that worked

Patch dist/openclaw-tools-*.js so createOpenClawTools(...) preloads the standalone plugin tool registry before calling resolveOpenClawPluginToolsForOptions(...), mirroring tools.catalog.

Conceptual diff:

-import { resolvePluginTools, ... } from "./tools-*.js";
+import { resolvePluginTools, ensureStandalonePluginToolRegistryLoaded, ... } from "./tools-*.js";

 if (options?.disablePluginTools) return tools;
+ensureStandalonePluginToolRegistryLoaded({
+  ...resolveOpenClawPluginToolInputs({
+    options,
+    resolvedConfig,
+    runtimeConfig: availabilityConfig,
+    getRuntimeConfig: ...
+  }),
+  toolAllowlist: options?.pluginToolAllowlist,
+  allowGatewaySubagentBinding: options?.allowGatewaySubagentBinding,
+});
 const wrappedPluginTools = resolveOpenClawPluginToolsForOptions({ ... });

After patch, I also used a valid per-agent allowlist for main:

{
  "agents": {
    "list": [
      {
        "id": "main",
        "tools": {
          "allow": [
            "agents_list", "apply_patch", "canvas", "edit", "exec", "image_generate",
            "message", "music_generate", "process", "read", "sessions_history",
            "sessions_send", "session_status", "sessions_list", "sessions_spawn",
            "subagents", "tts", "update_plan", "video_generate", "web_fetch",
            "write", "sessions_yield", "lobster", "llm-task"
          ]
        }
      }
    ]
  }
}

Verification after hotfix

  • openclaw config validate: valid
  • tools.effective for main includes both llm-task and lobster.
  • tools.invoke llm-task works and returns schema-validated JSON:
{
  "ok": true,
  "toolName": "llm-task",
  "details": { "json": { "ok": true, "value": 1 } }
}
  • tools.invoke lobster works for a no-side-effect smoke:
{
  "ok": true,
  "toolName": "lobster",
  "details": {
    "ok": true,
    "status": "ok",
    "output": ["hello"]
  }
}

and JSON smoke:

{
  "ok": true,
  "status": "ok",
  "output": [{ "ok": true }]
}

Suggested fixes

  1. Preload optional plugin tool runtime registry in createOpenClawTools(...) or in a shared plugin-tool resolution helper used by tools.effective, tools.invoke, and native agent tool assembly.
  2. Align docs/config behavior for optional plugin tools:
    • Either make alsoAllow participate in optional plugin discovery, or
    • update Lobster/llm-task docs to say optional plugins require an explicit allow entry in a scope where alsoAllow is not also present.
  3. Consider making tools.profile="full" + tools.alsoAllow meaningful, or document that full has no allowlist to merge into.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions