关于 claude-code-hooks
claude-code-hooks 是为创建 Claude Code 钩子提供参考的技能,面向构建事件驱动自动化的开发者。它涵盖事件、配置、输入输出与安全模式,并包含命令钩子和提示词钩子的示例。
主要功能
- 01参考 Claude Code 事件及触发时机
- 02配置工具执行前后的钩子
- 03控制权限并修改工具输入
- 04组合命令钩子与提示词钩子
- 05提供安全、调试与钩子模板
适用场景
- 01在执行危险命令前进行拦截
- 02工具调用后运行格式化或审计
- 03在 Claude 完成任务时触发测试
- 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 元数据 |
Stop | Claude 完成时 | 运行测试、生成摘要 |
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_DIR | Claude 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 $?
导航
资源
- references/hook-patterns.md — 常见模式
- references/hook-security.md — 安全指南
- data/sources.json — 文档链接
相关技能
- ../claude-code-commands/SKILL.md — 命令创建
- ../claude-code-agents/SKILL.md — Agent 创建
- ../ops-devops-platform/SKILL.md — CI/CD 集成
评论
支持 Markdown