claude-hooks

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Claude Code Hooks

Claude Code 钩子

Guide for creating hooks that execute shell commands or scripts in response to Claude Code events and tool calls.
本指南介绍如何创建可响应Claude Code事件与工具调用、执行Shell命令或脚本的钩子。

When to Use This Skill

适用场景

Activate this skill when:
  • Creating event-driven automations
  • Implementing custom validation or formatting
  • Integrating with external tools and services
  • Setting up project-specific workflows
  • Responding to tool execution events
在以下场景中使用该功能:
  • 创建事件驱动型自动化流程
  • 实现自定义验证或格式化
  • 集成外部工具与服务
  • 设置项目专属工作流
  • 响应工具执行事件

What Are Hooks?

什么是钩子?

Hooks are shell commands that execute automatically in response to specific events:
  • Tool Call Hooks: Trigger before/after specific tool calls
  • Lifecycle Hooks: Trigger on plugin install/uninstall
  • User Prompt Hooks: Trigger when users submit prompts
  • Custom Events: Application-specific trigger points
钩子是可响应特定事件自动执行的Shell命令:
  • 工具调用钩子:在特定工具调用前后触发
  • 生命周期钩子:在插件安装/卸载时触发
  • 用户提示钩子:在用户提交提示时触发
  • 自定义事件:应用专属的触发点

Hook Configuration

钩子配置

Location

配置位置

Hooks are configured in:
  • Plugin:
    <plugin-root>/.claude-plugin/hooks.json
  • User-level:
    .claude/hooks.json
  • Plugin manifest: Inline in
    plugin.json
钩子可在以下位置配置:
  • 插件级:
    <plugin-root>/.claude-plugin/hooks.json
  • 用户级:
    .claude/hooks.json
  • 插件清单:内联在
    plugin.json

File Structure

文件结构

Standalone hooks.json:
json
{
  "onToolCall": {
    "Write": {
      "before": ["./hooks/format-check.sh"],
      "after": ["./hooks/lint.sh"]
    },
    "Bash": {
      "before": ["./hooks/validate-command.sh"]
    }
  },
  "onInstall": ["./hooks/setup.sh"],
  "onUninstall": ["./hooks/cleanup.sh"],
  "onUserPromptSubmit": ["./hooks/log-prompt.sh"]
}
Inline in plugin.json:
json
{
  "hooks": {
    "onToolCall": {
      "Write": {
        "after": ["prettier --write {{file_path}}"]
      }
    }
  }
}
独立hooks.json文件:
json
{
  "onToolCall": {
    "Write": {
      "before": ["./hooks/format-check.sh"],
      "after": ["./hooks/lint.sh"]
    },
    "Bash": {
      "before": ["./hooks/validate-command.sh"]
    }
  },
  "onInstall": ["./hooks/setup.sh"],
  "onUninstall": ["./hooks/cleanup.sh"],
  "onUserPromptSubmit": ["./hooks/log-prompt.sh"]
}
内联在plugin.json中:
json
{
  "hooks": {
    "onToolCall": {
      "Write": {
        "after": ["prettier --write {{file_path}}"]
      }
    }
  }
}

Hook Types

钩子类型

Tool Call Hooks

工具调用钩子

Execute before or after specific tool calls.
Available Tools:
  • Read
    ,
    Write
    ,
    Edit
    ,
    MultiEdit
  • Bash
    ,
    BashOutput
  • Glob
    ,
    Grep
  • Task
    ,
    Skill
    ,
    SlashCommand
  • TodoWrite
  • WebFetch
    ,
    WebSearch
  • AskUserQuestion
Example:
json
{
  "onToolCall": {
    "Write": {
      "before": [
        "echo 'Writing file: {{file_path}}'",
        "./hooks/backup.sh {{file_path}}"
      ],
      "after": [
        "prettier --write {{file_path}}",
        "git add {{file_path}}"
      ]
    },
    "Edit": {
      "after": ["eslint --fix {{file_path}}"]
    }
  }
}
在特定工具调用前后执行。
支持的工具:
  • Read
    ,
    Write
    ,
    Edit
    ,
    MultiEdit
  • Bash
    ,
    BashOutput
  • Glob
    ,
    Grep
  • Task
    ,
    Skill
    ,
    SlashCommand
  • TodoWrite
  • WebFetch
    ,
    WebSearch
  • AskUserQuestion
示例:
json
{
  "onToolCall": {
    "Write": {
      "before": [
        "echo 'Writing file: {{file_path}}'",
        "./hooks/backup.sh {{file_path}}"
      ],
      "after": [
        "prettier --write {{file_path}}",
        "git add {{file_path}}"
      ]
    },
    "Edit": {
      "after": ["eslint --fix {{file_path}}"]
    }
  }
}

