Claude Code Hooks 选装实战指南
Claude Code Hooks 是一套事件驱动的自动化机制,允许开发者在 AI 代理生命周期的特定节点(如工具调用前后、会话开始/结束时)插入自定义逻辑。通过 Hooks,可以实现安全拦截、代码格式化、环境初始化及外部系统集成,将“信任模型”转变为“信任但验证”的确定性工作流。
Claude Code Hooks 实战指南
2026-06-02 | 覆盖危险拦截 + 桌面通知,三级分级体系,两脚本开箱即用
一、为什么需要 Hook
Skill 是"建议",Hook 是"强制"。CLAUE.md 告诉 AI 怎么做,遵守率约 80%;Hook 在工具调用前后直接拦截,100% 执行。
本文只做一件事:给你两个脚本 + 一个配置,复制即用。 不需要理解 Hook 原理,不需要研究社区 61 个 Hook。如果你对扩展感兴趣,文末有社区全目录供探索。
二、三层拦截:什么东西该拦、什么东西不该拦
核心原则:Hook 只拦 Claude,不拦你。 被拦后 Claude 会说"这个操作被拦截了,请手动执行",你复制到终端跑就行。
| 级别 | 标准 | 行为 | 案例 |
|---|---|---|---|
| 致命 | 不可恢复,误操作 = 灾难 | exit 2 硬掐,永不放过 | rm -rf /、DROP DATABASE、curl | bash |
| 高风险 | 可恢复但代价大 | exit 2 硬拦,你手动执行不受影响 | push --force、reset --hard、npm publish |
| 警告 | 正常操作仅提醒 | exit 0 打印,Claude 自行判断 | 单个 rm、rmdir |
三、配置(settings.json)
以下为 ~/.claude/settings.json 中的 hooks 配置。注意 matcher + hooks 必须嵌套,否则 schema 校验报错。
{
"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
}]
}]
}
}三个关键点:
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 文件时中文会乱码- 绝对路径 — Claude Code 不会展开
${USERPROFILE},必须写完整路径
四、脚本 1:危险命令拦截
文件路径:~/.claude/hooks/block-dangerous.ps1
# Claude Code PreToolUse Hook — 危险命令拦截
# 致命级:exit 2 硬掐,永不放过
# 高风险:exit 2 硬掐,手动执行不受影响
# 警告级:exit 0 打印提醒,Claude 自行判断
$input = [Console]::In.ReadToEnd() | ConvertFrom-Json
$cmd = $input.tool_input.command
# ============================================================
# 致命级 — 不可恢复,误操作 = 灾难,永不放过
# ============================================================
$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 重置数据库
'prisma\s+migrate\s+reset', # Prisma 重置
'chmod\s+777\s+/', # 根目录全开放权限
'curl.*\|.*bash', # 远程脚本直执行
'curl.*\|.*sh', # 同上
'wget.*\|.*bash', # 同上
'>\s+/dev/sda', # 覆写磁盘
'mkfs\.' # 格式化
)
foreach ($pattern in $fatal) {
if ($cmd -match $pattern) {
$stderr = @"
========================================
🛑 致命操作,已永久拦截
命令:$cmd
原因:不可恢复,误操作等于灾难
处理:请勿通过 Claude Code 执行此命令。
如确需执行,请手动在终端运行。
========================================
"@
Write-Error $stderr
exit 2
}
}
# ============================================================
# 高风险 — 可恢复但代价大,硬拦,手动执行不受影响
# ============================================================
$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', # 强制删分支
'git\s+checkout\s+\.', # 丢弃所有本地修改
'git\s+restore\s+\.', # 同上
'npm\s+publish', # 发布 npm 包
'npm\s+unpublish', # 撤回 npm 包
'pip\s+uninstall\s+-y', # 批量卸载 Python 包
'docker\s+rm\s+-f', # 强制删容器
'docker\s+rmi\s+-f', # 强制删镜像
'docker\s+system\s+prune', # 清理所有未用镜像
'kubectl\s+delete\s+deployment' # 删 K8s 部署
)
foreach ($pattern in $highRisk) {
if ($cmd -match $pattern) {
$stderr = @"
========================================
⚠️ 高风险操作,已拦截
命令:$cmd
原因:可恢复但代价大(丢提交/删环境/影响线上)
处理:Claude Code 不允许自动执行此操作。
请确认无误后,复制以下命令到终端手动执行:
$cmd
========================================
"@
Write-Error $stderr
exit 2
}
}
# ============================================================
# 警告级 — 正常操作,仅提醒
# ============================================================
$warnings = @(
'rm\s+-rf\s+\./', # rm -rf ./ (当前目录)
'rm\s+-rf\s+\w', # rm -rf 某个目录
'git\s+branch\s+-d', # 删已合并分支(安全,但提醒)
'del\s+/f\s+/s', # Windows 强制递归删
'rmdir\s+/s\s+/q' # Windows rmdir
)
foreach ($pattern in $warnings) {
if ($cmd -match $pattern) {
Write-Warning "⚠️ 提醒:即将执行 `$cmd`,请确认是否期望此操作。"
exit 0
}
}
# 一切正常,放行
exit 0五、脚本 2:桌面通知(WinRT Toast)
文件路径:~/.claude/hooks/toast-notify.ps1
技术选型:社区调查后采用 WinRT Toast API(与 GitHub 上 soulee-dev/claude-code-notify-powershell ⭐63 同方案),而非 NotifyIcon 托盘气泡。原因:
NotifyIcon气球通知关联 pwsh 窗口句柄 → 点击通知会跳到终端 → 无解- WinRT Toast 是 Windows 原生通知 → 无窗口句柄 → 点击自然消失 → 零缺陷
- 零依赖,纯 Windows 自带
powershell.exe+Windows.UI.NotificationsAPI - 加入
try-catch+NotifyIcon回退,极端情况下 WinRT 挂了也能弹通知
# Claude Code 桌面通知(零依赖,纯 Windows 自带)
# 事件:Stop / Notification
# 策略:WinRT Toast 优先,失败时回退 NotifyIcon 托盘气泡
# ── 从 stdin 读取 Claude Code 传来的 hook JSON ──
$json = ($input | Out-String) | ConvertFrom-Json -ErrorAction SilentlyContinue
$hookEvent = $json.hook_event_name
if (-not $hookEvent) { exit 0 } # 没读到有效事件,静默退出
# ── 根据事件类型选择消息 ──
switch ($hookEvent) {
"Stop" { $title = "Claude Code"; $message = "任务完成,回来看看吧" }
"Notification" { $title = "Claude Code —— 需要你的关注"; $message = "权限确认 / 等待输入" }
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("//text[@id='1']").InnerText = $title
$template.SelectSingleNode("//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 失败时用托盘气泡兜底
# ═══════════════════════════════════════════════════════════════
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()
}关键设计决策
| 决策 | 选择 | 原因 |
|---|---|---|
| 通知 API | Windows.UI.Notifications WinRT | 原生 Toast,无托盘图标,无窗口句柄 |
| 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 | 真实 GUID,不依赖快捷方式 |
| 事件区分 | 读 stdin JSON 的 hook_event_name | 一个脚本处理所有事件 |
| 空数据保护 | if (-not $hookEvent) { exit 0 } | stdin 为空时静默退出,不弹无效通知 |
| 错误回退 | try-catch + NotifyIcon 兜底 | WinRT 极罕见失败时仍能通知 |
| 异步执行 | "async": true | 不阻塞 Claude Code 返回 |
六、这些事不需要 Hook(你已有 Skill 覆盖)
| 场景 | 为什么不需要 | 已有的 Skill |
|---|---|---|
| 代码审查 | code-review-and-quality 自动触发五轴审查 | 项目全流程·阶段 6 |
| 提交规范 | git-commit 管 Conventional Commits | 项目全流程·阶段 7 |
| TDD 强制 | test-driven-development 铁律级约束 | 项目全流程·阶段 1 |
| 安全加固 | security-and-hardening 全局 OWASP 防护 | 项目全流程·阶段 6 |
| 部署监控 | canary-watch 上线后监测 | 项目全流程·阶段 7 |
| Token 审计 | context-budget 上下文消耗分析 | 场景工具 |
| 文档同步 | neat-freak 会话后自动同步 | 项目全流程·阶段 8 |
七、不建议装的 Hook
| Hook | 原因 |
|---|---|
| 语音 TTS(disler/hooks-mastery) | 依赖 ElevenLabs/OpenAI,太重 |
| Telegram/Slack 审批 | 不需要额外审批通道 |
| 记忆持久化(mann1x/claude-hooks) | 需要 Qdrant + Ollama |
| 全量审计日志 | 开发环境不需要 |
| 自动 Git Stage | 跟 git-commit 冲突 |
| auto-approve-* 系列 | 自动批准构建/测试/Docker,太激进 |
八、想探索更多?
npx cc-hook-registry search <关键词> # 61 个社区 Hook 可搜索安装
社区完整分类(61 个 Hook,来源 cc-hook-registry):
| 类别 | 数量 | 代表性 Hook |
|---|---|---|
| 安全拦截 | 16 | destructive-guard、secret-guard、block-database-wipe、no-sudo-guard |
| 质量保障 | 16 | syntax-check、enforce-tests、npm-publish-guard、diff-size-guard |
| 体验增强 | 4 | notify-waiting、session-handoff |
| 自动批准 | 14 | auto-approve-build、auto-approve-* 各语言版本 |
| 外部项目 | 4 | anipotts(9 hooks)、karanb192(4 hooks)、disler(教程)、johnlindquist(框架) |
值得关注的外部项目:
- anipotts/claude-code-tips — 9 个实战 Hook,设计哲学清晰
- karanb192/claude-code-hooks — 三级安全体系,开箱即用
到此这篇关于Claude Code Hooks 选装实战指南的文章就介绍到这了,更多相关Claude Code Hooks内容请搜索脚本之家以前的文章或继续浏览下面的相关文章,希望大家以后多多支持脚本之家!
相关文章
Claude Code 每次调用工具、等待输入、结束会话,都会触发对应的Hook生命周期事件,Hook 脚本除了做判断和记录,还可以把事件转发到本地 socket,让一个常驻进程处理所有状2026-06-02



最新评论