Skip to content

fix(plugins): include explicitly enabled plugins in startup plan (DOJ-4055)#1

Merged
lapc506 merged 1 commit into
dojo/v2026.5.7-fixesfrom
andres/doj-4055-fix-plugin-resolver
May 21, 2026
Merged

fix(plugins): include explicitly enabled plugins in startup plan (DOJ-4055)#1
lapc506 merged 1 commit into
dojo/v2026.5.7-fixesfrom
andres/doj-4055-fix-plugin-resolver

Conversation

@lapc506
Copy link
Copy Markdown
Collaborator

@lapc506 lapc506 commented May 21, 2026

Summary

21-line patch (1 file, +21/-0) to src/plugins/gateway-startup-plugin-ids.ts restoring pre-v2026.5.7 behavior for tool/hook/route plugins that declare no capability slot.

Problem

The shouldConsiderForGatewayStartup filter at line 134 builds plan.pluginIds (which becomes onlyPluginIds scope for loadOpenClawPlugins). Pre-patch, the filter only included plugins matching one of: manifest.activation.onStartup === true, context-engine slot, memory slot, channel/root/speech-provider/generation-provider gates, explicit-hook gate, or agent-harness match.

The DojoOS Agent plugin (which registers 43 tools, 11 hooks, and 17 HTTP routes via the SDK at module-import time) declares no channel, no provider contract, no memory slot, no activation.onStartup, and no agent-harness wiring. Every gate returned false. The plugin id was silently dropped from plan.pluginIds. Downstream, loader.ts:1715 (matchesScopedPluginRequest) skipped its discovery candidate before any import() ran.

5-breadcrumb instrumentation in the plugin (including a console.error("[DojoOS-plugin] module-loaded") on line 1 of index.ts before any imports) confirmed: zero breadcrumbs reached Cloud Run logs. The plugin module is never evaluated by Node. The failure is upstream of plugin code, in this resolver.

Fix

Adds one branch to shouldConsiderForGatewayStartup: for non-bundled plugins, treat explicit operator enablement (pluginsConfig.entries[id]?.enabled === true OR pluginsConfig.allow.includes(id) OR membership in activationSourcePlugins) as sufficient signal to include the plugin in the startup plan.

The branch is positioned at the end (after all capability gates) so plugins that ALSO declare a capability slot continue to short-circuit on the gate that fits them. Only plugins that pass NO capability gate but ARE explicitly enabled in config fall through to the new branch.

Bundled plugin behavior is unchanged (!manifest.bundled guard).

Test plan

  • src/plugins/bundled-plugin-metadata.test.ts: 30/30 ✓
  • src/plugins/loader.test.ts + manifest-registry.test.ts + setup-registry.test.ts + cli/plugins-cli.list.test.ts: 209/209 ✓
  • tsc --noEmit: no new errors (3 pre-existing errors in unrelated agents/pi-embedded-runner.*.test.ts files remain — TS2352 casts on AgentMessage, not touched by this PR)
  • pnpm install --frozen-lockfile clean under Node 22.22.2
  • pnpm run build + pnpm run ui:install + pnpm run ui:build clean
  • npm pack produces openclaw-2026.5.7.tgz (24.4 MB, 9,708 files) with SHA256 6224c7141406f8fdc52adfe59db12395a0dc58ce43e6f3565c29f2be3803f3a1
  • Released as v2026.5.7-dojo.2
  • Verified end-to-end on dojo-agent-internal-staging revision 00021-zpm (2026-05-20T23:52:17Z): [gateway] http server listening (2 plugins: openclaw-plugin, slack), [plugins] DojoOS Agent Plugin registered: 43 tools, 11 hooks, 17 routes (shared mode), /api/health HTTP 200, /api/sessions HTTP 401

Risk assessment

  • Over-inclusion of plugins: plugins explicitly enabled in config but lacking any capability gate are now included. This restores pre-v2026.5.7 behavior — operator opted in via config, this is desired, not a leak.
  • allow vs entries[id].enabled reconciliation: the new branch accepts either as sufficient. The previous semantics didn't have to reconcile because no path reached this code. Explicit by design.
  • Test coverage gap: this PR does NOT add a new test for "plugin explicitly enabled with no capability gate". I recommend adding one before merging — case shape outlined in the linked openspec tasks.md T-09. Happy to add in a follow-up commit if the maintainer prefers.

Linear

DOJ-4055 — plugin-load regression diagnosis chain (Race B + C + D + E) preserved in the consuming plugin repo's openspec/changes directory: doj-4055-plugin-load-fix.

Created by Claude Code on behalf of @lapc506.

🤖 Generated with Claude Code

…startup [DOJ-4055]

v2026.5.7 introduced a `shouldConsiderForGatewayStartup` filter in
`resolveGatewayStartupPluginPlanFromRegistry` that builds the list of
`onlyPluginIds` passed to `loadOpenClawPlugins`. The filter accepts a
plugin only when it declares `activation.onStartup === true`, is the
context-engine slot, or is a memory-startup plugin matching the dreaming
or memory-slot configuration.

For tool/hook/route plugins that the operator has explicitly enabled via
`plugins.entries.{id}.enabled = true` (and/or pinned in `plugins.allow`)
but that do NOT also expose a channel/provider/memory contract or declare
`activation.onStartup`, every `canStart*` path returns false and
`shouldConsiderForGatewayStartup` returns false. The plugin id is silently
dropped from `plan.pluginIds`. Downstream, the loader's
`matchesScopedPluginRequest` skips any candidate not in `onlyPluginIds`,
so the plugin module is never `import()`-ed.

Race B's instrumentation in the DojoOS Agent plugin confirmed this empirically:
five `console.error` breadcrumbs at the top of `dist/index.js` (well before
any sub-import) never fired, while the gateway emitted
`http server listening (1 plugin: slack)` and never logged
`DojoOS Agent Plugin registered`. Race D removed `plugins.load.paths` from
the gateway config (eliminating the redundant config-source candidate and
the matching `duplicate plugin id` warning), but the global candidate still
failed to load — because the gateway-startup filter, not duplicate
resolution, was excluding it.

This commit adds a single branch to `shouldConsiderForGatewayStartup`:
for any non-bundled plugin, treat an explicit
`entries.{id}.enabled === true` OR explicit `plugins.allow` membership as
sufficient signal to consider the plugin at gateway startup. Bundled
plugin semantics are unchanged (they keep relying on
`activation.onStartup`, slot configuration, and channel detection).

Tests: `src/plugins/bundled-plugin-metadata.test.ts` continues to pass
(30/30), including the empty-config-startup baseline and the
"starts Bonjour when explicitly enabled" case (Bonjour is bundled, so
it routes through the pre-existing paths; the new branch only widens
non-bundled startup behavior). Full plugin/loader/registry suite passes
(209/209: loader, manifest-registry, setup-registry, plugins-cli.list).

Scope: 21 lines added in a single file
(`src/plugins/gateway-startup-plugin-ids.ts`). No public type changes, no
config-schema additions, no architectural restructuring.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@lapc506 lapc506 merged commit 578af25 into dojo/v2026.5.7-fixes May 21, 2026
99 of 115 checks passed
@lapc506 lapc506 deleted the andres/doj-4055-fix-plugin-resolver branch May 21, 2026 02:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant