Skip to content

fix: keep bundled OpenClaw plugins image-owned#86754

Merged
steipete merged 3 commits into
openclaw:mainfrom
fuller-stack-dev:fix/docker-core-plugin-drift
May 26, 2026
Merged

fix: keep bundled OpenClaw plugins image-owned#86754
steipete merged 3 commits into
openclaw:mainfrom
fuller-stack-dev:fix/docker-core-plugin-drift

Conversation

@fuller-stack-dev

@fuller-stack-dev fuller-stack-dev commented May 26, 2026

Copy link
Copy Markdown
Member

Summary

  • Prefer the bundled install plan when a raw npm spec matches an OpenClaw-bundled plugin package, including scoped/versioned specs like @openclaw/[email protected].
  • Preserve explicit external npm overrides through the existing npm:<spec> escape hatch.
  • Document the Docker persistence boundary: external packages and install records live in mounted state, but bundled OpenClaw channel plugins should normally load from the image-matched copy.

Anonymized Source Evidence

A Docker-managed setup installed a pinned bundled channel package into mounted OpenClaw state, where it shadowed the bundled plugin from newer images.

  • Redacted config-audit output showed setup running channels add --channel discord --use-env.
  • Redacted config-audit output then showed plugins install @openclaw/[email protected] --pin --force.
  • Redacted install state recorded installRecords.discord.source = npm, spec = @openclaw/[email protected], and installPath = <state>/npm/node_modules/@openclaw/discord.
  • Redacted active plugin state showed the Discord plugin loading from <state>/npm/node_modules/@openclaw/discord, origin = global, packageVersion = 2026.5.20.
  • Redacted mounted npm state still pinned @openclaw/discord to 2026.5.20.
  • The runtime image and mounted plugin versions were split, so Docker could update the gateway image while continuing to load old bundled plugin code from persistent npm state.

Real behavior proof

Behavior addressed: Raw npm specs matching bundled OpenClaw plugin packages now resolve to the bundled image copy before npm fallback, so setup cannot pin a stale managed npm override unless the operator explicitly uses npm:<spec>.

Real environment tested: Local OpenClaw CLI from this PR branch, using a clean temporary state directory and a built dist/ tree.

Exact steps or command run after this patch:

export STATE_DIR="$(mktemp -d /tmp/openclaw-pr-86754.XXXXXX)"
OPENCLAW_STATE_DIR="$STATE_DIR" \
OPENCLAW_CONFIG_DIR="$STATE_DIR" \
OPENCLAW_CONFIG_PATH="$STATE_DIR/openclaw.json" \
OPENCLAW_WORKSPACE_DIR="$STATE_DIR/workspace" \
OPENCLAW_DISABLE_BONJOUR=1 \
node scripts/run-node.mjs plugins install @openclaw/[email protected] --pin --force

node -e 'const fs=require("fs"); const data=JSON.parse(fs.readFileSync(process.env.STATE_DIR+"/plugins/installs.json","utf8")); console.log(JSON.stringify(data.installRecords.discord,null,2));'

Evidence after fix: Redacted terminal output from the clean-state CLI smoke:

Using bundled plugin "discord" from <repo>/dist/extensions/discord for npm install spec "@openclaw/[email protected]" because this plugin ships with the current OpenClaw build. To force an external npm override, use npm:@openclaw/[email protected].
Installed plugin: discord
Restart the gateway to load plugins.
{
  "source": "path",
  "spec": "@openclaw/[email protected]",
  "sourcePath": "<repo>/dist/extensions/discord",
  "installPath": "<repo>/dist/extensions/discord",
  "installedAt": "<timestamp>"
}

Observed result after fix: The install completed as source: path with sourcePath and installPath pointing at the bundled Discord plugin under <repo>/dist/extensions/discord; it did not create a managed npm override for @openclaw/[email protected].

What was not tested: Already-persisted stale npm install records were not migrated; this PR only changes future install routing. Existing-state cleanup should be handled separately through doctor/update repair if maintainers want that behavior.

Tests

  • node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfo
  • node scripts/run-vitest.mjs src/cli/plugin-install-plan.test.ts src/cli/plugins-cli.install.test.ts -> 2 files passed, 100 tests passed
  • pnpm exec oxlint src/cli/plugin-install-plan.ts src/cli/plugin-install-plan.test.ts src/cli/plugins-cli.install.test.ts
  • pnpm docs:check-mdx
  • pnpm docs:check-links -- docs/cli/plugins.md docs/tools/plugin.md
  • git diff --check
  • Clean-state CLI smoke above

@openclaw-barnacle openclaw-barnacle Bot added cli CLI command changes scripts Repository scripts size: S triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 26, 2026
@clawsweeper

clawsweeper Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed May 26, 2026, 1:19 AM ET / 05:19 UTC.

