mcpField
C
claude-code-hooks

claude-code-hooks

github.com/vasilyu1983Agent 工作流51 次安装
代码仓库

关于 claude-code-hooks

claude-code-hooks 是为创建 Claude Code 钩子提供参考的技能,面向构建事件驱动自动化的开发者。它涵盖事件、配置、输入输出与安全模式,并包含命令钩子和提示词钩子的示例。

主要功能

  1. 01参考 Claude Code 事件及触发时机
  2. 02配置工具执行前后的钩子
  3. 03控制权限并修改工具输入
  4. 04组合命令钩子与提示词钩子
  5. 05提供安全、调试与钩子模板

适用场景

  1. 01在执行危险命令前进行拦截
  2. 02工具调用后运行格式化或审计
  3. 03在 Claude 完成任务时触发测试
  4. 04将 Claude Code 接入 CI/CD 流程

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/vasilyu1983/ai-agents-public --skill claude-code-hooks

安装后在 Claude Code 中输入/claude-code-hooks确认已加载。

详细介绍

Claude Code Hooks — 元参考

本技能提供创建 Claude Code hooks 的权威参考。构建由 Claude Code 事件触发的自动化时,请使用本技能。


何时使用本技能

  • 为 Claude Code 构建事件驱动的自动化
  • 创建 PreToolUse 防护措施,以阻止危险命令
  • 实现 PostToolUse 格式化程序、代码检查工具或审计工具
  • 添加用于测试或通知的 Stop hooks
  • 设置 SessionStart/SessionEnd 以管理环境
  • 将 Claude Code 集成到 CI/CD 管道中(无头模式)

快速参考

事件触发条件用例
SessionStart会话开始/恢复初始化环境
UserPromptSubmit用户提交提示词预处理/验证输入
PreToolUse工具执行前验证、阻止危险命令
PermissionRequest显示权限对话框时自动允许/拒绝权限
PostToolUse工具成功执行后格式化、审计、通知
PostToolUseFailure工具执行失败后捕获失败、提供指导
SubagentStart子 Agent 启动时检查子 Agent 元数据
StopClaude 完成时运行测试、生成摘要
SubagentStop子 Agent 完成时验证子 Agent 是否完成
Notification收到通知时向集成发送提醒
PreCompact压缩上下文前保留关键上下文
Setup--init/--maintenance初始化仓库/环境
SessionEnd会话结束时清理、保存状态

Hook 结构

.claude/hooks/
├── pre-tool-validate.sh
├── post-tool-format.sh
├── post-tool-audit.sh
├── stop-run-tests.sh
└── session-start-init.sh

配置

settings.json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/post-tool-format.sh"
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/pre-tool-validate.sh"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/stop-run-tests.sh"
          }
        ]
      }
    ]
  }
}

执行模型(2026 年 1 月)

  • Hooks 通过 stdin 接收 JSON 负载(应将其视为不可信输入),并以你的用户权限运行(位于 Bash 工具沙箱之外)。
  • 每条 hook 命令的默认超时时间为 60s;所有匹配的 hooks 并行运行;相同命令会去重。
Hook 输入(stdin)
{
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": {
    "command": "ls -la"
  }
}
环境变量(shell)
变量说明
CLAUDE_PROJECT_DIRClaude Code 启动时所在项目根目录的绝对路径
CLAUDE_PLUGIN_ROOT插件根目录(仅插件 hooks)
CLAUDE_CODE_REMOTE在远程/网页环境中为 "true";否则为空/本地
CLAUDE_ENV_FILE用于持久化 export ... 行的文件路径(在 SessionStart 中可用;Setup 是否支持请查阅文档)

退出代码

代码含义备注
0成功会解析写入 stdout 的 JSON,以执行结构化控制
2阻止性错误stderr 会作为消息;忽略 stdout 中的 JSON
其他非阻止性错误执行继续;在详细模式下可见 stderr

stdout 注入说明:对于 UserPromptSubmit、SessionStart 和 Setup,非 JSON stdout(退出代码为 0)会注入 Claude 的上下文;对于大多数其他事件,只有在详细模式下才会显示 stdout。


决策控制 + 输入修改(v2.0.10+)

PreToolUse hooks 可以允许/拒绝/询问,并可通过 updatedInput 修改工具输入。

Hook 输出架构
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow",
    "permissionDecisionReason": "Reason shown to user (and to Claude on deny)",
    "updatedInput": { "command": "echo 'modified'" },
    "additionalContext": "Extra context added before tool runs"
  }
}

