Claude Code Hooks 選裝實(shí)戰(zhàn)指南
Claude Code Hooks 是一套事件驅(qū)動的自動化機(jī)制,允許開發(fā)者在 AI 代理生命周期的特定節(jié)點(diǎn)(如工具調(diào)用前后、會話開始/結(jié)束時(shí))插入自定義邏輯。通過 Hooks,可以實(shí)現(xiàn)安全攔截、代碼格式化、環(huán)境初始化及外部系統(tǒng)集成,將“信任模型”轉(zhuǎn)變?yōu)?ldquo;信任但驗(yàn)證”的確定性工作流。
Claude Code Hooks 實(shí)戰(zhàn)指南
2026-06-02 | 覆蓋危險(xiǎn)攔截 + 桌面通知,三級分級體系,兩腳本開箱即用
一、為什么需要 Hook
Skill 是"建議",Hook 是"強(qiáng)制"。CLAUE.md 告訴 AI 怎么做,遵守率約 80%;Hook 在工具調(diào)用前后直接攔截,100% 執(zhí)行。
本文只做一件事:給你兩個(gè)腳本 + 一個(gè)配置,復(fù)制即用。 不需要理解 Hook 原理,不需要研究社區(qū) 61 個(gè) Hook。如果你對擴(kuò)展感興趣,文末有社區(qū)全目錄供探索。
二、三層攔截:什么東西該攔、什么東西不該攔
核心原則:Hook 只攔 Claude,不攔你。 被攔后 Claude 會說"這個(gè)操作被攔截了,請手動執(zhí)行",你復(fù)制到終端跑就行。
| 級別 | 標(biāo)準(zhǔn) | 行為 | 案例 |
|---|---|---|---|
| 致命 | 不可恢復(fù),誤操作 = 災(zāi)難 | exit 2 硬掐,永不放過 | rm -rf /、DROP DATABASE、curl | bash |
| 高風(fēng)險(xiǎn) | 可恢復(fù)但代價(jià)大 | exit 2 硬攔,你手動執(zhí)行不受影響 | push --force、reset --hard、npm publish |
| 警告 | 正常操作僅提醒 | exit 0 打印,Claude 自行判斷 | 單個(gè) rm、rmdir |
三、配置(settings.json)
以下為 ~/.claude/settings.json 中的 hooks 配置。注意 matcher + hooks 必須嵌套,否則 schema 校驗(yàn)報(bào)錯(cuò)。
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "pwsh.exe -NoProfile -ExecutionPolicy Bypass -File \"C:\\Users\\14437\\.claude\\hooks\\block-dangerous.ps1\""
}]
}],
"Stop": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "cmd /c chcp 65001 >nul && powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File \"C:\\Users\\14437\\.claude\\hooks\\toast-notify.ps1\"",
"async": true
}]
}],
"Notification": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "cmd /c chcp 65001 >nul && powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File \"C:\\Users\\14437\\.claude\\hooks\\toast-notify.ps1\"",
"async": true
}]
}]
}
}三個(gè)關(guān)鍵點(diǎn):
powershell.exe(5.1)而非pwsh.exe— WinRT Toast API 僅在 Windows 原生 PowerShell 5.1 中可用,PowerShell 7 無法加載Windows.UI.Notifications類型cmd /c chcp 65001 >nul &&— 切換控制臺代碼頁為 UTF-8,否則 PowerShell 5.1 讀取 .ps1 文件時(shí)中文會亂碼- 絕對路徑 — Claude Code 不會展開
${USERPROFILE},必須寫完整路徑
四、腳本 1:危險(xiǎn)命令攔截
文件路徑:~/.claude/hooks/block-dangerous.ps1
# Claude Code PreToolUse Hook — 危險(xiǎn)命令攔截
# 致命級:exit 2 硬掐,永不放過
# 高風(fēng)險(xiǎn):exit 2 硬掐,手動執(zhí)行不受影響
# 警告級:exit 0 打印提醒,Claude 自行判斷
$input = [Console]::In.ReadToEnd() | ConvertFrom-Json
$cmd = $input.tool_input.command
# ============================================================
# 致命級 — 不可恢復(fù),誤操作 = 災(zāi)難,永不放過
# ============================================================
$fatal = @(
'rm\s+-rf\s+/', # rm -rf / 根目錄
'rm\s+-rf\s+~', # rm -rf ~ 用戶目錄
'rm\s+-rf\s+\$HOME', # rm -rf $HOME
'DROP\s+DATABASE', # 刪庫
'migrate:fresh', # Laravel 重置數(shù)據(jù)庫
'prisma\s+migrate\s+reset', # Prisma 重置
'chmod\s+777\s+/', # 根目錄全開放權(quán)限
'curl.*\|.*bash', # 遠(yuǎn)程腳本直執(zhí)行
'curl.*\|.*sh', # 同上
'wget.*\|.*bash', # 同上
'>\s+/dev/sda', # 覆寫磁盤
'mkfs\.' # 格式化
)
foreach ($pattern in $fatal) {
if ($cmd -match $pattern) {
$stderr = @"
========================================
?? 致命操作,已永久攔截
命令:$cmd
原因:不可恢復(fù),誤操作等于災(zāi)難
處理:請勿通過 Claude Code 執(zhí)行此命令。
如確需執(zhí)行,請手動在終端運(yùn)行。
========================================
"@
Write-Error $stderr
exit 2
}
}
# ============================================================
# 高風(fēng)險(xiǎn) — 可恢復(fù)但代價(jià)大,硬攔,手動執(zhí)行不受影響
# ============================================================
$highRisk = @(
'git\s+push\s+.*--force', # git push --force
'git\s+push\s+.*-f\b', # git push -f
'git\s+reset\s+--hard', # git reset --hard
'git\s+clean\s+-f', # git clean -f/d/fd
'git\s+branch\s+-D', # 強(qiáng)制刪分支
'git\s+checkout\s+\.', # 丟棄所有本地修改
'git\s+restore\s+\.', # 同上
'npm\s+publish', # 發(fā)布 npm 包
'npm\s+unpublish', # 撤回 npm 包
'pip\s+uninstall\s+-y', # 批量卸載 Python 包
'docker\s+rm\s+-f', # 強(qiáng)制刪容器
'docker\s+rmi\s+-f', # 強(qiáng)制刪鏡像
'docker\s+system\s+prune', # 清理所有未用鏡像
'kubectl\s+delete\s+deployment' # 刪 K8s 部署
)
foreach ($pattern in $highRisk) {
if ($cmd -match $pattern) {
$stderr = @"
========================================
?? 高風(fēng)險(xiǎn)操作,已攔截
命令:$cmd
原因:可恢復(fù)但代價(jià)大(丟提交/刪環(huán)境/影響線上)
處理:Claude Code 不允許自動執(zhí)行此操作。
請確認(rèn)無誤后,復(fù)制以下命令到終端手動執(zhí)行:
$cmd
========================================
"@
Write-Error $stderr
exit 2
}
}
# ============================================================
# 警告級 — 正常操作,僅提醒
# ============================================================
$warnings = @(
'rm\s+-rf\s+\./', # rm -rf ./ (當(dāng)前目錄)
'rm\s+-rf\s+\w', # rm -rf 某個(gè)目錄
'git\s+branch\s+-d', # 刪已合并分支(安全,但提醒)
'del\s+/f\s+/s', # Windows 強(qiáng)制遞歸刪
'rmdir\s+/s\s+/q' # Windows rmdir
)
foreach ($pattern in $warnings) {
if ($cmd -match $pattern) {
Write-Warning "?? 提醒:即將執(zhí)行 `$cmd`,請確認(rèn)是否期望此操作。"
exit 0
}
}
# 一切正常,放行
exit 0五、腳本 2:桌面通知(WinRT Toast)
文件路徑:~/.claude/hooks/toast-notify.ps1
技術(shù)選型:社區(qū)調(diào)查后采用 WinRT Toast API(與 GitHub 上 soulee-dev/claude-code-notify-powershell ?63 同方案),而非 NotifyIcon 托盤氣泡。原因:
NotifyIcon氣球通知關(guān)聯(lián) pwsh 窗口句柄 → 點(diǎn)擊通知會跳到終端 → 無解- WinRT Toast 是 Windows 原生通知 → 無窗口句柄 → 點(diǎn)擊自然消失 → 零缺陷
- 零依賴,純 Windows 自帶
powershell.exe+Windows.UI.NotificationsAPI - 加入
try-catch+NotifyIcon回退,極端情況下 WinRT 掛了也能彈通知
# Claude Code 桌面通知(零依賴,純 Windows 自帶)
# 事件:Stop / Notification
# 策略:WinRT Toast 優(yōu)先,失敗時(shí)回退 NotifyIcon 托盤氣泡
# ── 從 stdin 讀取 Claude Code 傳來的 hook JSON ──
$json = ($input | Out-String) | ConvertFrom-Json -ErrorAction SilentlyContinue
$hookEvent = $json.hook_event_name
if (-not $hookEvent) { exit 0 } # 沒讀到有效事件,靜默退出
# ── 根據(jù)事件類型選擇消息 ──
switch ($hookEvent) {
"Stop" { $title = "Claude Code"; $message = "任務(wù)完成,回來看看吧" }
"Notification" { $title = "Claude Code —— 需要你的關(guān)注"; $message = "權(quán)限確認(rèn) / 等待輸入" }
default { exit 0 }
}
# ═══════════════════════════════════════════════════════════════
# 主方案:WinRT Toast
# ═══════════════════════════════════════════════════════════════
$ok = $false
try {
$template = [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime]::GetTemplateContent(
[Windows.UI.Notifications.ToastTemplateType, Windows.UI.Notifications, ContentType = WindowsRuntime]::ToastText02
)
$template.SelectSingleNode("http://text[@id='1']").InnerText = $title
$template.SelectSingleNode("http://text[@id='2']").InnerText = $message
$appId = "{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}\WindowsPowerShell\v1.0\powershell.exe"
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($appId).Show($template)
$ok = $true
} catch { }
# ═══════════════════════════════════════════════════════════════
# 回退方案:WinRT 失敗時(shí)用托盤氣泡兜底
# ═══════════════════════════════════════════════════════════════
if (-not $ok) {
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
Add-Type -Name _CC -Namespace _ -MemberDefinition '
[DllImport("kernel32.dll")] public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
'
$ptr = [_._CC]::GetConsoleWindow()
[_._CC]::ShowWindow($ptr, 0)
$balloon = New-Object System.Windows.Forms.NotifyIcon
$balloon.Icon = if ($hookEvent -eq "Notification") {
[System.Drawing.SystemIcons]::Warning
} else {
[System.Drawing.SystemIcons]::Information
}
$balloon.BalloonTipTitle = $title
$balloon.BalloonTipText = $message
$balloon.Visible = $true
$balloon.ShowBalloonTip(5000)
Start-Sleep -Seconds 6
$balloon.Dispose()
}關(guān)鍵設(shè)計(jì)決策
| 決策 | 選擇 | 原因 |
|---|---|---|
| 通知 API | Windows.UI.Notifications WinRT | 原生 Toast,無托盤圖標(biāo),無窗口句柄 |
| Shell 引擎 | powershell.exe(5.1) | WinRT 類型僅在 PowerShell 5.1 中可用 |
| 編碼方案 | cmd /c chcp 65001 + UTF-8 BOM .ps1 | PowerShell 5.1 讀腳本需要 BOM |
| XML 操作 | SelectSingleNode XPath | 比 GetElementsByTagName + Item() 更干凈 |
| AppUserModelID | {1AC14E77...} GUID | 真實(shí) GUID,不依賴快捷方式 |
| 事件區(qū)分 | 讀 stdin JSON 的 hook_event_name | 一個(gè)腳本處理所有事件 |
| 空數(shù)據(jù)保護(hù) | if (-not $hookEvent) { exit 0 } | stdin 為空時(shí)靜默退出,不彈無效通知 |
| 錯(cuò)誤回退 | try-catch + NotifyIcon 兜底 | WinRT 極罕見失敗時(shí)仍能通知 |
| 異步執(zhí)行 | "async": true | 不阻塞 Claude Code 返回 |
六、這些事不需要 Hook(你已有 Skill 覆蓋)
| 場景 | 為什么不需要 | 已有的 Skill |
|---|---|---|
| 代碼審查 | code-review-and-quality 自動觸發(fā)五軸審查 | 項(xiàng)目全流程·階段 6 |
| 提交規(guī)范 | git-commit 管 Conventional Commits | 項(xiàng)目全流程·階段 7 |
| TDD 強(qiáng)制 | test-driven-development 鐵律級約束 | 項(xiàng)目全流程·階段 1 |
| 安全加固 | security-and-hardening 全局 OWASP 防護(hù) | 項(xiàng)目全流程·階段 6 |
| 部署監(jiān)控 | canary-watch 上線后監(jiān)測 | 項(xiàng)目全流程·階段 7 |
| Token 審計(jì) | context-budget 上下文消耗分析 | 場景工具 |
| 文檔同步 | neat-freak 會話后自動同步 | 項(xiàng)目全流程·階段 8 |
七、不建議裝的 Hook
| Hook | 原因 |
|---|---|
| 語音 TTS(disler/hooks-mastery) | 依賴 ElevenLabs/OpenAI,太重 |
| Telegram/Slack 審批 | 不需要額外審批通道 |
| 記憶持久化(mann1x/claude-hooks) | 需要 Qdrant + Ollama |
| 全量審計(jì)日志 | 開發(fā)環(huán)境不需要 |
| 自動 Git Stage | 跟 git-commit 沖突 |
| auto-approve-* 系列 | 自動批準(zhǔn)構(gòu)建/測試/Docker,太激進(jìn) |
八、想探索更多?
npx cc-hook-registry search <關(guān)鍵詞> # 61 個(gè)社區(qū) Hook 可搜索安裝
社區(qū)完整分類(61 個(gè) Hook,來源 cc-hook-registry):
| 類別 | 數(shù)量 | 代表性 Hook |
|---|---|---|
| 安全攔截 | 16 | destructive-guard、secret-guard、block-database-wipe、no-sudo-guard |
| 質(zhì)量保障 | 16 | syntax-check、enforce-tests、npm-publish-guard、diff-size-guard |
| 體驗(yàn)增強(qiáng) | 4 | notify-waiting、session-handoff |
| 自動批準(zhǔn) | 14 | auto-approve-build、auto-approve-* 各語言版本 |
| 外部項(xiàng)目 | 4 | anipotts(9 hooks)、karanb192(4 hooks)、disler(教程)、johnlindquist(框架) |
值得關(guān)注的外部項(xiàng)目:
- anipotts/claude-code-tips — 9 個(gè)實(shí)戰(zhàn) Hook,設(shè)計(jì)哲學(xué)清晰
- karanb192/claude-code-hooks — 三級安全體系,開箱即用
到此這篇關(guān)于Claude Code Hooks 選裝實(shí)戰(zhàn)指南的文章就介紹到這了,更多相關(guān)Claude Code Hooks內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持腳本之家!
相關(guān)文章
Claude Code 每次調(diào)用工具、等待輸入、結(jié)束會話,都會觸發(fā)對應(yīng)的Hook生命周期事件,Hook 腳本除了做判斷和記錄,還可以把事件轉(zhuǎn)發(fā)到本地 socket,讓一個(gè)常駐進(jìn)程處理所有狀2026-06-02


