はじめに
七尾百合子さん、お誕生日 225日目 おめでとうございます! nikkieです。
シェルスクリプトではなく Python スクリプトで Claude Code のフックを書けると知り、手を動かしました。
目次
cchooks
Claude Code のフックの偉大さを実感した nikkie 氏。
積ん読の「Claude CodeのHooksは設定したほうがいい - じゃあ、おうちで学べる」を読んでいたところ、awesomeの存在を知ります(「なぜHooksを設定したほうがいいのか」参照)。
awesome-claude-code の Hooks を見ていたところ、Python ライブラリの存在に気づきました。
https://pypi.org/project/cchooks/
A lightweight Python SDK with a clean API and good documentation
cchooks で書いた Python スクリプトによるフック
hatch fmtと同様のフックを実装しました。
ディレクトリ構成
.claude/ ├── hooks/ │ └── format_python.py └── settings.local.json
settings.local.json
{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/format_python.py" } ] } ] } }
format_python.py(chmod u+xしています)
このフックを設定した後の Claude Code の様子です(動作確認のため think off です)
https://gist.github.com/ftnext/490250598c37698f5f1c6581945d2430
Hatch のメッセージの修正漏れがありましたが、このフックは通るまで逃さないので最終的にはちゃんと直せました!
実装メモ
PostToolUse の例を参考にしました。
https://github.com/GowayLee/cchooks/tree/v0.1.4?tab=readme-ov-file#posttooluse-auto-formatter
気づき
cchooks.create_context()で Claude Code がフックに入力した JSON を受け取ります。
c.tool_input.get("file_path", "").endswith(".py")でTrueが返ったら、c.tool_inputにはfile_pathというキーがあることになるので、c.tool_input["file_path"]とできる!
subprocess.run()でhatch fmtを実行。
整形が必要な場合はcchooks.exit_block()で Hatch の出力を Claude Code に見せています。
整形の必要がない場合はcchooks.exit_success()で終了します。
ref: https://github.com/GowayLee/cchooks/tree/v0.1.4?tab=readme-ov-file#direct-control
工夫
一番の工夫はシバンのuv run。
cchooks 自体が inline script metadata とめちゃめちゃ相性がいいと感じました。
Hatch をどうインストールするかについては(炎上覚悟で)uvxでやってみました。
例にあるPostToolUseContextかのチェックは(JSONファイルでの設定からそうに決まっているので)省略。
また、tool_nameのチェックも同様の理由で省略しました。
終わりに
cchooks を使って Python スクリプトで Claude Code のフックを書きました。
cchooks は inline script metadata と非常に相性がいいと思いますので、cchooks を使う際は一緒の使用をぜひご検討ください!(本家リポジトリに布教しに行こうかな)