HAMPU:開発速度向上:コミット前のテスト実行をClaude.mdからhooksに移す
Claude Codeの動作に対する決定論的な制御を提供し、LLMが実行を選択することに依存するのではなく、特定のアクションが常に実行されることを保証します。
うまく動かない
Claude Sonnet 4.icon
JSONパース: jqを使った.tool_input.commandの抽出は正常動作
条件判定: grep -q "git commit"のマッチング条件は適切
コマンド構文: zsh対応の||演算子を使用
できた
Claude Sonnet 4.icon
Claude Code フック設定のコツ
成功のポイント
1. exit code は 2 を使用
終了コード2: ブロッキングエラー。stderrがClaudeに自動的にフィードバックされ処理されます。以下のフックイベント別の動作を参照してください。
2. エラーメッセージは stderr に出力
# ✅ 正しい - Claude Codeにメッセージ表示
echo "エラーメッセージ" >&2
# ❌ 間違い - メッセージが表示されない
echo "エラーメッセージ"
3. 正規表現で行頭マッチ
# ✅ 正しい - 確実にマッチ
grep -E "^git (commit|push)"
# ❌ 間違い - 部分マッチで誤動作
grep -q "git commit"
失敗例と修正例
失敗例1: exit 1 + 標準出力
code:❌ 動作しない例
COMMAND=$(jq -r '.tool_input.command // ""')
if echo "$COMMAND" | grep -q "git commit"; then
echo "🔍 Running pre-commit checks..."
npm run test || { echo "Tests failed"; exit 1; }
fi
問題: exit 1でブロックされず、メッセージも表示されない
修正例1: exit 2 + stderr
code:# ✅ 動作する例
COMMAND=$(jq -r '.tool_input.command // ""')
if echo "$COMMAND" | grep -E "^git commit" >/dev/null; then
echo "🔍 テストを先に実行してください" >&2
echo "npm run test" >&2
exit 2
fi
失敗例2: 曖昧なマッチング
code:❌ 誤動作する例
if echo "$COMMAND" | grep "commit"; then
# "git add . && git commit" でマッチするが
# "committed", "uncommitted" などでも誤マッチ
修正例2: 厳密なマッチング
code: ✅ 正確にマッチ
if echo "$COMMAND" | grep -E "^git (commit|push)" >/dev/null; then
# 行頭の "git commit" または "git push" のみマッチ
ベストプラクティステンプレート
code:zsh
COMMAND=$(jq -r '.tool_input.command // ""')
if echo "$COMMAND" | grep -E "^git push" >/dev/null; then
echo "🔍 コミット前チェックが必要です" >&2
echo "以下のようにコミットしてください:" >&2
echo "npm run lint && npm run typecheck && npm run test && git push" >&2
exit 2
fi
重要な原則
1. exit 2: ブロック専用のexit code
2. stderr (>&2): Claude Codeへのメッセージ表示
3. 厳密な正規表現: 意図しないマッチを防ぐ
4. 分かりやすいメッセージ: ユーザーが次に何をすべきかを明示
TODO