Summary
After upgrading to OpenClaw 2026.5.2 (8b2a6e5), enabled plugin-backed tools such as browser, memory_search, and memory_get can disappear from the effective agent tool surface, even when:
plugins.entries.browser.enabled: true
plugins.entries.memory-core.enabled: true
browser.enabled: true
agents.defaults.memorySearch.enabled: true
tools.profile: "full" or the agent-level profile is "full"
The issue is not caused by the browser or memory plugins being disabled, nor by the full tool profile filtering them out. The failure appears to be in the plugin tool resolution/registry filtering path: disabled bundled plugin IDs are included in the required plugin ID set for tool discovery, and then getLoadedRuntimePluginRegistry() refuses to return the registry because those disabled plugins are not considered loaded. As a result, resolvePluginTools() returns no plugin tools at all, which drops unrelated enabled plugin tools (browser, memory_search, memory_get).
Expected behavior
If browser and memory-core are enabled and pass availability checks, their tools should be present in the effective tool list:
browser
memory_search
memory_get
Disabled unrelated bundled plugins with tool contracts (for example firecrawl, tavily, etc.) should not cause all plugin tools to be dropped.
Actual behavior
The effective tool list contains built-in/core tools such as read, exec, web_search, web_fetch, canvas, message, etc., but does not contain:
browser
memory_search
memory_get
A local effective inventory check showed the active tool entries included only core tools; the three plugin tools above were absent.
Sanitized configuration shape
The configuration has the relevant plugin/tool settings enabled. Sensitive/local values omitted:
openclaw plugins list also reports both bundled plugins enabled:
browser enabled
memory-core enabled
openclaw plugins doctor only reported an unrelated third-party/local plugin warning:
Diagnostics:
- minimax-web-search: plugin must declare contracts.tools before registering agent tools
That diagnostic is unrelated to browser and memory-core; it does not explain why all plugin tools are dropped.
Investigation details / suspected root cause
1. browser and memory tools are plugin-backed, not core-created in createOpenClawTools()
/usr/lib/node_modules/openclaw/dist/openclaw-tools-BDF6gNXk.js
createOpenClawTools() builds core tools first, then appends plugin tools:
const wrappedPluginTools = resolveOpenClawPluginToolsForOptions({
options,
resolvedConfig,
existingToolNames: new Set(tools.map((tool) => tool.name))
});
return [...tools, ...wrappedPluginTools];
The browser and memory tools come from plugin manifests/runtime registration:
/usr/lib/node_modules/openclaw/dist/extensions/browser/openclaw.plugin.json
{
"id": "browser",
"contracts": {
"tools": ["browser"]
}
}
/usr/lib/node_modules/openclaw/dist/extensions/memory-core/openclaw.plugin.json
{
"id": "memory-core",
"contracts": {
"tools": ["memory_get", "memory_search"]
}
}
Runtime registration also exists:
/usr/lib/node_modules/openclaw/dist/plugin-registration-DiVrZUS2.js
function registerBrowserPlugin(api) {
api.registerTool(((ctx) => createLazyBrowserTool(...)));
}
/usr/lib/node_modules/openclaw/dist/extensions/memory-core/index.js
api.registerTool((ctx) => createLazyMemorySearchTool(resolveMemoryToolOptions(ctx)), { names: ["memory_search"] });
api.registerTool((ctx) => createLazyMemoryGetTool(resolveMemoryToolOptions(ctx)), { names: ["memory_get"] });
2. full profile is not filtering these tools
/usr/lib/node_modules/openclaw/dist/tool-policy-shared-MN-JZIlL.js
browser, memory_search, and memory_get are known tool IDs. memory_search and memory_get are in the coding profile; browser has no default profile, but full is intentionally unrestricted:
const CORE_TOOL_PROFILES = {
minimal: { allow: listCoreToolIdsForProfile("minimal") },
coding: { allow: [...listCoreToolIdsForProfile("coding"), "bundle-mcp"] },
messaging: { allow: [...listCoreToolIdsForProfile("messaging"), "bundle-mcp"] },
full: {}
};
function resolveCoreToolProfilePolicy(profile) {
if (!profile) return;
const resolved = CORE_TOOL_PROFILES[profile];
if (!resolved) return;
if (!resolved.allow && !resolved.deny) return;
return { ... };
}
For profile: "full", resolveToolProfilePolicy("full") returns undefined, so there is no profile allowlist that would remove browser/memory tools.
3. localModelLean is also not the cause here
/usr/lib/node_modules/openclaw/dist/pi-tools-J9lznXGK.js
function applyModelProviderToolPolicy(tools, params) {
if (params?.config?.agents?.defaults?.experimental?.localModelLean === true) {
const leanDeny = new Set([
"browser",
"cron",
"message"
]);
tools = tools.filter((tool) => !leanDeny.has(tool.name));
}
...
}
This setting was not enabled in the inspected config. Also, even if it were enabled, it would only explain browser; it would not explain memory_search and memory_get disappearing.
4. The failure occurs in plugin tool resolution
/usr/lib/node_modules/openclaw/dist/tools-D9CRirqH.js
resolvePluginTools() calculates onlyPluginIds, then tries to reuse/load a runtime plugin registry:
const onlyPluginIds = resolvePluginToolRuntimePluginIds({ ... });
...
const registry = resolvePluginToolRegistry({
loadOptions: buildPluginRuntimeLoadOptions(context, {
activate: false,
toolDiscovery: true,
onlyPluginIds: runtimePluginIds,
runtimeOptions
}),
onlyPluginIds: runtimePluginIds
});
if (!registry) return tools;
In the failing environment, the equivalent onlyPluginIds set includes enabled plugin IDs such as browser and memory-core, but also disabled bundled plugins that merely declare tool contracts:
[
"browser",
"file-transfer",
"firecrawl",
"llm-task",
"memory-core",
"memory-wiki",
"skill-workshop",
"tavily",
"xai"
]
However, several of those bundled plugins are disabled (firecrawl, llm-task, memory-wiki, skill-workshop, tavily). They are included because the manifest/control-plane availability helper treats bundled plugins as available regardless of enabled state:
/usr/lib/node_modules/openclaw/dist/manifest-contract-eligibility-Bm6pc8ez.js
function isManifestPluginAvailableForControlPlane(params) {
if (params.plugin.origin === "bundled") return true;
return isInstalledPluginEnabled(params.snapshot.index, params.plugin.id, params.config);
}
The loader then produces a registry where those disabled plugins are present with status "disabled", while enabled ones are loaded:
plugins: [
["browser", "loaded"],
["file-transfer", "loaded"],
["firecrawl", "disabled"],
["llm-task", "disabled"],
["memory-core", "loaded"],
["memory-wiki", "disabled"],
["skill-workshop", "disabled"],
["tavily", "disabled"],
["xai", "loaded"]
]
The registry itself contains the expected tool factories for the enabled plugins:
registry.tools includes:
- browser declared ["browser"]
- memory-core ["memory_search"] declared ["memory_get", "memory_search"]
- memory-core ["memory_get"] declared ["memory_get", "memory_search"]
But resolvePluginToolRegistry() calls getLoadedRuntimePluginRegistry() with requiredPluginIds containing the disabled plugin IDs too.
/usr/lib/node_modules/openclaw/dist/active-runtime-registry-DkOuNyXa.js
function registryContainsPluginIds(registry, pluginIds) {
const loaded = new Set();
for (const plugin of registry.plugins ?? [])
if (plugin.status === void 0 || plugin.status === "loaded") loaded.add(plugin.id);
...
return pluginIds.every((pluginId) => loaded.has(pluginId));
}
Because disabled required plugin IDs are not in the loaded set, registryContainsPluginIds() returns false. Therefore getLoadedRuntimePluginRegistry() returns undefined, even though the registry contains valid loaded tools for browser and memory-core.
Then resolvePluginToolRegistry() returns no registry, and resolvePluginTools() returns an empty plugin tool list:
if (!registry) return tools; // tools is empty unless descriptor cache already supplied something
This drops all plugin-backed tools, including unrelated enabled plugins.
Why this looks like the concrete filtering layer
The tools are not removed by:
tools.profile: full resolves to no restrictive policy.
applyToolPolicyPipeline(): it only filters the list it receives; by this point the plugin tools were never appended.
applyModelProviderToolPolicy() / localModelLean: not enabled, and does not explain memory tools.
gateway.tools deny list: relevant to Gateway HTTP tool invocation, not the Pi agent tool surface; it also does not include browser/memory.
The effective drop happens before the final policy pipeline, in plugin tool registry resolution:
createOpenClawCodingTools()
-> createOpenClawTools()
-> resolveOpenClawPluginToolsForOptions()
-> resolvePluginTools()
-> resolvePluginToolRuntimePluginIds()
includes disabled bundled plugins with tool contracts
-> resolvePluginToolRegistry()
-> getLoadedRuntimePluginRegistry(requiredPluginIds = includes disabled plugins)
-> registryContainsPluginIds() rejects registry
-> returns [] plugin tools
Suggested fix direction
One of these would likely fix it:
- Make
resolvePluginToolRuntimePluginIds() exclude disabled plugins from onlyPluginIds when resolving runtime tool factories, even for bundled plugins.
- Or make
registryContainsPluginIds() treat requiredPluginIds as satisfied if the plugin is present but disabled due to config, instead of rejecting the whole registry.
- Or pass only the subset of actually loadable/enabled plugin IDs as
requiredPluginIds to getLoadedRuntimePluginRegistry().
Option 1 seems the least surprising: disabled plugin IDs should not be required for tool discovery, and should not block enabled plugin tools from loading.
Notes
No private paths, usernames, tokens, IPs, or local workspace identifiers are included here. The above details are limited to OpenClaw version, sanitized config shape, public bundled plugin IDs, and source/dist function names relevant to the bug.
Summary
After upgrading to OpenClaw
2026.5.2 (8b2a6e5), enabled plugin-backed tools such asbrowser,memory_search, andmemory_getcan disappear from the effective agent tool surface, even when:plugins.entries.browser.enabled: trueplugins.entries.memory-core.enabled: truebrowser.enabled: trueagents.defaults.memorySearch.enabled: truetools.profile: "full"or the agent-level profile is"full"The issue is not caused by the browser or memory plugins being disabled, nor by the
fulltool profile filtering them out. The failure appears to be in the plugin tool resolution/registry filtering path: disabled bundled plugin IDs are included in the required plugin ID set for tool discovery, and thengetLoadedRuntimePluginRegistry()refuses to return the registry because those disabled plugins are not considered loaded. As a result,resolvePluginTools()returns no plugin tools at all, which drops unrelated enabled plugin tools (browser,memory_search,memory_get).Expected behavior
If
browserandmemory-coreare enabled and pass availability checks, their tools should be present in the effective tool list:browsermemory_searchmemory_getDisabled unrelated bundled plugins with tool contracts (for example
firecrawl,tavily, etc.) should not cause all plugin tools to be dropped.Actual behavior
The effective tool list contains built-in/core tools such as
read,exec,web_search,web_fetch,canvas,message, etc., but does not contain:browsermemory_searchmemory_getA local effective inventory check showed the active tool entries included only core tools; the three plugin tools above were absent.
Sanitized configuration shape
The configuration has the relevant plugin/tool settings enabled. Sensitive/local values omitted:
{ "tools": { "profile": "full" }, "browser": { "enabled": true, "evaluateEnabled": true, "headless": true, "defaultProfile": "openclaw" }, "agents": { "defaults": { "memorySearch": { "enabled": true, "provider": "ollama", "model": "nomic-embed-text:latest", "fallback": "none" } }, "list": [ { "tools": { "profile": "full" } } ] }, "plugins": { "entries": { "browser": { "enabled": true }, "memory-core": { "enabled": true } } } }openclaw plugins listalso reports both bundled plugins enabled:browserenabledmemory-coreenabledopenclaw plugins doctoronly reported an unrelated third-party/local plugin warning:That diagnostic is unrelated to
browserandmemory-core; it does not explain why all plugin tools are dropped.Investigation details / suspected root cause
1.
browserand memory tools are plugin-backed, not core-created increateOpenClawTools()/usr/lib/node_modules/openclaw/dist/openclaw-tools-BDF6gNXk.jscreateOpenClawTools()builds core tools first, then appends plugin tools:The browser and memory tools come from plugin manifests/runtime registration:
/usr/lib/node_modules/openclaw/dist/extensions/browser/openclaw.plugin.json{ "id": "browser", "contracts": { "tools": ["browser"] } }/usr/lib/node_modules/openclaw/dist/extensions/memory-core/openclaw.plugin.json{ "id": "memory-core", "contracts": { "tools": ["memory_get", "memory_search"] } }Runtime registration also exists:
/usr/lib/node_modules/openclaw/dist/plugin-registration-DiVrZUS2.js/usr/lib/node_modules/openclaw/dist/extensions/memory-core/index.js2.
fullprofile is not filtering these tools/usr/lib/node_modules/openclaw/dist/tool-policy-shared-MN-JZIlL.jsbrowser,memory_search, andmemory_getare known tool IDs.memory_searchandmemory_getare in thecodingprofile;browserhas no default profile, butfullis intentionally unrestricted:For
profile: "full",resolveToolProfilePolicy("full")returnsundefined, so there is no profile allowlist that would removebrowser/memory tools.3.
localModelLeanis also not the cause here/usr/lib/node_modules/openclaw/dist/pi-tools-J9lznXGK.jsThis setting was not enabled in the inspected config. Also, even if it were enabled, it would only explain
browser; it would not explainmemory_searchandmemory_getdisappearing.4. The failure occurs in plugin tool resolution
/usr/lib/node_modules/openclaw/dist/tools-D9CRirqH.jsresolvePluginTools()calculatesonlyPluginIds, then tries to reuse/load a runtime plugin registry:In the failing environment, the equivalent
onlyPluginIdsset includes enabled plugin IDs such asbrowserandmemory-core, but also disabled bundled plugins that merely declare tool contracts:However, several of those bundled plugins are disabled (
firecrawl,llm-task,memory-wiki,skill-workshop,tavily). They are included because the manifest/control-plane availability helper treats bundled plugins as available regardless of enabled state:/usr/lib/node_modules/openclaw/dist/manifest-contract-eligibility-Bm6pc8ez.jsThe loader then produces a registry where those disabled plugins are present with status
"disabled", while enabled ones are loaded:The registry itself contains the expected tool factories for the enabled plugins:
But
resolvePluginToolRegistry()callsgetLoadedRuntimePluginRegistry()withrequiredPluginIdscontaining the disabled plugin IDs too./usr/lib/node_modules/openclaw/dist/active-runtime-registry-DkOuNyXa.jsBecause disabled required plugin IDs are not in the
loadedset,registryContainsPluginIds()returns false. ThereforegetLoadedRuntimePluginRegistry()returnsundefined, even though the registry contains valid loaded tools forbrowserandmemory-core.Then
resolvePluginToolRegistry()returns no registry, andresolvePluginTools()returns an empty plugin tool list:This drops all plugin-backed tools, including unrelated enabled plugins.
Why this looks like the concrete filtering layer
The tools are not removed by:
tools.profile:fullresolves to no restrictive policy.applyToolPolicyPipeline(): it only filters the list it receives; by this point the plugin tools were never appended.applyModelProviderToolPolicy()/localModelLean: not enabled, and does not explain memory tools.gateway.toolsdeny list: relevant to Gateway HTTP tool invocation, not the Pi agent tool surface; it also does not include browser/memory.The effective drop happens before the final policy pipeline, in plugin tool registry resolution:
Suggested fix direction
One of these would likely fix it:
resolvePluginToolRuntimePluginIds()exclude disabled plugins fromonlyPluginIdswhen resolving runtime tool factories, even for bundled plugins.registryContainsPluginIds()treatrequiredPluginIdsas satisfied if the plugin is present but disabled due to config, instead of rejecting the whole registry.requiredPluginIdstogetLoadedRuntimePluginRegistry().Option 1 seems the least surprising: disabled plugin IDs should not be required for tool discovery, and should not block enabled plugin tools from loading.
Notes
No private paths, usernames, tokens, IPs, or local workspace identifiers are included here. The above details are limited to OpenClaw version, sanitized config shape, public bundled plugin IDs, and source/dist function names relevant to the bug.