From 9ea0b76f0661803604e19f2dd7105caba64eecb9 Mon Sep 17 00:00:00 2001 From: George Zhang Date: Sun, 29 Mar 2026 10:17:37 -0700 Subject: [PATCH] docs(plugins): document before_install hook --- CHANGELOG.md | 1 + docs/automation/hooks.md | 25 +++++++++++++++++++++++++ docs/concepts/agent-loop.md | 3 +++ docs/plugins/building-plugins.md | 2 ++ docs/plugins/sdk-overview.md | 2 ++ docs/tools/plugin.md | 2 ++ 6 files changed, 35 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60f3f7f8938..7bbb5c91525 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ Docs: https://docs.openclaw.ai - LINE/outbound media: add LINE image, video, and audio outbound sends on the LINE-specific delivery path, including explicit preview/tracking handling for videos while keeping generic media sends on the existing image-only route. (#45826) Thanks @masatohoshino. - WhatsApp/reactions: agents can now react with emoji on incoming WhatsApp messages, enabling more natural conversational interactions like acknowledging a photo with ❤️ instead of typing a reply. Thanks @mcaxtr. - MCP: add remote HTTP/SSE server support for `mcp.servers` URL configs, including auth headers and safer config redaction for MCP credentials. (#50396) Thanks @dhananjai1729. +- Plugins/hooks: add a `before_install` hook so external security scanners and policy engines can inspect built-in install scan findings, add their own warnings, and block skill or plugin installs. (#56050) thanks @odysseus0. ### Fixes diff --git a/docs/automation/hooks.md b/docs/automation/hooks.md index 15bbcd9e436..af1660cc57d 100644 --- a/docs/automation/hooks.md +++ b/docs/automation/hooks.md @@ -495,6 +495,31 @@ The `pluginId` field is stamped automatically by the hook runner from the plugin If the gateway is unavailable or does not support plugin approvals, the tool call falls back to a soft block using the `description` as the block reason. +#### before_install + +Runs after the built-in install security scan and before installation continues. OpenClaw fires this hook for interactive skill installs as well as plugin bundle/package installs. + +Return fields: + +- **`findings`**: Additional scan findings to surface as warnings +- **`block`**: Set to `true` to block the install +- **`blockReason`**: Human-readable reason shown when blocked + +Event fields: + +- **`targetType`**: Install target category (`skill` or `plugin`) +- **`targetName`**: Human-readable skill name or plugin id for the install target +- **`sourceDir`**: Absolute path to the source directory being scanned +- **`source`**: Install origin when available (for example `openclaw-bundled`, `openclaw-workspace`, `plugin-bundle`, or `plugin-package`) +- **`builtinFindings`**: Findings already produced by the built-in scanner + +Decision semantics: + +- `before_install`: `{ block: true }` is terminal and stops lower-priority handlers. +- `before_install`: `{ block: false }` is treated as no decision. + +Use this hook for external security scanners, policy engines, or enterprise approval gates that need to audit install sources before they are installed. + #### Compaction lifecycle Compaction lifecycle hooks exposed through the plugin hook runner: diff --git a/docs/concepts/agent-loop.md b/docs/concepts/agent-loop.md index 3bb138f6912..b7ddabeb293 100644 --- a/docs/concepts/agent-loop.md +++ b/docs/concepts/agent-loop.md @@ -87,6 +87,7 @@ These run inside the agent loop or gateway pipeline: - **`agent_end`**: inspect the final message list and run metadata after completion. - **`before_compaction` / `after_compaction`**: observe or annotate compaction cycles. - **`before_tool_call` / `after_tool_call`**: intercept tool params/results. +- **`before_install`**: inspect built-in scan findings and optionally block skill or plugin installs. - **`tool_result_persist`**: synchronously transform tool results before they are written to the session transcript. - **`message_received` / `message_sending` / `message_sent`**: inbound + outbound message hooks. - **`session_start` / `session_end`**: session lifecycle boundaries. @@ -96,6 +97,8 @@ Hook decision rules for outbound/tool guards: - `before_tool_call`: `{ block: true }` is terminal and stops lower-priority handlers. - `before_tool_call`: `{ block: false }` is a no-op and does not clear a prior block. +- `before_install`: `{ block: true }` is terminal and stops lower-priority handlers. +- `before_install`: `{ block: false }` is a no-op and does not clear a prior block. - `message_sending`: `{ cancel: true }` is terminal and stops lower-priority handlers. - `message_sending`: `{ cancel: false }` is a no-op and does not clear a prior cancel. diff --git a/docs/plugins/building-plugins.md b/docs/plugins/building-plugins.md index 8b4375bf1a7..da8bc62baca 100644 --- a/docs/plugins/building-plugins.md +++ b/docs/plugins/building-plugins.md @@ -162,6 +162,8 @@ Hook guard semantics to keep in mind: - `before_tool_call`: `{ block: true }` is terminal and stops lower-priority handlers. - `before_tool_call`: `{ block: false }` is treated as no decision. - `before_tool_call`: `{ requireApproval: true }` pauses agent execution and prompts the user for approval via the exec approval overlay, Telegram buttons, Discord interactions, or the `/approve` command on any channel. +- `before_install`: `{ block: true }` is terminal and stops lower-priority handlers. +- `before_install`: `{ block: false }` is treated as no decision. - `message_sending`: `{ cancel: true }` is terminal and stops lower-priority handlers. - `message_sending`: `{ cancel: false }` is treated as no decision. diff --git a/docs/plugins/sdk-overview.md b/docs/plugins/sdk-overview.md index 12dafab4869..1e32ce797b9 100644 --- a/docs/plugins/sdk-overview.md +++ b/docs/plugins/sdk-overview.md @@ -198,6 +198,8 @@ AI CLI backend such as `claude-cli` or `codex-cli`. - `before_tool_call`: returning `{ block: true }` is terminal. Once any handler sets it, lower-priority handlers are skipped. - `before_tool_call`: returning `{ block: false }` is treated as no decision (same as omitting `block`), not as an override. +- `before_install`: returning `{ block: true }` is terminal. Once any handler sets it, lower-priority handlers are skipped. +- `before_install`: returning `{ block: false }` is treated as no decision (same as omitting `block`), not as an override. - `message_sending`: returning `{ cancel: true }` is terminal. Once any handler sets it, lower-priority handlers are skipped. - `message_sending`: returning `{ cancel: false }` is treated as no decision (same as omitting `cancel`), not as an override. diff --git a/docs/tools/plugin.md b/docs/tools/plugin.md index 6a927658be3..e7ea68c0714 100644 --- a/docs/tools/plugin.md +++ b/docs/tools/plugin.md @@ -263,6 +263,8 @@ Hook guard behavior for typed lifecycle hooks: - `before_tool_call`: `{ block: true }` is terminal; lower-priority handlers are skipped. - `before_tool_call`: `{ block: false }` is a no-op and does not clear an earlier block. +- `before_install`: `{ block: true }` is terminal; lower-priority handlers are skipped. +- `before_install`: `{ block: false }` is a no-op and does not clear an earlier block. - `message_sending`: `{ cancel: true }` is terminal; lower-priority handlers are skipped. - `message_sending`: `{ cancel: false }` is a no-op and does not clear an earlier cancel.