mirror of
https://fastgit.cc/github.com/openclaw/openclaw
synced 2026-04-30 22:12:32 +08:00
docs: add plugin hooks reference
This commit is contained in:
@@ -343,6 +343,10 @@
|
||||
"source": "Plugin Entry Points",
|
||||
"target": "插件入口点"
|
||||
},
|
||||
{
|
||||
"source": "Plugin hooks",
|
||||
"target": "插件钩子"
|
||||
},
|
||||
{
|
||||
"source": "Entry Points",
|
||||
"target": "入口点"
|
||||
|
||||
@@ -205,9 +205,12 @@ Runs `BOOT.md` from the active workspace when the gateway starts.
|
||||
|
||||
## Plugin hooks
|
||||
|
||||
Plugins can register hooks through the Plugin SDK for deeper integration: intercepting tool calls, modifying prompts, controlling message flow, and more. The Plugin SDK exposes 28 hooks covering model resolution, agent lifecycle, message flow, tool execution, subagent coordination, and gateway lifecycle.
|
||||
Plugins can register typed hooks through the Plugin SDK for deeper integration:
|
||||
intercepting tool calls, modifying prompts, controlling message flow, and more.
|
||||
Use plugin hooks when you need `before_tool_call`, `before_agent_reply`,
|
||||
`before_install`, or other in-process lifecycle hooks.
|
||||
|
||||
For the complete plugin hook reference including `before_tool_call`, `before_agent_reply`, `before_install`, and all other plugin hooks, see [Plugin Architecture](/plugins/architecture-internals#provider-runtime-hooks).
|
||||
For the complete plugin hook reference, see [Plugin hooks](/plugins/hooks).
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -315,5 +318,5 @@ Check for missing binaries (PATH), environment variables, config values, or OS c
|
||||
|
||||
- [CLI Reference: hooks](/cli/hooks)
|
||||
- [Webhooks](/automation/cron-jobs#webhooks)
|
||||
- [Plugin Architecture](/plugins/architecture-internals#provider-runtime-hooks) — full plugin hook reference
|
||||
- [Plugin hooks](/plugins/hooks) — in-process plugin lifecycle hooks
|
||||
- [Configuration](/gateway/configuration-reference#hooks)
|
||||
|
||||
@@ -40,7 +40,7 @@ flowchart TD
|
||||
| Audit what ran and when | Background Tasks | `openclaw tasks list` and `openclaw tasks audit` |
|
||||
| Multi-step research then summarize | Task Flow | Durable orchestration with revision tracking |
|
||||
| Run a script on session reset | Hooks | Event-driven, fires on lifecycle events |
|
||||
| Execute code on every tool call | Hooks | Hooks can filter by event type |
|
||||
| Execute code on every tool call | Plugin hooks | In-process hooks can intercept tool calls |
|
||||
| Always check compliance before replying | Standing Orders | Injected into every session automatically |
|
||||
|
||||
### Scheduled Tasks (Cron) vs Heartbeat
|
||||
@@ -83,7 +83,11 @@ See [Standing Orders](/automation/standing-orders).
|
||||
|
||||
### Hooks
|
||||
|
||||
Hooks are event-driven scripts triggered by agent lifecycle events (`/new`, `/reset`, `/stop`), session compaction, gateway startup, message flow, and tool calls. Hooks are automatically discovered from directories and can be managed with `openclaw hooks`.
|
||||
Internal hooks are event-driven scripts triggered by agent lifecycle events
|
||||
(`/new`, `/reset`, `/stop`), session compaction, gateway startup, and message
|
||||
flow. They are automatically discovered from directories and can be managed
|
||||
with `openclaw hooks`. For in-process tool-call interception, use
|
||||
[Plugin hooks](/plugins/hooks).
|
||||
|
||||
See [Hooks](/automation/hooks).
|
||||
|
||||
@@ -97,7 +101,7 @@ See [Heartbeat](/gateway/heartbeat).
|
||||
|
||||
- **Cron** handles precise schedules (daily reports, weekly reviews) and one-shot reminders. All cron executions create task records.
|
||||
- **Heartbeat** handles routine monitoring (inbox, calendar, notifications) in one batched turn every 30 minutes.
|
||||
- **Hooks** react to specific events (tool calls, session resets, compaction) with custom scripts.
|
||||
- **Hooks** react to specific events (session resets, compaction, message flow) with custom scripts. Plugin hooks cover tool calls.
|
||||
- **Standing orders** give the agent persistent context and authority boundaries.
|
||||
- **Task Flow** coordinates multi-step flows above individual tasks.
|
||||
- **Tasks** automatically track all detached work so you can inspect and audit it.
|
||||
@@ -108,6 +112,7 @@ See [Heartbeat](/gateway/heartbeat).
|
||||
- [Background Tasks](/automation/tasks) — task ledger for all detached work
|
||||
- [Task Flow](/automation/taskflow) — durable multi-step flow orchestration
|
||||
- [Hooks](/automation/hooks) — event-driven lifecycle scripts
|
||||
- [Plugin hooks](/plugins/hooks) — in-process tool, prompt, message, and lifecycle hooks
|
||||
- [Standing Orders](/automation/standing-orders) — persistent agent instructions
|
||||
- [Heartbeat](/gateway/heartbeat) — periodic main-session turns
|
||||
- [Configuration Reference](/gateway/configuration-reference) — all config keys
|
||||
|
||||
@@ -15,7 +15,7 @@ Running `openclaw hooks` with no subcommand is equivalent to `openclaw hooks lis
|
||||
Related:
|
||||
|
||||
- Hooks: [Hooks](/automation/hooks)
|
||||
- Plugin hooks: [Plugin hooks](/plugins/architecture-internals#provider-runtime-hooks)
|
||||
- Plugin hooks: [Plugin hooks](/plugins/hooks)
|
||||
|
||||
## List All Hooks
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ Hook decision rules for outbound/tool guards:
|
||||
- `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.
|
||||
|
||||
See [Plugin hooks](/plugins/architecture-internals#provider-runtime-hooks) for the hook API and registration details.
|
||||
See [Plugin hooks](/plugins/hooks) for the hook API and registration details.
|
||||
|
||||
Harnesses may adapt these hooks differently. The Codex app-server harness keeps
|
||||
OpenClaw plugin hooks as the compatibility contract for documented mirrored
|
||||
|
||||
@@ -1158,6 +1158,7 @@
|
||||
"group": "Building plugins",
|
||||
"pages": [
|
||||
"plugins/building-plugins",
|
||||
"plugins/hooks",
|
||||
"plugins/sdk-channel-plugins",
|
||||
"plugins/sdk-provider-plugins",
|
||||
"plugins/sdk-migration"
|
||||
|
||||
@@ -33,7 +33,7 @@ falls back to npm automatically.
|
||||
<Card title="Provider plugin" icon="cpu" href="/plugins/sdk-provider-plugins">
|
||||
Add a model provider (LLM, proxy, or custom endpoint)
|
||||
</Card>
|
||||
<Card title="Tool / hook plugin" icon="wrench">
|
||||
<Card title="Tool / hook plugin" icon="wrench" href="/plugins/hooks">
|
||||
Register agent tools, event hooks, or services — continue below
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -163,7 +163,8 @@ A single plugin can register any number of capabilities via the `api` object:
|
||||
| Embedded Pi extension | `api.registerEmbeddedExtensionFactory(...)` | [SDK Overview](/plugins/sdk-overview#registration-api) |
|
||||
| Agent tools | `api.registerTool(...)` | Below |
|
||||
| Custom commands | `api.registerCommand(...)` | [Entry Points](/plugins/sdk-entrypoints) |
|
||||
| Event hooks | `api.registerHook(...)` | [Entry Points](/plugins/sdk-entrypoints) |
|
||||
| Plugin hooks | `api.on(...)` | [Plugin hooks](/plugins/hooks) |
|
||||
| Internal event hooks | `api.registerHook(...)` | [Entry Points](/plugins/sdk-entrypoints) |
|
||||
| HTTP routes | `api.registerHttpRoute(...)` | [Internals](/plugins/architecture-internals#gateway-http-routes) |
|
||||
| CLI subcommands | `api.registerCli(...)` | [Entry Points](/plugins/sdk-entrypoints) |
|
||||
|
||||
@@ -197,7 +198,7 @@ If custom approval plumbing needs to detect that same bounded fallback case,
|
||||
prefer `isApprovalNotFoundError` from `openclaw/plugin-sdk/error-runtime`
|
||||
instead of matching approval-expiry strings manually.
|
||||
|
||||
See [SDK Overview hook decision semantics](/plugins/sdk-overview#hook-decision-semantics) for details.
|
||||
See [Plugin hooks](/plugins/hooks) for examples and the hook reference.
|
||||
|
||||
## Registering agent tools
|
||||
|
||||
|
||||
188
docs/plugins/hooks.md
Normal file
188
docs/plugins/hooks.md
Normal file
@@ -0,0 +1,188 @@
|
||||
---
|
||||
summary: "Plugin hooks: intercept agent, tool, message, session, and Gateway lifecycle events"
|
||||
title: "Plugin hooks"
|
||||
read_when:
|
||||
- You are building a plugin that needs before_tool_call, before_agent_reply, message hooks, or lifecycle hooks
|
||||
- You need to block, rewrite, or require approval for tool calls from a plugin
|
||||
- You are deciding between internal hooks and plugin hooks
|
||||
---
|
||||
|
||||
Plugin hooks are in-process extension points for OpenClaw plugins. Use them
|
||||
when a plugin needs to inspect or change agent runs, tool calls, message flow,
|
||||
session lifecycle, subagent routing, installs, or Gateway startup.
|
||||
|
||||
Use [internal hooks](/automation/hooks) instead when you want a small
|
||||
operator-installed `HOOK.md` script for command and Gateway events such as
|
||||
`/new`, `/reset`, `/stop`, `agent:bootstrap`, or `gateway:startup`.
|
||||
|
||||
## Quick start
|
||||
|
||||
Register typed plugin hooks with `api.on(...)` from your plugin entry:
|
||||
|
||||
```typescript
|
||||
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
||||
|
||||
export default definePluginEntry({
|
||||
id: "tool-preflight",
|
||||
name: "Tool Preflight",
|
||||
register(api) {
|
||||
api.on(
|
||||
"before_tool_call",
|
||||
async (event) => {
|
||||
if (event.toolName !== "web_search") {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
requireApproval: {
|
||||
title: "Run web search",
|
||||
description: `Allow search query: ${String(event.params.query ?? "")}`,
|
||||
severity: "info",
|
||||
timeoutMs: 60_000,
|
||||
timeoutBehavior: "deny",
|
||||
},
|
||||
};
|
||||
},
|
||||
{ priority: 50 },
|
||||
);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Hook handlers run sequentially in descending `priority`. Same-priority hooks
|
||||
keep registration order.
|
||||
|
||||
## Common hooks
|
||||
|
||||
| Hook | Use it for |
|
||||
| ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
|
||||
| `before_tool_call` | Rewrite tool params, block execution, or request user approval before a tool runs. |
|
||||
| `after_tool_call` | Observe tool results, errors, and duration after execution. |
|
||||
| `before_prompt_build` | Add dynamic context or system prompt text before the model call. |
|
||||
| `before_model_resolve` | Override provider or model before session messages are loaded. |
|
||||
| `before_agent_reply` | Short-circuit the model turn with a synthetic reply or silence. |
|
||||
| `llm_input` / `llm_output` | Observe provider input/output for conversation-aware plugins. |
|
||||
| `agent_end` | Observe final messages, success state, and run duration. |
|
||||
| `message_received` | Observe inbound channel messages after channel parsing. |
|
||||
| `message_sending` | Rewrite or cancel outbound channel messages. |
|
||||
| `message_sent` | Observe outbound delivery success or failure. |
|
||||
| `session_start` / `session_end` | Track session lifecycle boundaries. |
|
||||
| `before_compaction` / `after_compaction` | Observe or annotate compaction cycles. |
|
||||
| `subagent_spawning` / `subagent_delivery_target` / `subagent_spawned` / `subagent_ended` | Coordinate subagent routing and completion delivery. |
|
||||
| `gateway_start` / `gateway_stop` | Start or stop plugin services with the Gateway. |
|
||||
| `before_install` | Inspect skill or plugin install scans and optionally block. |
|
||||
|
||||
## Tool call policy
|
||||
|
||||
`before_tool_call` receives:
|
||||
|
||||
- `event.toolName`
|
||||
- `event.params`
|
||||
- optional `event.runId`
|
||||
- optional `event.toolCallId`
|
||||
- context fields such as `ctx.agentId`, `ctx.sessionKey`, `ctx.sessionId`, and
|
||||
diagnostic `ctx.trace`
|
||||
|
||||
It can return:
|
||||
|
||||
```typescript
|
||||
type BeforeToolCallResult = {
|
||||
params?: Record<string, unknown>;
|
||||
block?: boolean;
|
||||
blockReason?: string;
|
||||
requireApproval?: {
|
||||
title: string;
|
||||
description: string;
|
||||
severity?: "info" | "warning" | "critical";
|
||||
timeoutMs?: number;
|
||||
timeoutBehavior?: "allow" | "deny";
|
||||
onResolution?: (decision: string) => Promise<void> | void;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- `block: true` is terminal and skips lower-priority handlers.
|
||||
- `block: false` is treated as no decision.
|
||||
- `params` rewrites the tool parameters for execution.
|
||||
- `requireApproval` pauses the agent run and asks the user through plugin
|
||||
approvals. The `/approve` command can approve both exec and plugin approvals.
|
||||
- A lower-priority `block: true` can still block after a higher-priority hook
|
||||
requested approval.
|
||||
|
||||
## Prompt and model hooks
|
||||
|
||||
Use the phase-specific hooks for new plugins:
|
||||
|
||||
- `before_model_resolve`: receives only the current prompt and attachment
|
||||
metadata. Return `providerOverride` or `modelOverride`.
|
||||
- `before_prompt_build`: receives the current prompt and session messages.
|
||||
Return `prependContext`, `systemPrompt`, `prependSystemContext`, or
|
||||
`appendSystemContext`.
|
||||
|
||||
`before_agent_start` remains for compatibility. Prefer the explicit hooks above
|
||||
so your plugin does not depend on a legacy combined phase.
|
||||
|
||||
Non-bundled plugins that need `llm_input`, `llm_output`, or `agent_end` must set:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"my-plugin": {
|
||||
"hooks": {
|
||||
"allowConversationAccess": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Prompt-mutating hooks can be disabled per plugin with
|
||||
`plugins.entries.<id>.hooks.allowPromptInjection=false`.
|
||||
|
||||
## Message hooks
|
||||
|
||||
Use message hooks for channel-level routing and delivery policy:
|
||||
|
||||
- `message_received`: observe inbound content, sender, `threadId`, and metadata.
|
||||
- `message_sending`: rewrite `content` or return `{ cancel: true }`.
|
||||
- `message_sent`: observe final success or failure.
|
||||
|
||||
Prefer typed `threadId` and `replyToId` fields before using channel-specific
|
||||
metadata.
|
||||
|
||||
Decision rules:
|
||||
|
||||
- `message_sending` with `cancel: true` is terminal.
|
||||
- `message_sending` with `cancel: false` is treated as no decision.
|
||||
- Rewritten `content` continues to lower-priority hooks unless a later hook
|
||||
cancels delivery.
|
||||
|
||||
## Install hooks
|
||||
|
||||
`before_install` runs after the built-in scan for skill and plugin installs.
|
||||
Return additional findings or `{ block: true, blockReason }` to stop the
|
||||
install.
|
||||
|
||||
`block: true` is terminal. `block: false` is treated as no decision.
|
||||
|
||||
## Gateway lifecycle
|
||||
|
||||
Use `gateway_start` for plugin services that need Gateway-owned state. The
|
||||
context exposes `ctx.config`, `ctx.workspaceDir`, and `ctx.getCron?.()` for
|
||||
cron inspection and updates. Use `gateway_stop` to clean up long-running
|
||||
resources.
|
||||
|
||||
Do not rely on the internal `gateway:startup` hook for plugin-owned runtime
|
||||
services.
|
||||
|
||||
## Related
|
||||
|
||||
- [Building plugins](/plugins/building-plugins)
|
||||
- [Plugin SDK overview](/plugins/sdk-overview)
|
||||
- [Plugin entry points](/plugins/sdk-entrypoints)
|
||||
- [Internal hooks](/automation/hooks)
|
||||
- [Plugin architecture internals](/plugins/architecture-internals)
|
||||
@@ -17,6 +17,7 @@ reference for **what to import** and **what you can register**.
|
||||
- First plugin? Start with [Building plugins](/plugins/building-plugins).
|
||||
- Channel plugin? See [Channel plugins](/plugins/sdk-channel-plugins).
|
||||
- Provider plugin? See [Provider plugins](/plugins/sdk-provider-plugins).
|
||||
- Tool or lifecycle hook plugin? See [Plugin hooks](/plugins/hooks).
|
||||
</Tip>
|
||||
|
||||
## Import convention
|
||||
@@ -229,6 +230,9 @@ AI CLI backend such as `codex-cli`.
|
||||
| `api.on(hookName, handler, opts?)` | Typed lifecycle hook |
|
||||
| `api.onConversationBindingResolved(handler)` | Conversation binding callback |
|
||||
|
||||
See [Plugin hooks](/plugins/hooks) for examples, common hook names, and guard
|
||||
semantics.
|
||||
|
||||
### Hook decision semantics
|
||||
|
||||
- `before_tool_call`: returning `{ block: true }` is terminal. Once any handler sets it, lower-priority handlers are skipped.
|
||||
|
||||
@@ -164,6 +164,7 @@ Use these hubs to discover every page, including deep dives and reference docs t
|
||||
|
||||
- [Plugins overview](/tools/plugin)
|
||||
- [Building plugins](/plugins/building-plugins)
|
||||
- [Plugin hooks](/plugins/hooks)
|
||||
- [Plugin manifest](/plugins/manifest)
|
||||
- [Agent tools](/plugins/building-plugins#registering-agent-tools)
|
||||
- [Plugin bundles](/plugins/bundles)
|
||||
|
||||
Reference in New Issue
Block a user