使用 OpenClaw Hooks 自動化代理程式:設定指南
Hooks 是在你執行某些操作時會自動執行的腳本。主要分為兩類:
- Hooks(本頁面):在 Gateway 內部執行,當 agent 事件觸發時(例如
/new、/reset、/stop或生命週期事件)就會執行。 - Webhooks:外部 HTTP webhooks,讓其他系統可以觸發 OpenClaw 的工作。請參考 Webhook Hooks 或使用
openclaw webhooks取得 Gmail 輔助指令。
Hooks 也可以封裝在 plugin 裡面;請參考 Plugin hooks。使用 openclaw hooks list 可以同時查看獨立的 hooks 與由 plugin 管理的 hooks。
常見用途:
- 在你重置 session 時儲存記憶快照
- 保留指令的稽核軌跡,用於疑難排解或合規審查
- 在 session 開始或結束時觸發後續的自動化流程
- 當事件觸發時,將檔案寫入 agent workspace 或呼叫外部 API
只要你會寫簡單的 TypeScript function,你就能寫 hook。Managed 與封裝好的 hooks 是受信任的本地程式碼。Workspace hooks 會被自動偵測,但 OpenClaw 會保持禁用狀態,直到你明確透過 CLI 或設定檔啟用它們。
Hooks 系統讓你能夠:
- 在發送
/new指令時將 session 上下文儲存到記憶體中 - 記錄所有指令以供稽核
- 在 agent 生命週期事件中觸發自定義自動化
- 在不修改核心程式碼的情況下擴展 OpenClaw 的行為
內建 Hooks
Section titled “內建 Hooks”OpenClaw 附帶了四個會自動偵測的內建 hooks:
- 💾 session-memory:當你執行
/new或/reset時,將 session 上下文儲存到你的 agent workspace(預設為~/.openclaw/workspace/memory/) - 📎 bootstrap-extra-files:在
agent:bootstrap期間,從設定的 glob/路徑模式注入額外的 workspace 引導檔案 - 📝 command-logger:將所有指令事件記錄到
~/.openclaw/logs/commands.log - 🚀 boot-md:當 gateway 啟動時執行
BOOT.md(需要啟用內部 hooks)
列出可用的 hooks:
openclaw hooks list啟用 hook:
openclaw hooks enable session-memory檢查 hook 狀態:
openclaw hooks check取得詳細資訊:
openclaw hooks info session-memory在引導流程(openclaw onboard)期間,系統會提示你啟用建議的 hooks。小幫手會自動偵測符合條件的 hooks 並讓你選擇。
Hooks 在 Gateway 程序中執行。請將內建 hooks、managed hooks 以及 hooks.internal.load.extraDirs 視為受信任的本地程式碼。位於 <workspace>/hooks/ 下的 Workspace hooks 是屬於 repo 本地的程式碼,因此 OpenClaw 在載入它們之前,需要你執行明確的啟用步驟。
Hook 偵測機制
Section titled “Hook 偵測機制”Hooks 會自動從以下目錄偵測,優先順序由低到高(後者會覆蓋前者):
- 內建 hooks:隨 OpenClaw 附帶;npm 安裝版位於
<openclaw>/dist/hooks/bundled/(或編譯二進位檔旁的hooks/bundled/) - Plugin hooks:封裝在已安裝 plugin 中的 hooks(請參考 Plugin hooks)
- Managed hooks:
~/.openclaw/hooks/(使用者安裝,跨 workspace 共用;可以覆蓋內建與 plugin hooks)。透過hooks.internal.load.extraDirs設定的額外 hook 目錄也會被視為 managed hooks,並享有相同的覆蓋優先順序。 - Workspace hooks:
<workspace>/hooks/(每個 agent 獨立,預設禁用直到明確啟用;無法覆蓋來自其他來源的 hooks)
Workspace hooks 可以為 repo 增加新的 hook 名稱,但它們不能覆蓋具有相同名稱的內建、managed 或 plugin 提供的 hooks。
Managed hook 目錄可以是一個單獨的 hook,也可以是一個 hook pack(套件目錄)。
每個 hook 都是一個包含以下內容的目錄:
my-hook/├── HOOK.md # Metadata + documentation└── handler.ts # Handler implementationHook Packs (npm/封存檔)
Section titled “Hook Packs (npm/封存檔)”Hook packs 是標準的 npm 套件,透過 package.json 中的 openclaw.hooks 匯出一個或多個 hook。你可以用這個指令安裝:
openclaw plugins install <path-or-spec>Npm specs 僅限 registry(套件名稱 + 選填的精確版本或 dist-tag)。Git/URL/檔案路徑以及 semver 範圍都會被拒絕。
一般的 spec 和 @latest 會保持在穩定版本。如果 npm 將其中之一解析為預發佈版本(prerelease),OpenClaw 會停止執行並要求你明確選擇加入,例如使用 @beta / @rc 等標籤或精確的預發佈版本號。
package.json 範例:
{ "name": "@acme/my-hooks", "version": "0.1.0", "openclaw": { "hooks": ["./hooks/my-hook", "./hooks/other-hook"] }}每個項目都指向一個包含 HOOK.md 和 handler.ts(或 index.ts)的 hook 目錄。Hook packs 可以包含依賴項目;它們會被安裝在 ~/.openclaw/hooks/<id> 下。每個 openclaw.hooks 的項目在解析符號連結(symlink)後必須留在套件目錄內,超出範圍的項目將被拒絕。
安全提示:openclaw plugins install 會使用 npm install --ignore-scripts 安裝 hook-pack 的依賴項目(不執行生命週期腳本)。請確保 hook pack 的依賴樹是「純 JS/TS」,並避免使用依賴 postinstall 建置的套件。
Hook 結構
Section titled “Hook 結構”HOOK.md 格式
Section titled “HOOK.md 格式”HOOK.md 檔案包含 YAML frontmatter 的元數據以及 Markdown 文件:
---name: my-hookdescription: "Short description of what this hook does"homepage: https://docs.openclaw.ai/automation/hooks#my-hookmetadata: { "openclaw": { "emoji": "🔗", "events": ["command:new"], "requires": { "bins": ["node"] } } }---
# My Hook
Detailed documentation goes here...
## What It Does
- Listens for `/new` commands- Performs some action- Logs the result
## Requirements
- Node.js must be installed
## Configuration
No configuration needed.元數據欄位 (Metadata Fields)
Section titled “元數據欄位 (Metadata Fields)”metadata.openclaw 物件支援以下欄位:
emoji: 在 CLI 顯示的表情符號(例如"💾")events: 要監聽的事件陣列(例如["command:new", "command:reset"])export: 要使用的具名匯出(預設為"default")homepage: 文件 URLos: 需要的作業系統平台(例如["darwin", "linux"])requires: 選填的需求bins: 在 PATH 中需要的執行檔(例如["git", "node"])anyBins: 至少需要存在其中一個執行檔env: 需要的環境變數config: 需要的設定路徑(例如["workspace.dir"])
always: 繞過資格檢查(布林值)install: 安裝方法(針對內建 hook:[{"id":"bundled","kind":"bundled"}])
Handler 實作
Section titled “Handler 實作”handler.ts 檔案匯出一個 HookHandler 函式:
const myHandler = async (event) => { // Only trigger on 'new' command if (event.type !== "command" || event.action !== "new") { return; }
console.log(`[my-hook] New command triggered`); console.log(` Session: ${event.sessionKey}`); console.log(` Timestamp: ${event.timestamp.toISOString()}`);
// Your custom logic here
// Optionally send message to user event.messages.push("✨ My hook executed!");};
export default myHandler;事件上下文 (Event Context)
Section titled “事件上下文 (Event Context)”每個事件都包含:
{ type: 'command' | 'session' | 'agent' | 'gateway' | 'message', action: string, // e.g., 'new', 'reset', 'stop', 'received', 'sent' sessionKey: string, // Session identifier timestamp: Date, // When the event occurred messages: string[], // Push messages here to send to user context: { // Command events (command:new, command:reset): sessionEntry?: SessionEntry, // current session entry previousSessionEntry?: SessionEntry, // pre-reset entry (preferred for session-memory) commandSource?: string, // e.g., 'whatsapp', 'telegram' senderId?: string, workspaceDir?: string, cfg?: OpenClawConfig, // Command events (command:stop only): sessionId?: string, // Agent bootstrap events (agent:bootstrap): bootstrapFiles?: WorkspaceBootstrapFile[], // Message events (see Message Events section for full details): from?: string, // message:received to?: string, // message:sent content?: string, channelId?: string, success?: boolean, // message:sent }}指令事件 (Command Events)
Section titled “指令事件 (Command Events)”當代理指令發出時觸發:
command: 所有指令事件(通用監聽器)command:new: 當發出/new指令時command:reset: 當發出/reset指令時command:stop: 當發出/stop指令時
會話事件 (Session Events)
Section titled “會話事件 (Session Events)”session:compact:before: 在壓縮(compaction)總結歷史紀錄之前session:compact:after: 在壓縮完成並帶有總結元數據之後
內部 hook 負載會將這些發送為 type: "session" 且 action: "compact:before" / action: "compact:after";監聽器則使用上述組合鍵進行訂閱。特定的 handler 註冊使用 ${type}:${action} 的字面格式。對於這些事件,請註冊 session:compact:before 和 session:compact:after。
代理事件 (Agent Events)
Section titled “代理事件 (Agent Events)”agent:bootstrap: 在注入 workspace 引導檔案之前(hook 可以修改context.bootstrapFiles)
Gateway 事件
Section titled “Gateway 事件”當 Gateway 啟動時觸發:
gateway:startup: 在頻道啟動且 hook 載入之後
會話修補事件 (Session Patch Events)
Section titled “會話修補事件 (Session Patch Events)”當會話屬性被修改時觸發:
session:patch: 當會話更新時
會話事件上下文
Section titled “會話事件上下文”會話事件包含關於會話及其變更的豐富上下文:
{ sessionEntry: SessionEntry, // The complete updated session entry patch: { // The patch object (only changed fields) // Session identity & labeling label?: string | null, // Human-readable session label
// AI model configuration model?: string | null, // Model override (e.g., "claude-opus-4-5") thinkingLevel?: string | null, // Thinking level ("off"|"low"|"med"|"high") verboseLevel?: string | null, // Verbose output level reasoningLevel?: string | null, // Reasoning mode override elevatedLevel?: string | null, // Elevated mode override responseUsage?: "off" | "tokens" | "full" | null, // Usage display mode
// Tool execution settings execHost?: string | null, // Exec host (sandbox|gateway|node) execSecurity?: string | null, // Security mode (deny|allowlist|full) execAsk?: string | null, // Approval mode (off|on-miss|always) execNode?: string | null, // Node ID for host=node
// Subagent coordination spawnedBy?: string | null, // Parent session key (for subagents) spawnDepth?: number | null, // Nesting depth (0 = root)
// Communication policies sendPolicy?: "allow" | "deny" | null, // Message send policy groupActivation?: "mention" | "always" | null, // Group chat activation }, cfg: OpenClawConfig // Current gateway config}安全提示: 只有具備權限的用戶端(包括 Control UI)可以觸發 session:patch 事件。標準的 WebChat 用戶端無法修補會話(參見 PR #20800),因此 hook 不會從這些連線中觸發。
完整類型定義請參見 src/gateway/protocol/schema/sessions.ts 中的 SessionsPatchParamsSchema。
範例:會話修補日誌 Hook
Section titled “範例:會話修補日誌 Hook”const handler = async (event) => { if (event.type !== "session" || event.action !== "patch") { return; } const { patch } = event.context; console.log(`[session-patch] Session updated: ${event.sessionKey}`); console.log(`[session-patch] Changes:`, patch);};
export default handler;訊息事件 (Message Events)
Section titled “訊息事件 (Message Events)”當接收或發送訊息時觸發:
message: 所有訊息事件(通用監聽器)message:received: 當從任何頻道接收到傳入訊息時。在處理早期、媒體理解之前觸發。內容可能包含原始佔位符,例如尚未處理的媒體附件<media:audio>。message:transcribed: 當訊息已完全處理,包括音訊轉錄和連結理解。此時,transcript包含音訊訊息的完整轉錄文字。當你需要存取轉錄後的音訊內容時,請使用此 hook。message:preprocessed: 在所有媒體和連結理解完成後,針對每條訊息觸發,讓 hook 在代理看到之前存取完整豐富的內容(轉錄、圖片描述、連結摘要)。message:sent: 當傳出訊息成功發送時
訊息事件上下文
Section titled “訊息事件上下文”訊息事件包含關於訊息的豐富上下文:
// message:received context{ from: string, // Sender identifier (phone number, user ID, etc.) content: string, // Message content timestamp?: number, // Unix timestamp when received channelId: string, // Channel (e.g., "whatsapp", "telegram", "discord") accountId?: string, // Provider account ID for multi-account setups conversationId?: string, // Chat/conversation ID messageId?: string, // Message ID from the provider metadata?: { // Additional provider-specific data to?: string, provider?: string, surface?: string, threadId?: string | number, senderId?: string, senderName?: string, senderUsername?: string, senderE164?: string, guildId?: string, // Discord guild / server ID channelName?: string, // Channel name (e.g., Discord channel name) }}
// message:sent context{ to: string, // Recipient identifier content: string, // Message content that was sent success: boolean, // Whether the send succeeded error?: string, // Error message if sending failed channelId: string, // Channel (e.g., "whatsapp", "telegram", "discord") accountId?: string, // Provider account ID conversationId?: string, // Chat/conversation ID messageId?: string, // Message ID returned by the provider isGroup?: boolean, // Whether this outbound message belongs to a group/channel context groupId?: string, // Group/channel identifier for correlation with message:received}
// message:transcribed context{ from?: string, // Sender identifier to?: string, // Recipient identifier body?: string, // Raw inbound body before enrichment bodyForAgent?: string, // Enriched body visible to the agent transcript: string, // Audio transcript text timestamp?: number, // Unix timestamp when received channelId: string, // Channel (e.g., "telegram", "whatsapp") conversationId?: string, messageId?: string, senderId?: string, // Sender user ID senderName?: string, // Sender display name senderUsername?: string, provider?: string, // Provider name surface?: string, // Surface name mediaPath?: string, // Path to the media file that was transcribed mediaType?: string, // MIME type of the media}
// message:preprocessed context{ from?: string, // Sender identifier to?: string, // Recipient identifier body?: string, // Raw inbound body bodyForAgent?: string, // Final enriched body after media/link understanding transcript?: string, // Transcript when audio was present timestamp?: number, // Unix timestamp when received channelId: string, // Channel (e.g., "telegram", "whatsapp") conversationId?: string, messageId?: string, senderId?: string, // Sender user ID senderName?: string, // Sender display name senderUsername?: string, provider?: string, // Provider name surface?: string, // Surface name mediaPath?: string, // Path to the media file mediaType?: string, // MIME type of the media isGroup?: boolean, groupId?: string,}範例:訊息日誌 Hook
Section titled “範例:訊息日誌 Hook”const isMessageReceivedEvent = (event: { type: string; action: string }) => event.type === "message" && event.action === "received";const isMessageSentEvent = (event: { type: string; action: string }) => event.type === "message" && event.action === "sent";
const handler = async (event) => { if (isMessageReceivedEvent(event as { type: string; action: string })) { console.log(`[message-logger] Received from ${event.context.from}: ${event.context.content}`); } else if (isMessageSentEvent(event as { type: string; action: string })) { console.log(`[message-logger] Sent to ${event.context.to}: ${event.context.content}`); }};
export default handler;工具結果 Hook (Plugin API)
Section titled “工具結果 Hook (Plugin API)”這些 hook 不是事件流監聽器;它們讓插件在 OpenClaw 持久化工具結果之前,同步調整這些結果。
tool_result_persist: 在工具結果寫入會話記錄之前對其進行轉換。必須是同步的;返回更新後的工具結果負載,或返回undefined以保持原樣。參見 Agent Loop。
插件 Hook 事件
Section titled “插件 Hook 事件”透過插件 hook 執行器公開的壓縮生命週期 hook:
before_compaction: 在壓縮前執行,帶有計數/token 元數據after_compaction: 在壓縮後執行,帶有壓縮總結元數據
計劃中的事件類型:
session:start: 當新會話開始時session:end: 當會話結束時agent:error: 當代理遇到錯誤時
建立自定義 Hook
Section titled “建立自定義 Hook”1. 選擇位置
Section titled “1. 選擇位置”- Workspace hooks (
<workspace>/hooks/): 針對單一代理;可以新增 hook 名稱,但不能覆蓋同名的內建、託管或插件 hook。 - 託管 Hook (Managed hooks) (
~/.openclaw/hooks/): 跨 workspace 共用;可以覆蓋內建和插件 hook。
2. 建立目錄結構
Section titled “2. 建立目錄結構”mkdir -p ~/.openclaw/hooks/my-hookcd ~/.openclaw/hooks/my-hook3. 建立 HOOK.md
Section titled “3. 建立 HOOK.md”---name: my-hookdescription: "Does something useful"metadata: { "openclaw": { "emoji": "🎯", "events": ["command:new"] } }---
# My Custom Hook
This hook does something useful when you issue `/new`.4. 建立 handler.ts
Section titled “4. 建立 handler.ts”const handler = async (event) => { if (event.type !== "command" || event.action !== "new") { return; }
console.log("[my-hook] Running!"); // Your logic here};
export default handler;5. 啟用並測試
Section titled “5. 啟用並測試”# Verify hook is discoveredopenclaw hooks list
# Enable itopenclaw hooks enable my-hook
# Restart your gateway process (menu bar app restart on macOS, or restart your dev process)
# Trigger the event# Send /new via your messaging channel配置 (Configuration)
Section titled “配置 (Configuration)”新配置格式(推薦)
Section titled “新配置格式(推薦)”{ "hooks": { "internal": { "enabled": true, "entries": { "session-memory": { "enabled": true }, "command-logger": { "enabled": false } } } }}個別 Hook 配置
Section titled “個別 Hook 配置”Hook 可以有自定義配置:
{ "hooks": { "internal": { "enabled": true, "entries": { "my-hook": { "enabled": true, "env": { "MY_CUSTOM_VAR": "value" } } } } }}從額外目錄載入 Hook(會被視為受管理的 Hook,具有相同的覆蓋優先級):
{ "hooks": { "internal": { "enabled": true, "load": { "extraDirs": ["/path/to/more/hooks"] } } }}舊版配置格式(仍支援)
Section titled “舊版配置格式(仍支援)”舊的配置格式為了向後相容仍然有效:
{ "hooks": { "internal": { "enabled": true, "handlers": [ { "event": "command:new", "module": "./hooks/handlers/my-handler.ts", "export": "default" } ] } }}注意:module 必須是相對於 workspace 的路徑。絕對路徑或超出 workspace 範圍的訪問都會被拒絕。
遷移:針對新的 Hook 請使用新的自動偵測系統。舊版 handler 會在基於目錄的 Hook 之後載入。
CLI 命令 (CLI Commands)
Section titled “CLI 命令 (CLI Commands)”列出 Hook
Section titled “列出 Hook”# List all hooksopenclaw hooks list
# Show only eligible hooksopenclaw hooks list --eligible
# Verbose output (show missing requirements)openclaw hooks list --verbose
# JSON outputopenclaw hooks list --jsonHook 資訊
Section titled “Hook 資訊”# Show detailed info about a hookopenclaw hooks info session-memory
# JSON outputopenclaw hooks info session-memory --json# Show eligibility summaryopenclaw hooks check
# JSON outputopenclaw hooks check --json# Enable a hookopenclaw hooks enable session-memory
# Disable a hookopenclaw hooks disable command-logger內建 Hook 參考 (Bundled hook reference)
Section titled “內建 Hook 參考 (Bundled hook reference)”session-memory
Section titled “session-memory”當你執行 /new 或 /reset 時,將會話上下文儲存到記憶體中。
Events: command:new, command:reset
Requirements: 必須配置 workspace.dir
Output: <workspace>/memory/YYYY-MM-DD-slug.md(預設為 ~/.openclaw/workspace)
運作原理:
- 使用重置前的會話條目來定位正確的對話紀錄
- 從對話中提取最後 15 條使用者/助手訊息(可配置)
- 使用 LLM 生成具描述性的檔案名稱 slug
- 將會話 metadata 儲存到帶有日期的記憶檔案中
輸出範例:
# Session: 2026-01-16 14:30:00 UTC
- **Session Key**: agent:main:main- **Session ID**: abc123def456- **Source**: telegram
## Conversation Summary
user: Can you help me design the API?assistant: Sure! Let's start with the endpoints...檔案名稱範例:
2026-01-16-vendor-pitch.md2026-01-16-api-design.md2026-01-16-1430.md(如果 slug 生成失敗,則回退到時間戳記)
啟用:
openclaw hooks enable session-memorybootstrap-extra-files
Section titled “bootstrap-extra-files”在 agent:bootstrap 期間注入額外的引導檔案(例如 monorepo 本地的 AGENTS.md / TOOLS.md)。
Events: agent:bootstrap
Requirements: 必須配置 workspace.dir
Output: 不會寫入檔案;引導上下文僅在記憶體中修改。
Config:
{ "hooks": { "internal": { "enabled": true, "entries": { "bootstrap-extra-files": { "enabled": true, "paths": ["packages/*/AGENTS.md", "packages/*/TOOLS.md"] } } } }}配置選項:
paths(string[]): 從 workspace 解析的 glob/路徑模式。patterns(string[]):paths的別名。files(string[]):paths的別名。
備註:
- 路徑是相對於 workspace 解析的。
- 檔案必須留在 workspace 內(會經過 realpath 檢查)。
- 僅載入可識別的引導基準名稱(
AGENTS.md,SOUL.md,TOOLS.md,IDENTITY.md,USER.md,HEARTBEAT.md,BOOTSTRAP.md,MEMORY.md,memory.md)。 - 對於 subagent/cron 會話,適用更嚴格的白名單(
AGENTS.md,TOOLS.md,SOUL.md,IDENTITY.md,USER.md)。
啟用:
openclaw hooks enable bootstrap-extra-filescommand-logger
Section titled “command-logger”將所有命令事件記錄到集中式的稽核檔案中。
Events: command
Requirements: 無
Output: ~/.openclaw/logs/commands.log
運作原理:
- 擷取事件詳情(命令動作、時間戳記、session key、發送者 ID、source)
- 以 JSONL 格式附加到日誌檔案
- 在背景靜默執行
日誌條目範例:
{"timestamp":"2026-01-16T14:30:00.000Z","action":"new","sessionKey":"agent:main:main","senderId":"+1234567890","source":"telegram"}{"timestamp":"2026-01-16T15:45:22.000Z","action":"stop","sessionKey":"agent:main:main","senderId":"user@example.com","source":"whatsapp"}查看日誌:
# View recent commandstail -n 20 ~/.openclaw/logs/commands.log
# Pretty-print with jqcat ~/.openclaw/logs/commands.log | jq .
# Filter by actiongrep '"action":"new"' ~/.openclaw/logs/commands.log | jq .啟用:
openclaw hooks enable command-loggerboot-md
Section titled “boot-md”當 Gateway 啟動時(在 channel 啟動後)執行 BOOT.md。
必須啟用內部 Hook 才能執行此功能。
Events: gateway:startup
Requirements: 必須配置 workspace.dir
運作原理:
- 從你的 workspace 讀取
BOOT.md - 透過 agent 執行器執行指令
- 透過訊息工具發送任何要求的對外訊息
啟用:
openclaw hooks enable boot-md最佳實踐 (Best Practices)
Section titled “最佳實踐 (Best Practices)”保持 Handler 執行速度
Section titled “保持 Handler 執行速度”Hook 在命令處理期間執行。請保持它們輕量化:
// ✓ Good - async work, returns immediatelyconst handler: HookHandler = async (event) => { void processInBackground(event); // Fire and forget};
// ✗ Bad - blocks command processingconst handler: HookHandler = async (event) => { await slowDatabaseQuery(event); await evenSlowerAPICall(event);};優雅地處理錯誤
Section titled “優雅地處理錯誤”務必封裝具風險的操作:
const handler: HookHandler = async (event) => { try { await riskyOperation(event); } catch (err) { console.error("[my-handler] Failed:", err instanceof Error ? err.message : String(err)); // Don't throw - let other handlers run }};提早過濾事件
Section titled “提早過濾事件”如果事件不相關,請儘早返回:
const handler: HookHandler = async (event) => { // Only handle 'new' commands if (event.type !== "command" || event.action !== "new") { return; }
// Your logic here};使用特定的事件 Key
Section titled “使用特定的事件 Key”盡可能在 metadata 中指定確切的事件:
metadata: { "openclaw": { "events": ["command:new"] } } # Specific而非:
metadata: { "openclaw": { "events": ["command"] } } # General - more overhead啟用 Hook 日誌
Section titled “啟用 Hook 日誌”Gateway 在啟動時會記錄 Hook 的載入狀況:
Registered hook: session-memory -> command:newRegistered hook: bootstrap-extra-files -> agent:bootstrapRegistered hook: command-logger -> commandRegistered hook: boot-md -> gateway:startup檢查探索狀態
Section titled “檢查探索狀態”列出所有被偵測到的 Hook:
openclaw hooks list --verbose檢查註冊情況
Section titled “檢查註冊情況”在你的 handler 裡加入日誌,確認它真的有被呼叫:
const handler: HookHandler = async (event) => { console.log("[my-handler] Triggered:", event.type, event.action); // Your logic};驗證符合資格
Section titled “驗證符合資格”如果 Hook 沒有生效,可以用這個指令檢查原因:
openclaw hooks info my-hook在輸出結果中找看看是否有缺少的必要條件。
Gateway 日誌
Section titled “Gateway 日誌”監控 Gateway 日誌來觀察 Hook 的執行過程:
# macOS./scripts/clawlog.sh -f
# Other platformstail -f ~/.openclaw/gateway.log直接測試 Hook
Section titled “直接測試 Hook”你也可以單獨測試你的 handler:
import { test } from "vitest";import myHandler from "./hooks/my-hook/handler.js";
test("my handler works", async () => { const event = { type: "command", action: "new", sessionKey: "test-session", timestamp: new Date(), messages: [], context: { foo: "bar" }, };
await myHandler(event);
// Assert side effects});src/hooks/types.ts: Type definitions(類型定義)src/hooks/workspace.ts: 目錄掃描與載入src/hooks/frontmatter.ts: HOOK.md metadata 解析src/hooks/config.ts: 資格檢查src/hooks/hooks-status.ts: 狀態報告src/hooks/loader.ts: Dynamic module loader(動態模組載入器)src/cli/hooks-cli.ts: CLI 指令src/gateway/server-startup.ts: 在 Gateway 啟動時載入 Hooksrc/auto-reply/reply/commands-core.ts: 觸發指令事件
Gateway startup ↓Scan directories (bundled → plugin → managed + extra dirs → workspace) ↓Parse HOOK.md files ↓Sort by override precedence (bundled < plugin < managed < workspace) ↓Check eligibility (bins, env, config, os) ↓Load handlers from eligible hooks ↓Register handlers for eventsUser sends /new ↓Command validation ↓Create hook event ↓Trigger hook (all registered handlers) ↓Command processing continues ↓Session reset找不到 Hook
Section titled “找不到 Hook”-
檢查目錄結構:
Terminal window ls -la ~/.openclaw/hooks/my-hook/# Should show: HOOK.md, handler.ts -
驗證 HOOK.md 格式:
Terminal window cat ~/.openclaw/hooks/my-hook/HOOK.md# Should have YAML frontmatter with name and metadata -
列出所有探索到的 Hook:
Terminal window openclaw hooks list
Hook 不符合資格
Section titled “Hook 不符合資格”檢查需求設定:
openclaw hooks info my-hook看看是不是少了這些:
- Binaries(檢查 PATH)
- Environment variables
- Config values
- OS compatibility
Hook 未執行
Section titled “Hook 未執行”-
驗證 Hook 是否已啟用:
Terminal window openclaw hooks list# Should show ✓ next to enabled hooks -
重啟你的 Gateway 程序,讓 Hook 重新載入。
-
檢查 Gateway 日誌是否有錯誤:
Terminal window ./scripts/clawlog.sh | grep hook
Handler 錯誤
Section titled “Handler 錯誤”檢查 TypeScript 或匯入錯誤:
# Test import directlynode -e "import('./path/to/handler.ts').then(console.log)"如果你在設定過程中遇到任何問題,可以詢問 AI Setup Assistant 獲取即時幫助。
從舊版配置遷移到自動偵測 (Discovery)
Section titled “從舊版配置遷移到自動偵測 (Discovery)”遷移前:
{ "hooks": { "internal": { "enabled": true, "handlers": [ { "event": "command:new", "module": "./hooks/handlers/my-handler.ts" } ] } }}遷移後:
-
建立 hook 目錄:
Terminal window mkdir -p ~/.openclaw/hooks/my-hookmv ./hooks/handlers/my-handler.ts ~/.openclaw/hooks/my-hook/handler.ts -
建立 HOOK.md:
---name: my-hookdescription: "My custom hook"metadata: { "openclaw": { "emoji": "🎯", "events": ["command:new"] } }---# My HookDoes something useful. -
更新配置:
{"hooks": {"internal": {"enabled": true,"entries": {"my-hook": { "enabled": true }}}}} -
驗證並重啟你的 Gateway 程序:
Terminal window openclaw hooks list# Should show: 🎯 my-hook ✓
遷移的好處:
- 自動偵測
- CLI 管理
- 資格檢查
- 更好的文件說明
- 結構一致
OpenClaw Expert
還是卡住了?
如果這篇文件沒有解決你的情境,直接問 OpenClaw Expert,拿到可執行步驟。