Summary
The PR changes plugin install planning so raw registry specs matching bundled OpenClaw plugin packages resolve to the bundled image copy, adds CLI/helper coverage, and updates plugin and Clawdock docs for the npm: override.

PR surface: Source +24, Tests +82, Docs +12. Total +118 across 6 files.

Reproducibility: yes. from source inspection: current main returns null for scoped specs before bundled planning, then the install command proceeds to npm resolution. I did not run the CLI in this read-only review, but the PR body includes after-fix terminal output for the intended path-install result.

Review metrics: 1 noteworthy metric.

  • Install source routing changed: 1 raw registry-spec path redirected for bundled packages. This changes the source selected by existing plugins install @openclaw/<plugin> workflows and needs explicit compatibility acceptance before merge.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Maintainers should explicitly accept the bundled-first raw scoped package policy before merge.

Risk before merge

  • Merging changes raw scoped bundled @openclaw/* install specs from npm-managed installs to image-owned bundled path installs; operators intentionally using raw scoped specs for external overrides must switch to npm:.

Maintainer options:

  1. Accept bundled-first scoped specs (recommended)
    Land this if maintainers want bundled @openclaw/* packages to stay image-owned and accept requiring npm: for external npm overrides.
  2. Require upgrade cleanup proof first
    Ask for additional doctor/update proof before merge if maintainers want this PR to cover already-persisted stale npm install records, not only future installs.
  3. Pause if raw scoped specs must remain npm-owned
    Pause or replace the PR if raw scoped package specs are still expected to mean npm unless explicitly installed by plugin id or catalog flow.

Next step before merge
The remaining blocker is maintainer acceptance of the source-selection compatibility change, not a narrow automated code repair.

Security
Cleared: No concrete security or supply-chain regression was found; the diff narrows accidental npm shadowing and does not change dependencies, lockfiles, CI permissions, or downloaded artifact execution.

Review details

Best possible solution:

Land the bundled-first routing only if maintainers accept raw scoped bundled OpenClaw packages becoming image-owned by default, with npm: kept as the documented external override and doctor/update handling existing stale drift separately.

Do we have a high-confidence way to reproduce the issue?

Yes from source inspection: current main returns null for scoped specs before bundled planning, then the install command proceeds to npm resolution. I did not run the CLI in this read-only review, but the PR body includes after-fix terminal output for the intended path-install result.

Is this the best way to solve the issue?

Yes, if maintainers accept the compatibility policy. The code change is narrow, the tests cover helper and CLI behavior, docs now describe the npm: override, and current doctor code already covers stale bundled shadow cleanup separately.

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 505aca9ef7a4.

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes structured after-fix terminal output from a clean-state local CLI smoke showing the install record persisted as source: path under the bundled Discord path.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes structured after-fix terminal output from a clean-state local CLI smoke showing the install record persisted as source: path under the bundled Discord path.
  • remove rating: 🦐 gold shrimp: Current PR rating is rating: 🐚 platinum hermit, so this older rating label is no longer current.
  • remove status: ⏳ waiting on author: Current PR status label is status: 👀 ready for maintainer look.

Label justifications:

  • P2: This is a normal-priority CLI/plugin install compatibility fix with limited but real operator impact.
  • merge-risk: 🚨 compatibility: The PR changes install-source resolution for existing raw bundled package specs and requires npm: for the previous external npm override behavior.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes structured after-fix terminal output from a clean-state local CLI smoke showing the install record persisted as source: path under the bundled Discord path.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes structured after-fix terminal output from a clean-state local CLI smoke showing the install record persisted as source: path under the bundled Discord path.
Evidence reviewed

PR surface:

Source +24, Tests +82, Docs +12. Total +118 across 6 files.

View PR surface stats
Area Files Added Removed Net
Source 1 30 6 +24
Tests 2 85 3 +82
Docs 3 22 10 +12
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 6 137 19 +118

What I checked:

  • Repository policy read and applied: Root, docs, and scripts AGENTS.md were read; root policy treats plugin install routing, fallback behavior, persisted state, and docs alignment as compatibility-sensitive review surfaces. (AGENTS.md:18, 505aca9ef7a4)
  • Current main behavior: On current main, resolveBundledInstallPlanBeforeNpm only handles bare npm package names and returns null for scoped specs, so a raw @openclaw/discord@... spec continues into the npm install path. (src/cli/plugin-install-plan.ts:69, 505aca9ef7a4)
  • PR implementation: At PR head, the helper parses raw registry specs and checks both the exact spec and parsed package name against bundled npm specs before npm fallback, while the warning points operators to npm:<spec> for external overrides. (src/cli/plugin-install-plan.ts:87, 0fd6e1977e08)
  • PR regression coverage: The PR adds an install-command test proving @openclaw/[email protected] --pin --force does not call npm and persists a path install record pointing at the bundled Discord path. (src/cli/plugins-cli.install.test.ts:1074, 0fd6e1977e08)
  • Docs alignment: The latest PR head now documents that raw @openclaw/* package specs matching bundled plugins use the bundled copy and that npm:@openclaw/<plugin>@<version> forces the external npm package. Public docs: docs/cli/plugins.md. (docs/cli/plugins.md:176, 0fd6e1977e08)
  • Existing stale-state repair path: Current main already has doctor logic and docs for removing managed npm drift that shadows bundled plugins, so this PR can stay focused on future install routing rather than migrating every existing record inline. (src/commands/doctor/shared/missing-configured-plugin-install.ts:724, 505aca9ef7a4)

Likely related people:

  • Vincent Koc: Git blame/log in this checkout show the current central plugin install planning and bundled-source code coming from commit 6421808. (role: recent area contributor; confidence: medium; commits: 6421808c2703; files: src/cli/plugin-install-plan.ts, src/cli/plugins-install-command.ts, src/plugins/bundled-sources.ts)
  • steipete: The prior ClawSweeper feature-history evidence for this PR identified recent work on plugin install planning, plugin docs, and stale bundled-plugin repair in the same surface. (role: recent plugin install/docs contributor; confidence: medium; commits: d00d0a21c2dd, ad12d1fbce8f, 56960e33e658; files: src/cli/plugin-install-plan.ts, docs/cli/plugins.md, docs/tools/plugin.md)
  • Takhoffman: The prior review evidence connected this area to earlier bundled-channel precedence work, which is directly adjacent to the source-selection decision here. (role: prior bundled-precedence contributor; confidence: low; commits: 74624e619d41; files: src/cli/plugin-install-plan.ts, src/plugins/bundled-sources.ts, src/plugins/update.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels May 26, 2026
@clawsweeper

clawsweeper Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

✨ Hatched: 🥚 common Sunspot Proofling

Hatch command

Comment @clawsweeper hatch when this PR is hatchable.

Hatchability rules:

  • Merged PRs are hatchable.
  • Open PRs are hatchable when they are status: 👀 ready for maintainer look, status: 🚀 automerge armed, or labeled clawsweeper:automerge.
  • Closed unmerged PRs are hatchable only when one of those hatchable labels is still present in the durable record.

Rarity: 🥚 common.
Trait: sniffs out flaky tests.
Image traits: location release reef; accessory tiny test log scroll; palette cobalt, lime, and pearl; mood celebratory; pose leaning over a miniature review desk; shell woven fiber shell; lighting bright celebratory glints; background delicate sparkle particles.
Share on X: post this hatch
Copy: My PR egg hatched a 🥚 common Sunspot Proofling in ClawSweeper.

What is this egg doing here?
  • Eggs appear after the PR passes real-behavior proof. It is here for vibes, not verdicts: it does not change labels, ratings, merge decisions, or automation.
  • The shell reacts to review momentum: open follow-up work warms it up, re-review makes it wobble, and a clean final review lets it hatch.
  • Hatchability usually comes from sufficient real-behavior proof, no blocking P0/P1/P2 findings, no security attention needed, and clean correctness. A merged PR is already final, so merge makes the egg hatchable independently.
  • The hatch is seeded from this repository and PR number, so the same PR keeps the same creature; the reviewed head SHA can only change safe visual details.
  • Rarity is just collectible sparkle: 🥚 common, 🌱 uncommon, 💎 rare, ✨ glimmer, and 🌈 legendary.

@openclaw-barnacle openclaw-barnacle Bot removed the triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. label May 26, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels May 26, 2026
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed proof: sufficient ClawSweeper judged the real behavior proof convincing. labels May 26, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 26, 2026
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation and removed proof: sufficient ClawSweeper judged the real behavior proof convincing. labels May 26, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels May 26, 2026
@steipete steipete self-assigned this May 26, 2026
@steipete
steipete force-pushed the fix/docker-core-plugin-drift branch from 0fd6e19 to 8dd1521 Compare May 26, 2026 22:44
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 26, 2026
@steipete
steipete force-pushed the fix/docker-core-plugin-drift branch from 8dd1521 to 89aa839 Compare May 26, 2026 22:51
@steipete
steipete force-pushed the fix/docker-core-plugin-drift branch from 89aa839 to 40fa750 Compare May 26, 2026 22:51
@steipete
steipete merged commit 40fa750 into openclaw:main May 26, 2026
@steipete

Copy link
Copy Markdown
Contributor

Landed via fast-forward of the rebased PR head onto main.

Thanks @fuller-stack-dev!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli CLI command changes docs Improvements or additions to documentation merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. scripts Repository scripts size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants