hooks

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

hooks - 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/bash
bash
#!/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
undefined
if echo "$TOOL_INPUT" | grep -q "rm -rf /"; then echo "🚫 已阻止危险命令" >&2 exit 2 fi
exit 0
undefined

2. 実行権限付与

2. 添加执行权限

bash
chmod +x .claude/hooks/my-hook.sh
bash
chmod +x .claude/hooks/my-hook.sh

3. 設定ファイルに登録

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/bash
bash
#!/bin/bash

validate-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
undefined
case "$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
undefined

PostToolUse: コミット後の提案

PostToolUse:提交后建议

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

suggest-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
undefined
CHANGED=$(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
undefined

Stop: セッション終了時クリーンアップ

Stop:会话结束时清理

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

cleanup-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
undefined
bash
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 $? # 检查退出码

---

ベストプラクティス

最佳实践

  1. 非ブロッキング: 長時間処理は避ける
  2. stderr に出力: stdout ではなく stderr に出力
  3. 提案のみ: 自動実行せず、人間に判断を委ねる
  4. jq でパース: JSON パースには jq を使用
  5. フェイルセーフ: jq がない場合は許可(exit 0)
  1. 非阻塞:避免长时间处理
  2. 输出到stderr:输出到stderr而非stdout
  3. 仅建议:不自动执行,交由人工判断
  4. 用jq解析:使用jq解析JSON
  5. 故障安全:如果没有jq则允许执行(exit 0)