Lifecycle Hooks

生命周期钩子

Execute during plugin installation/uninstallation.
json
{
  "onInstall": [
    "./hooks/setup-dependencies.sh",
    "npm install",
    "echo 'Plugin installed successfully'"
  ],
  "onUninstall": [
    "./hooks/cleanup.sh",
    "echo 'Plugin uninstalled'"
  ]
}
在插件安装/卸载期间执行。
json
{
  "onInstall": [
    "./hooks/setup-dependencies.sh",
    "npm install",
    "echo 'Plugin installed successfully'"
  ],
  "onUninstall": [
    "./hooks/cleanup.sh",
    "echo 'Plugin uninstalled'"
  ]
}

User Prompt Submit Hook

用户提示提交钩子

Execute when user submits a prompt:
json
{
  "onUserPromptSubmit": [
    "./hooks/log-interaction.sh '{{prompt}}'",
    "./hooks/check-context.sh"
  ]
}
在用户提交提示时执行:
json
{
  "onUserPromptSubmit": [
    "./hooks/log-interaction.sh '{{prompt}}'",
    "./hooks/check-context.sh"
  ]
}

Hook Variables

钩子变量

Hooks have access to context-specific variables using
{{variable}}
syntax.
钩子可通过
{{variable}}
语法访问上下文专属变量。

Tool Call Variables

工具调用变量

Different tools provide different variables:
Write Tool:
  • {{file_path}}
    : Path to file being written
  • {{content}}
    : Content being written (before hooks only)
Edit Tool:
  • {{file_path}}
    : Path to file being edited
  • {{old_string}}
    : String being replaced
  • {{new_string}}
    : Replacement string
Bash Tool:
  • {{command}}
    : Command being executed
Read Tool:
  • {{file_path}}
    : Path to file being read
不同工具提供不同的变量:
Write工具:
  • {{file_path}}
    :待写入文件的路径
  • {{content}}
    :待写入的内容(仅在前置钩子中可用)
Edit工具:
  • {{file_path}}
    :待编辑文件的路径
  • {{old_string}}
    :待替换的字符串
  • {{new_string}}
    :替换后的字符串
Bash工具:
  • {{command}}
    :待执行的命令
Read工具:
  • {{file_path}}
    :待读取文件的路径

Global Variables

全局变量

Available in all hooks:
  • {{cwd}}
    : Current working directory
  • {{timestamp}}
    : Current Unix timestamp
  • {{user}}
    : Current user
  • {{plugin_root}}
    : Plugin installation directory
所有钩子均可使用:
  • {{cwd}}
    :当前工作目录
  • {{timestamp}}
    :当前Unix时间戳
  • {{user}}
    :当前用户
  • {{plugin_root}}
    :插件安装目录

User Prompt Variables

用户提示变量

  • {{prompt}}
    : User's submitted prompt text
  • {{prompt}}
    :用户提交的提示文本

Hook Examples

钩子示例

Auto-Format on Write

写入时自动格式化

json
{
  "onToolCall": {
    "Write": {
      "after": [
        "prettier --write {{file_path}}",
        "eslint --fix {{file_path}}"
      ]
    }
  }
}
json
{
  "onToolCall": {
    "Write": {
      "after": [
        "prettier --write {{file_path}}",
        "eslint --fix {{file_path}}"
      ]
    }
  }
}

Pre-Commit Validation

提交前验证

json
{
  "onToolCall": {
    "Bash": {
      "before": ["./hooks/validate-git-command.sh '{{command}}'"]
    }
  }
}
validate-git-command.sh:
bash
#!/bin/bash

COMMAND="$1"
json
{
  "onToolCall": {
    "Bash": {
      "before": ["./hooks/validate-git-command.sh '{{command}}'"]
    }
  }
}
validate-git-command.sh:
bash
#!/bin/bash

COMMAND="$1"

Block force push to main/master

禁止向main/master分支强制推送

if [[ "$COMMAND" =~ "git push --force" ]] && [[ "$COMMAND" =~ "main|master" ]]; then echo "ERROR: Force push to main/master is not allowed" exit 1 fi
exit 0
undefined
if [[ "$COMMAND" =~ "git push --force" ]] && [[ "$COMMAND" =~ "main|master" ]]; then echo "ERROR: Force push to main/master is not allowed" exit 1 fi
exit 0
undefined

Automatic Backups

自动备份

