D15 教的排程是看時間 —— 每天 23:00、每 7 天一次。但有些事你不知道它幾點會發生。
為什麼要HOOK。 你不知道自己明天幾點開電腦,所以排程處理不了「一開機就要做的事」。
hook 就是掛在事件上的那種觸發:條件一到自己跑,不用你叫,也不用等時間。
OpenClaw 做某些動作的時候會發出一個事件。你寫一個函式訂閱它,事件發生,Gateway 就呼叫你的函式。
一個 hook 就是一個資料夾,裡面兩個檔:
HOOK.md 宣告它叫什麼、掛哪個事件
handler.js 事件發生時要做什麼
內建的跟你自己寫的是同一種東西,結構完全一樣,連檔名都一樣。差別只有放在哪:內建的在套件裡,你寫的放 ~/.openclaw/hooks/你的名字/。hooks info 會標來源,一個是 openclaw-bundled,一個是 openclaw-managed。
openclaw hooks list
內建五個,開箱就有:
boot-md 開機時讀 workspace 的 BOOT.md,叫 agent 照著做
bootstrap-extra-files 把你指定的檔案一起塞進開場的背景資料
command-logger 把命令事件寫進集中的稽核檔
compaction-notifier 對話被壓縮時在聊天室通知你
session-memory 對話重置時把上下文存進記憶

第三個就是 D20 核准紀錄的來源 —— 那張帳本是這個 hook 在寫。
事件是固定清單,分五類:
command 新對話、重置、停止
session 自動重置、壓縮前、壓縮後、設定被改
agent 開場載入背景資料
gateway 啟動、關機、重啟前
message 收到訊息、語音轉完文字、前處理完、訊息送出
總共十六個。看懂這張表就知道 hook 能做什麼、不能做什麼。
文件給的範例 hook 只有八行,而且特別註明「用 JavaScript 寫,所以不需要 TypeScript 型別,也不需要 import 任何 SDK」。
對照內建的 boot-md,它的 handler 開頭有十八行 import:
import { i as agentCommandFromSystem } from "../../agent-command-CZJyvgsL.mjs";
import { r as defaultRuntime } from "../../runtime-KtFRxdRg.mjs";
檔名後面那串是 build hash,每次更新就換,而且路徑是 ../../ —— 只有放在套件目錄裡才解得開。內建 hook 能叫動 agent,是因為它拿得到這些內部模組。
所以能抄的只有外殼,不是實作。這條限制往下推出其他全部:
回傳值沒有用。 return 什麼都不會擋下或改寫原本的操作,只能做 —— 寫檔、發通知、記 log。
能掛「收到訊息的時候」,但不能掛「訊息內容是某某的時候」。 清單裡沒有這種事件。你可以在 message:received 裡自己判斷內容,但 message 那一類是觀察點,文件寫明不是阻止訊息繼續處理的方法。看得到,攔不下來。
它不在沙箱裡。 文件自己寫 trusted code,有 Gateway 的完整檔案、網路、環境權限。所以要用別人給的 hook 要先看過再開。
要改提示、攔工具呼叫、控制回覆內容 —— 這套機制做不到,得改成 PLUGIN。
boot-md 的 handler 做的事就是讀 BOOT.md,把內容當指令送去跑。所以你不用寫程式,直接用中文寫你要它開機做什麼就好。
但它是開一個臨時對話去做,做完把對話丟掉。所以別寫「讀一下某個檔,記住內容」——記的東西跟著那個對話一起消失。它適合:開機檢查、整理暫存、發通知。
建一個資料夾 ~/.openclaw/hooks/d22-demo/,裡面兩個檔。
HOOK.md:
---
name: d22-demo
description: "對話重置時留一行記號"
metadata:
{ "openclaw": { "events": ["command:new", "command:reset"] } }
---
handler.js:
export default function handler(event) {
if (event.type !== "command") return;
console.log("[d22-demo] reset hook ran, sessionKey=" + event.sessionKey);
event.messages.push("hook 跑過了。");
}
啟用,不用重開 Gateway,設定是熱重載的:
openclaw hooks enable d22-demo
啟用後兩秒,日誌出現:
[reload] config change detected (hooks.internal.entries.d22-demo)
[reload] config hot reload applied
接著在對話裡打 /new:
[d22-demo] reset hook ran, sessionKey=agent:labdemo:main
同一次重置還順便觸發了另外兩個內建 hook:session-memory 把上下文存成檔案,command-logger 在 commands.log 加了一行。一個動作三個 hook,這就是它平常在背後做的事。
boot-md 預設就是啟用的。但 workspace 裡沒有 BOOT.md、或者檔案是空的,它會直接跳過,不做事也不報錯,hooks list 一樣顯示 ready。我這台原本就是這種狀態。
而且 ready 只代表條件符合,不代表 Gateway 真的載入了它。要確認就去看日誌,或看它該產生的作用在不在。