Claude Code Hooks 选装实战指南

Written by

in

文章目录
  • 2026-06-02 | 覆盖危险拦截 + 桌面通知,三级分级体系,两脚本开箱即用
  • 目录
    • Claude Code Hooks 实战指南
      • 一、为什么需要 Hook
      • 二、三层拦截:什么东西该拦、什么东西不该拦
      • 三、配置(settings.json)
      • 四、脚本 1:危险命令拦截
      • 五、脚本 2:桌面通知(WinRT Toast)
        • 关键设计决策
      • 六、这些事不需要 Hook(你已有 Skill 覆盖)
        • 七、不建议装的 Hook
          • 八、想探索更多?

          Claude Code Hooks 是一套事件驱动的自动化机制,允许开发者在 AI 代理生命周期的特定节点(如工具调用前后、会话开始/结束时)插入自定义逻辑。通过 Hooks,可以实现安全拦截、代码格式化、环境初始化及外部系统集成,将“信任模型”转变为“信任但验证”的确定性工作流。

          2026-06-02 | 覆盖危险拦截 + 桌面通知,三级分级体系,两脚本开箱即用

          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

          以下为 ~/.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},必须写完整路径

          文件路径:~/.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 = @(
              'rms+-rfs+/',              # rm -rf / 根目录
              'rms+-rfs+~',              # rm -rf ~ 用户目录
              'rms+-rfs+$HOME',         # rm -rf $HOME
              'DROPs+DATABASE',           # 删库
              'migrate:fresh',             # Laravel 重置数据库
              'prismas+migrates+reset',  # Prisma 重置
              'chmods+777s+/',           # 根目录全开放权限
              '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 = @(
              'gits+pushs+.*--force',        # git push --force
              'gits+pushs+.*-fb',           # git push -f
              'gits+resets+--hard',          # git reset --hard
              'gits+cleans+-f',              # git clean -f/d/fd
              'gits+branchs+-D',             # 强制删分支
              'gits+checkouts+.',           # 丢弃所有本地修改
              'gits+restores+.',            # 同上
              'npms+publish',                 # 发布 npm 包
              'npms+unpublish',               # 撤回 npm 包
              'pips+uninstalls+-y',          # 批量卸载 Python 包
              'dockers+rms+-f',              # 强制删容器
              'dockers+rmis+-f',             # 强制删镜像
              'dockers+systems+prune',       # 清理所有未用镜像
              'kubectls+deletes+deployment'  # 删 K8s 部署
          )
          foreach ($pattern in $highRisk) {
              if ($cmd -match $pattern) {
                  $stderr = @"
          ========================================
          ⚠️  高风险操作,已拦截
          命令:$cmd
          原因:可恢复但代价大(丢提交/删环境/影响线上)
          处理:Claude Code 不允许自动执行此操作。
                请确认无误后,复制以下命令到终端手动执行:
                $cmd
          ========================================
          "@
                  Write-Error $stderr
                  exit 2
              }
          }
          # ============================================================
          # 警告级 — 正常操作,仅提醒
          # ============================================================
          $warnings = @(
              'rms+-rfs+./',           # rm -rf ./ (当前目录)
              'rms+-rfs+w',            # rm -rf 某个目录
              'gits+branchs+-d',        # 删已合并分支(安全,但提醒)
              'dels+/fs+/s',            # Windows 强制递归删
              'rmdirs+/ss+/q'           # Windows rmdir
          )
          foreach ($pattern in $warnings) {
              if ($cmd -match $pattern) {
                  Write-Warning "⚠️  提醒:即将执行 `$cmd`,请确认是否期望此操作。"
                  exit 0
              }
          }
          # 一切正常,放行
          exit 0

          文件路径:~/.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}WindowsPowerShellv1.0powershell.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 返回

          场景 为什么不需要 已有的 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 原因
          语音 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内容请搜索风君子博客以前的文章或继续浏览下面的相关文章,希望大家以后多多支持风君子博客!

          站内搜索