Plugin フックは、OpenClaw Plugin のインプロセス拡張ポイントです。Plugin がエージェント実行、ツール呼び出し、メッセージフロー、セッションライフサイクル、サブエージェントルーティング、インストール、または Gateway 起動を検査または変更する必要がある場合に使用します。Documentation Index
Fetch the complete documentation index at: https://docs.openclaw.ai/llms.txt
Use this file to discover all available pages before exploring further.
/new、/reset、/stop、agent:bootstrap、gateway:startup などのコマンドおよび Gateway イベント向けに、オペレーターがインストールする小さな HOOK.md スクリプトが必要な場合は、代わりに internal hooks を使用します。
クイックスタート
Plugin エントリからapi.on(...) を使って型付き Plugin フックを登録します。
priority の降順で順番に実行されます。同じ優先度のフックは登録順を維持します。
api.on(name, handler, opts?) は次を受け付けます。
priority- ハンドラーの順序(高いほど先に実行)。timeoutMs- 任意のフックごとの予算。設定すると、フックランナーは予算が経過した後にそのハンドラーを中断し、次のハンドラーへ進みます。これにより、遅いセットアップやリコール処理が呼び出し元に設定されたモデルタイムアウトを消費し続けることを防ぎます。省略すると、フックランナーが汎用的に適用するデフォルトの観測/判断タイムアウトを使用します。
hooks.timeouts.<hookName> は hooks.timeoutMs を上書きし、これは Plugin 作者が指定した api.on(..., { timeoutMs }) の値を上書きします。設定する各値は、600000 ミリ秒以下の正の整数である必要があります。1 つの Plugin があらゆる場所で長い予算を得ないように、遅いことが分かっているフックにはフックごとの上書きを優先してください。
各フックは、そのハンドラーを登録した Plugin の解決済み設定である event.context.pluginConfig を受け取ります。現在の Plugin オプションを必要とするフック判断に使用します。OpenClaw は、他の Plugin が見る共有イベントオブジェクトを変更せずに、ハンドラーごとにこれを注入します。
フックカタログ
フックは、拡張する対象の面ごとにグループ化されています。太字の名前は判断結果(ブロック、キャンセル、上書き、または承認要求)を受け付けます。それ以外はすべて観測専用です。 エージェントターンbefore_model_resolve- セッションメッセージの読み込み前にプロバイダーまたはモデルを上書きするagent_turn_prepare- キューに入った Plugin ターン注入を消費し、プロンプトフック前に同一ターンのコンテキストを追加するbefore_prompt_build- モデル呼び出し前に動的コンテキストまたはシステムプロンプトテキストを追加するbefore_agent_start- 互換性専用の結合フェーズ。上記 2 つのフックを優先するbefore_agent_run- モデル送信前に最終プロンプトとセッションメッセージを検査し、任意で実行をブロックするbefore_agent_reply- 合成返信または沈黙でモデルターンを短絡するbefore_agent_finalize- 自然な最終回答を検査し、もう 1 回のモデルパスを要求するagent_end- 最終メッセージ、成功状態、実行時間を観測するheartbeat_prompt_contribution- バックグラウンドモニターおよびライフサイクル Plugin 向けに Heartbeat 専用コンテキストを追加する
model_call_started/model_call_ended- プロンプトや応答内容なしで、サニタイズされたプロバイダー/モデル呼び出しメタデータ、タイミング、結果、境界付きのリクエスト ID ハッシュを観測するllm_input- プロバイダー入力(システムプロンプト、プロンプト、履歴)を観測するllm_output- プロバイダー出力を観測する
before_tool_call- ツールパラメーターを書き換える、実行をブロックする、または承認を要求するafter_tool_call- ツール結果、エラー、時間を観測するtool_result_persist- ツール結果から生成されるアシスタントメッセージを書き換えるbefore_message_write- 進行中のメッセージ書き込みを検査またはブロックする(まれ)
inbound_claim- エージェントルーティング前に受信メッセージを要求する(合成返信)message_received- 受信内容、送信者、スレッド、メタデータを観測するmessage_sending- 送信内容を書き換える、または配信をキャンセルするmessage_sent- 送信配信の成功または失敗を観測するbefore_dispatch- チャンネル引き渡し前に送信ディスパッチを検査または書き換えるreply_dispatch- 最終返信ディスパッチパイプラインに参加する
session_start/session_end- セッションライフサイクル境界を追跡するbefore_compaction/after_compaction- Compaction サイクルを観測または注釈するbefore_reset- セッションリセットイベント(/reset、プログラムによるリセット)を観測する
subagent_spawning/subagent_delivery_target/subagent_spawned/subagent_ended- サブエージェントのルーティングと完了配信を調整する
gateway_start/gateway_stop- Gateway とともに Plugin 所有のサービスを開始または停止するcron_changed- Gateway 所有の Cron ライフサイクル変更(追加、更新、削除、開始、完了、スケジュール)を観測するbefore_install- Skills または Plugin インストールスキャンを検査し、任意でブロックする
ツール呼び出しポリシー
before_tool_call は次を受け取ります。
event.toolNameevent.params- 任意の
event.derivedPaths。apply_patchなどのよく知られたツールエンベロープについて、ホストから導出された対象パスのベストエフォートなヒントを含みます。存在する場合、これらのパスは不完全なことや、ツールが実際に触れる内容を過大近似することがあります(たとえば、不正形式または部分的な入力の場合) - 任意の
event.runId - 任意の
event.toolCallId ctx.agentId、ctx.sessionKey、ctx.sessionId、ctx.runId、ctx.jobId(Cron 駆動の実行で設定)、診断用ctx.traceなどのコンテキストフィールド
block: trueは終端であり、低優先度のハンドラーをスキップします。block: falseは判断なしとして扱われます。paramsは実行用のツールパラメーターを書き換えます。requireApprovalはエージェント実行を一時停止し、Plugin 承認を通じてユーザーに確認します。/approveコマンドは exec 承認と Plugin 承認の両方を承認できます。- 高優先度のフックが承認を要求した後でも、低優先度の
block: trueがブロックできます。 onResolutionは、解決された承認判断(allow-once、allow-always、deny、timeout、またはcancelled)を受け取ります。
api.registerTrustedToolPolicy(...) で信頼済みツールポリシーを登録できます。これらは通常の before_tool_call フックおよび外部 Plugin の判断より前に実行されます。ワークスペースポリシー、予算適用、予約済みワークフローの安全性など、ホストが信頼するゲートにのみ使用してください。外部 Plugin は通常の before_tool_call フックを使用するべきです。
ツール結果の永続化
ツール結果には、UI レンダリング、診断、メディアルーティング、または Plugin 所有メタデータ向けの構造化されたdetails を含めることができます。details はプロンプト内容ではなく、ランタイムメタデータとして扱ってください。
- OpenClaw は、メタデータがモデルコンテキストにならないように、プロバイダー再生および Compaction 入力の前に
toolResult.detailsを取り除きます。 - 永続化されたセッションエントリは、境界付きの
detailsのみを保持します。大きすぎる details はコンパクトな要約とpersistedDetailsTruncated: trueに置き換えられます。 tool_result_persistとbefore_message_writeは最終的な永続化上限の前に実行されます。それでもフックは、返すdetailsを小さく保ち、プロンプトに関連するテキストをdetailsのみに置くことを避けるべきです。モデルから見えるツール出力はcontentに入れてください。
プロンプトとモデルフック
新しい Plugin にはフェーズ固有のフックを使用します。before_model_resolve: 現在のプロンプトと添付メタデータのみを受け取ります。providerOverrideまたはmodelOverrideを返します。agent_turn_prepare: 現在のプロンプト、準備済みセッションメッセージ、このセッション向けにドレインされた exactly-once のキュー済み注入を受け取ります。prependContextまたはappendContextを返します。before_prompt_build: 現在のプロンプトとセッションメッセージを受け取ります。prependContext、appendContext、systemPrompt、prependSystemContext、またはappendSystemContextを返します。heartbeat_prompt_contribution: Heartbeat ターンでのみ実行され、prependContextまたはappendContextを返します。ユーザー起点のターンを変更せずに現在の状態を要約する必要があるバックグラウンドモニター向けです。
before_agent_start は互換性のために残っています。Plugin がレガシーな結合フェーズに依存しないように、上記の明示的なフックを優先してください。
before_agent_run は、プロンプト構築後、かつプロンプトローカルの画像読み込みや llm_input 観測を含むあらゆるモデル入力の前に実行されます。現在のユーザー入力を prompt として受け取り、読み込まれたセッション履歴を messages に、アクティブなシステムプロンプトも受け取ります。モデルがプロンプトを読めるようになる前に実行を停止するには、{ outcome: "block", reason, message? } を返します。reason は内部用で、message はユーザー向けの置換です。サポートされる結果は pass と block のみです。サポートされていない判断形状はフェイルクローズします。
実行がブロックされると、OpenClaw は message.content 内の置換テキストと、ブロックした Plugin ID やタイムスタンプなどの非機密ブロックメタデータのみを保存します。元のユーザーテキストは、トランスクリプトや将来のコンテキストには保持されません。内部ブロック理由は機密として扱われ、トランスクリプト、履歴、ブロードキャスト、ログ、診断ペイロードから除外されます。可観測性では、ブロッカー ID、結果、タイムスタンプ、安全なカテゴリなどのサニタイズ済みフィールドを使用するべきです。
before_agent_start と agent_end には、OpenClaw がアクティブな実行を識別できる場合に event.runId が含まれます。同じ値は ctx.runId でも利用できます。Cron 駆動の実行では、ctx.jobId(発生元の Cron ジョブ ID)も公開されるため、Plugin フックはメトリクス、副作用、または状態を特定のスケジュール済みジョブにスコープできます。
チャンネル由来の実行では、ctx.messageProvider は discord や telegram などのプロバイダー面であり、ctx.channelId は OpenClaw がセッションキーまたは配信メタデータから導出できる場合の会話対象識別子です。
agent_end は観測フックであり、ターン後に fire-and-forget で実行されます。フックランナーは 30 秒のタイムアウトを適用するため、停止した Plugin や埋め込みエンドポイントがフック Promise を永遠に保留したままにすることはできません。タイムアウトはログに記録され、OpenClaw は継続します。ただし、Plugin が独自の中止シグナルも使用していない限り、Plugin 所有のネットワーク処理はキャンセルされません。
生のプロンプト、履歴、応答、ヘッダー、リクエスト本文、またはプロバイダーリクエスト ID を受け取るべきでないプロバイダー呼び出しテレメトリには、model_call_started と model_call_ended を使用します。これらのフックには、runId、callId、provider、model、任意の api/transport、終端の durationMs/outcome、OpenClaw が境界付きのプロバイダーリクエスト ID ハッシュを導出できる場合の upstreamRequestIdHash などの安定したメタデータが含まれます。
before_agent_finalize は、ハーネスが自然な最終アシスタント回答を受け入れようとしている場合にのみ実行されます。これは /stop のキャンセルパスではなく、ユーザーがターンを中止した場合には実行されません。確定前にもう 1 回モデルパスを行うようハーネスに依頼するには { action: "revise", reason } を返し、確定を強制するには { action: "finalize", reason? } を返します。続行するには結果を省略します。Codex ネイティブの Stop フックは、このフックに OpenClaw の
before_agent_finalize 判断として中継されます。
action: "revise" を返す場合、Plugin は retry メタデータを含めることで、追加のモデルパスを境界付きかつ再実行しても安全なものにできます。
instruction は、ハーネスに送信される修正理由に追加されます。
idempotencyKey により、ホストは同等の確定判断をまたいで同じ Plugin リクエストのリトライ回数を数えられます。また、maxAttempts は、自然な最終回答で続行する前にホストが許可する追加パスの回数に上限を設けます。
生の会話フック(before_model_resolve、
before_agent_reply、llm_input、llm_output、before_agent_finalize、
agent_end、または before_agent_run)を必要とする非バンドル Plugin は、次を設定する必要があります。
plugins.entries.<id>.hooks.allowPromptInjection=false で無効化できます。
セッション拡張と次ターン注入
ワークフロー Plugin は、api.registerSessionExtension(...) を使って小さな JSON 互換のセッション状態を永続化し、Gateway の
sessions.pluginPatch メソッドを通じて更新できます。セッション行は、登録された拡張状態を
pluginExtensions を通じて投影し、Control UI や他のクライアントが Plugin の内部を知らなくても Plugin 所有のステータスをレンダリングできるようにします。
Plugin が、次のモデルターンに正確に 1 回だけ到達する永続的なコンテキストを必要とする場合は、api.enqueueNextTurnInjection(...) を使用します。OpenClaw は、プロンプトフックの前にキューに入った注入を排出し、期限切れの注入を破棄し、Plugin ごとに idempotencyKey で重複排除します。これは、承認の再開、ポリシー要約、バックグラウンド監視の差分、コマンド継続など、次のターンでモデルに見えるべきだが永続的なシステムプロンプトテキストにはすべきでないものに適した継ぎ目です。
クリーンアップのセマンティクスは契約の一部です。セッション拡張のクリーンアップとランタイムライフサイクルのクリーンアップコールバックは、reset、delete、disable、または
restart を受け取ります。ホストは、reset/delete/disable の場合に、所有 Plugin の永続セッション拡張状態と保留中の次ターン注入を削除します。restart では永続セッション状態を保持しつつ、クリーンアップコールバックにより Plugin は古いランタイム世代のスケジューラージョブ、実行コンテキスト、その他のアウトオブバンドリソースを解放できます。
メッセージフック
チャネルレベルのルーティングと配信ポリシーには、メッセージフックを使用します。message_received: 受信コンテンツ、送信者、threadId、messageId、senderId、任意の実行/セッション相関、メタデータを観察します。message_sending:contentを書き換えるか、{ cancel: true }を返します。message_sent: 最終的な成功または失敗を観察します。
content に非表示の読み上げトランスクリプトが含まれることがあります。その
content を書き換えると、フックから見えるトランスクリプトのみが更新されます。メディアキャプションとしてはレンダリングされません。
メッセージフックコンテキストは、利用可能な場合に安定した相関フィールドを公開します。
ctx.sessionKey、ctx.runId、ctx.messageId、ctx.senderId、ctx.trace、
ctx.traceId、ctx.spanId、ctx.parentSpanId、ctx.callDepth です。レガシーメタデータを読む前に、これらのファーストクラスフィールドを優先してください。
チャネル固有のメタデータを使用する前に、型付きの threadId と replyToId フィールドを優先してください。
判断ルール:
cancel: trueを伴うmessage_sendingは終端です。cancel: falseを伴うmessage_sendingは、判断なしとして扱われます。- 書き換えられた
contentは、後続のフックが配信をキャンセルしない限り、より低い優先度のフックへ続行されます。 message_sendingは、キャンセル時にcancelReasonと境界付きのmetadataを返せます。新しいメッセージライフサイクル API は、これを理由cancelled_by_message_sending_hookの抑制された配信結果として公開します。レガシーの直接配信は、互換性のために空の結果配列を返し続けます。message_sentは観察専用です。ハンドラーの失敗はログに記録され、配信結果は変更されません。
インストールフック
before_install は、Skill と Plugin のインストールに対する組み込みスキャンの後に実行されます。追加の検出結果、またはインストールを停止するための { block: true, blockReason } を返します。
block: true は終端です。block: false は判断なしとして扱われます。
Gateway ライフサイクル
Gateway 所有の状態を必要とする Plugin サービスにはgateway_start を使用します。コンテキストは、cron の検査と更新用に ctx.config、ctx.workspaceDir、ctx.getCron?.() を公開します。長時間実行されるリソースをクリーンアップするには gateway_stop を使用します。
Plugin 所有のランタイムサービスで内部の gateway:startup フックに依存しないでください。
cron_changed は、Gateway 所有の cron ライフサイクルイベントに対して、added、updated、removed、started、finished、
scheduled の理由をカバーする型付きイベントペイロードで発火します。このイベントは、PluginHookGatewayCronJob スナップショット(存在する場合は state.nextRunAtMs、state.lastRunStatus、state.lastError を含む)に加え、not-requested | delivered | not-delivered | unknown の PluginHookGatewayCronDeliveryStatus を運びます。削除イベントでも削除されたジョブのスナップショットを運ぶため、外部スケジューラーは状態を照合できます。外部のウェイクスケジューラーを同期する場合は、ランタイムコンテキストの ctx.getCron?.() と ctx.config を使用し、期限チェックと実行については OpenClaw を信頼できる唯一の情報源にしてください。
今後の非推奨
フック周辺の一部サーフェスは非推奨ですが、引き続きサポートされています。次のメジャーリリース前に移行してください。inbound_claimおよびmessage_receivedハンドラー内の プレーンテキストのチャネルエンベロープ。フラットなエンベロープテキストを解析するのではなく、BodyForAgentと構造化されたユーザーコンテキストブロックを読んでください。詳しくは プレーンテキストのチャネルエンベロープ → BodyForAgent を参照してください。before_agent_startは互換性のために残っています。新しい Plugin は、結合されたフェーズの代わりにbefore_model_resolveとbefore_prompt_buildを使用してください。before_tool_callのonResolutionは、自由形式のstringではなく、型付きのPluginApprovalResolutionユニオン(allow-once/allow-always/deny/timeout/cancelled)を使用するようになりました。
command-auth → command-status の名前変更)については、
Plugin SDK 移行 → アクティブな非推奨 を参照してください。
関連
- Plugin SDK 移行 - アクティブな非推奨と削除タイムライン
- Plugin の構築
- Plugin SDK 概要
- Plugin エントリーポイント
- 内部フック
- Plugin アーキテクチャ内部