claude-hooks
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseClaude Code Hooks
Claude Code 钩子
Guide for creating hooks that execute shell commands or scripts in response to Claude Code events and tool calls.
本指南介绍如何创建可响应Claude Code事件与工具调用、执行Shell命令或脚本的钩子。
When to Use This Skill
适用场景
Activate this skill when:
- Creating event-driven automations
- Implementing custom validation or formatting
- Integrating with external tools and services
- Setting up project-specific workflows
- Responding to tool execution events
在以下场景中使用该功能:
- 创建事件驱动型自动化流程
- 实现自定义验证或格式化
- 集成外部工具与服务
- 设置项目专属工作流
- 响应工具执行事件
What Are Hooks?
什么是钩子?
Hooks are shell commands that execute automatically in response to specific events:
- Tool Call Hooks: Trigger before/after specific tool calls
- Lifecycle Hooks: Trigger on plugin install/uninstall
- User Prompt Hooks: Trigger when users submit prompts
- Custom Events: Application-specific trigger points
钩子是可响应特定事件自动执行的Shell命令:
- 工具调用钩子:在特定工具调用前后触发
- 生命周期钩子:在插件安装/卸载时触发
- 用户提示钩子:在用户提交提示时触发
- 自定义事件:应用专属的触发点
Hook Configuration
钩子配置
Location
配置位置
Hooks are configured in:
- Plugin:
<plugin-root>/.claude-plugin/hooks.json - User-level:
.claude/hooks.json - Plugin manifest: Inline in
plugin.json
钩子可在以下位置配置:
- 插件级:
<plugin-root>/.claude-plugin/hooks.json - 用户级:
.claude/hooks.json - 插件清单:内联在中
plugin.json
File Structure
文件结构
Standalone hooks.json:
json
{
"onToolCall": {
"Write": {
"before": ["./hooks/format-check.sh"],
"after": ["./hooks/lint.sh"]
},
"Bash": {
"before": ["./hooks/validate-command.sh"]
}
},
"onInstall": ["./hooks/setup.sh"],
"onUninstall": ["./hooks/cleanup.sh"],
"onUserPromptSubmit": ["./hooks/log-prompt.sh"]
}Inline in plugin.json:
json
{
"hooks": {
"onToolCall": {
"Write": {
"after": ["prettier --write {{file_path}}"]
}
}
}
}独立hooks.json文件:
json
{
"onToolCall": {
"Write": {
"before": ["./hooks/format-check.sh"],
"after": ["./hooks/lint.sh"]
},
"Bash": {
"before": ["./hooks/validate-command.sh"]
}
},
"onInstall": ["./hooks/setup.sh"],
"onUninstall": ["./hooks/cleanup.sh"],
"onUserPromptSubmit": ["./hooks/log-prompt.sh"]
}内联在plugin.json中:
json
{
"hooks": {
"onToolCall": {
"Write": {
"after": ["prettier --write {{file_path}}"]
}
}
}
}Hook Types
钩子类型
Tool Call Hooks
工具调用钩子
Execute before or after specific tool calls.
Available Tools:
- ,
Read,Write,EditMultiEdit - ,
BashBashOutput - ,
GlobGrep - ,
Task,SkillSlashCommand TodoWrite- ,
WebFetchWebSearch AskUserQuestion
Example:
json
{
"onToolCall": {
"Write": {
"before": [
"echo 'Writing file: {{file_path}}'",
"./hooks/backup.sh {{file_path}}"
],
"after": [
"prettier --write {{file_path}}",
"git add {{file_path}}"
]
},
"Edit": {
"after": ["eslint --fix {{file_path}}"]
}
}
}在特定工具调用前后执行。
支持的工具:
- ,
Read,Write,EditMultiEdit - ,
BashBashOutput - ,
GlobGrep - ,
Task,SkillSlashCommand TodoWrite- ,
WebFetchWebSearch AskUserQuestion
示例:
json
{
"onToolCall": {
"Write": {
"before": [
"echo 'Writing file: {{file_path}}'",
"./hooks/backup.sh {{file_path}}"
],
"after": [
"prettier --write {{file_path}}",
"git add {{file_path}}"
]
},
"Edit": {
"after": ["eslint --fix {{file_path}}"]
}
}
}Lifecycle Hooks
生命周期钩子
Execute during plugin installation/uninstallation.
json
{
"onInstall": [
"./hooks/setup-dependencies.sh",
"npm install",
"echo 'Plugin installed successfully'"
],
"onUninstall": [
"./hooks/cleanup.sh",
"echo 'Plugin uninstalled'"
]
}在插件安装/卸载期间执行。
json
{
"onInstall": [
"./hooks/setup-dependencies.sh",
"npm install",
"echo 'Plugin installed successfully'"
],
"onUninstall": [
"./hooks/cleanup.sh",
"echo 'Plugin uninstalled'"
]
}User Prompt Submit Hook
用户提示提交钩子
Execute when user submits a prompt:
json
{
"onUserPromptSubmit": [
"./hooks/log-interaction.sh '{{prompt}}'",
"./hooks/check-context.sh"
]
}在用户提交提示时执行:
json
{
"onUserPromptSubmit": [
"./hooks/log-interaction.sh '{{prompt}}'",
"./hooks/check-context.sh"
]
}Hook Variables
钩子变量
Hooks have access to context-specific variables using syntax.
{{variable}}钩子可通过语法访问上下文专属变量。
{{variable}}Tool Call Variables
工具调用变量
Different tools provide different variables:
Write Tool:
- : Path to file being written
{{file_path}} - : Content being written (before hooks only)
{{content}}
Edit Tool:
- : Path to file being edited
{{file_path}} - : String being replaced
{{old_string}} - : Replacement string
{{new_string}}
Bash Tool:
- : Command being executed
{{command}}
Read Tool:
- : Path to file being read
{{file_path}}
不同工具提供不同的变量:
Write工具:
- :待写入文件的路径
{{file_path}} - :待写入的内容(仅在前置钩子中可用)
{{content}}
Edit工具:
- :待编辑文件的路径
{{file_path}} - :待替换的字符串
{{old_string}} - :替换后的字符串
{{new_string}}
Bash工具:
- :待执行的命令
{{command}}
Read工具:
- :待读取文件的路径
{{file_path}}
Global Variables
全局变量
Available in all hooks:
- : Current working directory
{{cwd}} - : Current Unix timestamp
{{timestamp}} - : Current user
{{user}} - : Plugin installation directory
{{plugin_root}}
所有钩子均可使用:
- :当前工作目录
{{cwd}} - :当前Unix时间戳
{{timestamp}} - :当前用户
{{user}} - :插件安装目录
{{plugin_root}}
User Prompt Variables
用户提示变量
- : User's submitted prompt text
{{prompt}}
- :用户提交的提示文本
{{prompt}}
Hook Examples
钩子示例
Auto-Format on Write
写入时自动格式化
json
{
"onToolCall": {
"Write": {
"after": [
"prettier --write {{file_path}}",
"eslint --fix {{file_path}}"
]
}
}
}json
{
"onToolCall": {
"Write": {
"after": [
"prettier --write {{file_path}}",
"eslint --fix {{file_path}}"
]
}
}
}Pre-Commit Validation
提交前验证
json
{
"onToolCall": {
"Bash": {
"before": ["./hooks/validate-git-command.sh '{{command}}'"]
}
}
}validate-git-command.sh:
bash
#!/bin/bash
COMMAND="$1"json
{
"onToolCall": {
"Bash": {
"before": ["./hooks/validate-git-command.sh '{{command}}'"]
}
}
}validate-git-command.sh:
bash
#!/bin/bash
COMMAND="$1"Block force push to main/master
禁止向main/master分支强制推送
if [[ "$COMMAND" =~ "git push --force" ]] && [[ "$COMMAND" =~ "main|master" ]]; then
echo "ERROR: Force push to main/master is not allowed"
exit 1
fi
exit 0
undefinedif [[ "$COMMAND" =~ "git push --force" ]] && [[ "$COMMAND" =~ "main|master" ]]; then
echo "ERROR: Force push to main/master is not allowed"
exit 1
fi
exit 0
undefinedAutomatic Backups
自动备份
json
{
"onToolCall": {
"Write": {
"before": ["cp {{file_path}} {{file_path}}.backup"]
},
"Edit": {
"before": ["cp {{file_path}} {{file_path}}.backup"]
}
}
}json
{
"onToolCall": {
"Write": {
"before": ["cp {{file_path}} {{file_path}}.backup"]
},
"Edit": {
"before": ["cp {{file_path}} {{file_path}}.backup"]
}
}
}Logging and Analytics
日志与分析
json
{
"onToolCall": {
"Write": {
"after": ["./hooks/log-file-change.sh {{file_path}}"]
}
},
"onUserPromptSubmit": ["./hooks/log-prompt.sh '{{prompt}}'"]
}log-file-change.sh:
bash
#!/bin/bash
FILE="$1"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
echo "$TIMESTAMP - Modified: $FILE" >> .claude/file-changes.logjson
{
"onToolCall": {
"Write": {
"after": ["./hooks/log-file-change.sh {{file_path}}"]
}
},
"onUserPromptSubmit": ["./hooks/log-prompt.sh '{{prompt}}'"]
}log-file-change.sh:
bash
#!/bin/bash
FILE="$1"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
echo "$TIMESTAMP - Modified: $FILE" >> .claude/file-changes.logIntegration with External Tools
集成外部工具
json
{
"onToolCall": {
"Write": {
"after": [
"notify-send 'File Updated' 'Modified {{file_path}}'",
"curl -X POST https://api.example.com/notify -d 'file={{file_path}}'"
]
}
}
}json
{
"onToolCall": {
"Write": {
"after": [
"notify-send 'File Updated' 'Modified {{file_path}}'",
"curl -X POST https://api.example.com/notify -d 'file={{file_path}}'"
]
}
}
}Hook Execution
钩子执行
Execution Order
执行顺序
Multiple hooks execute in array order:
json
{
"onToolCall": {
"Write": {
"after": [
"echo 'Step 1'", // Runs first
"echo 'Step 2'", // Runs second
"echo 'Step 3'" // Runs third
]
}
}
}多个钩子按数组顺序执行:
json
{
"onToolCall": {
"Write": {
"after": [
"echo 'Step 1'", // 第一个执行
"echo 'Step 2'", // 第二个执行
"echo 'Step 3'" // 第三个执行
]
}
}
}Exit Codes
退出码
Before Hooks:
- Exit code : Continue with tool execution
0 - Exit code non-zero: Block tool execution, show error to user
After Hooks:
- Exit codes are logged but don't affect tool execution
- Tool has already completed
前置钩子:
- 退出码:继续执行工具
0 - 非零退出码:阻止工具执行,向用户显示错误信息
后置钩子:
- 退出码仅会被记录,不影响工具执行
- 工具已完成执行
Error Handling
错误处理
bash
#!/bin/bashbash
#!/bin/bashBefore hook - blocks tool on error
前置钩子 - 出错时阻止工具执行
if [[ ! -f "$1" ]]; then
echo "ERROR: File does not exist"
exit 1 # Blocks tool execution
fi
if [[ ! -f "$1" ]]; then
echo "ERROR: File does not exist"
exit 1 # 阻止工具执行
fi
Validation passed
验证通过
exit 0
undefinedexit 0
undefinedBest Practices
最佳实践
Keep Hooks Fast
保持钩子轻量化
Hooks block execution - keep them lightweight:
json
{
"onToolCall": {
"Write": {
// ✅ Fast linter
"after": ["eslint --fix {{file_path}}"]
// ❌ Slow test suite
// "after": ["npm test"]
}
}
}钩子会阻塞执行 - 请保持钩子轻量化:
json
{
"onToolCall": {
"Write": {
// ✅ 快速的代码检查工具
"after": ["eslint --fix {{file_path}}"]
// ❌ 缓慢的测试套件
// "after": ["npm test"]
}
}
}Use Absolute Paths
使用绝对路径
Reference scripts with paths relative to plugin:
json
{
"onInstall": ["${CLAUDE_PLUGIN_ROOT}/hooks/setup.sh"]
}使用相对于插件的路径引用脚本:
json
{
"onInstall": ["${CLAUDE_PLUGIN_ROOT}/hooks/setup.sh"]
}Validate Input
验证输入
Always validate hook variables:
bash
#!/bin/bash
FILE="$1"
if [[ -z "$FILE" ]]; then
echo "ERROR: No file path provided"
exit 1
fi
if [[ ! -f "$FILE" ]]; then
echo "ERROR: File does not exist: $FILE"
exit 1
fi始终验证钩子变量:
bash
#!/bin/bash
FILE="$1"
if [[ -z "$FILE" ]]; then
echo "ERROR: No file path provided"
exit 1
fi
if [[ ! -f "$FILE" ]]; then
echo "ERROR: File does not exist: $FILE"
exit 1
fiProvide Clear Feedback
提供清晰的反馈
bash
#!/bin/bash
echo "Running pre-commit checks..."
if ! npm run lint; then
echo "❌ Linting failed. Please fix errors before committing."
exit 1
fi
echo "✅ All checks passed"
exit 0bash
#!/bin/bash
echo "正在运行提交前检查..."
if ! npm run lint; then
echo "❌ 代码检查失败,请在提交前修复错误。"
exit 1
fi
echo "✅ 所有检查通过"
exit 0Handle Edge Cases
处理边缘情况
bash
#!/bin/bashbash
#!/bin/bashHandle files with spaces in names
处理名称含空格的文件
FILE="$1"
FILE="$1"
Validate file type
验证文件类型
if [[ ! "$FILE" =~ .(js|ts|jsx|tsx)$ ]]; then
Skip non-JavaScript files silently
exit 0
fi
if [[ ! "$FILE" =~ .(js|ts|jsx|tsx)$ ]]; then
静默跳过非JavaScript文件
exit 0
fi
Run formatter
运行格式化工具
prettier --write "$FILE"
undefinedprettier --write "$FILE"
undefinedSecurity Considerations
安全注意事项
Validate Commands
验证命令
Before hooks can block dangerous operations:
json
{
"onToolCall": {
"Bash": {
"before": ["./hooks/validate-command.sh '{{command}}'"]
}
}
}validate-command.sh:
bash
#!/bin/bash
COMMAND="$1"前置钩子可阻止危险操作:
json
{
"onToolCall": {
"Bash": {
"before": ["./hooks/validate-command.sh '{{command}}'"]
}
}
}validate-command.sh:
bash
#!/bin/bash
COMMAND="$1"Block dangerous patterns
阻止危险命令模式
DANGEROUS_PATTERNS=(
"rm -rf /"
"dd if="
"mkfs"
"> /dev/sda"
)
for pattern in "${DANGEROUS_PATTERNS[@]}"; do
if [[ "$COMMAND" =~ $pattern ]]; then
echo "ERROR: Dangerous command blocked: $pattern"
exit 1
fi
done
exit 0
undefinedDANGEROUS_PATTERNS=(
"rm -rf /"
"dd if="
"mkfs"
"> /dev/sda"
)
for pattern in "${DANGEROUS_PATTERNS[@]}"; do
if [[ "$COMMAND" =~ $pattern ]]; then
echo "ERROR: Dangerous command blocked: $pattern"
exit 1
fi
done
exit 0
undefinedLimit Hook Scope
限制钩子范围
Only hook necessary tools:
json
{
// ✅ Specific tools only
"onToolCall": {
"Write": { "after": ["./format.sh {{file_path}}"] }
}
// ❌ Don't hook everything unnecessarily
}仅为必要工具配置钩子:
json
{
// ✅ 仅针对特定工具
"onToolCall": {
"Write": { "after": ["./format.sh {{file_path}}"] }
}
// ❌ 不要不必要地为所有工具配置钩子
}Sanitize Variables
清理变量
bash
#!/bin/bashbash
#!/bin/bashSanitize file path
清理文件路径
FILE=$(realpath "$1")
FILE=$(realpath "$1")
Ensure file is within project
确保文件在项目目录内
if [[ ! "$FILE" =~ ^$(pwd) ]]; then
echo "ERROR: File outside project directory"
exit 1
fi
undefinedif [[ ! "$FILE" =~ ^$(pwd) ]]; then
echo "ERROR: File outside project directory"
exit 1
fi
undefinedDebugging Hooks
调试钩子
Enable Verbose Output
启用详细输出
json
{
"onToolCall": {
"Write": {
"before": ["set -x; ./hooks/debug.sh {{file_path}}; set +x"]
}
}
}json
{
"onToolCall": {
"Write": {
"before": ["set -x; ./hooks/debug.sh {{file_path}}; set +x"]
}
}
}Log Hook Execution
记录钩子执行
bash
#!/bin/bash
LOG_FILE=".claude/hooks.log"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
echo "$TIMESTAMP - Hook: $0, Args: $@" >> "$LOG_FILE"bash
#!/bin/bash
LOG_FILE=".claude/hooks.log"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
echo "$TIMESTAMP - Hook: $0, Args: $@" >> "$LOG_FILE"Rest of hook logic...
钩子其余逻辑...
undefinedundefinedTest Hooks Manually
手动测试钩子
bash
undefinedbash
undefinedTest hook with sample data
使用示例数据测试钩子
./hooks/format.sh "src/main.js"
./hooks/format.sh "src/main.js"
Check exit code
检查退出码
echo $?
undefinedecho $?
undefinedCommon Hook Patterns
常见钩子模式
Auto-Format Pipeline
自动格式化流水线
json
{
"onToolCall": {
"Write": {
"after": [
"prettier --write {{file_path}}",
"eslint --fix {{file_path}}"
]
},
"Edit": {
"after": [
"prettier --write {{file_path}}",
"eslint --fix {{file_path}}"
]
}
}
}json
{
"onToolCall": {
"Write": {
"after": [
"prettier --write {{file_path}}",
"eslint --fix {{file_path}}"
]
},
"Edit": {
"after": [
"prettier --write {{file_path}}",
"eslint --fix {{file_path}}"
]
}
}
}Test on Write
写入时测试
json
{
"onToolCall": {
"Write": {
"after": ["./hooks/run-relevant-tests.sh {{file_path}}"]
}
}
}json
{
"onToolCall": {
"Write": {
"after": ["./hooks/run-relevant-tests.sh {{file_path}}"]
}
}
}Git Integration
Git集成
json
{
"onToolCall": {
"Write": {
"after": ["git add {{file_path}}"]
},
"Edit": {
"after": ["git add {{file_path}}"]
}
}
}json
{
"onToolCall": {
"Write": {
"after": ["git add {{file_path}}"]
},
"Edit": {
"after": ["git add {{file_path}}"]
}
}
}Troubleshooting
故障排除
Hook Not Executing
钩子未执行
- Check hook file has execute permissions:
chmod +x hooks/script.sh - Verify path is correct relative to plugin root
- Check JSON syntax in hooks.json
- Look for errors in Claude Code logs
- 检查钩子文件是否有执行权限:
chmod +x hooks/script.sh - 验证路径相对于插件根目录是否正确
- 检查hooks.json中的JSON语法
- 查看Claude Code日志中的错误
Hook Blocking Tool
钩子阻止工具执行
- Check exit code of before hooks
- Add debug logging
- Test hook script manually
- Verify validation logic
- 检查前置钩子的退出码
- 添加调试日志
- 手动测试钩子脚本
- 验证逻辑
Variables Not Substituting
变量未替换
- Check variable name spelling: not
{{file_path}}{{filepath}} - Verify variable is available for that tool
- Quote variables in bash:
"{{file_path}}"
- 检查变量名称拼写:而非
{{file_path}}{{filepath}} - 验证该工具是否提供该变量
- 在Bash中为变量添加引号:
"{{file_path}}"
Templates
模板
Reference templates for common hook configurations:
claude-hooks/
└── templates/
├── plugin-hook.md # Plugin hook configuration example
└── skill-hook.md # Skill/subagent frontmatter hooks example参考常见钩子配置的模板:
claude-hooks/
└── templates/
├── plugin-hook.md # 插件钩子配置示例
└── skill-hook.md # 技能/子代理前置钩子示例Plugin Hook Template
插件钩子模板
Example configuration for defining hooks in a plugin's :
hooks/hooks.json- PostToolUse hook with matcher
Write|Edit - Uses for script references
${CLAUDE_PLUGIN_ROOT} - Includes timeout configuration
在插件的中定义钩子的示例配置:
hooks/hooks.json- 带匹配器的PostToolUse钩子
Write|Edit - 使用引用脚本
${CLAUDE_PLUGIN_ROOT} - 包含超时配置
Skill Hook Template
技能钩子模板
Example frontmatter for embedding hooks directly in skills:
- Supported events: PreToolUse, PostToolUse, Stop
- Hooks scoped to component lifecycle
- Runs only when skill/subagent is active
直接在技能中嵌入钩子的示例前置配置:
- 支持的事件:PreToolUse, PostToolUse, Stop
- 钩子作用域限定为组件生命周期
- 仅在技能/子代理激活时运行
References
参考资料
For more information:
- Claude Code Hooks Documentation: https://code.claude.com/docs/en/hooks
- Plugin Configuration: https://code.claude.com/docs/en/plugins#hooks
更多信息请查看:
- Claude Code 钩子文档:https://code.claude.com/docs/en/hooks
- 插件配置:https://code.claude.com/docs/en/plugins#hooks