注意:旧版 decision/reason 字段已弃用;建议使用 hookSpecificOutput.* 字段。

示例:重定向敏感文件编辑
#!/bin/bash
set -euo pipefail

INPUT="$(cat)"
FILE_PATH="$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')"

# Redirect package-lock.json edits to /dev/null
if [[ "$FILE_PATH" == *"package-lock.json" ]]; then
  UPDATED_INPUT="$(echo "$INPUT" | jq -c '.tool_input | .file_path = "/dev/null"')"
  jq -cn --argjson updatedInput "$UPDATED_INPUT" '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "allow",
      permissionDecisionReason: "Redirected write to /dev/null",
      updatedInput: $updatedInput
    }
  }'
  exit 0
fi

echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'
示例:从 Git Add 中移除敏感文件
#!/bin/bash
set -euo pipefail

INPUT="$(cat)"
TOOL_NAME="$(echo "$INPUT" | jq -r '.tool_name')"
CMD="$(echo "$INPUT" | jq -r '.tool_input.command // empty')"

if [[ "$TOOL_NAME" == "Bash" && "$CMD" =~ ^git[[:space:]]+add ]]; then
  # Remove .env files from staging
  SAFE_CMD="$(echo "$CMD" | sed 's/\.env[^ ]*//g')"
  if [[ "$SAFE_CMD" != "$CMD" ]]; then
    echo '{}' | jq -cn --arg cmd "$SAFE_CMD" '{
      hookSpecificOutput: {
        hookEventName: "PreToolUse",
        permissionDecision: "allow",
        permissionDecisionReason: "Removed .env from git add",
        updatedInput: { command: $cmd }
      }
    }'
    exit 0
  fi
fi

echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}'

基于提示词的 Hooks

对于复杂决策,请使用由大模型评估的 hooks(type: "prompt"),而不是 bash 脚本。它们最适用于 Stop 和 SubagentStop 决策。

配置
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Evaluate whether Claude should stop. Context JSON: $ARGUMENTS. Return {\"ok\": true} if all tasks are complete, otherwise {\"ok\": false, \"reason\": \"what remains\"}.",
            "timeout": 30
          }
        ]
      }
    ]
  }
}
响应架构
  • 允许:{"ok": true}
  • 阻止:{"ok": false, "reason": "Explanation shown to Claude"}
组合使用命令 Hook 和提示词 Hook

使用命令 hooks 进行快速、确定性检查。使用提示词 hooks 处理需要细致判断的决策:

{
  "Stop": [
    {
      "hooks": [
        { "type": "command", "command": ".claude/hooks/quick-check.sh" },
        { "type": "prompt", "prompt": "Verify code quality meets standards" }
      ]
    }
  ]
}

Hook 模板

工具调用前验证
#!/bin/bash
set -euo pipefail

INPUT="$(cat)"
TOOL_NAME="$(echo "$INPUT" | jq -r '.tool_name')"
CMD="$(echo "$INPUT" | jq -r '.tool_input.command // empty')"

if [[ "$TOOL_NAME" == "Bash" ]]; then
  # Block rm -rf /
  if echo "$CMD" | grep -qE 'rm\s+-rf\s+/'; then
    echo '{}' | jq -cn '{
      hookSpecificOutput: {
        hookEventName: "PreToolUse",
        permissionDecision: "deny",
        permissionDecisionReason: "Dangerous rm command detected"
      }
    }'
    exit 0
  fi

  # Block force push to main
  if echo "$CMD" | grep -qE 'git\s+push.*--force.*(main|master)'; then
    echo '{}' | jq -cn '{
      hookSpecificOutput: {
        hookEventName: "PreToolUse",
        permissionDecision: "deny",
        permissionDecisionReason: "Force push to main/master not allowed"
      }
    }'
    exit 0
  fi

  # Soft-warning: possible credential exposure
  if echo "$CMD" | grep -qE '(password|secret|api_key)\s*='; then
    echo '{}' | jq -cn '{
      hookSpecificOutput: {
        hookEventName: "PreToolUse",
        permissionDecision: "ask",
        permissionDecisionReason: "Possible credential exposure in command",
        additionalContext: "Command may include a secret. Confirm intent and avoid committing secrets."
      }
    }'
    exit 0
  fi
fi

exit 0
工具调用后格式化
#!/bin/bash
set -euo pipefail

INPUT="$(cat)"
TOOL_NAME="$(echo "$INPUT" | jq -r '.tool_name')"
FILE_PATH="$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')"

if [[ "$TOOL_NAME" =~ ^(Edit|Write)$ && -n "$FILE_PATH" && -f "$FILE_PATH" ]]; then
  case "$FILE_PATH" in
    *.js|*.ts|*.jsx|*.tsx|*.json|*.md)
      npx prettier --write "$FILE_PATH" 2>/dev/null || true
      ;;
    *.py)
      ruff format "$FILE_PATH" 2>/dev/null || true
      ;;
    *.go)
      gofmt -w "$FILE_PATH" 2>/dev/null || true
      ;;
    *.rs)
      rustfmt "$FILE_PATH" 2>/dev/null || true
      ;;
  esac
fi

exit 0
工具调用后安全审计
#!/bin/bash
set -euo pipefail

INPUT="$(cat)"
TOOL_NAME="$(echo "$INPUT" | jq -r '.tool_name')"
FILE_PATH="$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')"

if [[ "$TOOL_NAME" =~ ^(Edit|Write)$ && -n "$FILE_PATH" && -f "$FILE_PATH" ]]; then
  # Check for hardcoded secrets
  if grep -qE '(password|secret|api_key|token)\s*[:=]\s*["\x27][^"\x27]+["\x27]' "$FILE_PATH"; then
    echo "WARNING: Possible hardcoded secret in $FILE_PATH" >&2
  fi

  # Check for console.log in production code
  if [[ "$FILE_PATH" =~ \.(ts|js|tsx|jsx)$ ]] && grep -q 'console.log' "$FILE_PATH"; then
    echo "NOTE: console.log found in $FILE_PATH" >&2
  fi
fi

exit 0
Stop Hook(运行测试)
#!/bin/bash
set -euo pipefail

# Run tests after Claude finishes
cd "$CLAUDE_PROJECT_DIR"

# Detect test framework
if [[ -f "package.json" ]]; then
  if grep -q '"vitest"' package.json; then
    npm run test 2>&1 | head -50
  elif grep -q '"jest"' package.json; then
    npm test 2>&1 | head -50
  fi
elif [[ -f "pytest.ini" ]] || [[ -f "pyproject.toml" ]]; then
  pytest --tb=short 2>&1 | head -50
fi

exit 0
会话开始
#!/bin/bash
set -euo pipefail

cd "$CLAUDE_PROJECT_DIR"

# Check git status
echo "=== Git Status ==="
git status --short

# Check for uncommitted changes
if ! git diff --quiet; then
  echo "WARNING: Uncommitted changes detected"
fi

# Verify dependencies
if [[ -f "package.json" ]]; then
  if [[ ! -d "node_modules" ]]; then
    echo "NOTE: node_modules missing, run npm install"
  fi
fi

exit 0

匹配器

匹配器用于筛选哪些工具会触发钩子:

  • 精确匹配:Write 仅匹配 Write 工具
  • 正则表达式:Edit|Write 或 Notebook.*
  • 匹配全部:*(也适用于 "" 或省略匹配器)

安全最佳实践

HOOK SECURITY CHECKLIST

[ ] Validate all inputs with regex
[ ] Quote all variables: "$VAR" not $VAR
[ ] Use absolute paths
[ ] No eval with untrusted input
[ ] Set -euo pipefail at top
[ ] Keep hooks fast (<1 second)
[ ] Log actions for audit
[ ] Test manually before deploying

钩子组合

同一事件上的多个钩子
{
  "PostToolUse": [
    {
      "matcher": "Edit|Write",
      "hooks": [
        { "type": "command", "command": ".claude/hooks/format.sh" },
        { "type": "command", "command": ".claude/hooks/audit.sh" },
        { "type": "command", "command": ".claude/hooks/notify.sh" }
      ]
    }
  ]
}

所有匹配的钩子都会并行运行。如果需要严格排序(格式化 → lint → 测试),请编写一个按顺序运行它们的包装脚本。


调试钩子

# Test a PostToolUse hook manually (stdin JSON)
export CLAUDE_PROJECT_DIR="$(pwd)"
echo '{"hook_event_name":"PostToolUse","tool_name":"Edit","tool_input":{"file_path":"'"$(pwd)"'/src/app.ts"}}' \
  | bash .claude/hooks/post-tool-format.sh

# Check exit code
echo $?

导航

资源
相关技能

评论

支持 Markdown