🙌

Claude Code hooks で輝きたい

に公開

こんにちは。株式会社PeopleXの桑原@kyuwabaraです。2024年1月に入社し、バックエンドを中心にGoを書いたりTypeScriptを書いたりしています。

はじめに

この数ヶ月で Coding Agent と一緒にお仕事をする機会が増えた方も多いのではないかと思います。私もご多分に漏れず Claude Code にあれやこれやと投げかけて自分に合った使い方を探る日々を送っています。
そんな中で、7月初め頃から[1]でしょうか、Claude Code hooks という機能についての話題が SNS などで見られるようになってきました。この記事は、Claude Code hooks がどのように動いているのかをざっと調べた内容をまとめたものです。技術的に難しいことや深く踏み込んだことは書かれていないので、肩肘張らずにご笑覧いただけると幸いです。

公式ドキュメント

まずは公式ドキュメントを参照し、どのような仕組みかのあたりを付けました。

Claude Code hooks are user-defined shell commands that execute at various points in Claude Code’s lifecycle.

いろんなタイミングで実行される、ユーザーが定義するシェルコマンドとのこと。git の pre-commit hook みたいなもんですね。シェルコマンドなので拡張性も高そうです。

実行のタイミングは、例えば次のようなものがあります。

  • PreToolUse: Claude Code がツールパラメータを組み立てた後、ツールを使う前
  • PostToolUse: Claude Code がツールの実行に成功した後
  • UserPromptSubmit: ユーザーがプロンプトを送信した時

詳しくはリファレンスの Hook Eventsをご参照ください。

動かしてみる

さて、具体的にどんな動きをするのか、イベント発火が分かりやすい UserPromptSubmit を例にとって確かめてみます。まずはシンプルにログに出してみました。
/hooks で新しい hook の追加を試してみましたが、なぜかうまくいきませんでした。仕方がないのでQuickstartを参考に設定ファイルを直接編集。

~/.claude/settings.json
{
  "hooks": {
    "UserPromptSubmit": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "jq '.' >> ~/.claude/jq.log"
          }
        ]
      }
    ]
  }
}

jq.log の中身はこんな感じ[2]でした。

jq.log
{
  "session_id": "2e64c258-785b-456f-b0e1-97e8f28c1043",
  "transcript_path": "/中略/2e64c258-785b-456f-b0e1-97e8f28c1043.jsonl",
  "cwd": "/PATH/TO/CURRENT/DIR",
  "hook_event_name": "UserPromptSubmit",
  "prompt": "こんにちは"
}

どうやら標準入出力で取り回せる[3]ようです。スクリプトを書いておけば、入力したプロンプトに対して何らかの介入をした上で処理を継続させたりできそう。

Context に追記する

せっかくなので Context に追記するのを試してみました。設定ファイルを以下のように変更します。

~/.claude/settings.json
{
  "hooks": {
    "UserPromptSubmit": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "jq '.' | ~/.claude/string-monitor.sh"
          }
        ]
      }
    ]
  }
}

指定しているシェルスクリプトはこんな感じ。実行権限をお忘れなく(1敗)。

~/.claude/string-monitor.sh
#!/bin/bash
export LANG=ja_JP.UTF-8

check_patterns() {
  local input="$1"
  if [[ "$input" == *"ping"* ]]; then
    # 標準出力経由でコンテクストに介入するテスト
    echo 'pong、とだけ返してください'
  fi
}

if [[ -p /dev/stdin ]]; then
  input=$(cat)
else
  input="$1"
fi

check_patterns "$input"

動かしてみると・・・
pingという文字を検出するとpongとだけ返してくれるClaude Code
介入できている。

この例が実用的かどうかはともかく、シェルスクリプトを通して柔軟な処理が可能だということが分かります。Claude Code が CLI ツールであることの利点と言えるかもしれません。

まとめ

特定のタイミングで自由にコマンドを差し込める、非常に柔軟でパワフルな Claude Code hooks がどのように動作しているかを、簡単な例を見ながらご紹介しました。具体的/実用的な使い方の紹介はちょっと探せばたくさん出てきます。うまく活用して Claude Code との良好な関係作りにお役立てください。

おまけ

最終的に string-monitor.sh はこうなりました。

~/.claude/string-monitor.sh
#!/bin/bash
export LANG=ja_JP.UTF-8

check_patterns() {
  local input="$1"
  if [[ "$input" == *"ultrathink"* ]]; then
    osascript -e "display notification \"\ハァイ!/\" with title \"ultrathink!\"" 2>/dev/null
    say -v Albert 'Hi'
  fi
}

if [[ -p /dev/stdin ]]; then
  input=$(cat)
else
  input="$1"
fi

check_patterns "$input"

弊社では開発には mac を使用しているので、その他の環境では動かない[4]ことをご容赦ください。

実行するとこんな感じになります。
ultrathinkに反応してリアクションしてくれるところのスクリーンショット
zennには動画を貼れないので雰囲気だけでも

Inspired by

脚注
  1. 感度が高い方はもっと早くからご存じだったかもしれません。 ↩︎

  2. 記事を編集している2025-07-31現在、リファレンスにサンプルが記載されています。作業当時見落としたのかもしれません。 ↩︎

  3. これもリファレンスに記載がありました。ちゃんと読みましょう。 ↩︎

  4. osascript と say[5] が動かない。notify-send とか VOICEVOX とか使ってなんとか出来るかも。音声ファイルは固定でいいのでコマンドラインから再生できればなんとでもなるはず。 ↩︎

  5. Albert くんの声が渋くておすすめ。 ↩︎

PeopleXテックブログ

Discussion