hooks
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesehooks - Claude Code Hooks
Hooks - Claude Code 钩子
Claude Code の Hook 作成・管理ガイド。
Claude Code Hook 创建与管理指南。
概要
概述
Hooks はツール実行の前後に自動で実行されるスクリプト。
| タイプ | タイミング | 用途 |
|---|---|---|
| PreToolUse | ツール実行前 | 検証、危険操作ブロック |
| PostToolUse | ツール実行後 | 提案、ログ記録 |
| Stop | 会話終了時 | クリーンアップ |
Hooks 是在工具执行前后自动运行的脚本。
| 类型 | 时机 | 用途 |
|---|---|---|
| PreToolUse | 工具执行前 | 验证、阻止危险操作 |
| PostToolUse | 工具执行后 | 建议、日志记录 |
| Stop | 会话结束时 | 清理 |
Hook 作成
创建Hook
1. スクリプト作成
1. 创建脚本
bash
#!/bin/bashbash
#!/bin/bash.claude/hooks/my-hook.sh
.claude/hooks/my-hook.sh
環境変数
环境变量
TOOL_NAME: ツール名 (Write, Edit, Bash, etc.)
TOOL_NAME: 工具名称 (Write, Edit, Bash等)
TOOL_INPUT: JSON形式の入力パラメータ
TOOL_INPUT: JSON格式的输入参数
終了コード
退出码
0: 成功(許可)
0: 成功(允许)
1: 警告(許可、メッセージ表示)
1: 警告(允许,显示消息)
2: ブロック(実行を停止)
2: 阻止(停止执行)
例: 危険なコマンドをブロック
示例:阻止危险命令
if echo "$TOOL_INPUT" | grep -q "rm -rf /"; then
echo "🚫 危険なコマンドをブロックしました" >&2
exit 2
fi
exit 0
undefinedif echo "$TOOL_INPUT" | grep -q "rm -rf /"; then
echo "🚫 已阻止危险命令" >&2
exit 2
fi
exit 0
undefined2. 実行権限付与
2. 添加执行权限
bash
chmod +x .claude/hooks/my-hook.shbash
chmod +x .claude/hooks/my-hook.sh3. 設定ファイルに登録
3. 在配置文件中注册
json
// .claude/settings.local.json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/path/to/project/.claude/hooks/my-hook.sh"
}
]
}
]
}
}json
// .claude/settings.local.json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/path/to/project/.claude/hooks/my-hook.sh"
}
]
}
]
}
}実用的な Hook 例
实用Hook示例
PreToolUse: 危険操作ブロック
PreToolUse:阻止危险操作
bash
#!/bin/bashbash
#!/bin/bashvalidate-dangerous-ops.sh
validate-dangerous-ops.sh
case "$TOOL_NAME" in
"Bash")
COMMAND=$(echo "$TOOL_INPUT" | jq -r '.command // empty')
# force push をブロック
if echo "$COMMAND" | grep -qE 'git push.*(--force|-f).*(main|master)'; then
echo "🚫 main/master への force push は禁止です" >&2
exit 2
fi
;;"Write"|"Edit")
FILE_PATH=$(echo "$TOOL_INPUT" | jq -r '.file_path // empty')
# .env ファイル編集を警告
if echo "$FILE_PATH" | grep -qE '\.env'; then
echo "⚠️ 環境変数ファイルを編集しようとしています" >&2
exit 1 # 警告のみ
fi
;;esac
exit 0
undefinedcase "$TOOL_NAME" in
"Bash")
COMMAND=$(echo "$TOOL_INPUT" | jq -r '.command // empty')
# 阻止强制推送
if echo "$COMMAND" | grep -qE 'git push.*(--force|-f).*(main|master)'; then
echo "🚫 禁止向main/master分支强制推送" >&2
exit 2
fi
;;"Write"|"Edit")
FILE_PATH=$(echo "$TOOL_INPUT" | jq -r '.file_path // empty')
# 警告.env文件编辑
if echo "$FILE_PATH" | grep -qE '\.env'; then
echo "⚠️ 正在尝试编辑环境变量文件" >&2
exit 1 # 仅警告
fi
;;esac
exit 0
undefinedPostToolUse: コミット後の提案
PostToolUse:提交后建议
bash
#!/bin/bashbash
#!/bin/bashsuggest-after-commit.sh
suggest-after-commit.sh
git commit 後のみ発火
仅在git commit后触发
if ! echo "$TOOL_INPUT" | grep -q "git commit"; then
exit 0
fi
if ! echo "$TOOL_INPUT" | grep -q "git commit"; then
exit 0
fi
変更ファイルをチェック
检查变更文件
CHANGED=$(git diff-tree --no-commit-id --name-only -r HEAD 2>/dev/null)
if echo "$CHANGED" | grep -q "schema"; then
echo "" >&2
echo "💡 スキーマが変更されました" >&2
echo " マイグレーションファイルの作成を検討してください" >&2
exit 1
fi
exit 0
undefinedCHANGED=$(git diff-tree --no-commit-id --name-only -r HEAD 2>/dev/null)
if echo "$CHANGED" | grep -q "schema"; then
echo "" >&2
echo "💡 已修改Schema" >&2
echo " 建议考虑创建迁移文件" >&2
exit 1
fi
exit 0
undefinedStop: セッション終了時クリーンアップ
Stop:会话结束时清理
bash
#!/bin/bashbash
#!/bin/bashcleanup-on-stop.sh
cleanup-on-stop.sh
マージ済みブランチの確認
检查已合并分支
MERGED=$(git branch --merged main | grep -v main | grep -v '*')
if [ -n "$MERGED" ]; then
echo "" >&2
echo "🧹 マージ済みブランチがあります:" >&2
echo "$MERGED" >&2
echo " 削除を検討してください: git branch -d <branch>" >&2
exit 1
fi
exit 0
---MERGED=$(git branch --merged main | grep -v main | grep -v '*')
if [ -n "$MERGED" ]; then
echo "" >&2
echo "🧹 存在已合并的分支:" >&2
echo "$MERGED" >&2
echo " 建议考虑删除:git branch -d <branch>" >&2
exit 1
fi
exit 0
---設定構造
配置结构
json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit|Bash", // 正規表現でマッチ
"hooks": [
{ "type": "command", "command": "/path/to/hook.sh" }
]
}
],
"PostToolUse": [
{
"hooks": [
{ "type": "command", "command": "/path/to/hook.sh" }
]
}
],
"Stop": [
{
"hooks": [
{ "type": "command", "command": "/path/to/hook.sh" }
]
}
]
}
}json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit|Bash", // 使用正则表达式匹配
"hooks": [
{ "type": "command", "command": "/path/to/hook.sh" }
]
}
],
"PostToolUse": [
{
"hooks": [
{ "type": "command", "command": "/path/to/hook.sh" }
]
}
],
"Stop": [
{
"hooks": [
{ "type": "command", "command": "/path/to/hook.sh" }
]
}
]
}
}デバッグ
调试
bash
undefinedbash
undefined直接実行してテスト
直接运行测试
TOOL_NAME="Bash" TOOL_INPUT='{"command":"git push --force main"}' ./my-hook.sh
echo $? # 終了コード確認
---TOOL_NAME="Bash" TOOL_INPUT='{"command":"git push --force main"}' ./my-hook.sh
echo $? # 检查退出码
---ベストプラクティス
最佳实践
- 非ブロッキング: 長時間処理は避ける
- stderr に出力: stdout ではなく stderr に出力
- 提案のみ: 自動実行せず、人間に判断を委ねる
- jq でパース: JSON パースには jq を使用
- フェイルセーフ: jq がない場合は許可(exit 0)
- 非阻塞:避免长时间处理
- 输出到stderr:输出到stderr而非stdout
- 仅建议:不自动执行,交由人工判断
- 用jq解析:使用jq解析JSON
- 故障安全:如果没有jq则允许执行(exit 0)