Claude Code Hooks 选装实战指南

  发布时间:2026-06-03 11:45:51   作者:Slow菜鸟   我要评论
Claudede Hooks实战指南,涵盖三级拦截体系,两脚本开箱即用,覆盖致命、高风险、警告三级操作,通过配置settings.json灵活定制拦截策略,支持PowerShell与原生Toast通知,适用于安全与质量保障,本文介绍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 DATABASEcurl | bash
高风险可恢复但代价大exit 2 硬拦,你手动执行不受影响push --forcereset --hardnpm publish
警告正常操作仅提醒exit 0 打印,Claude 自行判断单个 rmrmdir

三、配置(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
      }]
    }]
  }
}

三个关键点:

  1. powershell.exe(5.1)而非 pwsh.exe — WinRT Toast API 仅在 Windows 原生 PowerShell 5.1 中可用,PowerShell 7 无法加载 Windows.UI.Notifications 类型
  2. cmd /c chcp 65001 >nul && — 切换控制台代码页为 UTF-8,否则 PowerShell 5.1 读取 .ps1 文件时中文会乱码
  3. 绝对路径 — 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.Notifications API
  • 加入 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()
}

关键设计决策

决策选择原因
通知 APIWindows.UI.Notifications WinRT原生 Toast,无托盘图标,无窗口句柄
Shell 引擎powershell.exe(5.1)WinRT 类型仅在 PowerShell 5.1 中可用
编码方案cmd /c chcp 65001 + UTF-8 BOM .ps1PowerShell 5.1 读脚本需要 BOM
XML 操作SelectSingleNode XPathGetElementsByTagName + 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 Stagegit-commit 冲突
auto-approve-* 系列自动批准构建/测试/Docker,太激进

八、想探索更多?

npx cc-hook-registry search <关键词>   # 61 个社区 Hook 可搜索安装

社区完整分类(61 个 Hook,来源 cc-hook-registry):

类别数量代表性 Hook
安全拦截16destructive-guard、secret-guard、block-database-wipe、no-sudo-guard
质量保障16syntax-check、enforce-tests、npm-publish-guard、diff-size-guard
体验增强4notify-waiting、session-handoff
自动批准14auto-approve-build、auto-approve-* 各语言版本
外部项目4anipotts(9 hooks)、karanb192(4 hooks)、disler(教程)、johnlindquist(框架)

值得关注的外部项目:

到此这篇关于Claude Code Hooks 选装实战指南的文章就介绍到这了,更多相关Claude Code Hooks内容请搜索脚本之家以前的文章或继续浏览下面的相关文章,希望大家以后多多支持脚本之家!

相关文章

  • 一文详解Claude Code中Hooks的使用

    Claude Code 每次调用工具、等待输入、结束会话,都会触发对应的Hook生命周期事件,Hook 脚本除了做判断和记录,还可以把事件转发到本地 socket,让一个常驻进程处理所有状
    2026-06-02

最新评论