Skip to content

[Bug]: openclaw plugins install nests a full copy of openclaw via peer-dep auto-install — 800+ MB bloat and ~15s startup tax per command #69498

@Adam-Researchh

Description

@Adam-Researchh

Bug type

Regression (worked before, now fails)

Beta release blocker

No

Summary

openclaw plugins install runs npm install in the plugin directory, and npm 7+'s auto-install-peers behavior installs openclaw itself as a nested dependency of the plugin, dragging in openclaw's entire transitive tree (lancedb, slack, lark, baileys, jimp, pdfjs, koffi, napi-rs, etc.) and adding a ~15-second module-resolution tax to every CLI subcommand.

Steps to reproduce

  1. Install OpenClaw 2026.4.15 globally (pnpm/npm — both reproduce).
  2. Run openclaw plugins install @martian-engineering/lossless-claw (any plugin whose package.json declares peerDependencies: { "openclaw": "*" } reproduces this).
  3. du -sh ~/.openclaw/extensions/lossless-claw/node_modules/817 MB.
  4. du -sh ~/.openclaw/extensions/lossless-claw/node_modules/openclaw/97 MB (a nested second copy of openclaw itself).
  5. time openclaw config get meta → ~23s wall, ~32s user CPU. Trivial command, ~15s of which is module-resolution / dlopen overhead from the nested openclaw and its native deps.
  6. Quarantine just the nested copy: mv ~/.openclaw/extensions/lossless-claw/node_modules/openclaw /tmp/.
  7. Re-run time openclaw config get meta7.6s (matches the time when the entire extension is hidden — proving the nested openclaw was the entire 15s tax).

Expected behavior

peerDependencies on openclaw should not cause a second copy of openclaw to be installed inside the plugin's node_modules/. The host CLI is already openclaw and should satisfy the peer at load time. Either:

  • Install plugins with --omit=peer (or --legacy-peer-deps) so npm 7+ doesn't auto-install missing peers, or
  • Symlink/inject the running openclaw into the plugin's node_modules/openclaw so npm sees it as already satisfied, or
  • Configure Node's module resolution so import 'openclaw' from the plugin resolves to the host install path.

Devastating-sized native deps (lancedb, koffi, jimp, napi-rs, pdfjs) should never end up in a plugin install just because the plugin peer-depends on openclaw.

Actual behavior

~/.openclaw/extensions/<plugin>/node_modules/ ends up at hundreds of MBs with a self-referential nested openclaw and its full chat/vector/native-binding dep tree. Every subcommand pays ~15s of import + dlopen overhead. Plugin authors and end-users have no signal anything is wrong — the plugin loads and works, it's just slow on every invocation.

Top offenders observed in ~/.openclaw/extensions/lossless-claw/node_modules/ (lossless-claw itself only declares 4 runtime deps totaling ~16 MB):

Module Size Reachable from?
openclaw/ 97 MB (the nested copy itself)
@lancedb/ 92 MB nested openclaw only
@jimp/ 88 MB nested openclaw only
pdfjs-dist/ 40 MB nested openclaw only
koffi/ 28 MB nested openclaw only
@napi-rs/ 25 MB nested openclaw only
@larksuiteoapi/ 24 MB nested openclaw only
typescript/ 23 MB dev-dep leak
@img/ 16 MB nested openclaw only

openclaw plugins inspect lossless-claw reports the install as Source: npm, Spec: @martian-engineering/lossless-claw@0.9.2, confirming this came from openclaw plugins install, not a manual drop.

OpenClaw version

2026.4.15 (041266a)

Operating system

macOS 26.3.1 (arm64), Node 25.8.0

Install method

npm global (package manager: pnpm per openclaw status)

Model

openai-codex/gpt-5.4

Provider / routing chain

openclaw -> openai-codex

Additional provider/model setup details

Not relevant — the bug is in openclaw plugins install, independent of model/provider routing.

Logs, screenshots, and evidence

$ cat ~/.openclaw/extensions/lossless-claw/package.json | jq '.dependencies, .peerDependencies, .scripts.build'
{
  "@mariozechner/pi-agent-core": "0.66.1",
  "@mariozechner/pi-ai": "0.66.1",
  "@mariozechner/pi-coding-agent": "0.66.1",
  "@sinclair/typebox": "0.34.48"
}
{ "openclaw": "*" }
"esbuild index.ts --bundle --platform=node --target=node22 --format=esm --outfile=dist/index.js --external:openclaw --external:\"@mariozechner/*\" --minify-whitespace"

# Direct deps total ~16 MB. Actual node_modules:
$ du -sh ~/.openclaw/extensions/lossless-claw/node_modules/
817M

# The nested openclaw is a full copy of the host install:
$ du -sh ~/.openclaw/extensions/lossless-claw/node_modules/openclaw/
 97M

# Timing comparison:
$ time openclaw config get meta > /dev/null
openclaw config get meta > /dev/null  31.11s user 2.15s system 143% cpu 23.240 total

$ mv ~/.openclaw/extensions/lossless-claw/node_modules/openclaw /tmp/quarantine/
$ time openclaw config get meta > /dev/null
openclaw config get meta > /dev/null  11.03s user 0.57s system 152% cpu  7.592 total

# (Same 7.6s as when the entire extension dir is hidden — so the nested openclaw is the *entire* tax.)

Impact and severity

  • Affected: every plugin that declares peerDependencies: { "openclaw": "*" } (or any version range) installed via openclaw plugins install on a machine with npm 7+.
  • Severity: Medium. Plugins still load and work; UX is significantly degraded. ~15s added latency on every CLI invocation, plus ~700 MB of unneeded disk per such plugin.
  • Frequency: Always reproduces on the configurations above. 3/3 timed openclaw status runs were ~19s wall (vs. ~4s expected); 3/3 trivial commands like config get meta were ~23s.
  • Consequence: CLI feels broken, users assume openclaw itself is slow, plugin authors get blamed for slow startup that's not their fault. Plus large unnecessary disk consumption per plugin.

Additional information

This is the unintended consequence of the fix for #53517 ("openclaw plugins install does not install peer dependency"). That fix made openclaw plugins install properly run npm install, which under npm 7+ auto-installs peer deps. For plugins whose peer is openclaw itself, that means installing a fresh second copy of the host CLI as a child of the plugin — recursive in spirit, since openclaw is what's installing the plugin.

Suggested fix: openclaw plugins install should pass --omit=peer to npm (and resolve the host's openclaw via symlink, hoist, or NODE_PATH for plugins that genuinely need to import 'openclaw' at runtime). Probably also --omit=dev — TypeScript leaked in here as a 23 MB devDep.

Metadata

Metadata

Assignees

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