Skip to content

before_install hook not triggered by CLI openclaw plugins install #91593

Description

@Trump-last

Summary

The before_install plugin hook is never triggered when installing plugins via the CLI command openclaw plugins install <spec>, even when a plugin that registers a before_install handler is already installed and loaded in the running Gateway. The hook fires correctly when installing via the Gateway chat command /plugins install.

This means enterprise policy and security scanner plugins cannot enforce install-time checks through the most common installation path.

Steps to Reproduce

  1. Install a plugin that registers a before_install hook handler
  2. Start the Gateway (openclaw gateway run)
  3. Verify the hook is registered (e.g., via probe logging in the handler)
  4. Run: openclaw plugins install @openclaw/browser-plugin
  5. Observe: the before_install handler is never invoked

For comparison, repeating the install via Gateway chat /plugins install @openclaw/browser-plugin correctly triggers the hook.

Expected Behavior

before_install should fire for all plugin installation paths, as documented in PR #56050:

It now covers:

  • interactive skill installs
  • plugin bundle installs
  • plugin package installs
  • single-file plugin installs

CLI openclaw plugins install is a plugin package install path and should be covered.

Root Cause

The CLI and Gateway run in separate processes with independent memory spaces. The before_install hook depends on a process-local singleton (getGlobalHookRunner()) that is only initialized when the plugin system is loaded.

CLI process flow:

  1. src/cli/command-catalog.ts — there is no catalog entry for ["plugins", "install"]
  2. src/cli/command-path-policy.ts:12-20 — falls through to default policy loadPlugins: "never"
  3. src/cli/command-bootstrap.ts:33-35ensureCliCommandBootstrap returns immediately when loadPlugins is false, never calling loadOpenClawPlugins()
  4. src/plugins/hook-runner-global.ts:60-62getGlobalHookRunner() returns null in the CLI process
  5. src/plugins/install-security-scan.runtime.ts:726-728 — the null check silently returns undefined, skipping the hook entirely

Gateway process flow (works correctly):

  1. Gateway startup calls loadGatewayStartupPlugins()loadOpenClawPlugins()activatePluginRegistry()initializeGlobalHookRunner()
  2. The hook runner singleton is populated with all registered handlers
  3. runBeforeInstallHook finds the runner and executes the hook

The key issue is that Symbol.for singleton state is process-isolated — the CLI process cannot see the Gateway process's initialized hook runner.

Impact

Suggested Fix Directions

Option A — Load plugins for plugins install in CLI:

Add a catalog entry in src/cli/command-catalog.ts:

{
  commandPath: ["plugins", "install"],
  exact: true,
  policy: { loadPlugins: "always" },
},

This would cause the CLI process to load the plugin registry and initialize the hook runner before executing the install. Trade-off: increased CLI startup latency for the install command.

Option B — Delegate CLI installs to Gateway via RPC:

When a Gateway is running, route openclaw plugins install through a Gateway RPC call (e.g., skills.install or a dedicated endpoint) so the install executes in the Gateway process where plugins are already loaded. This avoids the startup cost but requires Gateway connectivity.

References

  • PR feat(plugins): add before_install hook for install policy checks #56050 — introduced before_install hook
  • Codex Bot P1 comment on install-security-scan.runtime.ts:42-44: "Initialize hooks before running install security scans"
  • Greptile Bot P1: "block: true is logged but installation is never actually prevented"
  • src/plugins/hook-runner-global.ts — singleton hook runner
  • src/plugins/install-security-scan.runtime.ts:700-771runBeforeInstallHook
  • src/cli/command-catalog.ts — declarative command routing (no ["plugins", "install"] entry)

Metadata

Metadata

Assignees

Labels

P1High-priority user-facing bug, regression, or broken workflow.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:queueable-fixClawSweeper marked this issue as an existing queue_fix_pr work candidate.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:securitySecurity boundary, credential, authz, sandbox, or sensitive-data risk.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

Type

No type

Fields

Priority

None yet

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions