Build This Now
Build This Now
キーボードショートカットステータスラインガイド
フックガイドClaude Code クロスプラットフォームフックClaude Code セットアップフックストップフック自己検証する Claude Code エージェントClaude Code セッションフックClaude Code コンテキストバックアップフックスキルアクティベーションフックClaude Code パーミッションフックClaude CodeのMCPツールフックCommands to Skills
Skills, Subagents, HooksSubagent Sweet SpotCLAUDE.md Best PracticesFix Context Limit
speedy_devvkoen_salo
Blog/Toolkit/Hooks/Stop Hooks

ストップフック

ストップフックはテストが失敗、ビルドが壊れている、またはlintがエラー状態のうちはClaude Codeがターンを終了するのをブロックする。4つの強制パターンとループ保護のセーフガード。

設定をやめて、構築を始めよう。

AIオーケストレーション付きSaaSビルダーテンプレート。

企業向けに構築している実績を見る →
speedy_devvWritten by speedy_devvPublished Feb 25, 2026Toolkit hubHooks index

問題: Claudeがレスポンスをまとめるが、作業は実際には終わっていない。テストはまだ失敗している。ファイルは半分しか書けていない。「終わった?」と聞くと「はい」と答えるが、ビルドはレッドのままだ。

即効策: このストップフックを追加すれば、テストがグリーンになるまでClaudeはターンを終了できなくなる:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python .claude/hooks/test-gate.py"
          }
        ]
      }
    ]
  }
}
#!/usr/bin/env python3
import json
import sys
import subprocess
 
input_data = json.load(sys.stdin)
 
# CRITICAL: Prevent infinite loops
if input_data.get('stop_hook_active', False):
    sys.exit(0)
 
# Run tests
result = subprocess.run(['npm', 'test'], capture_output=True, timeout=60)
 
if result.returncode != 0:
    output = {
        "decision": "block",
        "reason": "Tests are failing. Fix them before completing."
    }
    print(json.dumps(output))
    sys.exit(0)
 
sys.exit(0)

これ以降、Claudeはテストスイートが失敗した状態でターンを閉じることが文字通りできなくなる。

ストップフックの仕組み

Claudeがレスポンスを終了しようとするたびにこのフックが発火する。起こりうることは3つ:

  1. 停止を許可 - Exit 0で終了し、ターンが正常に終わる。
  2. 停止をブロック - {"decision": "block", "reason": "..."} を返すと、Claudeが継続する。
  3. バリデーションを実行 - テスト、チェック、任意のスクリプトを起動する。

ペイロード

{
  "session_id": "uuid-string",
  "stop_hook_active": false,
  "transcript_path": "/path/to/transcript.jsonl"
}

stop_hook_active に注意する。trueの場合、Claudeはすでに以前のブロックによる強制継続状態にある。このフラグを見落とすと無限ループになる。

パターン1: テストゲート

すべてのテストが通過するまでターンを開いたままにする:

#!/usr/bin/env python3
import json
import sys
import subprocess
 
input_data = json.load(sys.stdin)
 
if input_data.get('stop_hook_active', False):
    sys.exit(0)
 
result = subprocess.run(
    ['npm', 'test', '--passWithNoTests'],
    capture_output=True,
    timeout=120
)
 
if result.returncode != 0:
    # Extract last 10 lines of test output for context
    stderr = result.stderr.decode()[-500:] if result.stderr else ""
    print(json.dumps({
        "decision": "block",
        "reason": f"Tests failing. Output: {stderr}"
    }))
    sys.exit(0)
 
sys.exit(0)

パターン2: ビルドバリデーション

プロジェクトがコンパイルされるまでブロックする:

#!/usr/bin/env python3
import json
import sys
import subprocess
 
input_data = json.load(sys.stdin)
 
if input_data.get('stop_hook_active', False):
    sys.exit(0)
 
result = subprocess.run(
    ['npm', 'run', 'build'],
    capture_output=True,
    timeout=180
)
 
if result.returncode != 0:
    print(json.dumps({
        "decision": "block",
        "reason": "Build failed. Fix compilation errors before completing."
    }))
    sys.exit(0)
 
sys.exit(0)

パターン3: リントチェック

lintエラーが残ったままターンを終了させない:

#!/usr/bin/env python3
import json
import sys
import subprocess
 
input_data = json.load(sys.stdin)
 
if input_data.get('stop_hook_active', False):
    sys.exit(0)
 
result = subprocess.run(
    ['npx', 'eslint', 'src/', '--max-warnings=0'],
    capture_output=True,
    timeout=60
)
 
if result.returncode != 0:
    print(json.dumps({
        "decision": "block",
        "reason": "Lint errors detected. Run eslint --fix or resolve manually."
    }))
    sys.exit(0)
 
sys.exit(0)

パターン4: タスク完了マーカー

特定のタスクフラグでターンをゲートする:

#!/usr/bin/env python3
import json
import sys
from pathlib import Path
 
input_data = json.load(sys.stdin)
 
if input_data.get('stop_hook_active', False):
    sys.exit(0)
 
# Check for incomplete task marker
marker = Path('.claude/incomplete-task')
if marker.exists():
    task_info = marker.read_text().strip()
    print(json.dumps({
        "decision": "block",
        "reason": f"Task incomplete: {task_info}. Finish it before stopping."
    }))
    sys.exit(0)
 
sys.exit(0)

作業開始時にマーカーを配置する:

echo "Implement user authentication" > .claude/incomplete-task

作業が完了したらクリアする:

rm .claude/incomplete-task

無限ループの防止

stop_hook_active フラグが重要な理由はこれだ。なければこうなる:

Claude responds → Stop hook fires → "block" → Claude continues
                                            ↓
Claude responds → Stop hook fires → INFINITE LOOP (without flag check)

常にフラグを最初に確認する:

if input_data.get('stop_hook_active', False):
    sys.exit(0)  # Allow stopping, break the loop

複数チェックの組み合わせ

1つのフックで複数のゲートを連鎖できる:

#!/usr/bin/env python3
import json
import sys
import subprocess
 
input_data = json.load(sys.stdin)
 
if input_data.get('stop_hook_active', False):
    sys.exit(0)
 
checks = [
    (['npm', 'run', 'lint'], "Lint errors"),
    (['npm', 'run', 'typecheck'], "Type errors"),
    (['npm', 'test'], "Test failures"),
]
 
for cmd, error_msg in checks:
    result = subprocess.run(cmd, capture_output=True, timeout=120)
    if result.returncode != 0:
        print(json.dumps({
            "decision": "block",
            "reason": f"{error_msg} detected. Fix before completing."
        }))
        sys.exit(0)
 
sys.exit(0)

ストップフックを使うべき場面

適切なユースケース:

  • 「タスク完了」前にテストスイートをグリーンにする
  • ビルドが正常にコンパイルされていることを確認する
  • lintやタイプエラーを検出する
  • 自分なりの「完了」の定義に合わせたカスタムルール

適切でないユースケース:

  • 60秒のタイムアウトより長く実行されるもの
  • ネットワークにアクセスしてフレークするチェック
  • 人間の回答が必要なプロンプト(ここではインタラクションできない)

設定

.claude/settings.json に設定する:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python .claude/hooks/stop-validation.py"
          }
        ]
      }
    ]
  }
}

複数のフックを同時に並列で実行できる。いずれか1つから block が返るとClaudeは継続する。

デバッグ

ループにはまった場合

  • スクリプトの先頭で stop_hook_active を読み込んでいるか再確認する
  • ログに記録する: echo "stop_hook_active: $stop_hook_active" >> ~/.claude/stop-debug.log

ブロックが機能しない場合

  • JSONは {"decision": "block", "reason": "..."} の形式でなければならない
  • Exit code 0を使う。2ではない。Exit 2は別のブロックパスに使われる。

テストが長時間実行される場合

  • フックのタイムアウトは60秒
  • より小さなサブセットを実行するか、テストスイートを高速化する

「Ralph Wilgum」パターン

