



















@@ -0,0 +1,188 @@
1+---
2+summary: "Plugin hooks: intercept agent, tool, message, session, and Gateway lifecycle events"
3+title: "Plugin hooks"
4+read_when:
5+ - You are building a plugin that needs before_tool_call, before_agent_reply, message hooks, or lifecycle hooks
6+ - You need to block, rewrite, or require approval for tool calls from a plugin
7+ - You are deciding between internal hooks and plugin hooks
8+---
9+10+Plugin hooks are in-process extension points for OpenClaw plugins. Use them
11+when a plugin needs to inspect or change agent runs, tool calls, message flow,
12+session lifecycle, subagent routing, installs, or Gateway startup.
13+14+Use [internal hooks](/automation/hooks) instead when you want a small
15+operator-installed `HOOK.md` script for command and Gateway events such as
16+`/new`, `/reset`, `/stop`, `agent:bootstrap`, or `gateway:startup`.
17+18+## Quick start
19+20+Register typed plugin hooks with `api.on(...)` from your plugin entry:
21+22+```typescript
23+import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
24+25+export default definePluginEntry({
26+ id: "tool-preflight",
27+ name: "Tool Preflight",
28+ register(api) {
29+api.on(
30+"before_tool_call",
31+async (event) => {
32+if (event.toolName !== "web_search") {
33+return;
34+ }
35+36+return {
37+ requireApproval: {
38+ title: "Run web search",
39+ description: `Allow search query: ${String(event.params.query ?? "")}`,
40+ severity: "info",
41+ timeoutMs: 60_000,
42+ timeoutBehavior: "deny",
43+ },
44+ };
45+ },
46+ { priority: 50 },
47+ );
48+ },
49+});
50+```
51+52+Hook handlers run sequentially in descending `priority`. Same-priority hooks
53+keep registration order.
54+55+## Common hooks
56+57+| Hook | Use it for |
58+| ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
59+| `before_tool_call` | Rewrite tool params, block execution, or request user approval before a tool runs. |
60+| `after_tool_call` | Observe tool results, errors, and duration after execution. |
61+| `before_prompt_build` | Add dynamic context or system prompt text before the model call. |
62+| `before_model_resolve` | Override provider or model before session messages are loaded. |
63+| `before_agent_reply` | Short-circuit the model turn with a synthetic reply or silence. |
64+| `llm_input` / `llm_output` | Observe provider input/output for conversation-aware plugins. |
65+| `agent_end` | Observe final messages, success state, and run duration. |
66+| `message_received` | Observe inbound channel messages after channel parsing. |
67+| `message_sending` | Rewrite or cancel outbound channel messages. |
68+| `message_sent` | Observe outbound delivery success or failure. |
69+| `session_start` / `session_end` | Track session lifecycle boundaries. |
70+| `before_compaction` / `after_compaction` | Observe or annotate compaction cycles. |
71+| `subagent_spawning` / `subagent_delivery_target` / `subagent_spawned` / `subagent_ended` | Coordinate subagent routing and completion delivery. |
72+| `gateway_start` / `gateway_stop` | Start or stop plugin services with the Gateway. |
73+| `before_install` | Inspect skill or plugin install scans and optionally block. |
74+75+## Tool call policy
76+77+`before_tool_call` receives:
78+79+- `event.toolName`
80+- `event.params`
81+- optional `event.runId`
82+- optional `event.toolCallId`
83+- context fields such as `ctx.agentId`, `ctx.sessionKey`, `ctx.sessionId`, and
84+ diagnostic `ctx.trace`
85+86+It can return:
87+88+```typescript
89+type BeforeToolCallResult = {
90+ params?: Record<string, unknown>;
91+ block?: boolean;
92+ blockReason?: string;
93+ requireApproval?: {
94+ title: string;
95+ description: string;
96+ severity?: "info" | "warning" | "critical";
97+ timeoutMs?: number;
98+ timeoutBehavior?: "allow" | "deny";
99+ onResolution?: (decision: string) => Promise<void> | void;
100+ };
101+};
102+```
103+104+Rules:
105+106+- `block: true` is terminal and skips lower-priority handlers.
107+- `block: false` is treated as no decision.
108+- `params` rewrites the tool parameters for execution.
109+- `requireApproval` pauses the agent run and asks the user through plugin
110+ approvals. The `/approve` command can approve both exec and plugin approvals.
111+- A lower-priority `block: true` can still block after a higher-priority hook
112+ requested approval.
113+114+## Prompt and model hooks
115+116+Use the phase-specific hooks for new plugins:
117+118+- `before_model_resolve`: receives only the current prompt and attachment
119+ metadata. Return `providerOverride` or `modelOverride`.
120+- `before_prompt_build`: receives the current prompt and session messages.
121+ Return `prependContext`, `systemPrompt`, `prependSystemContext`, or
122+`appendSystemContext`.
123+124+`before_agent_start` remains for compatibility. Prefer the explicit hooks above
125+so your plugin does not depend on a legacy combined phase.
126+127+Non-bundled plugins that need `llm_input`, `llm_output`, or `agent_end` must set:
128+129+```json
130+{
131+"plugins": {
132+"entries": {
133+"my-plugin": {
134+"hooks": {
135+"allowConversationAccess": true
136+ }
137+ }
138+ }
139+ }
140+}
141+```
142+143+Prompt-mutating hooks can be disabled per plugin with
144+`plugins.entries.<id>.hooks.allowPromptInjection=false`.
145+146+## Message hooks
147+148+Use message hooks for channel-level routing and delivery policy:
149+150+- `message_received`: observe inbound content, sender, `threadId`, and metadata.
151+- `message_sending`: rewrite `content` or return `{ cancel: true }`.
152+- `message_sent`: observe final success or failure.
153+154+Prefer typed `threadId` and `replyToId` fields before using channel-specific
155+metadata.
156+157+Decision rules:
158+159+- `message_sending` with `cancel: true` is terminal.
160+- `message_sending` with `cancel: false` is treated as no decision.
161+- Rewritten `content` continues to lower-priority hooks unless a later hook
162+ cancels delivery.
163+164+## Install hooks
165+166+`before_install` runs after the built-in scan for skill and plugin installs.
167+Return additional findings or `{ block: true, blockReason }` to stop the
168+install.
169+170+`block: true` is terminal. `block: false` is treated as no decision.
171+172+## Gateway lifecycle
173+174+Use `gateway_start` for plugin services that need Gateway-owned state. The
175+context exposes `ctx.config`, `ctx.workspaceDir`, and `ctx.getCron?.()` for
176+cron inspection and updates. Use `gateway_stop` to clean up long-running
177+resources.
178+179+Do not rely on the internal `gateway:startup` hook for plugin-owned runtime
180+services.
181+182+## Related
183+184+- [Building plugins](/plugins/building-plugins)
185+- [Plugin SDK overview](/plugins/sdk-overview)
186+- [Plugin entry points](/plugins/sdk-entrypoints)
187+- [Internal hooks](/automation/hooks)
188+- [Plugin architecture internals](/plugins/architecture-internals)
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。