create-hook
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCreate Hook Command
创建 Hook 命令
Analyze the project, suggest practical hooks, and create them with proper testing.
分析项目,建议实用的 Hook,并通过正确的测试创建它们。
Your Task (/create-hook)
你的任务(/create-hook)
- Analyze environment - Detect tooling and existing hooks
- Suggest hooks - Based on your project configuration
- Configure hook - Ask targeted questions and create the script
- Test & validate - Ensure the hook works correctly
- 分析环境 - 检测工具链和现有 Hook
- 建议 Hook - 根据项目配置提出建议
- 配置 Hook - 提出有针对性的问题并创建脚本
- 测试与验证 - 确保 Hook 正确工作
Your Workflow
工作流
1. Environment Analysis & Suggestions
1. 环境分析与建议
Automatically detect the project tooling and suggest relevant hooks:
When TypeScript is detected ():
tsconfig.json- PostToolUse hook: "Type-check files after editing"
- PreToolUse hook: "Block edits with type errors"
When Prettier is detected (, ):
.prettierrcprettier.config.js- PostToolUse hook: "Auto-format files after editing"
- PreToolUse hook: "Require formatted code"
When ESLint is detected ():
.eslintrc.*- PostToolUse hook: "Lint and auto-fix after editing"
- PreToolUse hook: "Block commits with linting errors"
When package.json has scripts:
- script → "Run tests before commits"
test - script → "Validate build before commits"
build
When a git repository is detected:
- PreToolUse/Bash hook: "Prevent commits with secrets"
- PostToolUse hook: "Security scan on file changes"
Decision Tree:
Project has TypeScript? → Suggest type checking hooks
Project has formatter? → Suggest formatting hooks
Project has tests? → Suggest test validation hooks
Security sensitive? → Suggest security hooks
+ Scan for additional patterns and suggest custom hooks based on:
- Custom scripts in package.json
- Unique file patterns or extensions
- Development workflow indicators
- Project-specific tooling configurations自动检测项目工具链,并建议相关 Hook:
检测到 TypeScript 时():
tsconfig.json- PostToolUse Hook:“编辑后对文件进行类型检查”
- PreToolUse Hook:“阻止存在类型错误的编辑”
检测到 Prettier 时(、):
.prettierrcprettier.config.js- PostToolUse Hook:“编辑后自动格式化文件”
- PreToolUse Hook:“要求代码已格式化”
检测到 ESLint 时():
.eslintrc.*- PostToolUse Hook:“编辑后执行 lint 并自动修复”
- PreToolUse Hook:“阻止存在 lint 错误的提交”
当 package.json 中包含 scripts 时:
- script → “提交前运行测试”
test - script → “提交前验证构建”
build
检测到 Git 仓库时:
- PreToolUse/Bash Hook:“防止提交包含密钥的内容”
- PostToolUse Hook:“文件变更时执行安全扫描”
决策树:
Project has TypeScript? → Suggest type checking hooks
Project has formatter? → Suggest formatting hooks
Project has tests? → Suggest test validation hooks
Security sensitive? → Suggest security hooks
+ Scan for additional patterns and suggest custom hooks based on:
- Custom scripts in package.json
- Unique file patterns or extensions
- Development workflow indicators
- Project-specific tooling configurations2. Hook Configuration
2. Hook 配置
Start by asking: "What should this hook do?" and offer relevant suggestions from your analysis.
Then understand the context from the user's description and only ask about details you're unsure about:
-
Trigger timing: When should it run?
- : Before file operations (can block)
PreToolUse - : After file operations (feedback/fixes)
PostToolUse - : Before processing requests
UserPromptSubmit - Other event types as needed
-
Tool matcher: Which tools should trigger it? (,
Write,Edit,Bashetc)* -
Scope:,
global, orprojectproject-local -
Response approach:
- Exit codes only: Simple (exit 0 = success, exit 2 = block in PreToolUse)
- JSON response: Advanced control (blocking, context, decisions)
- Guide based on complexity: simple pass/fail → exit codes, rich feedback → JSON
-
Blocking behavior (if relevant): "Should this stop operations when issues are found?"
- PreToolUse: Can block operations (security, validation)
- PostToolUse: Usually provide feedback only
-
Claude integration (CRITICAL): "Should Claude Code automatically see and fix issues this hook detects?"
- If YES: Use for error communication
additionalContext - If NO: Use for silent operation
suppressOutput: true
- If YES: Use
-
Context pollution: "Should successful operations be silent to avoid noise?"
- Recommend YES for formatting, routine checks
- Recommend NO for security alerts, critical errors
-
File filtering: "What file types should this hook process?"
首先询问:“这个 Hook 应该做什么?”,并提供根据分析结果生成的建议。
然后根据用户的描述了解上下文,只询问尚不确定的细节:
-
触发时机:何时运行?
- :文件操作之前(可以阻止操作)
PreToolUse - :文件操作之后(提供反馈或修复)
PostToolUse - :处理请求之前
UserPromptSubmit - 根据需要使用其他事件类型
-
Tool matcher:哪些工具应触发它?(、
Write、Edit、Bash等)* -
作用域:、
global或projectproject-local -
响应方式:
- 仅使用退出码:简单(退出 0 表示成功;在 PreToolUse 中退出 2 表示阻止)
- JSON 响应:高级控制(阻止、上下文、决策)
- 根据复杂度提供建议:简单的通过/失败 → 退出码;丰富的反馈 → JSON
-
阻止行为(如相关):“发现问题时是否应停止操作?”
- PreToolUse:可以阻止操作(安全、验证)
- PostToolUse:通常只提供反馈
-
Claude 集成(关键):“Claude Code 是否应自动查看并修复此 Hook 检测到的问题?”
- 如果是:使用 传达错误
additionalContext - 如果否:使用 静默运行
suppressOutput: true
- 如果是:使用
-
上下文污染:“成功的操作是否应保持静默以避免噪声?”
- 对格式化和常规检查推荐选择“是”
- 对安全警报和严重错误推荐选择“否”
-
文件过滤:“此 Hook 应处理哪些文件类型?”
3. Hook Creation
3. Hook 创建
You should:
- Create hooks directory: or
~/.claude/hooks/based on scope.claude/hooks/ - Generate script: Create hook script with:
- Proper shebang and executable permissions
- Project-specific commands (use detected config paths)
- Comments explaining the hook's purpose
- Update settings: Add hook configuration to appropriate settings.json
- Use absolute paths: Avoid relative paths to scripts and executables. Use to reference project root
$CLAUDE_PROJECT_DIR - Offer validation: Ask if the user wants you to test the hook
Key Implementation Standards:
- Read JSON from stdin (never use argv)
- Use top-level /
additionalContextfor Claude communicationsystemMessage - Include for successful operations
suppressOutput: true - Provide specific error counts and actionable feedback
- Focus on changed files rather than entire codebase
- Support common development workflows
⚠️ CRITICAL: Input/Output Format
This is where most hook implementations fail. Pay extra attention to:
- Input: Reading JSON from stdin correctly (not argv)
- Output: Using correct top-level JSON structure for Claude communication
- Documentation: Consulting official docs for exact schemas when in doubt
你应当:
- 创建 Hooks 目录:根据作用域使用 或
~/.claude/hooks/.claude/hooks/ - 生成脚本:创建包含以下内容的 Hook 脚本:
- 正确的 shebang 和可执行权限
- 项目专用命令(使用检测到的配置路径)
- 解释 Hook 用途的注释
- 更新设置:将 Hook 配置添加到适当的 settings.json 中
- 使用绝对路径:避免对脚本和可执行文件使用相对路径。使用 引用项目根目录
$CLAUDE_PROJECT_DIR - 提供验证选项:询问用户是否要测试该 Hook
关键实现标准:
- 从 stdin 读取 JSON(绝不使用 argv)
- 使用顶层 /
additionalContext与 Claude 通信systemMessage - 为成功的操作包含
suppressOutput: true - 提供具体的错误数量和可操作的反馈
- 聚焦于变更的文件,而不是整个代码库
- 支持常见的开发工作流
⚠️ 关键:输入/输出格式
这是大多数 Hook 实现失败的地方。请特别注意:
- 输入:正确从 stdin 读取 JSON(而不是 argv)
- 输出:使用正确的顶层 JSON 结构与 Claude 通信
- 文档:如有疑问,请查阅官方文档以获取准确的 schema
4. Testing & Validation
4. 测试与验证
CRITICAL: Test both happy and sad paths:
Happy Path Testing:
- Test expected success scenario - Create conditions where hook should pass
- Examples: TypeScript (valid code), Linting (formatted code), Security (safe commands)
Sad Path Testing: 2. Test expected failure scenario - Create conditions where hook should fail/warn
- Examples: TypeScript (type errors), Linting (unformatted code), Security (dangerous operations)
Verification Steps: 3. Verify expected behavior: Check if it blocks/warns/provides context as intended
Example Testing Process:
- For a hook preventing file deletion: Create a test file, attempt the protected action, and verify the hook prevents it
If Issues Occur, you should:
- Check hook registration in settings
- Verify script permissions ()
chmod +x - Test with simplified version first
- Debug with detailed hook execution analysis
关键:同时测试正常路径和异常路径:
正常路径测试:
- 测试预期成功场景 - 创建 Hook 应通过的条件
- 示例:TypeScript(有效代码)、Linting(格式正确的代码)、Security(安全命令)
异常路径测试: 2. 测试预期失败场景 - 创建 Hook 应失败或发出警告的条件
- 示例:TypeScript(类型错误)、Linting(格式不正确的代码)、Security(危险操作)
验证步骤: 3. 验证预期行为:检查 Hook 是否按预期阻止操作、发出警告或提供上下文
测试流程示例:
- 对于阻止文件删除的 Hook:创建测试文件,尝试执行受保护的操作,并验证 Hook 是否阻止了它
如果出现问题,你应当:
- 检查 settings 中的 Hook 注册情况
- 验证脚本权限()
chmod +x - 首先使用简化版本进行测试
- 使用详细的 Hook 执行分析进行调试
Hook Templates
Hook 模板
Type Checking (PostToolUse)
类型检查(PostToolUse)
#!/usr/bin/env node
// Read stdin JSON, check .ts/.tsx files only
// Run: npx tsc --noEmit --pretty
// Output: JSON with additionalContext for errors#!/usr/bin/env node
// Read stdin JSON, check .ts/.tsx files only
// Run: npx tsc --noEmit --pretty
// Output: JSON with additionalContext for errorsAuto-formatting (PostToolUse)
自动格式化(PostToolUse)
#!/usr/bin/env node
// Read stdin JSON, check supported file types
// Run: npx prettier --write [file]
// Output: JSON with suppressOutput: true#!/usr/bin/env node
// Read stdin JSON, check supported file types
// Run: npx prettier --write [file]
// Output: JSON with suppressOutput: trueSecurity Scanning (PreToolUse)
安全扫描(PreToolUse)
bash
#!/bin/bashbash
#!/bin/bashRead stdin JSON, check for secrets/keys
Read stdin JSON, check for secrets/keys
Block if dangerous patterns found
Block if dangerous patterns found
Exit 2 to block, 0 to continue
Exit 2 to block, 0 to continue
_Complete templates available at: <https://docs.claude.com/en/docs/claude-code/hooks#examples>_
_完整模板见:<https://docs.claude.com/en/docs/claude-code/hooks#examples>_Quick Reference
快速参考
📖 Official Docs: https://docs.claude.com/en/docs/claude-code/hooks.md
Common Patterns:
- stdin input:
JSON.parse(process.stdin.read()) - File filtering: Check extensions before processing
- Success response:
{continue: true, suppressOutput: true} - Error response:
{continue: true, additionalContext: "error details"} - Block operation: in PreToolUse hooks
exit(2)
Hook Types by Use Case:
- Code Quality: PostToolUse for feedback and fixes
- Security: PreToolUse to block dangerous operations
- CI/CD: PreToolUse to validate before commits
- Development: PostToolUse for automated improvements
Hook Execution Best Practices:
- Hooks run in parallel according to official documentation
- Design for independence since execution order isn't guaranteed
- Plan hook interactions carefully when multiple hooks affect the same files
常见模式:
- stdin 输入:
JSON.parse(process.stdin.read()) - 文件过滤:处理前检查扩展名
- 成功响应:
{continue: true, suppressOutput: true} - 错误响应:
{continue: true, additionalContext: "error details"} - 阻止操作:在 PreToolUse Hook 中执行
exit(2)
按用例划分的 Hook 类型:
- 代码质量:使用 PostToolUse 提供反馈和修复
- 安全:使用 PreToolUse 阻止危险操作
- CI/CD:使用 PreToolUse 在提交前进行验证
- 开发:使用 PostToolUse 实现自动化改进
Hook 执行最佳实践:
- 根据官方文档,Hooks 会并行运行
- 由于执行顺序无法保证,应确保彼此独立
- 当多个 Hook 影响相同文件时,谨慎规划 Hook 之间的交互
Success Criteria
成功标准
✅ Hook created successfully when:
- Script has executable permissions
- Registered in correct settings.json
- Responds correctly to test scenarios
- Integrates properly with Claude for automated fixes
- Follows project conventions and detected tooling
Result: The user gets a working hook that enhances their development workflow with intelligent automation and quality checks.
Documentation Index
Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt Use this file to discover all available pages before exploring further.
✅ 满足以下条件时,Hook 即创建成功:
- 脚本具有可执行权限
- 已注册到正确的 settings.json 中
- 能够正确响应测试场景
- 与 Claude 正确集成以自动执行修复
- 遵循项目约定和检测到的工具链
结果:用户获得一个可正常工作的 Hook,通过智能自动化和质量检查提升开发工作流。
文档索引
在 https://code.claude.com/docs/llms.txt 获取完整的文档索引 在进一步探索之前,使用此文件发现所有可用页面。
Automate workflows with hooks
使用 Hooks 自动化工作流
Run shell commands automatically when Claude Code edits files, finishes tasks, or needs input. Format code, send notifications, validate commands, and enforce project rules.
Hooks are user-defined shell commands that execute at specific points in Claude Code's lifecycle. They provide deterministic control over Claude Code's behavior, ensuring certain actions always happen rather than relying on the LLM to choose to run them. Use hooks to enforce project rules, automate repetitive tasks, and integrate Claude Code with your existing tools.
For decisions that require judgment rather than deterministic rules, you can also use prompt-based hooks or agent-based hooks that use a Claude model to evaluate conditions.
<Tip>
This guide covers common use cases and how to get started. For full event schemas, JSON input/output formats, and advanced features like async hooks and MCP tool hooks, see the [Hooks reference](/en/hooks).
</Tip>当 Claude Code 编辑文件、完成任务或需要输入时自动运行 shell 命令。格式化代码、发送通知、验证命令并执行项目规则。
Hooks 是用户定义的 shell 命令,会在 Claude Code 生命周期的特定节点执行。它们为 Claude Code 的行为提供确定性控制,确保特定操作始终发生,而不是依赖 LLM 决定是否运行。使用 Hooks 可以执行项目规则、自动处理重复任务,并将 Claude Code 与现有工具集成。
对于需要判断而非确定性规则的决策,还可以使用 基于 prompt 的 Hooks或基于 Agent 的 Hooks,由 Claude 模型评估条件。
<Tip>
本指南涵盖常见用例以及入门方法。有关完整事件 schema、JSON 输入/输出格式,以及异步 Hooks 和 MCP Tool Hooks 等高级功能,请参阅 [Hooks reference](/en/hooks)。
</Tip>Set up your first hook
设置第一个 Hook
The fastest way to create a hook is through the interactive menu in Claude Code. This walkthrough creates a desktop notification hook, so you get alerted whenever Claude is waiting for your input instead of watching the terminal.
<Steps>
<Step title="Open the hooks menu">
Type `/hooks` in the Claude Code CLI. You'll see a list of all available hook events, plus an option to disable all hooks. Each event corresponds to a point in Claude's lifecycle where you can run custom code. Select `Notification` to create a hook that fires when Claude needs your attention.
</Step>
<Step title="Configure the matcher">
The menu shows a list of matchers, which filter when the hook fires. Set the matcher to `*` to fire on all notification types. You can narrow it later by changing the matcher to a specific value like `permission_prompt` or `idle_prompt`.
</Step>
<Step title="Add your command">
Select `+ Add new hook…`. The menu prompts you for a shell command to run when the event fires. Hooks run any shell command you provide, so you can use your platform's built-in notification tool. Copy the command for your OS:
/hooks<Tabs>
<Tab title="macOS">
Uses [`osascript`](https://ss64.com/mac/osascript.html) to trigger a native macOS notification through AppleScript:
```
osascript -e 'display notification "Claude Code needs your attention" with title "Claude Code"'
```
</Tab>
<Tab title="Linux">
Uses `notify-send`, which is pre-installed on most Linux desktops with a notification daemon:
```
notify-send 'Claude Code' 'Claude Code needs your attention'
```
</Tab>
<Tab title="Windows (PowerShell)">
Uses PowerShell to show a native message box through .NET's Windows Forms:
```
powershell.exe -Command "[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Claude Code needs your attention', 'Claude Code')"
```
</Tab>
</Tabs>创建 Hook 的最快方式是通过 Claude Code 中的 交互式菜单。本演练将创建一个桌面通知 Hook,这样每当 Claude 等待你输入时都能收到提醒,而不必一直盯着终端。
<Steps>
<Step title="打开 Hooks 菜单">
在 Claude Code CLI 中输入 `/hooks`。你会看到所有可用的 Hook 事件列表,以及禁用所有 Hooks 的选项。每个事件对应 Claude 生命周期中的一个节点,你可以在该节点运行自定义代码。选择 `Notification` 来创建一个 Hook,在 Claude 需要你关注时触发。
</Step>
<Step title="配置 matcher">
菜单会显示 matcher 列表,用于筛选 Hook 的触发条件。将 matcher 设置为 `*` 可触发所有通知类型。稍后可以将 matcher 改为 `permission_prompt` 或 `idle_prompt` 等具体值以缩小范围。
</Step>
<Step title="添加命令">
选择 `+ Add new hook…`。菜单会提示输入事件触发时要运行的 shell 命令。Hooks 可以运行你提供的任何 shell 命令,因此可以使用操作系统内置的通知工具。复制适用于你的操作系统的命令:
/hooks<Tabs>
<Tab title="macOS">
使用 [`osascript`](https://ss64.com/mac/osascript.html) 通过 AppleScript 触发原生 macOS 通知:
```
osascript -e 'display notification "Claude Code needs your attention" with title "Claude Code"'
```
</Tab>
<Tab title="Linux">
使用 `notify-send`,它预安装在大多数运行通知守护进程的 Linux 桌面系统上:
```
notify-send 'Claude Code' 'Claude Code needs your attention'
```
</Tab>
<Tab title="Windows(PowerShell)">
使用 PowerShell 通过 .NET 的 Windows Forms 显示原生消息框:
```
powershell.exe -Command "[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Claude Code needs your attention', 'Claude Code')"
```
</Tab>
</Tabs>What you can automate
可以自动化的内容
Hooks let you run code at key points in Claude Code's lifecycle: format files after edits, block commands before they execute, send notifications when Claude needs input, inject context at session start, and more. For the full list of hook events, see the Hooks reference.
Each example includes a ready-to-use configuration block that you add to a settings file. The most common patterns:
Hooks 可以在 Claude Code 生命周期的关键节点运行代码,例如在编辑后格式化文件、在执行命令前阻止命令、在 Claude 需要输入时发送通知、在会话开始时注入上下文等。有关完整 Hook 事件列表,请参阅 Hooks reference。
每个示例都包含一个可直接使用的配置块,你需要将其添加到 settings 文件中。最常见的模式包括:
Get notified when Claude needs input
在 Claude 需要输入时收到通知
Get a desktop notification whenever Claude finishes working and needs your input, so you can switch to other tasks without checking the terminal.
This hook uses the event, which fires when Claude is waiting for input or permission. Each tab below uses the platform's native notification command. Add this to , or use the interactive walkthrough above to configure it with :
<Tabs>
<Tab title="macOS">
```json theme={null}
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
}
]
}
]
}
}
```
</Tab>
<Tab title="Linux">
```json theme={null}
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "notify-send 'Claude Code' 'Claude Code needs your attention'"
}
]
}
]
}
}
```
</Tab>
<Tab title="Windows (PowerShell)">
```json theme={null}
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "powershell.exe -Command \"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Claude Code needs your attention', 'Claude Code')\""
}
]
}
]
}
}
```
</Tab>
</Tabs>Notification~/.claude/settings.json/hooks每当 Claude 完成工作并需要你输入时都显示桌面通知,这样你就可以切换到其他任务,而无需检查终端。
此 Hook 使用 事件,该事件会在 Claude 等待输入或权限时触发。下方每个选项卡都使用对应平台的原生通知命令。将此配置添加到 ,或使用上方的交互式演练通过 进行配置:
<Tabs>
<Tab title="macOS">
```json theme={null}
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
}
]
}
]
}
}
```
</Tab>
<Tab title="Linux">
```json theme={null}
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "notify-send 'Claude Code' 'Claude Code needs your attention'"
}
]
}
]
}
}
```
</Tab>
<Tab title="Windows(PowerShell)">
```json theme={null}
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "powershell.exe -Command \"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Claude Code needs your attention', 'Claude Code')\""
}
]
}
]
}
}
```
</Tab>
</Tabs>Notification~/.claude/settings.json/hooksAuto-format code after edits
编辑后自动格式化代码
Automatically run Prettier on every file Claude edits, so formatting stays consistent without manual intervention.
This hook uses the event with an matcher, so it runs only after file-editing tools. The command extracts the edited file path with and passes it to Prettier. Add this to in your project root:
PostToolUseEdit|Writejq.claude/settings.jsonjson
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
]
}
}在 Claude 编辑每个文件后自动运行 Prettier,确保格式保持一致而无需手动干预。
此 Hook 使用 事件和 matcher,因此只会在文件编辑工具运行后触发。命令通过 提取已编辑文件的路径,并将其传递给 Prettier。将此配置添加到项目根目录的 :
PostToolUseEdit|Writejq.claude/settings.jsonjson
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
]
}
}Block edits to protected files
阻止编辑受保护的文件
Prevent Claude from modifying sensitive files like , , or anything in . Claude receives feedback explaining why the edit was blocked, so it can adjust its approach.
.envpackage-lock.json.git/This example uses a separate script file that the hook calls. The script checks the target file path against a list of protected patterns and exits with code 2 to block the edit.
<Steps>
<Step title="Create the hook script">
Save this to `.claude/hooks/protect-files.sh`:
```bash theme={null}
#!/bin/bash
# protect-files.sh
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")
for pattern in "${PROTECTED_PATTERNS[@]}"; do
if [[ "$FILE_PATH" == *"$pattern"* ]]; then
echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
exit 2
fi
done
exit 0
``````bash theme={null}
chmod +x .claude/hooks/protect-files.sh
``````json theme={null}
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
}
]
}
]
}
}
```阻止 Claude 修改 、 或 中的内容等敏感文件。Claude 会收到说明阻止原因的反馈,从而能够调整处理方式。
.envpackage-lock.json.git/此示例使用 Hook 调用的独立脚本文件。脚本会将目标文件路径与受保护模式列表进行比较,并以退出码 2 退出以阻止编辑。
<Steps>
<Step title="创建 Hook 脚本">
将以下内容保存为 `.claude/hooks/protect-files.sh`:
```bash theme={null}
#!/bin/bash
# protect-files.sh
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")
for pattern in "${PROTECTED_PATTERNS[@]}"; do
if [[ "$FILE_PATH" == *"$pattern"* ]]; then
echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
exit 2
fi
done
exit 0
``````bash theme={null}
chmod +x .claude/hooks/protect-files.sh
``````json theme={null}
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
}
]
}
]
}
}
```Re-inject context after compaction
压缩后重新注入上下文
When Claude's context window fills up, compaction summarizes the conversation to free space. This can lose important details. Use a hook with a matcher to re-inject critical context after every compaction.
SessionStartcompactAny text your command writes to stdout is added to Claude's context. This example reminds Claude of project conventions and recent work. Add this to in your project root:
.claude/settings.jsonjson
{
"hooks": {
"SessionStart": [
{
"matcher": "compact",
"hooks": [
{
"type": "command",
"command": "echo 'Reminder: use Bun, not npm. Run bun test before committing. Current sprint: auth refactor.'"
}
]
}
]
}
}You can replace the with any command that produces dynamic output, like to show recent commits. For injecting context on every session start, consider using CLAUDE.md instead. For environment variables, see in the reference.
echogit log --oneline -5CLAUDE_ENV_FILE当 Claude 的上下文窗口填满时,压缩功能会总结对话以释放空间。这可能导致重要细节丢失。使用带有 matcher 的 Hook,可以在每次压缩后重新注入关键上下文。
compactSessionStart命令写入 stdout 的任何文本都会添加到 Claude 的上下文中。此示例用于提醒 Claude 了解项目约定和最近的工作。将此配置添加到项目根目录的 :
.claude/settings.jsonjson
{
"hooks": {
"SessionStart": [
{
"matcher": "compact",
"hooks": [
{
"type": "command",
"command": "echo 'Reminder: use Bun, not npm. Run bun test before committing. Current sprint: auth refactor.'"
}
]
}
]
}
}可以将 替换为任何生成动态输出的命令,例如使用 显示最近的提交。如果要在每次会话开始时注入上下文,可以考虑使用 CLAUDE.md。有关环境变量,请参阅参考文档中的 。
echogit log --oneline -5CLAUDE_ENV_FILEHow hooks work
Hooks 的工作方式
Hook events fire at specific lifecycle points in Claude Code. When an event fires, all matching hooks run in parallel, and identical hook commands are automatically deduplicated. The table below shows each event and when it triggers:
| Event | When it fires |
|---|---|
| When a session begins or resumes |
| When you submit a prompt, before Claude processes it |
| Before a tool call executes. Can block it |
| When a permission dialog appears |
| After a tool call succeeds |
| After a tool call fails |
| When Claude Code sends a notification |
| When a subagent is spawned |
| When a subagent finishes |
| When Claude finishes responding |
| Before context compaction |
| When a session terminates |
Each hook has a that determines how it runs. Most hooks use , which runs a shell command. Two other options use a Claude model to make decisions: for single-turn evaluation and for multi-turn verification with tool access. See Prompt-based hooks and Agent-based hooks for details.
type"type": "command""type": "prompt""type": "agent"Hook 事件会在 Claude Code 生命周期的特定节点触发。事件触发时,所有匹配的 Hooks 都会并行运行,完全相同的 Hook 命令会被自动去重。下表列出了每个事件及其触发时机:
| 事件 | 触发时机 |
|---|---|
| 会话开始或恢复时 |
| 提交 prompt 后、Claude 处理之前 |
| 工具调用执行之前,可以阻止调用 |
| 权限对话框出现时 |
| 工具调用成功后 |
| 工具调用失败后 |
| Claude Code 发送通知时 |
| 创建 subagent 时 |
| subagent 完成时 |
| Claude 完成响应时 |
| 上下文压缩之前 |
| Claude Code 会话终止时 |
每个 Hook 都有一个决定其运行方式的 。大多数 Hooks 使用 运行 shell 命令。另有两个选项使用 Claude 模型作出决策:用于单轮评估的 ,以及用于支持工具访问的多轮验证的 。有关详细信息,请参阅 Prompt-based hooks和 Agent-based hooks。
type"type": "command""type": "prompt""type": "agent"Read input and return output
读取输入并返回输出
Hooks communicate with Claude Code through stdin, stdout, stderr, and exit codes. When an event fires, Claude Code passes event-specific data as JSON to your script's stdin. Your script reads that data, does its work, and tells Claude Code what to do next via the exit code.
Hooks 通过 stdin、stdout、stderr 和退出码与 Claude Code 通信。事件触发时,Claude Code 会将特定于事件的数据作为 JSON 传递给脚本的 stdin。脚本读取数据、执行工作,并通过退出码告知 Claude Code 下一步应该执行什么。
Hook input
Hook 输入
Every event includes common fields like and , but each event type adds different data. For example, when Claude runs a Bash command, a hook receives something like this on stdin:
session_idcwdPreToolUsejson
{
"session_id": "abc123", // unique ID for this session
"cwd": "/Users/sarah/myproject", // working directory when the event fired
"hook_event_name": "PreToolUse", // which event triggered this hook
"tool_name": "Bash", // the tool Claude is about to use
"tool_input": { // the arguments Claude passed to the tool
"command": "npm test" // for Bash, this is the shell command
}
}Your script can parse that JSON and act on any of those fields. hooks get the text instead, hooks get the (startup, resume, compact), and so on. See Common input fields in the reference for shared fields, and each event's section for event-specific schemas.
UserPromptSubmitpromptSessionStartsource每个事件都包含 、 等通用字段,但不同事件类型会添加不同的数据。例如,当 Claude 运行 Bash 命令时, Hook 可能会在 stdin 中收到以下内容:
session_idcwdPreToolUsejson
{
"session_id": "abc123", // unique ID for this session
"cwd": "/Users/sarah/myproject", // working directory when the event fired
"hook_event_name": "PreToolUse", // which event triggered this hook
"tool_name": "Bash", // the tool Claude is about to use
"tool_input": { // the arguments Claude passed to the tool
"command": "npm test" // for Bash, this is the shell command
}
}脚本可以解析该 JSON,并基于其中任意字段执行操作。 Hooks 获得 文本, Hooks 获得 (startup、resume、compact),依此类推。有关共享字段,请参阅参考文档中的 Common input fields;有关事件专用 schema,请参阅每个事件的对应章节。
UserPromptSubmitpromptSessionStartsourceHook output
Hook 输出
Your script tells Claude Code what to do next by writing to stdout or stderr and exiting with a specific code. For example, a hook that wants to block a command:
PreToolUsebash
#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')
if echo "$COMMAND" | grep -q "drop table"; then
echo "Blocked: dropping tables is not allowed" >&2 # stderr becomes Claude's feedback
exit 2 # exit 2 = block the action
fi
exit 0 # exit 0 = let it proceedThe exit code determines what happens next:
- Exit 0: the action proceeds. For and
UserPromptSubmithooks, anything you write to stdout is added to Claude's context.SessionStart - Exit 2: the action is blocked. Write a reason to stderr, and Claude receives it as feedback so it can adjust.
- Any other exit code: the action proceeds. Stderr is logged but not shown to Claude. Toggle verbose mode with to see these messages in the transcript.
Ctrl+O
脚本通过写入 stdout 或 stderr 并以特定代码退出来告知 Claude Code 下一步应该执行什么。例如,以下 Hook 会阻止某条命令:
PreToolUsebash
#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')
if echo "$COMMAND" | grep -q "drop table"; then
echo "Blocked: dropping tables is not allowed" >&2 # stderr becomes Claude's feedback
exit 2 # exit 2 = block the action
fi
exit 0 # exit 0 = let it proceed退出码决定接下来发生什么:
- 退出 0:操作继续。对于 和
UserPromptSubmitHooks,写入 stdout 的任何内容都会添加到 Claude 的上下文中。SessionStart - 退出 2:操作被阻止。将原因写入 stderr,Claude 会将其作为反馈并据此调整。
- 其他退出码:操作继续。stderr 会被记录,但不会展示给 Claude。按 可切换详细模式以查看这些消息。
Ctrl+O
Structured JSON output
结构化 JSON 输出
Exit codes give you two options: allow or block. For more control, exit 0 and print a JSON object to stdout instead.
<Note>
Use exit 2 to block with a stderr message, or exit 0 with JSON for structured control. Don't mix them: Claude Code ignores JSON when you exit 2.
</Note>
For example, a hook can deny a tool call and tell Claude why, or escalate it to the user for approval:
PreToolUsejson
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Use rg instead of grep for better performance"
}
}Claude Code reads and cancels the tool call, then feeds back to Claude as feedback. These three options are specific to :
permissionDecisionpermissionDecisionReasonPreToolUse- : proceed without showing a permission prompt
"allow" - : cancel the tool call and send the reason to Claude
"deny" - : show the permission prompt to the user as normal
"ask"
Other events use different decision patterns. For example, and hooks use a top-level field, while uses . See the summary table in the reference for a full breakdown by event.
PostToolUseStopdecision: "block"PermissionRequesthookSpecificOutput.decision.behaviorFor hooks, use instead to inject text into Claude's context. Prompt-based hooks () handle output differently: see Prompt-based hooks.
UserPromptSubmitadditionalContexttype: "prompt"退出码只有允许或阻止两种选择。若需要更精细的控制,可以退出 0 并将 JSON 对象输出到 stdout。
<Note>
使用退出码 2 和 stderr 消息阻止操作,或使用退出 0 和 JSON 进行结构化控制。不要混用:退出 2 时 Claude Code 会忽略 JSON。
</Note>
例如, Hook 可以拒绝工具调用并告知 Claude 原因,也可以将请求升级给用户审批:
PreToolUsejson
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Use rg instead of grep for better performance"
}
}Claude Code 读取 并取消工具调用,然后将 作为反馈传回 Claude。以下三个选项专用于 :
permissionDecisionpermissionDecisionReasonPreToolUse- :继续执行且不显示权限提示
"allow" - :取消工具调用并向 Claude 发送原因
"deny" - :像平常一样向用户显示权限提示
"ask"
其他事件使用不同的决策模式。例如, 和 Hooks 使用顶层 字段,而 使用 。完整概览请参阅参考文档中的汇总表。
PostToolUseStopdecision: "block"PermissionRequesthookSpecificOutput.decision.behavior对于 Hooks,请改用 将文本注入 Claude 的上下文。基于 prompt 的 Hooks()使用不同的输出方式,详见 Prompt-based hooks。
UserPromptSubmitadditionalContexttype: "prompt"Filter hooks with matchers
使用 matcher 过滤 Hooks
Without a matcher, a hook fires on every occurrence of its event. Matchers let you narrow that down. For example, if you want to run a formatter only after file edits (not after every tool call), add a matcher to your hook:
PostToolUsejson
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "prettier --write ..." }
]
}
]
}
}The matcher is a regex pattern that matches the tool name. The hook only fires when Claude uses the or tool, not when it uses , , or any other tool.
"Edit|Write"EditWriteBashReadEach event type matches on a specific field. Matchers support exact strings and regex patterns:
| Event | What the matcher filters | Example matcher values |
|---|---|---|
| tool name | |
| how the session started | |
| why the session ended | |
| notification type | |
| agent type | |
| what triggered compaction | |
| no matcher support | always fires on every occurrence |
| agent type | same values as |
A few more examples showing matchers on different event types:
<Tabs>
<Tab title="Log every Bash command">
Match only `Bash` tool calls and log each command to a file. The `PostToolUse` event fires after the command completes, so `tool_input.command` contains what ran. The hook receives the event data as JSON on stdin, and `jq -r '.tool_input.command'` extracts just the command string, which `>>` appends to the log file:
```json theme={null}
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.command' >> ~/.claude/command-log.txt"
}
]
}
]
}
}
```The command below extracts the tool name from the hook's JSON input with `jq` and writes it to stderr, where it shows up in verbose mode (`Ctrl+O`):
```json theme={null}
{
"hooks": {
"PreToolUse": [
{
"matcher": "mcp__github__.*",
"hooks": [
{
"type": "command",
"command": "echo \"GitHub tool called: $(jq -r '.tool_name')\" >&2"
}
]
}
]
}
}
``````json theme={null}
{
"hooks": {
"SessionEnd": [
{
"matcher": "clear",
"hooks": [
{
"type": "command",
"command": "rm -f /tmp/claude-scratch-*.txt"
}
]
}
]
}
}
```For full matcher syntax, see the Hooks reference.
不使用 matcher 时,每次出现对应事件都会触发 Hook。Matchers 可以缩小触发范围。例如,如果希望只在编辑文件后运行格式化程序,可以为 Hook 添加 matcher:
PostToolUsejson
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "prettier --write ..." }
]
}
]
}
}"Edit|Write"EditWriteBashRead每种事件类型匹配特定字段。Matchers 支持精确字符串和正则表达式模式:
| 事件 | matcher 筛选的内容 | matcher 示例值 |
|---|---|---|
| 工具名称 | |
| 会话启动方式 | |
| 会话结束原因 | |
| 通知类型 | |
| Agent 类型 | |
| 触发压缩的原因 | |
| 不支持 matcher | 每次出现时始终触发 |
| Agent 类型 | 与 |
下面给出了不同事件类型 matcher 的更多示例:
<Tabs>
<Tab title="记录每条 Bash 命令">
仅匹配 `Bash` 工具调用,并将每条命令记录到文件。`PostToolUse` 事件在命令完成后触发,因此 `tool_input.command` 中包含已执行的命令。Hook 通过 stdin 接收事件 JSON 数据,`jq -r '.tool_input.command'` 会提取命令字符串,再由 `>>` 将其追加到日志文件:
```json theme={null}
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.command' >> ~/.claude/command-log.txt"
}
]
}
]
}
}
```以下命令使用 `jq` 从 Hook 的 JSON 输入中提取工具名称,并将其写入 stderr;该内容会显示在详细模式(`Ctrl+O`)中:
```json theme={null}
{
"hooks": {
"PreToolUse": [
{
"matcher": "mcp__github__.*",
"hooks": [
{
"type": "command",
"command": "echo \"GitHub tool called: $(jq -r '.tool_name')\" >&2"
}
]
}
]
}
}
``````json theme={null}
{
"hooks": {
"SessionEnd": [
{
"matcher": "clear",
"hooks": [
{
"type": "command",
"command": "rm -f /tmp/claude-scratch-*.txt"
}
]
}
]
}
}
```有关完整的 matcher 语法,请参阅 Hooks reference。
Configure hook location
配置 Hook 位置
Where you add a hook determines its scope:
| Location | Scope | Shareable |
|---|---|---|
| All your projects | No, local to your machine |
| Single project | Yes, can be committed to the repo |
| Single project | No, gitignored |
| Managed policy settings | Organization-wide | Yes, admin-controlled |
Plugin | When plugin is enabled | Yes, bundled with the plugin |
| Skill or agent frontmatter | While the skill or agent is active | Yes, defined in the component file |
You can also use the menu in Claude Code to add, delete, and view hooks interactively. To disable all hooks at once, use the toggle at the bottom of the menu or set in your settings file.
/hooks/hooks"disableAllHooks": trueHooks added through the menu take effect immediately. If you edit settings files directly while Claude Code is running, the changes won't take effect until you review them in the menu or restart your session.
/hooks/hooks添加 Hook 的位置决定其作用域:
| 位置 | 作用域 | 可共享 |
|---|---|---|
| 所有项目 | 否,仅限本机 |
| 单个项目 | 是,可以提交到仓库 |
| 单个项目 | 否,已被 Git 忽略 |
| 托管策略设置 | 组织范围 | 是,由管理员控制 |
Plugin | 启用 Plugin 时 | 是,随 Plugin 一起分发 |
| Skill 或 agent frontmatter | Skill 或 Agent 处于活动状态时 | 是,在组件文件中定义 |
还可以使用 Claude Code 中的 菜单交互式添加、删除和查看 Hooks。要一次性禁用所有 Hooks,请使用菜单底部的开关,或在 settings 文件中设置 。
/hooks"disableAllHooks": true通过 菜单添加的 Hooks 会立即生效。如果在 Claude Code 运行时直接编辑 settings 文件,则需要在 菜单中查看更改或重启会话后才会生效。
/hooks/hooksPrompt-based hooks
基于 prompt 的 Hooks
For decisions that require judgment rather than deterministic rules, use hooks. Instead of running a shell command, Claude Code sends your prompt and the hook's input data to a Claude model (Haiku by default) to make the decision. You can specify a different model with the field if you need more capability.
type: "prompt"modelThe model's only job is to return a yes/no decision as JSON:
- : the action proceeds
"ok": true - : the action is blocked. The model's
"ok": falseis fed back to Claude so it can adjust."reason"
This example uses a hook to ask the model whether all requested tasks are complete. If the model returns , Claude keeps working and uses the as its next instruction:
Stop"ok": falsereasonjson
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "Check if all tasks are complete. If not, respond with {\"ok\": false, \"reason\": \"what remains to be done\"}."
}
]
}
]
}
}For full configuration options, see Prompt-based hooks in the reference.
对于需要判断而非确定性规则的决策,请使用 Hooks。Claude Code 不会运行 shell 命令,而是将你的 prompt 和 Hook 输入数据发送给 Claude 模型(默认使用 Haiku)作出决策。如果需要更强的能力,可以通过 字段指定其他模型。
type: "prompt"model模型唯一的任务是返回 yes/no 决策 JSON:
- :操作继续
"ok": true - :操作被阻止。模型的
"ok": false会反馈给 Claude,以便其调整。"reason"
此示例使用 Hook 让模型判断所有请求的任务是否已经完成。如果模型返回 ,Claude 会继续工作,并将 作为下一条指令:
Stop"ok": false"reasonjson
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "Check if all tasks are complete. If not, respond with {\"ok\": false, \"reason\": \"what remains to be done\"}."
}
]
}
]
}
}有关完整的配置选项,请参阅参考文档中的 Prompt-based hooks。
Agent-based hooks
基于 Agent 的 Hooks
When verification requires inspecting files or running commands, use hooks. Unlike prompt hooks which make a single LLM call, agent hooks spawn a subagent that can read files, search code, and use other tools to verify conditions before returning a decision.
type: "agent"Agent hooks use the same / response format as prompt hooks, but with a longer default timeout of 60 seconds and up to 50 tool-use turns.
"ok""reason"This example verifies that tests pass before allowing Claude to stop:
json
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "agent",
"prompt": "Verify that all unit tests pass. Run the test suite and check the results. $ARGUMENTS",
"timeout": 120
}
]
}
]
}
}Use prompt hooks when the hook input data alone is enough to make a decision. Use agent hooks when you need to verify something against the actual state of the codebase.
For full configuration options, see Agent-based hooks in the reference.
当验证需要检查文件或运行命令时,请使用 Hooks。与只发起单次 LLM 调用的 prompt Hooks 不同,Agent Hooks 会创建 subagent,使其能够读取文件、搜索代码并使用其他工具验证条件,然后返回决策。
type: "agent"Agent Hooks 使用与 prompt Hooks 相同的 / 响应格式,但默认超时时间为 60 秒,最多可使用 50 轮工具。
"ok""reason"此示例验证所有测试是否通过,然后才允许 Claude 停止:
json
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "agent",
"prompt": "Verify that all unit tests pass. Run the test suite and check the results. $ARGUMENTS",
"timeout": 120
}
]
}
]
}
}当仅依靠 Hook 输入数据就足以作出决策时,使用 prompt Hooks;当需要根据代码库的实际状态进行验证时,使用 Agent Hooks。
有关完整的配置选项,请参阅参考文档中的 Agent-based hooks。
Limitations and troubleshooting
限制与故障排除
Limitations
限制
- Hooks communicate through stdout, stderr, and exit codes only. They cannot trigger slash commands or tool calls directly.
- Hook timeout is 10 minutes by default, configurable per hook with the field (in seconds).
timeout - hooks cannot undo actions since the tool has already executed.
PostToolUse - hooks do not fire in non-interactive mode (
PermissionRequest). Use-phooks for automated permission decisions.PreToolUse - hooks fire whenever Claude finishes responding, not only at task completion. They do not fire on user interrupts.
Stop
- Hooks 仅通过 stdout、stderr 和退出码通信,不能直接触发 slash command 或工具调用。
- Hook 默认超时时间为 10 分钟,可以通过每个 Hook 的 字段以秒为单位配置。
timeout - Hooks 无法撤销操作,因为工具已经执行。
PostToolUse - Hooks 在非交互模式(
PermissionRequest)下不会触发。请使用-pHooks 进行自动化权限决策。PreToolUse - Hooks 会在 Claude 每次完成响应时触发,而不仅是在任务完成时触发。用户中断时不会触发。
Stop
Hook not firing
Hook 未触发
The hook is configured but never executes.
- Run and confirm the hook appears under the correct event
/hooks - Check that the matcher pattern matches the tool name exactly (matchers are case-sensitive)
- Verify you're triggering the right event type (e.g., fires before tool execution,
PreToolUsefires after)PostToolUse - If using hooks in non-interactive mode (
PermissionRequest), switch to-pinsteadPreToolUse
Hook 已配置,但从未执行。
- 运行 ,确认 Hook 出现在正确的事件下
/hooks - 检查 matcher 模式是否与工具名称完全匹配(matchers 区分大小写)
- 验证是否触发了正确的事件类型(例如,在工具执行前触发,
PreToolUse在工具执行后触发)PostToolUse - 如果在非交互模式()下使用
-pHooks,请改用PermissionRequestPreToolUse
Hook error in output
输出中出现 Hook 错误
You see a message like "PreToolUse hook error: ..." in the transcript.
-
Your script exited with a non-zero code unexpectedly. Test it manually by piping sample JSON:bash
echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh echo $? # Check the exit code
- If you see "command not found", use absolute paths or to reference scripts
$CLAUDE_PROJECT_DIR
- If you see "jq: command not found", install or use Python/Node.js for JSON parsing
jq - If the script isn't running at all, make it executable:
chmod +x ./my-hook.sh
在记录中出现类似“PreToolUse hook error: ...”的消息。
- 脚本意外地以非零代码退出。通过传入示例 JSON 手动测试:
bash
echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh echo $? # Check the exit code
- 如果出现“command not found”,请使用绝对路径,或使用 引用脚本
$CLAUDE_PROJECT_DIR
- 如果出现“jq: command not found”,请安装 ,或使用 Python/Node.js 解析 JSON
jq - 如果脚本完全没有运行,请使其可执行:
chmod +x ./my-hook.sh
/hooks
shows no hooks configured
/hooks/hooks
未显示已配置的 Hooks
/hooksYou edited a settings file but the hooks don't appear in the menu.
- Restart your session or open to reload. Hooks added through the
/hooksmenu take effect immediately, but manual file edits require a reload./hooks - Verify your JSON is valid (trailing commas and comments are not allowed)
- Confirm the settings file is in the correct location: for project hooks,
.claude/settings.jsonfor global hooks~/.claude/settings.json
你编辑了 settings 文件,但 Hooks 没有出现在菜单中。
- 重启会话或打开 重新加载。通过
/hooks菜单添加的 Hooks 会立即生效,但手动编辑文件需要重新加载。/hooks - 验证 JSON 是否有效(不允许尾随逗号和注释)
- 确认 settings 文件位置正确:项目 Hooks 使用 ,全局 Hooks 使用
.claude/settings.json~/.claude/settings.json
Stop hook runs forever
Stop Hook 无限运行
Claude keeps working in an infinite loop instead of stopping.
Your Stop hook script needs to check whether it already triggered a continuation. Parse the field from the JSON input and exit early if it's :
stop_hook_activetruebash
#!/bin/bash
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
exit 0 # Allow Claude to stop
fiClaude 持续工作并陷入无限循环,而不是停止。
你的 Stop Hook 脚本需要检查它是否已经触发过一次继续操作。解析 JSON 输入中的 字段,如果值为 ,则提前退出:
stop_hook_activetruebash
#!/bin/bash
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
exit 0 # Allow Claude to stop
fi... rest of your hook logic
... rest of your hook logic
undefinedundefinedJSON validation failed
JSON 验证失败
Claude Code shows a JSON parsing error even though your hook script outputs valid JSON.
When Claude Code runs a hook, it spawns a shell that sources your profile ( or ). If your profile contains unconditional statements, that output gets prepended to your hook's JSON:
~/.zshrc~/.bashrcechoShell ready on arm64
{"decision": "block", "reason": "Not allowed"}Claude Code tries to parse this as JSON and fails. To fix this, wrap echo statements in your shell profile so they only run in interactive shells:
bash
undefined即使 Hook 脚本输出的是有效 JSON,Claude Code 仍显示 JSON 解析错误。
Claude Code 运行 Hook 时会启动一个加载你的配置文件( 或 )的 shell。如果配置文件中包含无条件执行的 语句,其输出会被添加到 Hook JSON 前面:
~/.zshrc~/.bashrcechoShell ready on arm64
{"decision": "block", "reason": "Not allowed"}Claude Code 会尝试将此内容解析为 JSON 并失败。要解决此问题,请将 echo 语句放入 shell 配置文件的交互模式条件中:
bash
undefinedIn ~/.zshrc or ~/.bashrc
In ~/.zshrc or ~/.bashrc
if [[ $- == i ]]; then
echo "Shell ready"
fi
The `$-` variable contains shell flags, and `i` means interactive. Hooks run in non-interactive shells, so the echo is skipped.if [[ $- == i ]]; then
echo "Shell ready"
fi
`$-` 变量包含 shell 标志,其中 `i` 表示交互模式。Hooks 在非交互 shell 中运行,因此会跳过 echo。Debug techniques
调试技巧
Toggle verbose mode with to see hook output in the transcript, or run for full execution details including which hooks matched and their exit codes.
Ctrl+Oclaude --debug按 切换详细模式以在记录中查看 Hook 输出,或运行 查看完整的执行详情,包括哪些 Hooks 匹配及其退出码。
Ctrl+Oclaude --debugLearn more
了解更多
- Hooks reference: full event schemas, JSON output format, async hooks, and MCP tool hooks
- Security considerations: review before deploying hooks in shared or production environments
- Bash command validator example: complete reference implementation
Documentation Index
Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt Use this file to discover all available pages before exploring further.
- Hooks reference:完整事件 schema、JSON 输出格式、异步 Hooks 和 MCP Tool Hooks
- Security considerations:在共享或生产环境中部署 Hooks 前进行审查
- Bash command validator example:完整的参考实现
文档索引
在 https://code.claude.com/docs/llms.txt 获取完整的文档索引 在进一步探索之前,使用此文件发现所有可用页面。
Hooks reference
Hooks 参考
<Tip> For a quickstart guide with examples, see [Automate workflows with hooks](/en/hooks-guide). </Tip>Reference for Claude Code hook events, configuration schema, JSON input/output formats, exit codes, async hooks, prompt hooks, and MCP tool hooks.
Hooks are user-defined shell commands or LLM prompts that execute automatically at specific points in Claude Code's lifecycle. Use this reference to look up event schemas, configuration options, JSON input/output formats, and advanced features like async hooks and MCP tool hooks. If you're setting up hooks for the first time, start with the guide instead.
<Tip> 有关包含示例的快速入门指南,请参阅 [Automate workflows with hooks](/en/hooks-guide)。 </Tip>Claude Code Hook 事件、配置 schema、JSON 输入/输出格式、退出码、异步 Hooks、prompt Hooks 和 MCP Tool Hooks 的参考文档。
Hooks 是用户定义的 shell 命令或 LLM prompts,会在 Claude Code 生命周期的特定节点自动执行。使用本参考文档查询事件 schema、配置选项、JSON 输入/输出格式,以及异步 Hooks 和 MCP Tool Hooks 等高级功能。如果首次设置 Hooks,请先阅读指南。
Hook lifecycle
Hook 生命周期
Hooks fire at specific points during a Claude Code session. When an event fires and a matcher matches, Claude Code passes JSON context about the event to your hook handler. For command hooks, this arrives on stdin. Your handler can then inspect the input, take action, and optionally return a decision. Some events fire once per session, while others fire repeatedly inside the agentic loop:
<div style={{maxWidth: "500px", margin: "0 auto"}}>
<Frame>
<img src="https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=5c25fedbc3db6f8882af50c3cc478c32" alt="Hook lifecycle diagram showing the sequence of hooks from SessionStart through the agentic loop to SessionEnd" data-og-width="8876" width="8876" data-og-height="12492" height="12492" data-path="images/hooks-lifecycle.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=280&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=62406fcd5d4a189cc8842ee1bd946b84 280w, https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=560&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=fa3049022a6973c5f974e0f95b28169d 560w, https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=840&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=bd2890897db61a03160b93d4f972ff8e 840w, https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=1100&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=7ae8e098340479347135e39df4a13454 1100w, https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=1650&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=848a8606aab22c2ccaa16b6a18431e32 1650w, https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=2500&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=f3a9ef7feb61fa8fe362005aa185efbc 2500w" />
</Frame>
</div>
The table below summarizes when each event fires. The Hook events section documents the full input schema and decision control options for each one.
| Event | When it fires |
|---|---|
| When a session begins or resumes |
| When you submit a prompt, before Claude processes it |
| Before a tool call executes. Can block it |
| When a permission dialog appears |
| After a tool call succeeds |
| After a tool call fails |
| When Claude Code sends a notification |
| When a subagent is spawned |
| When a subagent finishes |
| When Claude finishes responding |
| Before context compaction |
| When a session terminates |
Hooks 会在 Claude Code 会话生命周期的特定节点触发。事件触发且 matcher 匹配后,Claude Code 会将事件相关 JSON 上下文传递给 Hook 处理器。对于 command Hooks,这些数据通过 stdin 传入。处理器随后可以检查输入、执行操作,并选择返回决策。有些事件每个会话只触发一次,而其他事件会在 Agent 循环中反复触发:
<div style={{maxWidth: "500px", margin: "0 auto"}}>
<Frame>
<img src="https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=c5c25fedbc3db6f8882af50c3cc478c32" alt="展示从 SessionStart 到 Agent 循环再到 SessionEnd 的 Hook 生命周期顺序图" data-og-width="8876" width="8876" height="12492" data-path="images/hooks-lifecycle.png" data-optimize="true" data-og-height="12492" srcset="https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=280&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=24a9ee15b19b0c4ba05b6d62ec6ec545 280w, https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=560&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=cbce02757f1ea14d2a49e8b460e8c1d5 560w, https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=880&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=adb6d6f90c1a16720c9be1073b114b3a 880w, https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=1200&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=e7022e313b3c1663f4f1f3bd0c43a3d 1200w, https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=1600&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=4c1bf2dd3f23e8c67dfd2fc1b4a67da8 1600w, https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=2000&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=7686a37a293ce5f68a9946a64af8f7c7c 2000w, https://mintcdn.com/claude-code/z2YM37Ycg6eMbID3/images/hooks-lifecycle.png?w=2800&fit=max&auto=format&n=z2YM37Ycg6eMbID3&q=85&s=1d1f7c89d2b52c4f0769e7ce4eab4f6 2800w" />
</Frame>
</div>
下表汇总了每个事件的触发时机。Hook events章节记录了每个事件的完整输入 schema 和决策控制选项。
| 事件 | 触发时机 |
|---|---|
| 会话开始或恢复时 |
| 提交 prompt 后、Claude 处理之前 |
| 工具调用执行之前,可以阻止调用 |
| 权限对话框出现时 |
| 工具调用成功后 |
| 工具调用失败后 |
| Claude Code 发送通知时 |
| 创建 subagent 时 |
| subagent 完成时 |
| Claude 完成响应时 |
| 上下文压缩之前 |
| Claude Code 会话终止时 |
How a hook resolves
Hook 的解析方式
To see how these pieces fit together, consider this hook that blocks destructive shell commands. The hook runs before every Bash tool call:
PreToolUseblock-rm.shjson
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/block-rm.sh"
}
]
}
]
}
}The script reads the JSON input from stdin, extracts the command, and returns a of if it contains :
permissionDecision"deny"rm -rfbash
#!/bin/bash为了了解这些部分如何协同工作,请考虑以下阻止破坏性 shell 命令的 Hook。该 Hook 会在每次 Bash 工具调用前运行 :
PreToolUseblock-rm.shjson
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/block-rm.sh"
}
]
}
]
}
}脚本从 stdin 读取 JSON 输入、提取命令,并在命令包含 时返回 形式的 :
rm -rf"deny"permissionDecisionbash
#!/bin/bash.claude/hooks/block-rm.sh
.claude/hooks/block-rm.sh
COMMAND=$(jq -r '.tool_input.command')
if echo "$COMMAND" | grep -q 'rm -rf'; then
jq -n '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "Destructive command blocked by hook"
}
}'
else
exit 0 # allow the command
fi
Now suppose Claude Code decides to run `Bash "rm -rf /tmp/build"`. Here's what happens:
<Frame>
<img src="https://mintcdn.com/claude-code/s7NM0vfd_wres2nf/images/hook-resolution.svg?fit=max&auto=format&n=s7NM0vfd_wres2nf&q=85&s=7c13f51ffcbc37d22a593b27e2f2de72" alt="Hook resolution flow: PreToolUse event fires, matcher checks for Bash match, hook handler runs, result returns to Claude Code" data-og-width="780" width="780" data-og-height="290" height="290" data-path="images/hook-resolution.svg" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/claude-code/s7NM0vfd_wres2nf/images/hook-resolution.svg?w=280&fit=max&auto=format&n=s7NM0vfd_wres2nf&q=85&s=36a39a07e8bc1995dcb4639e09846905 280w, https://mintcdn.com/claude-code/s7NM0vfd_wres2nf/images/hook-resolution.svg?w=560&fit=max&auto=format&n=s7NM0vfd_wres2nf&q=85&s=6568d90c596c7605bbac2c325b0a0c86 560w, https://mintcdn.com/claude-code/s7NM0vfd_wres2nf/images/hook-resolution.svg?w=840&fit=max&auto=format&n=s7NM0vfd_wres2nf&q=85&s=255a6f68b9475a0e41dbde7b88002dad 840w, https://mintcdn.com/claude-code/s7NM0vfd_wres2nf/images/hook-resolution.svg?w=1100&fit=max&auto=format&n=s7NM0vfd_wres2nf&q=85&s=dcecf8d5edc88cd2bc49deb006d5760d 1100w, https://mintcdn.com/claude-code/s7NM0vfd_wres2nf/images/hook-resolution.svg?w=1650&fit=max&auto=format&n=s7NM0vfd_wres2nf&q=85&s=04fe51bf69ae375e9fd517f18674e35f 1650w, https://mintcdn.com/claude-code/s7NM0vfd_wres2nf/images/hook-resolution.svg?w=2500&fit=max&auto=format&n=s7NM0vfd_wres2nf&q=85&s=b1b76e0b77fddb5c7fa7bf302dacd80b 2500w" />
</Frame>
<Steps>
<Step title="Event fires">
The `PreToolUse` event fires. Claude Code sends the tool input as JSON on stdin to the hook:
```json theme={null}
{ "tool_name": "Bash", "tool_input": { "command": "rm -rf /tmp/build" }, ... }
```
</Step>
<Step title="Matcher checks">
The matcher `"Bash"` matches the tool name, so `block-rm.sh` runs. If you omit the matcher or use `"*"`, the hook runs on every occurrence of the event. Hooks only skip when a matcher is defined and doesn't match.
</Step>
<Step title="Hook handler runs">
The script extracts `"rm -rf /tmp/build"` from the input and finds `rm -rf`, so it prints a decision to stdout:
```json theme={null}
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Destructive command blocked by hook"
}
}
```
If the command had been safe (like `npm test`), the script would hit `exit 0` instead, which tells Claude Code to allow the tool call with no further action.
</Step>
<Step title="Claude Code acts on the result">
Claude Code reads the JSON decision, blocks the tool call, and shows Claude the reason.
</Step>
</Steps>
The [Configuration](#configuration) section below documents the full schema, and each [hook event](#hook-events) section documents what input your command receives and what output it can return.COMMAND=$(jq -r '.tool_input.command')
if echo "$COMMAND" | grep -q 'rm -rf'; then
jq -n '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "Destructive command blocked by hook"
}
}'
else
exit 0 # allow the command
fi
现在假设 Claude Code 决定运行 `Bash` 工具并执行 `rm -rf /tmp/build`,将会发生以下情况:
<Frame>
<img src="https://mintcdn.com/claude-code/s7NM0vfd_wres2nf/images/hook-resolution.svg?fit=max&auto=format&n=s7NM0vfd_wres2nf&q=85&s=3b30c34a8e4b04fe31a6e40ecf3f4987" alt="Hook 解析流程:PreToolUse 事件触发、matcher 检查 Bash 匹配、Hook 处理器运行,并将结果返回给 Claude Code" data-og-width="780" width="780" height="290" data-path="images/hook-resolution.svg" data-optimize="true" data-og-height="290" srcset="https://mintcdn.com/claude-code/s7NM0vfd_wres2nf/images/hook-resolution.svg?w=280&fit=max&auto=format&n=s7NM0vfd_wres2nf&q=85&s=9e78b9dba7fd59d87a0e6b87b465ae3 280w, https://mintcdn.com/claude-code/s7NM0vfd_wres2nf/images/hook-resolution.svg?w=560&fit=max&auto=format&n=s7NM0vfd_wres2nf&q=85&s=baf15d481250252aedbe6ce5b28767d 560w, https://mintcdn.com/claude-code/s7NM0vfd_wres2nf/images/hook-resolution.svg?w=840&fit=max&auto=format&n=s7NM0vfd_wres2nf&q=85&s=3d12ee7fd1822cd57164a912674b804b 840w, https://mintcdn.com/claude-code/s7NM0vfd_wres2nf/images/hook-resolution.svg?w=1120&fit=max&auto=format&n=s7NM0vfd_wres2nf&q=85&s=e5ba1a66fce44653b6351f7710a3bb29 1120w, https://mintcdn.com/claude-code/s7NM0vfd_wres2nf/images/hook-resolution.svg?w=1400&fit=max&auto=format&n=s7NM0vfd_wres2nf&q=85&s=9c72fc4fd5c9d5200c35a7b3f3d31d3 1400w, https://mintcdn.com/claude-code/s7NM0vfd_wres2nf/images/hook-resolution.svg?w=1680&fit=max&auto=format&n=s7NM0vfd_wres2nf&q=85&s=3cc9d1d9c2204489502588319c7af3d 1680w, https://mintcdn.com/claude-code/s7NM0vfd_wres2nf/images/hook-resolution.svg?w=1960&fit=max&auto=format&n=s7NM0vfd_wres2nf&q=85&s=3d3d4a20c1b6e19d9d17e36e4025a284 1960w, https://mintcdn.com/claude-code/s7NM0vfd_wres2nf/images/hook-resolution.svg?w=2240&fit=max&auto=format&n=s7NM0vfd_wres2nf&q=85&s=9bfeafda81b3750f328a98d6ed9823b 2240w" />
</Frame>
<Steps>
<Step title="事件触发">
`PreToolUse` 事件触发。Claude Code 通过 stdin 将工具输入作为 JSON 发送给 Hook:
```json theme={null}
{ "tool_name": "Bash", "tool_input": { "command": "rm -rf /tmp/build" }, ... }
```
</Step>
<Step title="Matcher 检查">
matcher `"Bash"` 与工具名称匹配,因此会运行 `block-rm.sh`。如果省略 matcher 或使用 `"*"`,Hook 会在每次出现该事件时运行。只有在已定义 matcher 且其不匹配时,Hook 才会跳过。
</Step>
<Step title="Hook 处理器运行">
脚本从输入中提取 `"rm -rf /tmp/build"` 并找到 `rm -rf`,随后将决策输出到 stdout:
```json theme={null}
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Destructive command blocked by hook"
}
}
```
如果命令是安全的(例如 `npm test`),脚本会改为执行 `exit 0`,这会告诉 Claude Code 允许工具调用且不执行其他操作。
</Step>
<Step title="Claude Code 处理结果">
Claude Code 读取 JSON 决策,阻止工具调用,并向 Claude 展示原因。
</Step>
</Steps>
下方的 [Configuration](#configuration)章节记录了完整 schema,每个 [hook event](#hook-events)章节则记录 command 接收的输入以及可以返回的输出。Configuration
配置
Hooks are defined in JSON settings files. The configuration has three levels of nesting:
- Choose a hook event to respond to, like or
PreToolUseStop - Add a matcher group to filter when it fires, like "only for the Bash tool"
- Define one or more hook handlers to run when matched
See How a hook resolves above for a complete walkthrough with an annotated example.
<Note>
This page uses specific terms for each level: **hook event** for the lifecycle point, **matcher group** for the filter, and **hook handler** for the shell command, prompt, or agent that runs. "Hook" on its own refers to the general feature.
</Note>Hooks 在 JSON settings 文件中定义。配置包含三个嵌套层级:
- 选择要响应的 hook event,例如 或
PreToolUseStop - 添加 matcher group来筛选触发时机,例如“仅用于 Bash 工具”
- 定义匹配后运行的一个或多个 hook handler
有关完整的标注示例,请参阅上方的 How a hook resolves。
<Note>
本页使用特定术语表示各层级:**hook event** 表示生命周期节点,**matcher group** 表示筛选器,**hook handler** 表示运行的 shell 命令、prompt 或 Agent。单独使用 **Hook** 时表示整个功能。
</Note>Hook locations
Hook 位置
Where you define a hook determines its scope:
| Location | Scope | Shareable |
|---|---|---|
| All your projects | No, local to your machine |
| Single project | Yes, can be committed to the repo |
| Single project | No, gitignored |
| Managed policy settings | Organization-wide | Yes, admin-controlled |
Plugin | When plugin is enabled | Yes, bundled with the plugin |
| Skill or agent frontmatter | While the component is active | Yes, defined in the component file |
For details on settings file resolution, see settings. Enterprise administrators can use to block user, project, and plugin hooks. See Hook configuration.
allowManagedHooksOnly定义 Hook 的位置决定其作用域:
| 位置 | 作用域 | 可共享 |
|---|---|---|
| 所有项目 | 否,仅限本机 |
| 单个项目 | 是,可以提交到仓库 |
| 单个项目 | 否,已被 Git 忽略 |
| 托管策略设置 | 组织范围 | 是,由管理员控制 |
Plugin | 启用 Plugin 时 | 是,随 Plugin 一起分发 |
| Skill 或 agent frontmatter | 组件处于活动状态时 | 是,在组件文件中定义 |
有关 settings 文件解析方式的详细信息,请参阅 settings。企业管理员可以使用 阻止用户、项目和 Plugin Hooks。有关详细信息,请参阅 Hook configuration。
allowManagedHooksOnlyMatcher patterns
Matcher 模式
The field is a regex string that filters when hooks fire. Use , , or omit entirely to match all occurrences. Each event type matches on a different field:
matcher"*"""matcher| Event | What the matcher filters | Example matcher values |
|---|---|---|
| tool name | |
| how the session started | |
| why the session ended | |
| notification type | |
| agent type | |
| what triggered compaction | |
| agent type | same values as |
| no matcher support | always fires on every occurrence |
The matcher is a regex, so matches either tool and matches any tool starting with Notebook. The matcher runs against a field from the JSON input that Claude Code sends to your hook on stdin. For tool events, that field is . Each hook event section lists the full set of matcher values and the input schema for that event.
Edit|WriteNotebook.*tool_nameThis example runs a linting script only when Claude writes or edits a file:
json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "/path/to/lint-check.sh"
}
]
}
]
}
}UserPromptSubmitStopmatchermatcher"*"""matcher| 事件 | matcher 筛选的内容 | matcher 示例值 |
|---|---|---|
| 工具名称 | |
| 会话启动方式 | |
| 会话结束原因 | |
| 通知类型 | |
| Agent 类型 | |
| 触发压缩的原因 | |
| Agent 类型 | 与 |
| 不支持 matcher | 每次出现时始终触发 |
Matcher 是正则表达式,因此 可以匹配任一工具, 可以匹配所有以 Notebook 开头的工具。Matcher 会针对 Claude Code 通过 stdin 发送给 Hook 的 JSON 输入中的某个字段运行。对于工具事件,该字段为 。每个 hook event章节都列出了完整的 matcher 值和输入 schema。
Edit|WriteNotebook.*tool_name此示例仅在 Claude 写入或编辑文件时运行 lint 脚本:
json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "/path/to/lint-check.sh"
}
]
}
]
}
}UserPromptSubmitStopmatcherMatch MCP tools
匹配 MCP 工具
MCP server tools appear as regular tools in tool events (, , , ), so you can match them the same way you match any other tool name.
PreToolUsePostToolUsePostToolUseFailurePermissionRequestMCP tools follow the naming pattern , for example:
mcp__<server>__<tool>- : Memory server's create entities tool
mcp__memory__create_entities - : Filesystem server's read file tool
mcp__filesystem__read_file - : GitHub server's search tool
mcp__github__search_repositories
Use regex patterns to target specific MCP tools or groups of tools:
- matches all tools from the
mcp__memory__.*servermemory - matches any tool containing "write" from any server
mcp__.*__write.*
This example logs all memory server operations and validates write operations from any MCP server:
json
{
"hooks": {
"PreToolUse": [
{
"matcher": "mcp__memory__.*",
"hooks": [
{
"type": "command",
"command": "echo 'Memory operation initiated' >> ~/mcp-operations.log"
}
]
},
{
"matcher": "mcp__.*__write.*",
"hooks": [
{
"type": "command",
"command": "/home/user/scripts/validate-mcp-write.py"
}
]
}
]
}
}MCP server 工具会像常规工具一样出现在工具事件(、、、)中,因此可以使用与常规工具名称相同的方式进行匹配。
PreToolUsePostToolUsePostToolUseFailurePermissionRequestMCP 工具遵循 命名模式,例如:
mcp__<server>__<tool>- :Memory server 的创建实体工具
mcp__memory__create_entities - :Filesystem server 的读取文件工具
mcp__filesystem__read_file - :GitHub server 的搜索仓库工具
mcp__github__search_repositories
使用正则表达式模式可以定位特定 MCP 工具或工具组:
- 匹配
mcp__memory__.*server 的所有工具memory - 匹配任意 server 中名称包含“write”的工具
mcp__.*__write.*
此示例记录所有 memory server 操作,并验证任意 MCP server 的写操作:
json
{
"hooks": {
"PreToolUse": [
{
"matcher": "mcp__memory__.*",
"hooks": [
{
"type": "command",
"command": "echo 'Memory operation initiated' >> ~/mcp-operations.log"
}
]
},
{
"matcher": "mcp__.*__write.*",
"hooks": [
{
"type": "command",
"command": "/home/user/scripts/validate-mcp-write.py"
}
]
}
]
}
}Hook handler fields
Hook handler 字段
Each object in the inner array is a hook handler: the shell command, LLM prompt, or agent that runs when the matcher matches. There are three types:
hooks- Command hooks (): run a shell command. Your script receives the event's JSON input on stdin and communicates results back through exit codes and stdout.
type: "command" - Prompt hooks (): send a prompt to a Claude model for single-turn evaluation. The model returns a yes/no decision as JSON. See Prompt-based hooks.
type: "prompt" - Agent hooks (): spawn a subagent that can use tools like Read, Grep, and Glob to verify conditions before returning a decision. See Agent-based hooks.
type: "agent"
内部 数组中的每个对象都是一个 Hook handler,即 matcher 匹配后运行的 shell 命令、LLM prompt 或 Agent。共有三种类型:
hooks- Command hooks():运行 shell 命令。脚本通过 stdin 接收事件的 JSON 输入,并通过退出码和 stdout 传达结果。
type: "command" - Prompt hooks():将 prompt 发送给 Claude 模型进行单轮评估。模型返回 yes/no 决策 JSON。有关详细信息,请参阅 Prompt-based hooks。
type: "prompt" - Agent hooks():创建 subagent,使其可以使用 Read、Grep 和 Glob 等工具验证条件,然后返回决策。有关详细信息,请参阅 Agent-based hooks。
type: "agent"
Common fields
通用字段
These fields apply to all hook types:
| Field | Required | Description |
|---|---|---|
| yes | |
| no | Seconds before canceling. Defaults: 600 for command, 30 for prompt, 60 for agent |
| no | Custom spinner message displayed while the hook runs |
| no | If |
以下字段适用于所有 Hook 类型:
| 字段 | 必需 | 说明 |
|---|---|---|
| 是 | |
| 否 | 取消前的秒数。默认值:command 为 600,prompt 为 30,agent 为 60 |
| 否 | Hook 运行期间显示的自定义加载提示信息 |
| 否 | 如果为 |
Command hook fields
Command hook 字段
In addition to the common fields, command hooks accept these fields:
| Field | Required | Description |
|---|---|---|
| yes | Shell command to execute |
| no | If |
除通用字段外,command Hooks 还接受以下字段:
| 字段 | 必需 | 说明 |
|---|---|---|
| 是 | 要执行的 shell 命令 |
| 否 | 如果为 |
Prompt and agent hook fields
Prompt 和 Agent hook 字段
In addition to the common fields, prompt and agent hooks accept these fields:
| Field | Required | Description |
|---|---|---|
| yes | Prompt text to send to the model. Use |
| no | Model to use for evaluation. Defaults to a fast model |
All matching hooks run in parallel, and identical handlers are deduplicated automatically. Handlers run in the current directory with Claude Code's environment. The environment variable is set to in remote web environments and not set in the local CLI.
$CLAUDE_CODE_REMOTE"true"除通用字段外,prompt 和 Agent Hooks 还接受以下字段:
| 字段 | 必需 | 说明 |
|---|---|---|
| 是 | 发送给模型的 prompt 文本。使用 |
| 否 | 用于评估的模型,默认为快速模型 |
所有匹配的 Hooks 都会并行运行,完全相同的处理器会被自动去重。处理器在当前目录中运行,并使用 Claude Code 的环境。远程 Web 环境中会设置 环境变量并将其设为 ,本地 CLI 中不会设置该变量。
$CLAUDE_CODE_REMOTE"true"Reference scripts by path
通过路径引用脚本
Use environment variables to reference hook scripts relative to the project or plugin root, regardless of the working directory when the hook runs:
- : the project root. Wrap in quotes to handle paths with spaces.
$CLAUDE_PROJECT_DIR - : the plugin's root directory, for scripts bundled with a plugin.
${CLAUDE_PLUGIN_ROOT}
```json theme={null}
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/check-style.sh"
}
]
}
]
}
}
```This example runs a formatting script bundled with the plugin:
```json theme={null}
{
"description": "Automatic code formatting",
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh",
"timeout": 30
}
]
}
]
}
}
```
See the [plugin components reference](/en/plugins-reference#hooks) for details on creating plugin hooks.使用环境变量引用相对于项目或 Plugin 根目录的 Hook 脚本,无论 Hook 运行时的工作目录是什么:
- :项目根目录。添加引号以处理包含空格的路径。
$CLAUDE_PROJECT_DIR - :Plugin 的根目录,用于存放随 plugin 一起分发的脚本。
${CLAUDE_PLUGIN_ROOT}
```json theme={null}
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/check-style.sh"
}
]
}
]
}
}
```此示例运行随 Plugin 一起分发的格式化脚本:
```json theme={null}
{
"description": "Automatic code formatting",
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh",
"timeout": 30
}
]
}
]
}
}
```
有关创建 Plugin Hooks 的详细信息,请参阅 [plugin components reference](/en/plugins-reference#hooks)。Hooks in skills and agents
Skills 和 Agents 中的 Hooks
In addition to settings files and plugins, hooks can be defined directly in skills and subagents using frontmatter. These hooks are scoped to the component's lifecycle and only run when that component is active.
All hook events are supported. For subagents, hooks are automatically converted to since that is the event that fires when a subagent completes.
StopSubagentStopHooks use the same configuration format as settings-based hooks but are scoped to the component's lifetime and cleaned up when it finishes.
This skill defines a hook that runs a security validation script before each command:
PreToolUseBashyaml
---
name: secure-operations
description: Perform operations with security checks
hooks:
PreToolUse:
- matcher: "Bash"
hooks:
- type: command
command: "./scripts/security-check.sh"
---Agents use the same format in their YAML frontmatter.
除 settings 文件和 Plugins 外,还可以直接使用 frontmatter 在 skills 和 subagents 中定义 Hooks。这些 Hooks 的作用域限定为组件生命周期,只在组件处于活动状态时运行。
支持所有 Hook 事件。对于 subagents, Hooks 会自动转换为 ,因为 subagent 完成时触发的是该事件。
StopSubagentStopHooks 使用与基于 settings 的 Hooks 相同的配置格式,但作用域限定为组件生命周期,并在组件完成时清理。
此 Skill 定义了一个 Hook,用于在每条 命令前运行安全验证脚本:
PreToolUseBashyaml
---
name: secure-operations
description: Perform operations with security checks
hooks:
PreToolUse:
- matcher: "Bash"
hooks:
- type: command
command: "./scripts/security-check.sh"
---Agents 在 YAML frontmatter 中使用相同格式。
The /hooks
menu
/hooks/hooks
菜单
/hooksType in Claude Code to open the interactive hooks manager, where you can view, add, and delete hooks without editing settings files directly. For a step-by-step walkthrough, see Set up your first hook in the guide.
/hooksEach hook in the menu is labeled with a bracket prefix indicating its source:
- : from
[User]~/.claude/settings.json - : from
[Project].claude/settings.json - : from
[Local].claude/settings.local.json - : from a plugin's
[Plugin], read-onlyhooks/hooks.json
在 Claude Code 中输入 打开交互式 Hooks 管理器,无需直接编辑 settings 文件即可查看、添加和删除 Hooks。有关分步演练,请参阅指南中的 Set up your first hook。
/hooks菜单中的每个 Hook 都使用方括号前缀标示来源:
- :来自
[User]~/.claude/settings.json - :来自
[Project].claude/settings.json - :来自
[Local].claude/settings.local.json - :来自 Plugin 的
[Plugin],只读hooks/hooks.json
Disable or remove hooks
禁用或移除 Hooks
To remove a hook, delete its entry from the settings JSON file, or use the menu and select the hook to delete it.
/hooksTo temporarily disable all hooks without removing them, set in your settings file or use the toggle in the menu. There is no way to disable an individual hook while keeping it in the configuration.
"disableAllHooks": true/hooksDirect edits to hooks in settings files don't take effect immediately. Claude Code captures a snapshot of hooks at startup and uses it throughout the session. This prevents malicious or accidental hook modifications from taking effect mid-session without your review. If hooks are modified externally, Claude Code warns you and requires review in the menu before changes apply.
/hooks要移除 Hook,请删除 settings JSON 文件中的对应条目,或使用 菜单并选择要删除的 Hook。
/hooks如果只想临时禁用所有 Hooks 而不将其移除,可以在 settings 文件中设置 ,或使用 菜单中的开关。无法在保留配置的情况下单独禁用某个 Hook。
"disableAllHooks": true/hooks在 settings 文件中直接编辑 Hooks 不会立即生效。Claude Code 会在启动时捕获 Hooks 快照,并在整个会话中使用该快照。这样可以防止恶意或意外的 Hook 修改在未经审查的情况下于会话中途生效。如果 Hooks 被外部修改,Claude Code 会发出警告,并要求先在 菜单中审查更改,然后才会应用。
/hooksHook input and output
Hook 输入和输出
Hooks receive JSON data via stdin and communicate results through exit codes, stdout, and stderr. This section covers fields and behavior common to all events. Each event's section under Hook events includes its specific input schema and decision control options.
Hooks 通过 stdin 接收 JSON 数据,并通过退出码、stdout 和 stderr 传达结果。本节介绍所有事件共有的字段和行为。每个事件在 Hook events下的对应章节都会介绍其专用输入 schema 和决策控制选项。
Common input fields
通用输入字段
All hook events receive these fields via stdin as JSON, in addition to event-specific fields documented in each hook event section:
| Field | Description |
|---|---|
| Current session identifier |
| Path to conversation JSON |
| Current working directory when the hook is invoked |
| Current permission mode: |
| Name of the event that fired |
For example, a hook for a Bash command receives this on stdin:
PreToolUsejson
{
"session_id": "abc123",
"transcript_path": "/home/user/.claude/projects/.../transcript.jsonl",
"cwd": "/home/user/my-project",
"permission_mode": "default",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": {
"command": "npm test"
}
}The and fields are event-specific. Each hook event section documents the additional fields for that event.
tool_nametool_input除各事件在 Hook events下记录的专用字段外,所有 Hook 事件都会通过 stdin 接收以下 JSON 字段:
| 字段 | 说明 |
|---|---|
| 当前会话标识符 |
| 对话 JSON 的路径 |
| 调用 Hook 时的工作目录 |
| 当前权限模式: |
| 触发的事件名称 |
例如,用于 Bash 命令的 Hook 会在 stdin 中收到以下内容:
PreToolUsejson
{
"session_id": "abc123",
"transcript_path": "/home/user/.claude/projects/.../transcript.jsonl",
"cwd": "/home/user/my-project",
"permission_mode": "default",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": {
"command": "npm test"
}
}Exit code output
退出码输出
The exit code from your hook command tells Claude Code whether the action should proceed, be blocked, or be ignored.
Exit 0 means success. Claude Code parses stdout for JSON output fields. JSON output is only processed on exit 0. For most events, stdout is only shown in verbose mode (). The exceptions are and , where stdout is added as context that Claude can see and act on.
Ctrl+OUserPromptSubmitSessionStartExit 2 means a blocking error. Claude Code ignores stdout and any JSON in it. Instead, stderr text is fed back to Claude as an error message. The effect depends on the event: blocks the tool call, rejects the prompt, and so on. See exit code 2 behavior for the full list.
PreToolUseUserPromptSubmitAny other exit code is a non-blocking error. stderr is shown in verbose mode () and execution continues.
Ctrl+OFor example, a hook command script that blocks dangerous Bash commands:
bash
#!/bin/bashHook 命令的退出码会告知 Claude Code 应继续、阻止还是忽略操作。
退出 0 表示成功。Claude Code 会解析 stdout 中的 JSON 输出字段。只有退出 0 时才会处理 JSON 输出。对于大多数事件,stdout 只会在详细模式()中显示。例外情况是 和 ,它们的 stdout 会作为 Claude 可以看到并采取行动的上下文添加进去。
Ctrl+OUserPromptSubmitSessionStart退出 2 表示阻止错误。Claude Code 会忽略 stdout 及其中的任何 JSON,而是将 stderr 文本作为错误消息反馈给 Claude。具体效果取决于事件: 会阻止工具调用, 会拒绝 prompt,依此类推。有关完整列表,请参阅 exit code 2 behavior。
PreToolUseUserPromptSubmit其他退出码 表示非阻止错误。stderr 会在详细模式()中显示,执行会继续。
Ctrl+O例如,以下 Hook 命令脚本会阻止危险的 Bash 命令:
bash
#!/bin/bashReads JSON input from stdin, checks the command
Reads JSON input from stdin, checks the command
command=$(jq -r '.tool_input.command' < /dev/stdin)
if [[ "$command" == rm* ]]; then
echo "Blocked: rm commands are not allowed" >&2
exit 2 # Blocking error: tool call is prevented
fi
exit 0 # Success: tool call proceeds
undefinedcommand=$(jq -r '.tool_input.command' < /dev/stdin)
if [[ "$command" == rm* ]]; then
echo "Blocked: rm commands are not allowed" >&2
exit 2 # Blocking error: tool call is prevented
fi
exit 0 # Success: tool call proceeds
undefinedExit code 2 behavior per event
各事件的退出码 2 行为
Exit code 2 is the way a hook signals "stop, don't do this." The effect depends on the event, because some events represent actions that can be blocked (like a tool call that hasn't happened yet) and others represent things that already happened or can't be prevented.
| Hook event | Can block? | What happens on exit 2 |
|---|---|---|
| Yes | Blocks the tool call |
| Yes | Denies the permission |
| Yes | Blocks prompt processing and erases the prompt |
| Yes | Prevents Claude from stopping, continues the conversation |
| Yes | Prevents the subagent from stopping |
| No | Shows stderr to Claude (tool already ran) |
| No | Shows stderr to Claude (tool already failed) |
| No | Shows stderr to user only |
| No | Shows stderr to user only |
| No | Shows stderr to user only |
| No | Shows stderr to user only |
| No | Shows stderr to user only |
退出码 2 是 Hook 表示“停止,不要这样做”的方式。其效果取决于事件,因为有些事件代表尚未发生且可以阻止的操作,而其他事件代表已经发生或无法阻止的事情。
| Hook 事件 | 可以阻止? | 退出 2 时的行为 |
|---|---|---|
| 是 | 阻止工具调用 |
| 是 | 拒绝权限请求 |
| 是 | 阻止处理 prompt 并将其从上下文中删除 |
| 是 | 阻止 Claude 停止并继续对话 |
| 是 | 阻止 subagent 停止 |
| 否 | 向 Claude 显示 stderr(工具已运行) |
| 否 | 向 Claude 显示 stderr(工具已失败) |
| 否 | 仅向用户显示 stderr |
| 否 | 仅向用户显示 stderr |
| 否 | 仅向用户显示 stderr |
| 否 | 仅向用户显示 stderr |
| 否 | 仅向用户显示 stderr |
JSON output
JSON 输出
Exit codes let you allow or block, but JSON output gives you finer-grained control. Instead of exiting with code 2 to block, exit 0 and print a JSON object to stdout. Claude Code reads specific fields from that JSON to control behavior, including decision control for blocking, allowing, or escalating to the user.
<Note>
You must choose one approach per hook, not both: either use exit codes alone for signaling, or exit 0 and print JSON for structured control. Claude Code only processes JSON on exit 0. If you exit 2, any JSON is ignored.
</Note>
Your hook's stdout must contain only the JSON object. If your shell profile prints text on startup, it can interfere with JSON parsing. See JSON validation failed in the troubleshooting guide.
The JSON object supports three kinds of fields:
- Universal fields like work across all events. These are listed in the table below.
continue - Top-level and
decisionare used by some events to block or provide feedback.reason - is a nested object for events that need richer control. It requires a
hookSpecificOutputfield set to the event name.hookEventName
| Field | Default | Description |
|---|---|---|
| | If |
| none | Message shown to the user when |
| | If |
| none | Warning message shown to the user |
To stop Claude entirely regardless of event type:
json
{ "continue": false, "stopReason": "Build failed, fix errors before continuing" }退出码只允许允许或阻止两种结果,而 JSON 输出可以提供更精细的控制。可以退出 0 并将 JSON 对象输出到 stdout,而不是使用退出码 2 阻止操作。Claude Code 会读取该 JSON 中的特定字段来控制行为,包括用于阻止、允许或升级给用户的决策控制。
<Note>
每个 Hook 必须选择一种方式,不能同时使用:根据信号使用退出码,或者退出 0 并输出 JSON 进行结构化控制。Claude Code 只在退出 0 时处理 JSON。如果退出 2,JSON 会被忽略。
</Note>
Hook 的 stdout 必须只包含 JSON 对象。如果 shell 配置文件在启动时输出文本,可能会干扰 JSON 解析。请参阅故障排除指南中的 JSON validation failed。
JSON 对象支持三类字段:
- 通用字段,例如适用于所有事件的
continue - 顶层 和
decision,用于某些事件阻止操作或提供反馈reason - ,用于需要更丰富控制的事件。它要求包含设置为事件名称的
hookSpecificOutput字段hookEventName
| 字段 | 默认值 | 说明 |
|---|---|---|
| | 如果为 |
| 无 | 当 |
| | 如果为 |
| 无 | 展示给用户的警告消息 |
无论事件类型如何,要完全停止 Claude:
json
{ "continue": false, "stopReason": "Build failed, fix errors before continuing" }Decision control
决策控制
Not every event supports blocking or controlling behavior through JSON. The events that do each use a different set of fields to express that decision. Use this table as a quick reference before writing a hook:
| Events | Decision pattern | Key fields |
|---|---|---|
| UserPromptSubmit, PostToolUse, PostToolUseFailure, Stop, SubagentStop | Top-level | |
| PreToolUse | | |
| PermissionRequest | | |
Here are examples of each pattern in action:
<Tabs>
<Tab title="Top-level decision">
Used by `UserPromptSubmit`, `PostToolUse`, `PostToolUseFailure`, `Stop`, and `SubagentStop`. The only value is `"block"` — to allow the action to proceed, omit `decision` from your JSON, or exit 0 without any JSON at all:
```json theme={null}
{
"decision": "block",
"reason": "Test suite must pass before proceeding"
}
``````json theme={null}
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Database writes are not allowed"
}
}
``````json theme={null}
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow",
"updatedInput": {
"command": "npm run lint"
}
}
}
}
```For extended examples including Bash command validation, prompt filtering, and auto-approval scripts, see What you can automate in the guide and the Bash command validator reference implementation.
并非所有事件都支持通过 JSON 阻止或控制行为。支持的事件分别使用不同字段表达决策。编写 Hook 前,可使用此表快速查阅:
| 事件 | 决策模式 | 关键字段 |
|---|---|---|
| UserPromptSubmit、PostToolUse、PostToolUseFailure、Stop、SubagentStop | 顶层 | |
| PreToolUse | | |
| PermissionRequest | | |
以下是每种模式的应用示例:
<Tabs>
<Tab title="顶层 decision">
用于 `UserPromptSubmit`、`PostToolUse`、`PostToolUseFailure`、`Stop` 和 `SubagentStop`。唯一值为 `"block"`。若要允许操作继续,请省略 `decision` 字段,或退出 0 且不输出任何 JSON:
```json theme={null}
{
"decision": "block",
"reason": "Test suite must pass before proceeding"
}
``````json theme={null}
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Database writes are not allowed"
}
}
``````json theme={null}
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow",
"updatedInput": {
"command": "npm run lint"
}
}
}
}
```有关 Bash 命令验证、prompt 过滤和自动批准脚本的更多示例,请参阅指南中的 What you can automate以及 Bash command validator reference implementation。
Hook events
Hook 事件
Each event corresponds to a point in Claude Code's lifecycle where hooks can run. The sections below are ordered to match the lifecycle: from session setup through the agentic loop to session end. Each section describes when the event fires, what matchers it supports, the JSON input it receives, and how to control behavior through output.
每个事件都对应 Claude Code 生命周期中的一个节点,Hooks 可以在该节点运行。以下章节按生命周期顺序排列:从会话设置、Agent 循环到会话结束。每个章节都会说明事件的触发时机、支持的 matcher、接收的 JSON 输入以及可以控制行为的输出方式。
SessionStart
SessionStart
Runs when Claude Code starts a new session or resumes an existing session. Useful for loading development context like existing issues or recent changes to your codebase, or setting up environment variables. For static context that does not require a script, use CLAUDE.md instead.
SessionStart runs on every session, so keep these hooks fast.
The matcher value corresponds to how the session was initiated:
| Matcher | When it fires |
|---|---|
| New session |
| |
| |
| Auto or manual compaction |
在 Claude Code 启动新会话或恢复现有会话时运行。适用于加载开发上下文,例如现有 issue 或代码库的近期变更,也可用于设置环境变量。对于不需要脚本的静态上下文,请改用 CLAUDE.md。
SessionStart 会在每个会话中运行,因此这些 Hooks 应保持快速执行。
Matcher 值对应会话的启动方式:
| Matcher | 触发时机 |
|---|---|
| 新会话 |
| |
| |
| 自动或手动压缩 |
SessionStart input
SessionStart 输入
In addition to the common input fields, SessionStart hooks receive , , and optionally . The field indicates how the session started: for new sessions, for resumed sessions, after , or after compaction. The field contains the model identifier. If you start Claude Code with , an field contains the agent name.
sourcemodelagent_typesource"startup""resume""clear"/clear"compact"modelclaude --agent <name>agent_typejson
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "SessionStart",
"source": "startup",
"model": "claude-sonnet-4-5-20250929"
}除通用输入字段外,SessionStart Hooks 还会接收 、 和可选的 。 字段表示会话的启动方式:新会话为 ,恢复会话为 ,执行 后为 ,压缩后为 。 字段包含模型标识符。如果使用 启动 Claude Code, 字段会包含 Agent 名称。
sourcemodelagent_typesource"startup""resume"/clear"clear""compact"modelclaude --agent <name>agent_typejson
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "SessionStart",
"source": "startup",
"model": "claude-sonnet-4-5-20250929"
}SessionStart decision control
SessionStart 决策控制
Any text your hook script prints to stdout is added as context for Claude. In addition to the JSON output fields available to all hooks, you can return these event-specific fields:
| Field | Description |
|---|---|
| String added to Claude's context. Multiple hooks' values are concatenated |
json
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "My additional context here"
}
}Hook 脚本输出到 stdout 的任何文本都会作为上下文添加到 Claude 中。除所有 Hook 均可使用的 JSON 输出字段外,还可以返回以下事件专用字段:
| 字段 | 说明 |
|---|---|
| 添加到 Claude 上下文的字符串。多个 Hook 的值会连接在一起 |
json
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "My additional context here"
}
}Persist environment variables
持久化环境变量
SessionStart hooks have access to the environment variable, which provides a file path where you can persist environment variables for subsequent Bash commands.
CLAUDE_ENV_FILETo set individual environment variables, write statements to . Use append () to preserve variables set by other hooks:
exportCLAUDE_ENV_FILE>>bash
#!/bin/bash
if [ -n "$CLAUDE_ENV_FILE" ]; then
echo 'export NODE_ENV=production' >> "$CLAUDE_ENV_FILE"
echo 'export DEBUG_LOG=true' >> "$CLAUDE_ENV_FILE"
echo 'export PATH="$PATH:./node_modules/.bin"' >> "$CLAUDE_ENV_FILE"
fi
exit 0To capture all environment changes from setup commands, compare the exported variables before and after:
bash
#!/bin/bash
ENV_BEFORE=$(export -p | sort)SessionStart Hooks 可以访问 环境变量,该变量提供一个文件路径,用于持久化后续 Bash 命令使用的环境变量。
CLAUDE_ENV_FILE要设置单个环境变量,请将 语句写入 。使用 追加,以保留其他 Hook 设置的变量:
exportCLAUDE_ENV_FILE>>bash
#!/bin/bash
if [ -n "$CLAUDE_ENV_FILE" ]; then
echo 'export NODE_ENV=production' >> "$CLAUDE_ENV_FILE"
echo 'export DEBUG_LOG=true' >> "$CLAUDE_ENV_FILE"
echo 'export PATH="$PATH:./node_modules/.bin"' >> "$CLAUDE_ENV_FILE"
fi
exit 0若要捕获设置命令所做的所有环境变更,请比较执行前后的导出变量:
bash
#!/bin/bash
ENV_BEFORE=$(export -p | sort)Run your setup commands that modify the environment
Run your setup commands that modify the environment
source ~/.nvm/nvm.sh
nvm use 20
if [ -n "$CLAUDE_ENV_FILE" ]; then
ENV_AFTER=$(export -p | sort)
comm -13 <(echo "$ENV_BEFORE") <(echo "$ENV_AFTER") >> "$CLAUDE_ENV_FILE"
fi
exit 0
Any variables written to this file will be available in all subsequent Bash commands that Claude Code executes during the session.
<Note>
`CLAUDE_ENV_FILE` is available for SessionStart hooks. Other hook types do not have access to this variable.
</Note>source ~/.nvm/nvm.sh
nvm use 20
if [ -n "$CLAUDE_ENV_FILE" ]; then
ENV_AFTER=$(export -p | sort)
comm -13 <(echo "$ENV_BEFORE") <(echo "$ENV_AFTER") >> "$CLAUDE_ENV_FILE"
fi
exit 0
写入此文件的所有变量都将在会话期间 Claude Code 后续执行的所有 Bash 命令中可用。
<Note>
`CLAUDE_ENV_FILE` 仅适用于 SessionStart Hooks,其他 Hook 类型无法访问此变量。
</Note>UserPromptSubmit
UserPromptSubmit
Runs when the user submits a prompt, before Claude processes it. This allows you
to add additional context based on the prompt/conversation, validate prompts, or
block certain types of prompts.
在用户提交 prompt 后、Claude 处理之前运行。允许你根据 prompt 或对话添加额外上下文、验证 prompt,或阻止特定类型的 prompt。
UserPromptSubmit input
UserPromptSubmit 输入
In addition to the common input fields, UserPromptSubmit hooks receive the field containing the text the user submitted.
promptjson
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "UserPromptSubmit",
"prompt": "Write a function to calculate the factorial of a number"
}除通用输入字段外,UserPromptSubmit Hooks 还会接收 字段,其中包含用户提交的文本。
promptjson
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "UserPromptSubmit",
"prompt": "Write a function to calculate the factorial of a number"
}UserPromptSubmit decision control
UserPromptSubmit 决策控制
UserPromptSubmitThere are two ways to add context to the conversation on exit code 0:
- Plain text stdout: any non-JSON text written to stdout is added as context
- JSON with : use the JSON format below for more control. The
additionalContextfield is added as contextadditionalContext
Plain stdout is shown as hook output in the transcript. The field is added more discretely.
additionalContextTo block a prompt, return a JSON object with set to :
decision"block"| Field | Description |
|---|---|
| |
| Shown to the user when |
| String added to Claude's context |
json
{
"decision": "block",
"reason": "Explanation for decision",
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "My additional context here"
}
}UserPromptSubmit Hooks 可以控制用户 prompt 是否被处理,并添加上下文。所有 JSON 输出字段均可使用。
退出码为 0 时,可以通过两种方式将上下文添加到对话:
- 纯文本 stdout:写入 stdout 的任何非 JSON 文本都会作为上下文添加
- 包含 的 JSON:使用以下 JSON 格式进行更精确的控制。
additionalContext字段会作为上下文添加additionalContext
纯 stdout 会作为 Hook 输出显示在记录中,而 字段的添加方式更隐蔽。
additionalContext要阻止 prompt,请返回将 设置为 的 JSON 对象:
decision"block"| 字段 | 说明 |
|---|---|
| |
| 当 |
| 添加到 Claude 上下文的字符串 |
json
{
"decision": "block",
"reason": "Explanation for decision",
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "My additional context here"
}
}PreToolUse
PreToolUse
Runs after Claude creates tool parameters and before processing the tool call. Matches on tool name: , , , , , , , , , and any MCP tool names.
BashEditWriteReadGlobGrepTaskWebFetchWebSearchUse PreToolUse decision control to allow, deny, or ask for permission to use the tool.
在 Claude 创建工具参数后、处理工具调用之前运行。按工具名称匹配:、、、、、、、、 以及任意 MCP 工具名称。
BashEditWriteReadGlobGrepTaskWebFetchWebSearch使用 PreToolUse 决策控制允许、拒绝或请求用户授权使用工具。
PreToolUse input
PreToolUse 输入
In addition to the common input fields, PreToolUse hooks receive , , and . The fields depend on the tool:
tool_nametool_inputtool_use_idtool_inputBash
Bash
Executes shell commands.
| Field | Type | Example | Description |
|---|---|---|---|
| string | | The shell command to execute |
| string | | Optional description of what the command does |
| number | | Optional timeout in milliseconds |
| boolean | | Whether to run the command in background |
执行 shell 命令。
| 字段 | 类型 | 示例 | 说明 |
|---|---|---|---|
| string | | 要执行的 shell 命令 |
| string | | 命令用途的可选说明 |
| number | | 可选超时时间,单位为毫秒 |
| boolean | | 是否在后台运行命令 |
Write
Write
Creates or overwrites a file.
| Field | Type | Example | Description |
|---|---|---|---|
| string | | Absolute path to the file to write |
| string | | Content to write to the file |
创建或覆盖文件。
| 字段 | 类型 | 示例 | 说明 |
|---|---|---|---|
| string | | 要写入文件的绝对路径 |
| string | | 要写入文件的内容 |
Edit
Edit
Replaces a string in an existing file.
| Field | Type | Example | Description |
|---|---|---|---|
| string | | Absolute path to the file to edit |
| string | | Text to find and replace |
| string | | Replacement text |
| boolean | | Whether to replace all occurrences |
替换现有文件中的字符串。
| 字段 | 类型 | 示例 | 说明 |
|---|---|---|---|
| string | | 要编辑文件的绝对路径 |
| string | | 要查找并替换的文本 |
| string | | 替换文本 |
| boolean | | 是否替换所有匹配项 |
Read
Read
Reads file contents.
| Field | Type | Example | Description |
|---|---|---|---|
| string | | Absolute path to the file to read |
| number | | Optional line number to start reading from |
| number | | Optional number of lines to read |
读取文件内容。
| 字段 | 类型 | 示例 | 说明 |
|---|---|---|---|
| string | | 要读取文件的绝对路径 |
| number | | 可选起始行号 |
| number | | 可选读取行数 |
Glob
Glob
Finds files matching a glob pattern.
| Field | Type | Example | Description |
|---|---|---|---|
| string | | Glob pattern to match files against |
| string | | Optional directory to search in. Defaults to current working directory |
查找与 glob 模式匹配的文件。
| 字段 | 类型 | 示例 | 说明 |
|---|---|---|---|
| string | | 用于匹配文件的 glob 模式 |
| string | | 可选搜索目录,默认为当前工作目录 |
Grep
Grep
Searches file contents with regular expressions.
| Field | Type | Example | Description |
|---|---|---|---|
| string | | Regular expression pattern to search for |
| string | | Optional file or directory to search in |
| string | | Optional glob pattern to filter files |
| string | | |
| boolean | | Case insensitive search |
| boolean | | Enable multiline matching |
使用正则表达式搜索文件内容。
| 字段 | 类型 | 示例 | 说明 |
|---|---|---|---|
| string | | 要搜索的正则表达式模式 |
| string | | 可选文件或目录搜索路径 |
| string | | 可选文件 glob 过滤模式 |
| string | | |
| boolean | | 区分大小写 |
| boolean | | 启用多行匹配 |
WebFetch
WebFetch
Fetches and processes web content.
| Field | Type | Example | Description |
|---|---|---|---|
| string | | URL to fetch content from |
| string | | Prompt to run on the fetched content |
获取并处理 Web 内容。
| 字段 | 类型 | 示例 | 说明 |
|---|---|---|---|
| string | | 要获取内容的 URL |
| string | | 用于处理已获取内容的 prompt |
WebSearch
WebSearch
Searches the web.
| Field | Type | Example | Description |
|---|---|---|---|
| string | | Search query |
| array | | Optional: only include results from these domains |
| array | | Optional: exclude results from these domains |
搜索 Web。
| 字段 | 类型 | 示例 | 说明 |
|---|---|---|---|
| string | | 搜索查询 |
| array | | 可选,仅包含这些域名的结果 |
| array | | 可选,排除这些域名的结果 |
Task
Task
Spawns a subagent.
| Field | Type | Example | Description |
|---|---|---|---|
| string | | The task for the agent to perform |
| string | | Short description of the task |
| string | | Type of specialized agent to use |
| string | | Optional model alias to override the default |
创建 subagent。
| 字段 | 类型 | 示例 | 说明 |
|---|---|---|---|
| string | | Agent 要执行的任务 |
| string | | 任务的简短说明 |
| string | | 要使用的专用 Agent 类型 |
| string | | 可选模型别名,用于覆盖默认模型 |
PreToolUse decision control
PreToolUse 决策控制
PreToolUsedecisionhookSpecificOutput| Field | Description |
|---|---|
| |
| For |
| Modifies the tool's input parameters before execution. Combine with |
| String added to Claude's context before the tool executes |
json
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"permissionDecisionReason": "My reason here",
"updatedInput": {
"field_to_modify": "new value"
},
"additionalContext": "Current environment: production. Proceed with caution."
}
}PreToolUse Hooks 可以控制工具调用是否继续。与使用顶层 字段的其他 Hooks 不同,PreToolUse 在 对象中返回决策。因此它提供更丰富的控制:允许、拒绝或请求确认三种结果,并且可以在执行前修改工具输入。
decisionhookSpecificOutput| 字段 | 说明 |
|---|---|
| |
| 对于 |
| 在执行前修改工具输入参数。与 |
| 在工具执行前添加到 Claude 上下文的字符串 |
json
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"permissionDecisionReason": "My reason here",
"updatedInput": {
"field_to_modify": "new value"
},
"additionalContext": "Current environment: production. Proceed with caution."
}
}PermissionRequest
PermissionRequest
Runs when the user is shown a permission dialog.
Use PermissionRequest decision control to allow or deny on behalf of the user.
Matches on tool name, same values as PreToolUse.
在向用户显示权限对话框时运行。
使用 PermissionRequest 决策控制代表用户允许或拒绝。
按工具名称匹配,取值与 PreToolUse 相同。
PermissionRequest input
PermissionRequest 输入
PermissionRequest hooks receive and fields like PreToolUse hooks, but without . An optional array contains the "always allow" options the user would normally see in the permission dialog. The difference is when the hook fires: PermissionRequest hooks run when a permission dialog is about to be shown to the user, while PreToolUse hooks run before tool execution regardless of permission status.
tool_nametool_inputtool_use_idpermission_suggestionsjson
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PermissionRequest",
"tool_name": "Bash",
"tool_input": {
"command": "rm -rf node_modules",
"description": "Remove node_modules directory"
},
"permission_suggestions": [
{ "type": "toolAlwaysAllow", "tool": "Bash" }
]
}PermissionRequest Hooks 接收与 PreToolUse Hooks 类似的 和 字段,但不包含 。可选的 数组包含用户通常会在权限对话框中看到的“始终允许”选项。两者区别在于触发时机:PermissionRequest Hooks 在权限对话框即将向用户显示时运行,而 PreToolUse Hooks 无论权限状态如何,都会在工具执行前运行。
tool_nametool_inputtool_use_idpermission_suggestionsjson
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PermissionRequest",
"tool_name": "Bash",
"tool_input": {
"command": "rm -rf node_modules",
"description": "Remove node_modules directory"
},
"permission_suggestions": [
{ "type": "toolAlwaysAllow", "tool": "Bash" }
]
}PermissionRequest decision control
PermissionRequest 决策控制
PermissionRequestdecision| Field | Description |
|---|---|
| |
| For |
| For |
| For |
| For |
json
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow",
"updatedInput": {
"command": "npm run lint"
}
}
}
}PermissionRequest Hooks 可以允许或拒绝权限请求。除所有 Hook 均可使用的 JSON 输出字段外,Hook 脚本还可以返回包含以下事件专用字段的 对象:
decision| 字段 | 说明 |
|---|---|
| |
| 仅用于 |
| 仅用于 |
| 仅用于 |
| 仅用于 |
json
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow",
"updatedInput": {
"command": "npm run lint"
}
}
}
}PostToolUse
PostToolUse
Runs immediately after a tool completes successfully.
Matches on tool name, same values as PreToolUse.
在工具成功完成后立即运行。
按工具名称匹配,取值与 PreToolUse 相同。
PostToolUse input
PostToolUse 输入
PostToolUsetool_inputtool_responsejson
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PostToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/file.txt",
"content": "file content"
},
"tool_response": {
"filePath": "/path/to/file.txt",
"success": true
},
"tool_use_id": "toolu_01ABC123..."
}PostToolUse Hooks 在工具成功执行后触发。输入同时包括 (发送给工具的参数)和 (工具返回的结果)。两者的确切 schema 取决于工具。
tool_inputtool_responsejson
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PostToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/file.txt",
"content": "file content"
},
"tool_response": {
"filePath": "/path/to/file.txt",
"success": true
},
"tool_use_id": "toolu_01ABC123..."
}PostToolUse decision control
PostToolUse 决策控制
PostToolUse| Field | Description |
|---|---|
| |
| Explanation shown to Claude when |
| Additional context for Claude to consider |
| For MCP tools only: replaces the tool's output with the provided value |
json
{
"decision": "block",
"reason": "Explanation for decision",
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "Additional information for Claude"
}
}PostToolUse Hooks 可以在工具执行后向 Claude 提供反馈。除所有 Hook 均可使用的 JSON 输出字段外,还可以返回以下事件专用字段:
| 字段 | 说明 |
|---|---|
| |
| 当 |
| Claude 需要考虑的额外上下文 |
| 仅用于 MCP 工具:使用提供的值替换工具输出 |
json
{
"decision": "block",
"reason": "Explanation for decision",
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "Additional information for Claude"
}
}PostToolUseFailure
PostToolUseFailure
Runs when a tool execution fails. This event fires for tool calls that throw errors or return failure results. Use this to log failures, send alerts, or provide corrective feedback to Claude.
Matches on tool name, same values as PreToolUse.
在工具执行失败时运行。对于抛出错误或返回失败结果的工具调用,会触发此事件。可用于记录失败、发送警报或向 Claude 提供纠正反馈。
按工具名称匹配,取值与 PreToolUse 相同。
PostToolUseFailure input
PostToolUseFailure 输入
PostToolUseFailure hooks receive the same and fields as PostToolUse, along with error information as top-level fields:
tool_nametool_inputjson
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PostToolUseFailure",
"tool_name": "Bash",
"tool_input": {
"command": "npm test",
"description": "Run test suite"
},
"tool_use_id": "toolu_01ABC123...",
"error": "Command exited with non-zero status code 1",
"is_interrupt": false
}| Field | Description |
|---|---|
| String describing what went wrong |
| Optional boolean indicating whether the failure was caused by user interruption |
PostToolUseFailure Hooks 接收与 PostToolUse 相同的 和 字段,并将错误信息作为顶层字段提供:
tool_nametool_inputjson
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PostToolUseFailure",
"tool_name": "Bash",
"tool_input": {
"command": "npm test",
"description": "Run test suite"
},
"tool_use_id": "toolu_01ABC123...",
"error": "Command exited with non-zero status code 1",
"is_interrupt": false
}| 字段 | 说明 |
|---|---|
| 描述问题的字符串 |
| 可选布尔值,指示失败是否由用户中断引起 |
PostToolUseFailure decision control
PostToolUseFailure 决策控制
PostToolUseFailure| Field | Description |
|---|---|
| Additional context for Claude to consider alongside the error |
json
{
"hookSpecificOutput": {
"hookEventName": "PostToolUseFailure",
"additionalContext": "Additional information about the failure for Claude"
}
}PostToolUseFailure Hooks 可以在工具失败后向 Claude 提供上下文。除所有 Hook 均可使用的 JSON 输出字段外,还可以返回以下事件专用字段:
| 字段 | 说明 |
|---|---|
| Claude 需要考虑的额外上下文,与错误一同提供 |
json
{
"hookSpecificOutput": {
"hookEventName": "PostToolUseFailure",
"additionalContext": "Additional information about the failure for Claude"
}
}Notification
Notification
Runs when Claude Code sends notifications. Matches on notification type: , , , . Omit the matcher to run hooks for all notification types.
permission_promptidle_promptauth_successelicitation_dialogUse separate matchers to run different handlers depending on the notification type. This configuration triggers a permission-specific alert script when Claude needs permission approval and a different notification when Claude has been idle:
json
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [
{
"type": "command",
"command": "/path/to/permission-alert.sh"
}
]
},
{
"matcher": "idle_prompt",
"hooks": [
{
"type": "command",
"command": "/path/to/idle-notification.sh"
}
]
}
]
}
}在 Claude Code 发送通知时运行。按通知类型匹配:、、、。省略 matcher 可运行所有通知类型的 Hooks。
permission_promptidle_promptauth_successelicitation_dialog使用不同的 matcher,可以根据通知类型运行不同的处理器。以下配置会在 Claude 需要权限批准时触发权限专用警报脚本,并在 Claude 空闲时触发另一条通知:
json
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [
{
"type": "command",
"command": "/path/to/permission-alert.sh"
}
]
},
{
"matcher": "idle_prompt",
"hooks": [
{
"type": "command",
"command": "/path/to/idle-notification.sh"
}
]
}
]
}
}Notification input
Notification 输入
In addition to the common input fields, Notification hooks receive with the notification text, an optional , and indicating which type fired.
messagetitlenotification_typejson
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "Notification",
"message": "Claude needs your permission to use Bash",
"title": "Permission needed",
"notification_type": "permission_prompt"
}Notification hooks cannot block or modify notifications. In addition to the JSON output fields available to all hooks, you can return to add context to the conversation:
additionalContext| Field | Description |
|---|---|
| String added to Claude's context |
json
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "Notification",
"message": "Claude needs your permission to use Bash",
"title": "Permission needed",
"notification_type": "permission_prompt"
}Notification Hooks 无法阻止或修改通知。除所有 Hook 均可使用的 JSON 输出字段外,还可以返回 ,将上下文添加到对话:
additionalContext| 字段 | 说明 |
|---|---|
| 添加到 Claude 上下文的字符串 |
SubagentStart
SubagentStart
Runs when a Claude Code subagent is spawned via the Task tool. Supports matchers to filter by agent type name (built-in agents like , , , or custom agent names from ).
BashExplorePlan.claude/agents/在通过 Task 工具创建 Claude Code subagent 时运行。支持使用 matcher 按 Agent 类型名称筛选,例如内置 Agent 、、,或 中的自定义 Agent 名称。
BashExplorePlan.claude/agents/SubagentStart input
SubagentStart 输入
In addition to the common input fields, SubagentStart hooks receive with the unique identifier for the subagent and with the agent name (built-in agents like , , , or custom agent names).
agent_idagent_type"Bash""Explore""Plan"json
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "SubagentStart",
"agent_id": "agent-abc123",
"agent_type": "Explore"
}SubagentStart hooks cannot block subagent creation, but they can inject context into the subagent. In addition to the JSON output fields available to all hooks, you can return:
| Field | Description |
|---|---|
| String added to the subagent's context |
json
{
"hookSpecificOutput": {
"hookEventName": "SubagentStart",
"additionalContext": "Follow security guidelines for this task"
}
}除通用输入字段外,SubagentStart Hooks 还会接收 (subagent 的唯一标识符)和 (Agent 名称,如 、、 或自定义 Agent 名称)。
agent_idagent_type"Bash""Explore""Plan"json
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "SubagentStart",
"agent_id": "agent-abc123",
"agent_type": "Explore"
}SubagentStart Hooks 无法阻止 subagent 创建,但可以向 subagent 注入上下文。除所有 Hook 均可使用的 JSON 输出字段外,还可以返回:
| 字段 | 说明 |
|---|---|
| 添加到 subagent 上下文的字符串 |
json
{
"hookSpecificOutput": {
"hookEventName": "SubagentStart",
"additionalContext": "Follow security guidelines for this task"
}
}SubagentStop
SubagentStop
Runs when a Claude Code subagent has finished responding. Matches on agent type, same values as SubagentStart.
在 Claude Code subagent 完成响应时运行。按 Agent 类型匹配,取值与 SubagentStart 相同。
SubagentStop input
SubagentStop 输入
In addition to the common input fields, SubagentStop hooks receive , , , and . The field is the value used for matcher filtering. The is the main session's transcript, while is the subagent's own transcript stored in a nested folder.
stop_hook_activeagent_idagent_typeagent_transcript_pathagent_typetranscript_pathagent_transcript_pathsubagents/json
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../abc123.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "SubagentStop",
"stop_hook_active": false,
"agent_id": "def456",
"agent_type": "Explore",
"agent_transcript_path": "~/.claude/projects/.../abc123/subagents/agent-def456.jsonl"
}SubagentStop hooks use the same decision control format as Stop hooks.
SubagentStop Hooks 接收 、、 和 。 字段是用于 matcher 筛选的值。 是主会话的记录,而 是 subagent 自己的记录,存储在嵌套的 文件夹中。
stop_hook_activeagent_idagent_typeagent_transcript_pathagent_typetranscript_pathagent_transcript_pathsubagents/json
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../abc123.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "SubagentStop",
"stop_hook_active": false,
"agent_id": "def456",
"agent_type": "Explore",
"agent_transcript_path": "~/.claude/projects/.../abc123/subagents/agent-def456.jsonl"
}SubagentStop Hooks 使用与 Stop Hooks相同的决策控制格式。
Stop
Stop
Runs when the main Claude Code agent has finished responding. Does not run if
the stoppage occurred due to a user interrupt.
在主 Claude Code Agent 完成响应时运行。如果停止是由用户中断导致的,则不会运行。
Stop input
Stop 输入
In addition to the common input fields, Stop hooks receive . This field is when Claude Code is already continuing as a result of a stop hook. Check this value or process the transcript to prevent Claude Code from running indefinitely.
stop_hook_activetruejson
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "Stop",
"stop_hook_active": true
}除通用输入字段外,Stop Hooks 还会接收 。当 Claude Code 已经因 Stop Hook 而继续工作时,该字段为 。应检查此值或处理记录,以防止 Claude Code 无限运行。
stop_hook_activetruejson
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../abc123.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "Stop",
"stop_hook_active": true
}Stop decision control
Stop 决策控制
StopSubagentStop| Field | Description |
|---|---|
| |
| Required when |
json
{
"decision": "block",
"reason": "Must be provided when Claude is blocked from stopping"
}Stop 和 SubagentStop Hooks 可以控制 Claude 是否继续。除所有 Hook 均可使用的 JSON 输出字段外,还可以返回以下事件专用字段:
| 字段 | 说明 |
|---|---|
| |
| 当 |
json
{
"decision": "block",
"reason": "Must be provided when Claude is blocked from stopping"
}PreCompact
PreCompact
Runs before Claude Code is about to run a compact operation.
The matcher value indicates whether compaction was triggered manually or automatically:
| Matcher | When it fires |
|---|---|
| |
| Auto-compact when the context window is full |
在 Claude Code 即将执行压缩操作之前运行。
Matcher 值表示压缩是由手动还是自动触发:
| Matcher | 触发时机 |
|---|---|
| |
| 上下文窗口填满时自动压缩 |
PreCompact input
PreCompact 输入
In addition to the common input fields, PreCompact hooks receive and . For , contains what the user passes into . For , is empty.
triggercustom_instructionsmanualcustom_instructions/compactautocustom_instructionsjson
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PreCompact",
"trigger": "manual",
"custom_instructions": ""
}除通用输入字段外,PreCompact Hooks 还会接收 和 。对于 , 包含用户传入 的内容;对于 , 为空。
triggercustom_instructionsmanualcustom_instructions/compactautocustom_instructionsjson
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PreCompact",
"trigger": "manual",
"custom_instructions": ""
}SessionEnd
SessionEnd
Runs when a Claude Code session ends. Useful for cleanup tasks, logging session
statistics, or saving session state. Supports matchers to filter by exit reason.
The field in the hook input indicates why the session ended:
reason| Reason | Description |
|---|---|
| Session cleared with |
| User logged out |
| User exited while prompt input was visible |
| Bypass permissions mode was disabled |
| Other exit reasons |
在 Claude Code 会话结束时运行。适用于清理任务、记录会话统计信息或保存会话状态。支持按退出原因匹配。
Hook 输入中的 字段表示会话结束原因:
reason| 原因 | 说明 |
|---|---|
| 使用 |
| 用户退出登录 |
| 显示 prompt 输入时用户退出 |
| bypass permissions 模式被禁用 |
| 其他退出原因 |
SessionEnd input
SessionEnd 输入
In addition to the common input fields, SessionEnd hooks receive a field indicating why the session ended. See the reason table above for all values.
reasonjson
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "SessionEnd",
"reason": "other"
}SessionEnd hooks have no decision control. They cannot block session termination but can perform cleanup tasks.
json
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "SessionEnd",
"reason": "other"
}SessionEnd Hooks 没有决策控制。它们无法阻止会话终止,但可以执行清理任务。
Prompt-based hooks
基于 prompt 的 Hooks
In addition to Bash command hooks (), Claude Code supports prompt-based hooks () that use an LLM to evaluate whether to allow or block an action. Prompt-based hooks work with the following events: , , , , , , and .
type: "command"type: "prompt"PreToolUsePostToolUsePostToolUseFailurePermissionRequestUserPromptSubmitStopSubagentStop除 Bash command Hooks()外,Claude Code 还支持基于 prompt 的 Hooks(),使用 LLM 判断是否允许或阻止操作。基于 prompt 的 Hooks 支持以下事件:、、、、、 和 。
type: "command"type: "prompt"PreToolUsePostToolUsePostToolUseFailurePermissionRequestUserPromptSubmitStopSubagentStopHow prompt-based hooks work
基于 prompt 的 Hooks 如何工作
Instead of executing a Bash command, prompt-based hooks:
- Send the hook input and your prompt to a Claude model, Haiku by default
- The LLM responds with structured JSON containing a decision
- Claude Code processes the decision automatically
基于 prompt 的 Hooks 不会执行 Bash 命令,而是:
- 将 Hook 输入和你的 prompt 发送给 Claude 模型,默认使用 Haiku
- LLM 返回包含决策的结构化 JSON
- Claude Code 自动处理该决策
Prompt hook configuration
Prompt hook 配置
Set to and provide a string instead of a . Use the placeholder to inject the hook's JSON input data into your prompt text. Claude Code sends the combined prompt and input to a fast Claude model, which returns a JSON decision.
type"prompt"promptcommand$ARGUMENTSThis hook asks the LLM to evaluate whether all tasks are complete before allowing Claude to finish:
Stopjson
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "Evaluate if Claude should stop: $ARGUMENTS. Check if all tasks are complete."
}
]
}
]
}
}| Field | Required | Description |
|---|---|---|
| yes | Must be |
| yes | The prompt text to send to the LLM. Use |
| no | Model to use for evaluation. Defaults to a fast model |
| no | Timeout in seconds. Default: 30 |
将 设置为 ,并提供 字符串而不是 。使用 占位符将 Hook 的 JSON 输入数据注入 prompt 文本。Claude Code 会将组合后的 prompt 和输入发送给快速 Claude 模型,该模型返回 JSON 决策。
type"prompt"promptcommand$ARGUMENTS此 Hook 让 LLM 在允许 Claude 完成前评估所有任务是否已完成:
Stopjson
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "Evaluate if Claude should stop: $ARGUMENTS. Check if all tasks are complete."
}
]
}
]
}
}| 字段 | 必需 | 说明 |
|---|---|---|
| 是 | 必须为 |
| 是 | 发送给 LLM 的 prompt 文本。使用 |
| 否 | 用于评估的模型,默认为快速模型 |
| 否 | 超时时间,单位为秒,默认值为 30 |
Response schema
响应 schema
The LLM must respond with JSON containing:
json
{
"ok": true | false,
"reason": "Explanation for the decision"
}| Field | Description |
|---|---|
| |
| Required when |
LLM 必须返回包含以下内容的 JSON:
json
{
"ok": true | false,
"reason": "Explanation for the decision"
}| 字段 | 说明 |
|---|---|
| |
| 当 |
Example: Multi-criteria Stop hook
示例:多条件 Stop hook
This hook uses a detailed prompt to check three conditions before allowing Claude to stop. If is , Claude continues working with the provided reason as its next instruction. hooks use the same format to evaluate whether a subagent should stop:
Stop"ok"falseSubagentStopjson
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "You are evaluating whether Claude should stop working. Context: $ARGUMENTS\n\nAnalyze the conversation and determine if:\n1. All user-requested tasks are complete\n2. Any errors need to be addressed\n3. Follow-up work is needed\n\nRespond with JSON: {\"ok\": true} to allow stopping, or {\"ok\": false, \"reason\": \"your explanation\"} to continue working.",
"timeout": 30
}
]
}
]
}
}此 Hook 使用详细 prompt,在允许 Claude 停止前检查三个条件。如果 为 ,Claude 会继续工作,并将提供的 作为下一条指令。 Hooks 使用相同格式来评估 subagent 是否应停止:
Stop"ok"falsereasonSubagentStopjson
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "You are evaluating whether Claude should stop working. Context: $ARGUMENTS\n\nAnalyze the conversation and determine if:\n1. All user-requested tasks are complete\n2. Any errors need to be addressed\n3. Follow-up work is needed\n\nRespond with JSON: {\"ok\": true} to allow stopping, or {\"ok\": false, \"reason\": \"your explanation\"} to continue working.",
"timeout": 30
}
]
}
]
}
}Agent-based hooks
基于 Agent 的 Hooks
Agent-based hooks () are like prompt-based hooks but with multi-turn tool access. Instead of a single LLM call, an agent hook spawns a subagent that can read files, search code, and inspect the codebase to verify conditions. Agent hooks support the same events as prompt-based hooks.
type: "agent"基于 Agent 的 Hooks()与基于 prompt 的 Hooks 类似,但支持多轮工具访问。Agent Hook 不会只发起单次 LLM 调用,而是创建 subagent,使其能够读取文件、搜索代码并检查代码库来验证条件。Agent Hooks 支持与基于 prompt 的 Hooks 相同的事件。
type: "agent"How agent hooks work
Agent hooks 如何工作
When an agent hook fires:
- Claude Code spawns a subagent with your prompt and the hook's JSON input
- The subagent can use tools like Read, Grep, and Glob to investigate
- After up to 50 turns, the subagent returns a structured decision
{ "ok": true/false } - Claude Code processes the decision the same way as a prompt hook
Agent hooks are useful when verification requires inspecting actual files or test output, not just evaluating the hook input data alone.
Agent Hook 触发时:
- Claude Code 使用你的 prompt 和 Hook 的 JSON 输入创建 subagent
- Subagent 可以使用 Read、Grep 和 Glob 等工具进行调查
- 最多经过 50 轮后,subagent 返回结构化的 决策
{ "ok": true/false } - Claude Code 以与 prompt Hook 相同的方式处理该决策
当验证需要检查实际文件或测试输出,而不仅是评估 Hook 输入数据时,Agent Hooks 非常有用。
Agent hook configuration
Agent hook 配置
Set to and provide a string. The configuration fields are the same as prompt hooks, with a longer default timeout:
type"agent"prompt| Field | Required | Description |
|---|---|---|
| yes | Must be |
| yes | Prompt describing what to verify. Use |
| no | Model to use. Defaults to a fast model |
| no | Timeout in seconds. Default: 60 |
The response schema is the same as prompt hooks: to allow or to block.
{ "ok": true }{ "ok": false, "reason": "..." }This hook verifies that all unit tests pass before allowing Claude to finish:
Stopjson
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "agent",
"prompt": "Verify that all unit tests pass. Run the test suite and check the results. $ARGUMENTS",
"timeout": 120
}
]
}
]
}
}| 字段 | 必需 | 说明 |
|---|---|---|
| 是 | 必须为 |
| 是 | 描述验证内容的 prompt。使用 |
| 否 | 要使用的模型,默认为快速模型 |
| 否 | 超时时间,单位为秒,默认值为 60 |
响应 schema 与 prompt Hooks 相同: 允许操作, 阻止操作。
{ "ok": true }{ "ok": false, "reason": "..." }此 Hook 在允许 Claude 完成前验证所有单元测试是否通过:
Stopjson
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "agent",
"prompt": "Verify that all unit tests pass. Run the test suite and check the results. $ARGUMENTS",
"timeout": 120
}
]
}
]
}
}Run hooks in the background
在后台运行 Hooks
By default, hooks block Claude's execution until they complete. For long-running tasks like deployments, test suites, or external API calls, set to run the hook in the background while Claude continues working. Async hooks cannot block or control Claude's behavior: response fields like , , and have no effect, because the action they would have controlled has already completed.
"async": truedecisionpermissionDecisioncontinue默认情况下,Hooks 会阻塞 Claude 的执行,直到完成。对于部署、测试套件或外部 API 调用等耗时任务,可设置 ,让 Hook 在后台运行,同时 Claude 继续工作。异步 Hooks 无法阻止或控制 Claude 的行为:、 和 等响应字段均不起作用,因为其原本要控制的操作已经完成。
"async": truedecisionpermissionDecisioncontinueConfigure an async hook
配置异步 Hook
Add to a command hook's configuration to run it in the background without blocking Claude. This field is only available on hooks.
"async": truetype: "command"This hook runs a test script after every tool call. Claude continues working immediately while executes for up to 120 seconds. When the script finishes, its output is delivered on the next conversation turn:
Writerun-tests.shjson
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "/path/to/run-tests.sh",
"async": true,
"timeout": 120
}
]
}
]
}
}The field sets the maximum time in seconds for the background process. If not specified, async hooks use the same 10-minute default as sync hooks.
timeout在 command Hook 的配置中添加 ,即可在后台运行而不阻塞 Claude。此字段仅适用于 Hooks。
"async": truetype: "command"此 Hook 会在每次 工具调用后运行测试脚本。Claude 会立即继续工作,而 最多运行 120 秒。脚本完成后,其输出会在下一轮对话中送达:
Writerun-tests.shjson
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "/path/to/run-tests.sh",
"async": true,
"timeout": 120
}
]
}
]
}
}timeoutHow async hooks execute
异步 Hooks 的执行方式
When an async hook fires, Claude Code starts the hook process and immediately continues without waiting for it to finish. The hook receives the same JSON input via stdin as a synchronous hook.
After the background process exits, if the hook produced a JSON response with a or field, that content is delivered to Claude as context on the next conversation turn.
systemMessageadditionalContext异步 Hook 触发时,Claude Code 会启动 Hook 进程并立即继续,不等待其完成。Hook 通过 stdin 接收与同步 Hook 相同的 JSON 输入。
后台进程退出后,如果 Hook 产生了包含 或 字段的 JSON 响应,该内容会在下一轮对话中作为上下文送达 Claude。
systemMessageadditionalContextExample: run tests after file changes
示例:文件变更后运行测试
This hook starts a test suite in the background whenever Claude writes a file, then reports the results back to Claude when the tests finish. Save this script to in your project and make it executable with :
.claude/hooks/run-tests-async.shchmod +xbash
#!/bin/bash此 Hook 会在 Claude 写入文件时在后台启动测试套件,并在测试完成后将结果报告给 Claude。将此脚本保存到项目中的 ,并通过 使其可执行:
.claude/hooks/run-tests-async.shchmod +xbash
#!/bin/bashrun-tests-async.sh
run-tests-async.sh
Read hook input from stdin
Read hook input from stdin
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
Only run tests for source files
Only run tests for source files
if [[ "$FILE_PATH" != *.ts && "$FILE_PATH" != *.js ]]; then
exit 0
fi
if [[ "$FILE_PATH" != *.ts && "$FILE_PATH" != *.js ]]; then
exit 0
fi
Run tests and report results via systemMessage
Run tests and report results via systemMessage
RESULT=$(npm test 2>&1)
EXIT_CODE=$?
if [ $EXIT_CODE -eq 0 ]; then
echo "{"systemMessage": "Tests passed after editing $FILE_PATH"}"
else
echo "{"systemMessage": "Tests failed after editing $FILE_PATH: $RESULT"}"
fi
Then add this configuration to `.claude/settings.json` in your project root. The `async: true` flag lets Claude keep working while tests run:
```json theme={null}
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/run-tests-async.sh",
"async": true,
"timeout": 300
}
]
}
]
}
}RESULT=$(npm test 2>&1)
EXIT_CODE=$?
if [ $EXIT_CODE -eq 0 ]; then
echo "{"systemMessage": "Tests passed after editing $FILE_PATH"}"
else
echo "{"systemMessage": "Tests failed after editing $FILE_PATH: $RESULT"}"
fi
然后将以下配置添加到项目根目录的 `.claude/settings.json`。`async: true` 标志可让 Claude 在测试运行时继续工作:
```json theme={null}
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/run-tests-async.sh",
"async": true,
"timeout": 300
}
]
}
]
}
}Limitations
限制
Async hooks have several constraints compared to synchronous hooks:
- Only hooks support
type: "command". Prompt-based hooks cannot run asynchronously.async - Async hooks cannot block tool calls or return decisions. By the time the hook completes, the triggering action has already proceeded.
- Hook output is delivered on the next conversation turn. If the session is idle, the response waits until the next user interaction.
- Each execution creates a separate background process. There is no deduplication across multiple firings of the same async hook.
异步 Hooks 与同步 Hooks 相比存在以下限制:
- 只有 Hooks 支持
type: "command"。基于 prompt 的 Hooks 无法异步运行。async - 异步 Hooks 无法阻止工具调用或返回决策。Hook 完成时,触发它的操作已经继续执行。
- Hook 输出会在下一轮对话中送达。如果会话处于空闲状态,响应会等到下一次用户交互。
- 每次执行都会创建独立的后台进程。同一个异步 Hook 多次触发时不会跨执行去重。
Security considerations
安全注意事项
Disclaimer
免责声明
Hooks run with your system user's full permissions.
<Warning>
Hooks execute shell commands with your full user permissions. They can modify, delete, or access any files your user account can access. Review and test all hook commands before adding them to your configuration.
</Warning>Hooks 以系统用户的完整权限运行。
<Warning>
Hooks 会使用你的完整用户权限执行 shell 命令。它们可以修改、删除或访问用户账户有权访问的任何文件。将 Hook 命令添加到配置前,请先审查并测试所有命令。
</Warning>Security best practices
安全最佳实践
Keep these practices in mind when writing hooks:
- Validate and sanitize inputs: never trust input data blindly
- Always quote shell variables: use not
"$VAR"$VAR - Block path traversal: check for in file paths
.. - Use absolute paths: specify full paths for scripts, using for the project root
"$CLAUDE_PROJECT_DIR" - Skip sensitive files: avoid ,
.env, keys, etc..git/
编写 Hooks 时请注意以下实践:
- 验证并清理输入:绝不要盲目信任输入数据
- 始终为 shell 变量添加引号:使用 ,而不是
"$VAR"$VAR - 阻止路径遍历:检查文件路径中是否存在
.. - 使用绝对路径:为脚本指定完整路径,并使用 表示项目根目录
"$CLAUDE_PROJECT_DIR" - 跳过敏感文件:避免处理 、
.env、密钥等内容.git/
Debug hooks
调试 Hooks
Run to see hook execution details, including which hooks matched, their exit codes, and output. Toggle verbose mode with to see hook progress in the transcript.
claude --debugCtrl+O[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Getting matching hook commands for PostToolUse with query: Write
[DEBUG] Found 1 hook matchers in settings
[DEBUG] Matched 1 hooks for query "Write"
[DEBUG] Found 1 hook commands to execute
[DEBUG] Executing hook command: <Your command> with timeout 600000ms
[DEBUG] Hook command completed with status 0: <Your stdout>For troubleshooting common issues like hooks not firing, infinite Stop hook loops, or configuration errors, see Limitations and troubleshooting in the guide.
运行 可查看 Hook 执行详情,包括哪些 Hooks 匹配、退出码和输出。按 切换详细模式,即可在记录中查看 Hook 进度。
claude --debugCtrl+O[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Getting matching hook commands for PostToolUse with query: Write
[DEBUG] Found 1 hook matchers in settings
[DEBUG] Matched 1 hooks for query "Write"
[DEBUG] Found 1 hook commands to execute
[DEBUG] Executing hook command: <Your command> with timeout 600000ms
[DEBUG] Hook command completed with status 0: <Your stdout>有关 Hook 未触发、Stop Hook 无限循环或配置错误等常见问题的故障排除,请参阅指南中的 Limitations and troubleshooting。