json
{
  "onToolCall": {
    "Write": {
      "before": ["cp {{file_path}} {{file_path}}.backup"]
    },
    "Edit": {
      "before": ["cp {{file_path}} {{file_path}}.backup"]
    }
  }
}
json
{
  "onToolCall": {
    "Write": {
      "before": ["cp {{file_path}} {{file_path}}.backup"]
    },
    "Edit": {
      "before": ["cp {{file_path}} {{file_path}}.backup"]
    }
  }
}

Logging and Analytics

日志与分析

json
{
  "onToolCall": {
    "Write": {
      "after": ["./hooks/log-file-change.sh {{file_path}}"]
    }
  },
  "onUserPromptSubmit": ["./hooks/log-prompt.sh '{{prompt}}'"]
}
log-file-change.sh:
bash
#!/bin/bash

FILE="$1"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

echo "$TIMESTAMP - Modified: $FILE" >> .claude/file-changes.log
json
{
  "onToolCall": {
    "Write": {
      "after": ["./hooks/log-file-change.sh {{file_path}}"]
    }
  },
  "onUserPromptSubmit": ["./hooks/log-prompt.sh '{{prompt}}'"]
}
log-file-change.sh:
bash
#!/bin/bash

FILE="$1"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

echo "$TIMESTAMP - Modified: $FILE" >> .claude/file-changes.log

Integration with External Tools

集成外部工具

json
{
  "onToolCall": {
    "Write": {
      "after": [
        "notify-send 'File Updated' 'Modified {{file_path}}'",
        "curl -X POST https://api.example.com/notify -d 'file={{file_path}}'"
      ]
    }
  }
}
json
{
  "onToolCall": {
    "Write": {
      "after": [
        "notify-send 'File Updated' 'Modified {{file_path}}'",
        "curl -X POST https://api.example.com/notify -d 'file={{file_path}}'"
      ]
    }
  }
}

Hook Execution

钩子执行

Execution Order

执行顺序

Multiple hooks execute in array order:
json
{
  "onToolCall": {
    "Write": {
      "after": [
        "echo 'Step 1'",  // Runs first
        "echo 'Step 2'",  // Runs second
        "echo 'Step 3'"   // Runs third
      ]
    }
  }
}
多个钩子按数组顺序执行:
json
{
  "onToolCall": {
    "Write": {
      "after": [
        "echo 'Step 1'",  // 第一个执行
        "echo 'Step 2'",  // 第二个执行
        "echo 'Step 3'"   // 第三个执行
      ]
    }
  }
}

Exit Codes

退出码

Before Hooks:
  • Exit code
    0
    : Continue with tool execution
  • Exit code non-zero: Block tool execution, show error to user
After Hooks:
  • Exit codes are logged but don't affect tool execution
  • Tool has already completed
前置钩子:
  • 退出码
    0
    :继续执行工具
  • 非零退出码:阻止工具执行,向用户显示错误信息
后置钩子:
  • 退出码仅会被记录,不影响工具执行
  • 工具已完成执行

Error Handling

错误处理

bash
#!/bin/bash
bash
#!/bin/bash

Before hook - blocks tool on error

前置钩子 - 出错时阻止工具执行

if [[ ! -f "$1" ]]; then echo "ERROR: File does not exist" exit 1 # Blocks tool execution fi
if [[ ! -f "$1" ]]; then echo "ERROR: File does not exist" exit 1 # 阻止工具执行 fi

Validation passed

验证通过

exit 0
undefined
exit 0
undefined

Best Practices

最佳实践

Keep Hooks Fast

保持钩子轻量化

Hooks block execution - keep them lightweight:
json
{
  "onToolCall": {
    "Write": {
      // ✅ Fast linter
      "after": ["eslint --fix {{file_path}}"]

      // ❌ Slow test suite
      // "after": ["npm test"]
    }
  }
}
钩子会阻塞执行 - 请保持钩子轻量化:
json
{
  "onToolCall": {
    "Write": {
      // ✅ 快速的代码检查工具
      "after": ["eslint --fix {{file_path}}"]

      // ❌ 缓慢的测试套件
      // "after": ["npm test"]
    }
  }
}

Use Absolute Paths

使用绝对路径

Reference scripts with paths relative to plugin:
json
{
  "onInstall": ["${CLAUDE_PLUGIN_ROOT}/hooks/setup.sh"]
}
使用相对于插件的路径引用脚本:
json
{
  "onInstall": ["${CLAUDE_PLUGIN_ROOT}/hooks/setup.sh"]
}

Validate Input

验证输入

Always validate hook variables:
bash
#!/bin/bash

FILE="$1"

if [[ -z "$FILE" ]]; then
  echo "ERROR: No file path provided"
  exit 1
fi

if [[ ! -f "$FILE" ]]; then
  echo "ERROR: File does not exist: $FILE"
  exit 1
