この記事は Claude on SonicGarden の記事です。ソニックガーデンのプログラマが、Claude Codeの活用について書いています。#claude_on_sonicgarden
きっかけ
Claude Codeの hooks 機能 を使おうとして、「発火させたいタイミングとちょっと違うんだよな」と感じたことはないでしょうか。Stop や PreToolUse など用意されているイベントは便利ですが、どれも「Claude Code自身のライフサイクル」に紐づいたもので、自分のやりたいタイミングに綺麗にハマらないことがあります。
そんなときは、ワークフローをTodoWriteを使ったスキルにすることで、自分が実行したいタイミングのhookを自作できるよ、という話です。
追記: 最近のバージョンでは、タスクリスト用のツールが
TodoWriteからTask*系ツール(TaskCreate/TaskUpdateなど)に変わっています。この記事の仕組みはそのままTask*でも成立します(各ステップをTaskCreateで登録し、TaskUpdateで1個ずつ消化していく)。新しくスキルを書くならTask*がよさそうです。以下のTodoWriteはTask*に読み替えてください。
Claude Code標準hooksの守備範囲
標準で用意されているhooksが発火できるタイミングは、2026年4月時点で27種類あります(公式ドキュメント)。代表的なものを挙げると:
-
SessionStart/SessionEnd -
UserPromptSubmit/Stop -
PreToolUse/PostToolUse -
SubagentStart/SubagentStop -
TaskCreated/TaskCompleted -
PreCompact/PostCompact
などです。どれも「Claude Codeがこういう状態になったら」が起点で、「自作ワークフローのこのステップが終わったら」というような要求は拾えません。
スキル+TodoWriteで任意タイミングhookを作る
仕組み
やっていることは単純です。
- ワークフローをスキル化する
- スキルの先頭で全ステップを
TodoWriteに登録させる - hookを発火させたいタイミング用のTodoも、ほかのステップと並べて登録しておく
各ステップがTodoとして並ぶので、Claude Codeは1個ずつ in_progress → completed と消化していきます。好きなタイミング用のTodoを混ぜておけば、そのタイミングでhookが走るという仕組みです。
hookと言っても特別な仕掛けがあるわけではなく、Todoリストに並ぶ1ステップにすぎません。ただ、並べるタイミングを自由に選べるので、「テストの後・レビューの前」のような標準hooksでは表現できないタイミングを作れます。
Markdown手順書ではなくTodoWriteで書く理由
Markdownに「Step 1、Step 2、...」と並べるだけだと、フェーズを飛ばされたり、レビューを1回で終わらされたり、そもそも守られなかったりします。TodoWriteに並べておくと1個ずつ completed にする挙動になるので、独自タイミングのhookも守られやすくなります。
この話は 別記事 で詳しく書いたのでここでは深掘りしません。
dev-workflowではこうやっている
実例として、自分が公開している dev-workflow というスキルの中身を紹介します。計画 → レビュー → 実装 → チェック → コードレビュー → ルール更新、という流れを回すスキルです。
全ステップをTodoWriteに登録する
スキルの先頭で、以下のような登録をさせています。
Register all workflow phases with `TodoWrite`:
- Step 2: Create Plan
- Step 3: Plan Review
- Step 5: Implement
- Step 6: Simplify
- Step 7: Check / Test
- Step 8: Code Review
- Step 9: Update Rules
- Step 10: Completion Hooks
ワークフロー本体はスキルにハードコードされていてチームで共有する前提ですが、そこに1箇所だけ個人が自由に処理を差し込めるhookポイントを用意しています。それが Step 10 です。
Step 10:ワークフロー完了hook
ユーザーが設定ファイルに以下のように書くと、ワークフロー完了時に任意のスキルやコマンドを実行できます。
# .claude/dev-workflow.local.md
hooks:
on_complete:
- "Skill(work-complete)"
- "afplay /System/Library/Sounds/Glass.aiff"
.local.md は個人設定ファイルで、gitignoreされるのが前提。つまりチーム共有のワークフローは変えずに、自分だけが実行したい処理を差し込める設計です。PR作成用スキルを呼んだり、完了通知を出したり、好きなことができます。
スキル側では、先頭の設定読み込みステップで on_complete が設定されていれば Step 10: Completion Hooks をTodoWriteに登録します。Step 10の処理内容は「登録されたエントリを順番に実行する」だけ。
### Step 10: Completion Hooks
Skip this step if `hooks.on_complete` is not configured.
1. Execute each entry in `hooks.on_complete` in order:
- `Skill(<name>)` pattern: invoke the skill
- Other strings: execute as a Bash command
2. If a hook fails, report the error but continue executing remaining hooks
標準の Stop hookでも似たことはできそうですが、「このスキルを使ったワークフローが正常完了したときだけ」というスコープに絞れるのが違いです。普通にClaude Codeを使っているときは発火しません。
同様の設計で「Step 5(実装)が終わった後に走らせるhook」「Step 8(コードレビュー)の前に走らせるhook」のように、好きなタイミング用のhookポイントを増やすことも可能ですし、おそらく今後増やすことになると思います。
守られる保証はない
TodoWriteに並べたからといって100%守られるわけではありません。途中で脱線してTodoを completed にし損ねたり、Todoが残っているのに次のステップに進んだりする可能性はあります。
ただ実際使っている感覚としてはほとんどのケースで意図したとおりに実行してくれているので十分現実的な手段だと思います。
おわりに
ワークフローをスキル化してTodoWriteで進行管理すると、Claude Codeの標準hooksでは届かない独自タイミングに処理を差し込めます。dev-workflow ではチーム共有のワークフローに対して、個人ごとに差し込める完了hookを用意する形で運用しています。
独自のワークフロースキルを書いている方は、hook差し込みポイントを意図的に設計すると面白いかもしれません。
今回実装例として紹介した dev-workflow スキルは以下のリポジトリで公開しています。
hiroro-work/claude-plugins
この記事はZenn/Qiitaにクロスポストしています