2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Mac]ClaudeCodeのStop Hooksを使ってユーザー応答待ちのとき「だけ」デスクトップ通知する

Last updated at Posted at 2025-07-02

Claude CodeのHooksで遊んでみました。

ユーザーの応答待ちのときに通知する、のような制御をしたかったんですが、
何も考えずにやると、ツールの完了時にも通知が鳴ったりしてわずらわしかったので、
ユーザーの応答待ちに入ったときだけに通知する方法を模索してみました

ちなみにMacです

うまくいくと、下記のようにデスクトップ通知+音声通知してくれるようになります。

CleanShot 2025-07-02 at 10.25.36@2x.png

結論

1.0.41のアプデで簡単になりました

~/.claude/settings.json

{
  # ...
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"応答完了しました\" with title \"Claude Code\" subtitle \"タスク完了\"'"
          },
          {
            "type": "command",
            "command": "say \"できたぜぇ!?\""
          }
        ]
      }
    ],
  }
}

だけです。


以下1.0.40以前のバージョンで無駄に頑張ったやつを供養のため載せときます

deprecated なぜこの仕組みが必要か?

Claude CodeのStopフックは、何らかの処理が完了するたびに作動します。これにはツールの実行完了も含まれるため、何も考えず下記のようにやると通知が過剰になりがちです。

~/.claude/settings.json

{
  # ...
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "say \"できたぜぇ!?\""
          }
        ]
      }
    ]
  }
}

Claudeアシスタントからの最後のメッセージが「ツール使用(tool_use)」なのか、それとも「テキスト応答(text)」なのかを判別し、「テキスト応答」のときだけ通知を出すようにします。

(余談) Notification Hooksだとどうなるか?

~/.claude/settings.json

{
  // ...
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "say \"確認してね!?\"'"
          }
        ]
      }
    ]
  }
}

これでもイケると思いきや、通知されるときとされない時があってよくわからないw

deprecated 事前準備:jq のインストール

このスクリプトは、JSONを処理するためのコマンドラインツール jq を利用します。もしインストールしていない場合は、Homebrewを使ってインストールしてください。

brew install jq

deprecated 設定手順

ステップ1: settings.json にフックを追加

まず、Claude Codeの設定ファイルに、処理完了時に特定のスクリプトを呼び出すための設定を追記します。

  1. ~/.claude/settings.json を開きます。
  2. 以下のhooksブロックを追記(または既存のhooksにマージ)してください。
{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/notify_on_task_completed.sh"
          }
        ]
      }
    ]
  }
}

この設定は、「Claudeの処理が停止(Stop)したら、常に指定したコマンド(notify_on_task_completed.sh)を実行する」という意味です。

ステップ2: 通知判定スクリプトを作成

次に、通知を送るかどうかを判断するシェルスクリプトを作成します。

  1. ~/.claude/ ディレクトリに notify_on_task_completed.sh という名前で新しいファイルを作成します。
  2. 以下のスクリプトをそのまま貼り付けてください。

ステップ3: スクリプトに実行権限を付与

作成したスクリプトが実行できるように、ターミナルで以下のコマンドを実行してください。

chmod +x ~/.claude/notify_on_task_completed.sh

deprecated 仕組みの解説

deprecated 通知条件

このスクリプトの肝はjq を使ってトランスクリプト内の最新アシスタントメッセージの種類をチェックしている部分です。

【ツール実行時のメッセージ構造】
{
  "role": "assistant",
  "message": {
    "content": [{
      "type": "tool_use",    ← これは無視される
      "name": "Read",
      "input": {...}
    }]
  }
}

【ユーザー応答時のメッセージ構造】
{
  "role": "assistant", 
  "message": {
    "content": [{
      "type": "text",        ← これだけが通知対象
      "text": "ファイルを作成しました。"
    }]
  }
}

スクリプトは後者、つまり typetext のメッセージを検知した場合にのみ、通知(osascriptsay)を実行します。これにより、不要な通知をカットしています。

deprecated 誤検出を防ぐために2段階の検出

通知条件に合致した場合、15s待ってから再度ログを取得し、条件を再確認させています。

        # 通知条件に合致しない場合は即座に終了
        if [ -z "$LAST_MESSAGE" ]; then
            exit 0
        fi
        
        # 通知条件に合致した場合のみ待機
        sleep 15
        
        # まだ自分のプロセスIDが記録されているか確認
        if [ ! -f "$LOCK_FILE" ] || [ "$(cat $LOCK_FILE 2>/dev/null)" != "$$" ]; then
            # 他のプロセスに置き換えられた場合は終了
            exit 0
        fi
        
        # 再度最新のアシスタントメッセージを確認
        LAST_MESSAGE=$(tail -50 "$TRANSCRIPT_PATH" | grep '"role":"assistant"' | while read -r line; do

なぜこれをやっているかというと、下記のような、「さあ作りますよ〜」とか、「色々考えてます」、みたいな出力に対しても

CleanShot 2025-07-02 at 11.36.03@2x.png

【ユーザー応答時のメッセージ構造】
{
  "role": "assistant", 
  "message": {
    "content": [{
      "type": "text",        ← これだけが通知対象
      "text": "ファイルを作成しました。"
    }]
  }
}

↑を満たしてしまい、誤反応してしまうためです。

なので一度条件に合致したら、ちょっと待ち、再度ログを取得して、次のメッセージが来てなければ完了として通知しています。もっとやり方ないの?

いちおう、非同期になってるので本体のClaudeCodeがブロックされることはありません。
自信ないので何かあればご指摘ください🙏

あと、普通にpythonでやればよかった...orz

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?