OpenClaw Repro: plugin registry overwrite during subagent-style tool resolution
This repository reproduces an OpenClaw bug where plugin tool resolution can replace the process-global active plugin registry when:
OPENCLAW_STATE_DIRis relative- the first plugin load happens under one
cwd - a later tool-resolution load happens under a different
cwd - the later load uses a different
workspaceDir, so the loader cache key changes
The repro uses a tiny local plugin channel called demo-feishu instead of the real feishu plugin. The bug mechanism is the same: a plugin-backed message channel is initially valid, then becomes unknown after resolvePluginTools() reloads plugins and overwrites the active registry with an empty one.
Requirements
- Node.js 22+
pnpmgit
Usage
Install this repo's tiny dependency first:
pnpm install
Then run the broken-path repro:
pnpm repro
Expected output:
before.isDemoFeishuChannelKnownistrueafter.isDemoFeishuChannelKnownisfalse- the script prints
Reproduced: resolvePluginTools() replaced the active plugin registry.
You can also run the non-broken comparison with an absolute state dir:
pnpm repro:absolute-state-dir
Expected output:
before.isDemoFeishuChannelKnownistrueafter.isDemoFeishuChannelKnownistrue- the script prints
As expected: absolute OPENCLAW_STATE_DIR avoids the repro.
Optional local source override
If you already have an OpenClaw checkout with dependencies installed, you can skip the vendored clone and point the script at that tree:
OPENCLAW_REPO_DIR=/path/to/openclaw pnpm repro
What the script does
1. Clones openclaw/openclaw into .vendor/openclaw 2. Checks out commit ff6541f69d2e6cd88424953b13a43a20fa7aefb9 3. Installs OpenClaw dependencies once 4. Builds OpenClaw once if dist/plugin-sdk/* is missing 5. Creates a tiny auto-discovered plugin under a synthetic state dir 6. Loads plugins once from the main workspace 7. Changes cwd to a sub-workspace and triggers resolvePluginTools() 8. Shows that the plugin channel disappears only in the relative-state-dir case
Why this matters
In the unfixed implementation, resolvePluginTools() calls loadOpenClawPlugins() with the default activating behavior. When the second load sees a different plugin root set, it can replace the active registry and make plugin channels fail later message-channel validation.










