Claude Code に追加された Hook 機能を使って、これまで CLAUDE.md や githooks で実現していたツールの実行を Claude Code の設定に移してみる。format は公式でも利用例として紹介されている。
今回は format は編集時 PostToolUse 、lint と test は git commit
の PreToolUse で実行したいと考え、最終的には次のように設定した:
{
"hooks": {
"PostToolUse": [{
"matcher": "Write|Edit|MultiEdit",
"hooks": [{
"type": "command",
"command": "jq -r '.tool_input.file_path | select(endswith(\".js\") or endswith(\".ts\") or endswith(\".jsx\") or endswith(\".tsx\")) or endswith(\".json\")) or endswith(\".css\"))' | xargs -r bun biome format --write"
}]
}],
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "jq -r '.tool_input.command // \"\"' | grep -q \"^git commit\" && (bun run lint 1>/dev/null; [ $? -eq 1 ] && echo '{\"decision\":\"block\",\"reason\":\"Lint errors found. Fix them before committing.\"}' && exit 2) || true"
}, {
"type": "command",
"command": "jq -r '.tool_input.command // \"\"' | grep -q \"^git commit\" && (bun run test 1>/dev/null; [ $? -eq 1 ] && echo '{\"decision\":\"block\",\"reason\":\"Tests failed. Fix them before committing.\"}' && exit 2) || true"
}]
}]
}
}
format と lint には biome を使っていて、 test は monorepo でパッケージごとに異なるツールを利用している。設定のポイントとして、例えば biome lint
の Lint Error は Exit code が 1 なのでそのままでは git commit
が止まらない。そのため PreToolUse では、コマンドがエラーだったときに詳細な JSON と Exit code 2 を返すようにしている。少し読みやすくするとこうなる:
jq -r '.tool_input.command // \"\"' | grep -q \"^git commit\"
&& (bun run lint 1>/dev/null;
[ $? -eq 1 ]
&& echo '{\"decision\":\"block\",\"reason\":\"Lint errors found. Fix them before committing.\"}'
&& exit 2)
|| true
これで今のところうまく動いているよう見える。これが便利かはまだ体感できていないので、すぐにやめる可能性はある。