このパターンはコミュニティのテクニックで、ストップフックを使って永続的なタスクループを強制する:

  1. セッション開始時にタスクマーカーを配置する
  2. マーカーが存在する間はストップフックがブロックする
  3. Claudeに完了の証明としてマーカーを削除させる
  4. 作業が残っているのに誤って「完了」と言われることがなくなる

結果: Claudeはベストエフォートから保証された完了にシフトする。

次のステップ

  • メインのフックガイドですべてのフックタイプを確認する
  • コンテキストリカバリーを設定してセッションをコンパクション後も存続させる
  • スキルアクティベーションで自動的なスキル読み込みを設定する
  • 自動承認フローのパーミッションフックを確認する

Continue in Hooks

  • Slash Commands Are Now Skills: Migrating Commands to Skills
    Claude Code slash commands and skills now do the same thing. Here is how to migrate .claude/commands to .claude/skills and why it pays off.
  • Claude Code セットアップフック
    スクリプト、エージェント、ドキュメントをClaude Codeのセットアップフックに組み合わせる方法。1つのコマンドで決定論的スクリプトを実行し、診断エージェントに出力を渡し、自動更新されるドキュメントを記録する。
  • Claude Code コンテキストバックアップフック
    StatusLineを活用したClaude Codeのコンテキストバックアップフック。10Kトークンごとに構造化されたスナップショットを書き込み、自動圧縮によってエラー文字列・関数シグネチャ・判断内容が失われるのを防ぐ。
  • Claude Code クロスプラットフォームフック
    Claude Codeのクロスプラットフォームフック: .cmd・.sh・.ps1のラッパーを捨て、nodeを直接呼び出すことで、1つの.mjsファイルがmacOS・Linux・Windowsで動く方法。
  • フックガイド
    Claude Code フックの基礎から実践まで: 終了コード、JSON出力、非同期コマンド、HTTPエンドポイント、PreToolUseとPostToolUseのマッチャー、本番環境パターン。
  • Claude CodeのMCPツールフック
    type: mcp_toolを使ってClaude CodeのフックからMCPサーバーのツールを直接呼び出す方法。スキーマ、変数展開の構文、ユースケース、本番パターンまで解説します。

More from Toolkit

  • CLAUDE.md, Skills, Subagents, Hooks: When to Use Which
    Claude Code skills vs subagents vs hooks vs CLAUDE.md: a plain mental model for picking the right primitive, with token costs and examples.
  • Claude Code Subagents: The 3 to 5 Agent Sweet Spot
    Claude code subagents work best at 3-5 concurrent agents. Here is why that ceiling exists, how to set them up, and what to use past it.
  • CLAUDE.md Best Practices: The File That Makes Claude Code Reliable
    CLAUDE.md best practices: keep it under 200 lines, write it by hand, and use hooks when you need real enforcement, not advice.
  • How to Fix Claude Code Running Out of Context
    Claude Code running out of context is a session design problem. Fix it with /compact, lean CLAUDE.md, skills, and subagents, not a bigger window.

設定をやめて、構築を始めよう。

AIオーケストレーション付きSaaSビルダーテンプレート。

企業向けに構築している実績を見る →

Claude Code セットアップフック

スクリプト、エージェント、ドキュメントをClaude Codeのセットアップフックに組み合わせる方法。1つのコマンドで決定論的スクリプトを実行し、診断エージェントに出力を渡し、自動更新されるドキュメントを記録する。

自己検証する Claude Code エージェント

自己検証する Claude Code エージェント: PostToolUse リントフック、Stop フック、読み取り専用レビュアーのサブエージェントをエージェント定義に組み込み、不良な出力が出荷されないようにする。

On this page

ストップフックの仕組み
ペイロード
パターン1: テストゲート
パターン2: ビルドバリデーション
パターン3: リントチェック
パターン4: タスク完了マーカー
無限ループの防止
複数チェックの組み合わせ
ストップフックを使うべき場面
設定
デバッグ
「Ralph Wilgum」パターン
次のステップ

設定をやめて、構築を始めよう。

AIオーケストレーション付きSaaSビルダーテンプレート。

企業向けに構築している実績を見る →