MO STORIES
Claude Code Hooks 完整教學(2026):自動化排程、Slash Command 與專案工作流
如果你 Google「Claude Code Hooks」,多半會看到官方文件那幾頁。 技術細節都對,但你看完還是不知道 —— hook 到底什麼時候用、什麼時候用 cron 比較好、5 種 hook 類型差在哪? 這篇是我跑了 30+ hook、踩過 5 個坑之後整理的實作版本。 如果你只想知道結論: Hook = ...

Claude Code Hooks 完整教學(2026):自動化排程、Slash Command 與專案工作流
如果你 Google「Claude Code Hooks」,多半會看到官方文件那幾頁。
技術細節都對,但你看完還是不知道 ——
hook 到底什麼時候用、什麼時候用 cron 比較好、5 種 hook 類型差在哪?
這篇是我跑了 30+ hook、踩過 5 個坑之後整理的實作版本。
如果你只想知道結論:
- Hook = 事件驅動自動化(不是時間驅動)
- 5 種類型 + 1 個排程器 = 90% 情境都涵蓋
- settings.json 是入口,但要避開 3 個雷區
下面開始。
Hook 是什麼?跟 cron 差在哪
Claude Code Hooks 是 Claude Code 在「特定事件發生時」自動跑指令的機制。
跟 cron 最大的差別:
| 維度 | cron / scheduled-tasks | Claude Code Hooks |
|---|---|---|
| 觸發方式 | 時間(每 5 分鐘 / 每天 09:00) | 事件(工具呼叫前後 / agent 停止 / session 開始) |
| 適合情境 | 定期掃描、健康檢查、固定排程 | 對 Claude 動作的即時反應 |
| 執行環境 | 系統 cron daemon | Claude Code 自身 process |
| context | 沒有 | 帶 tool name、prompt、session 資訊 |
簡單說:
- 要做「每天早上 9 點寄電子報」 → 用 cron / scheduled-tasks
- 要做「每次 Claude 寫完一篇文章自動 sync 到 Notion」 → 用 hook
兩者可以搭配用,不是替代關係。
Claude Code 的 5 種 Hook 類型
截至 2026 年 4 月,Claude Code 支援 5 種 hook:
| Hook 類型 | 觸發時機 | 常見用途 |
|---|---|---|
PreToolUse |
Claude 呼叫工具前 | 攔截危險指令、改寫參數、要求人工確認 |
PostToolUse |
Claude 呼叫工具後 | 結果驗證、log 記錄、後續通知 |
Stop |
Agent 停止時 | session summary、自動 commit、清理 temp 檔 |
UserPromptSubmit |
使用者送訊息時 | inject context、檢查格式、attach 檔案 |
SessionStart |
session 開始時 | 載入專案規則、初始化環境變數、印 todo 清單 |
每種 hook 都對應一個事件 → 你寫的指令會在那個瞬間被執行。
觸發鏈(重要)
順序很重要,不然會踩坑:
SessionStart
→ UserPromptSubmit(每次你送訊息)
→ PreToolUse(每次 Claude 用工具前)
→ [tool 真正執行]
→ PostToolUse(每次工具執行後)
→ Stop(agent 結束回合)
settings.json 完整設定範例
Hook 寫在 .claude/settings.json(專案層)或 ~/.claude/settings.json(使用者層)。
最小可運作範例
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "echo '⚠️ Claude 想寫檔案,按 Enter 繼續' && read"
}
]
}
]
}
}
這個 hook 每次 Claude 用 Write 工具前會等你按 Enter。
完整範例(5 種 hook 都用)
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "cat .claude/rules/quick-summary.md"
}
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "echo \"[$(date +%H:%M)] $CLAUDE_USER_PROMPT\" >> .claude/prompt-log.txt"
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/check-dangerous-commands.js"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/lint-edited-file.js \"$CLAUDE_TOOL_FILE_PATH\""
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/write-daily-summary.js"
}
]
}
]
}
}
5 個我自己用的 hook(實戰)
下面是我在瘦桑 repo 跑了 3 個月以上的 hook,每個都解決一個具體痛點。
Hook 1:寫完文章自動 sync 到 Notion
痛點:每寫完一篇 SEO 文,都要記得跑 node scripts/notion/sync-to-notion.cjs。常常忘。
解法:PostToolUse hook 偵測到 articles/*.md 被 Edit 或 Write,自動 sync。
{
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/auto-sync-articles.js \"$CLAUDE_TOOL_FILE_PATH\""
}
]
}
]
}
.claude/hooks/auto-sync-articles.js:
const path = require('path');
const { spawn } = require('child_process');
const filePath = process.argv[2];
if (!filePath) process.exit(0);
if (!filePath.match(/^articles\/.*\.md$/)) process.exit(0);
console.log(`✅ 偵測到文章編輯 ${filePath},自動 sync 到 Notion...`);
spawn('node', ['scripts/notion/sync-to-notion.cjs', filePath], {
stdio: 'inherit',
detached: true,
});
Hook 2:commit 前自動跑 lint
痛點:Claude 寫的東西常踩品牌禁句型與禁詞列表(規則寫在 .claude/rules/brand-voice.md)。
解法:PreToolUse 偵測到 git commit Bash 指令前,先跑 lint。
// .claude/hooks/check-dangerous-commands.js
const cmd = process.env.CLAUDE_TOOL_BASH_COMMAND || '';
if (cmd.startsWith('git commit')) {
const { execSync } = require('child_process');
try {
execSync('node scripts/lint/brand-voice.js', { stdio: 'inherit' });
} catch (e) {
console.error('❌ 品牌語氣 lint 失敗,commit 取消');
process.exit(2); // exit code 2 = block tool execution
}
}
exit 2 會讓 Claude 中止執行那個工具,等於攔截 commit。
Hook 3:改完 .env 自動重啟 dev server
痛點:改完 .env 變數要手動重啟 npm run dev 才生效,常常忘。
// PostToolUse hook (matcher: "Edit|Write")
const filePath = process.argv[2];
if (filePath?.endsWith('.env') || filePath?.endsWith('.env.local')) {
const { execSync } = require('child_process');
console.log('♻️ .env 已修改,重啟 dev server...');
execSync('pkill -f "next dev" || true && npm run dev &');
}
Hook 4:跑完測試自動發 Slack 通知
痛點:CI 跑完不會主動通知,要去 GitHub 看。
// PostToolUse hook (matcher: "Bash")
const cmd = process.env.CLAUDE_TOOL_BASH_COMMAND || '';
const exitCode = process.env.CLAUDE_TOOL_EXIT_CODE;
if (cmd.includes('npm test') || cmd.includes('vitest')) {
const status = exitCode === '0' ? '✅ PASS' : '❌ FAIL';
fetch(process.env.SLACK_WEBHOOK_URL, {
method: 'POST',
body: JSON.stringify({ text: `Test ${status}: ${cmd}` }),
});
}
Hook 5:session 結束自動寫 daily summary
痛點:每天忙完,記不得做了什麼。
// Stop hook
const fs = require('fs');
const today = new Date().toISOString().slice(0, 10);
const summaryPath = `journal/${today.slice(0, 7).replace('-', '/')}/${today}-claude-log.md`;
const log = `\n[${new Date().toLocaleTimeString('zh-TW')}] Session ended.\n`;
fs.appendFileSync(summaryPath, log);
進階版可以叫 Claude 把那個 session 的對話內容自動摘要進去。
排程任務 vs Hooks:什麼時候用哪個?
兩者的決策樹:
| 我的需求 | 用什麼 |
|---|---|
| 每天 09:00 跑一次 | scheduled-tasks(cron) |
| 每次寫完檔案後 | PostToolUse hook |
| 攔截危險指令 | PreToolUse hook |
| 每週五自動跑分析 | scheduled-tasks |
| 每次 Claude 結束自動 commit | Stop hook |
| 監測 GitHub PR 狀態(每 5 min) | scheduled-tasks |
| 改完設定自動套用 | PostToolUse hook |
| 每次新訊息加 context | UserPromptSubmit hook |
簡單記法:
- 時間驅動 = scheduled-tasks
- 事件驅動 = hooks
踩過的 3 個坑
坑 1:hook 卡死整個 agent
寫了一個 hook 沒設 timeout,跑進無窮迴圈。整個 Claude Code 卡住要 ctrl+C 強殺。
解法:每個 hook 指令加 timeout:
{
"type": "command",
"command": "timeout 10 node .claude/hooks/my-hook.js"
}
10 秒沒跑完就強制終止。
坑 2:環境變數沒帶到
Hook 跑的是 child process,預設不會繼承所有 env。
解法:在 hook script 開頭明確 source .env:
require('dotenv').config({ path: '/absolute/path/to/.env' });
不要用相對路徑。Hook 的 cwd 不一定是專案根目錄。
坑 3:自動化跑無窮迴圈
最危險的坑:PostToolUse hook 觸發 → hook 改檔 → 再觸發 PostToolUse → 無限。
例子:你寫 PostToolUse hook 在 Edit 後 auto-format,但 auto-format 也用 Edit 工具 → 觸發自己。
解法:
- Hook 用 spawn 而非工具呼叫(不會再觸發 hook)
- 加防禦:
if (process.env.CLAUDE_HOOK_INVOKED === '1') {
console.log('⏭ skip recursive hook');
process.exit(0);
}
process.env.CLAUDE_HOOK_INVOKED = '1';
FAQ
Hook 寫在專案層還是使用者層?
- 專案層(
.claude/settings.json):跟團隊共享、checked into git - 使用者層(
~/.claude/settings.json):個人習慣、所有專案都生效
我的習慣:核心邏輯(如 lint)放專案層,個人偏好(如通知)放使用者層。
為什麼我的 hook 沒觸發?
3 個常見原因:
- JSON 語法錯:
.claude/settings.json有逗號錯位,整個 hooks 物件被忽略 - matcher 寫錯:
"Edit"vs"Edit|Write"寫錯不報錯,靜默失敗 - Hook 指令在 PATH 找不到:用絕對路徑
/usr/local/bin/node ...比較穩
Hook 可以呼叫 Claude API 嗎?
可以。例如 Stop hook 呼叫 Claude API 把 session 對話摘要進 daily summary。
但要注意成本——每次 Stop 都打 API 會累積。
Hook 裡可以用其他語言嗎?
可以。type: "command" 跑的是 shell command,所以 Python、Go、Bash 都行。
但 Node.js 最方便,因為通常專案內已經有 dependencies。
Hook 失敗會怎樣?
依 exit code:
0= 成功,繼續執行1= 失敗但不 block,Claude 繼續做事2= 失敗且 block,Claude 中止當前工具呼叫
寫 PreToolUse 想攔截動作,記得 process.exit(2)。
小結
Claude Code Hooks 是 Claude Code 自動化的第二支柱(第一支柱是 scheduled-tasks)。
5 種類型分清楚:
- PreToolUse → 攔截 / 改寫 / 確認
- PostToolUse → 驗證 / 通知 / 後續動作
- Stop → summary / commit / 清理
- UserPromptSubmit → 加 context
- SessionStart → 載入規則
決策一句話:時間用 cron,事件用 hook。
如果你才剛開始,建議先從一個 PostToolUse + Stop hook 跑起來。3 天就會回不去手動。
延伸閱讀

關於作者 | 10+ 經驗
MO 編輯
WordPress 效能優化專家 / MO Design Studio 共同創辦人
關注設計 × 工程的平衡協作,擅長以簡潔語言說故事。專門幫已有網站的品牌做速度升級。相信好網站不用重做,只需要正確的優化。
延伸閱讀

n8n + Telegram 自動化教學:打造 AI 通知機器人完整指南(2026)
用 n8n 串接 Telegram Bot,打造即時通知機器人。從建立 Bot、取得 Token 到四種實用自動化範例,免費、低延遲、雙向互動。...

用 Claude Code 打造個人 AI Agent:Hooks、排程、MCP 完整教學(2026)
>-...

n8n 做 SEO 自動化教學|不想再花冤枉錢買軟體了嗎?這招學起來
不想再手動查排名、整理關鍵字?教你如何利用開源自動化工具 n8n 串接 API,打造專屬於你品牌的 SEO 監控與報告自動化系統。...
訂閱瘦生活電子報
每週一封故事信——分享如何用減法思維剔除雜訊、做對的事、過好生活。不說教,不推銷,只有真實的取捨紀錄。