fi
始终验证钩子变量:
bash
#!/bin/bash

FILE="$1"

if [[ -z "$FILE" ]]; then
  echo "ERROR: No file path provided"
  exit 1
fi

if [[ ! -f "$FILE" ]]; then
  echo "ERROR: File does not exist: $FILE"
  exit 1
fi

Provide Clear Feedback

提供清晰的反馈

bash
#!/bin/bash

echo "Running pre-commit checks..."

if ! npm run lint; then
  echo "❌ Linting failed. Please fix errors before committing."
  exit 1
fi

echo "✅ All checks passed"
exit 0
bash
#!/bin/bash

echo "正在运行提交前检查..."

if ! npm run lint; then
  echo "❌ 代码检查失败,请在提交前修复错误。"
  exit 1
fi

echo "✅ 所有检查通过"
exit 0

Handle Edge Cases

处理边缘情况

bash
#!/bin/bash
bash
#!/bin/bash

Handle files with spaces in names

处理名称含空格的文件

FILE="$1"
FILE="$1"

Validate file type

验证文件类型

if [[ ! "$FILE" =~ .(js|ts|jsx|tsx)$ ]]; then

Skip non-JavaScript files silently

exit 0 fi
if [[ ! "$FILE" =~ .(js|ts|jsx|tsx)$ ]]; then

静默跳过非JavaScript文件

exit 0 fi

Run formatter

运行格式化工具

prettier --write "$FILE"
undefined
prettier --write "$FILE"
undefined

Security Considerations

安全注意事项

Validate Commands

验证命令

Before hooks can block dangerous operations:
json
{
  "onToolCall": {
    "Bash": {
      "before": ["./hooks/validate-command.sh '{{command}}'"]
    }
  }
}
validate-command.sh:
bash
#!/bin/bash

COMMAND="$1"
前置钩子可阻止危险操作:
json
{
  "onToolCall": {
    "Bash": {
      "before": ["./hooks/validate-command.sh '{{command}}'"]
    }
  }
}
validate-command.sh:
bash
#!/bin/bash

COMMAND="$1"

Block dangerous patterns

阻止危险命令模式

DANGEROUS_PATTERNS=( "rm -rf /" "dd if=" "mkfs" "> /dev/sda" )
for pattern in "${DANGEROUS_PATTERNS[@]}"; do if [[ "$COMMAND" =~ $pattern ]]; then echo "ERROR: Dangerous command blocked: $pattern" exit 1 fi done
exit 0
undefined
DANGEROUS_PATTERNS=( "rm -rf /" "dd if=" "mkfs" "> /dev/sda" )
for pattern in "${DANGEROUS_PATTERNS[@]}"; do if [[ "$COMMAND" =~ $pattern ]]; then echo "ERROR: Dangerous command blocked: $pattern" exit 1 fi done
exit 0
undefined

Limit Hook Scope

限制钩子范围

Only hook necessary tools:
json
{
  // ✅ Specific tools only
  "onToolCall": {
    "Write": { "after": ["./format.sh {{file_path}}"] }
  }

  // ❌ Don't hook everything unnecessarily
}
仅为必要工具配置钩子:
json
{
  // ✅ 仅针对特定工具
  "onToolCall": {
    "Write": { "after": ["./format.sh {{file_path}}"] }
  }

  // ❌ 不要不必要地为所有工具配置钩子
}

Sanitize Variables

清理变量

bash
#!/bin/bash
bash
#!/bin/bash

Sanitize file path

清理文件路径

FILE=$(realpath "$1")
FILE=$(realpath "$1")

Ensure file is within project

确保文件在项目目录内

if [[ ! "$FILE" =~ ^$(pwd) ]]; then echo "ERROR: File outside project directory" exit 1 fi
undefined
if [[ ! "$FILE" =~ ^$(pwd) ]]; then echo "ERROR: File outside project directory" exit 1 fi
undefined

Debugging Hooks

调试钩子

Enable Verbose Output

启用详细输出

json
{
  "onToolCall": {
    "Write": {
      "before": ["set -x; ./hooks/debug.sh {{file_path}}; set +x"]
    }
  }
}
json
{
  "onToolCall": {
    "Write": {
      "before": ["set -x; ./hooks/debug.sh {{file_path}}; set +x"]
    }
  }
}

Log Hook Execution

记录钩子执行

bash
#!/bin/bash

LOG_FILE=".claude/hooks.log"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

echo "$TIMESTAMP - Hook: $0, Args: $@" >> "$LOG_FILE"
bash
#!/bin/bash

LOG_FILE=".claude/hooks.log"
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

echo "$TIMESTAMP - Hook: $0, Args: $@" >> "$LOG_FILE"

Rest of hook logic...

钩子其余逻辑...

undefined
undefined

Test Hooks Manually

手动测试钩子

bash
undefined
bash
undefined

Test hook with sample data

使用示例数据测试钩子

./hooks/format.sh "src/main.js"
./hooks/format.sh "src/main.js"

Check exit code

检查退出码

echo $?
undefined
echo $?
undefined

Common Hook Patterns

常见钩子模式

Auto-Format Pipeline

自动格式化流水线

json
{
  "onToolCall": {
    "Write": {
      "after": [
        "prettier --write {{file_path}}",
        "eslint --fix {{file_path}}"
      ]
    },
    "Edit": {
      "after": [
        "prettier --write {{file_path}}",
        "eslint --fix {{file_path}}"
      ]
    }
  }
}
json
{
  "onToolCall": {
    "Write": {
      "after": [
        "prettier --write {{file_path}}",
        "eslint --fix {{file_path}}"
      ]
    },
    "Edit": {
      "after": [
        "prettier --write {{file_path}}",
        "eslint --fix {{file_path}}"
      ]
    }
  }
}

Test on Write

写入时测试

json
{
  "onToolCall": {
    "Write": {
      "after": ["./hooks/run-relevant-tests.sh {{file_path}}"]
    }
  }
}
json
{
  "onToolCall": {
    "Write": {
      "after": ["./hooks/run-relevant-tests.sh {{file_path}}"]
    }
  }
}

Git Integration

Git集成

json
{
  "onToolCall": {
    "Write": {
      "after": ["git add {{file_path}}"]
    },
    "Edit": {
      "after": ["git add {{file_path}}"]
    }
  }
}
json
{
  "onToolCall": {
    "Write": {
      "after": ["git add {{file_path}}"]
    },
    "Edit": {
      "after": ["git add {{file_path}}"]
    }
  }
}

Troubleshooting

故障排除

Hook Not Executing

钩子未执行

  • Check hook file has execute permissions:
    chmod +x hooks/script.sh
  • Verify path is correct relative to plugin root
  • Check JSON syntax in hooks.json
  • Look for errors in Claude Code logs
  • 检查钩子文件是否有执行权限:
    chmod +x hooks/script.sh
  • 验证路径相对于插件根目录是否正确
  • 检查hooks.json中的JSON语法
  • 查看Claude Code日志中的错误

Hook Blocking Tool

钩子阻止工具执行

  • Check exit code of before hooks
  • Add debug logging
  • Test hook script manually
  • Verify validation logic
  • 检查前置钩子的退出码
  • 添加调试日志
  • 手动测试钩子脚本
  • 验证逻辑

Variables Not Substituting

变量未替换

  • Check variable name spelling:
    {{file_path}}
    not
    {{filepath}}
  • Verify variable is available for that tool
  • Quote variables in bash:
    "{{file_path}}"
  • 检查变量名称拼写:
    {{file_path}}
    而非
    {{filepath}}
  • 验证该工具是否提供该变量
  • 在Bash中为变量添加引号:
    "{{file_path}}"

Templates

模板

Reference templates for common hook configurations:
claude-hooks/
└── templates/
    ├── plugin-hook.md    # Plugin hook configuration example
    └── skill-hook.md     # Skill/subagent frontmatter hooks example
参考常见钩子配置的模板:
claude-hooks/
└── templates/
    ├── plugin-hook.md    # 插件钩子配置示例
    └── skill-hook.md     # 技能/子代理前置钩子示例

Plugin Hook Template

插件钩子模板

Example configuration for defining hooks in a plugin's
hooks/hooks.json
:
  • PostToolUse hook with
    Write|Edit
    matcher
  • Uses
    ${CLAUDE_PLUGIN_ROOT}
    for script references
  • Includes timeout configuration
在插件的
hooks/hooks.json
中定义钩子的示例配置:
  • Write|Edit
    匹配器的PostToolUse钩子
  • 使用
    ${CLAUDE_PLUGIN_ROOT}
    引用脚本
  • 包含超时配置

Skill Hook Template

技能钩子模板

Example frontmatter for embedding hooks directly in skills:
  • Supported events: PreToolUse, PostToolUse, Stop
  • Hooks scoped to component lifecycle
  • Runs only when skill/subagent is active
直接在技能中嵌入钩子的示例前置配置:
  • 支持的事件:PreToolUse, PostToolUse, Stop
  • 钩子作用域限定为组件生命周期
  • 仅在技能/子代理激活时运行

References

参考资料

For more information:
更多信息请查看: