自己検証する Claude Code エージェント
自己検証する Claude Code エージェント: PostToolUse リントフック、Stop フック、読み取り専用レビュアーのサブエージェントをエージェント定義に組み込み、不良な出力が出荷されないようにする。
設定をやめて、構築を始めよう。
AIオーケストレーション付きSaaSビルダーテンプレート。
問題点: エージェントが一見問題なさそうな成果物を返す。するとリンターが叫び、エクスポートが欠けており、ファイル全体がスキップされていた。実行が終わって 20 分後のレビューでやっと気づく。
すぐに使えるコード: PostToolUse フックをエージェント定義に直接追加する。このエージェントが書いたファイルはすべて、あなたが見る前にリンターを通過する:
# .claude/agents/frontend-builder.md
---
name: frontend-builder
description: Build React components with automatic quality checks
model: sonnet
hooks:
PostToolUse:
- matcher: "Write|Edit"
hooks:
- type: command
command: 'npx eslint --fix "$CLAUDE_TOOL_INPUT_FILE_PATH" && npx prettier --write "$CLAUDE_TOOL_INPUT_FILE_PATH"'
---
You are a frontend builder agent. Create React components following
the project's established patterns. Every file you write is automatically
linted and formatted by your embedded hooks.このエージェントでリントされていないコードは選択肢にならない。チェックはそのエージェントのアイデンティティの一部であり、後付けで追加するものではない。
自己検証エージェントには 3 つの階層がある。それぞれが異なる種類のバグを捕捉し、きれいに積み重なる。
マイクロはツール呼び出しごと。エージェント定義の PostToolUse フックが、ファイルが書き込まれた直後にリンター、フォーマッター、型チェッカーを実行する。問題が起きた数秒後に捕捉される。
マクロはジョブ全体。エージェントが終了しようとすると、Stop フックが本質的な質問を投げかける: 必要なファイルは存在するか、エクスポートはあるか、テストスイートはグリーンか。いずれかが失敗すれば、エージェントは仕事が完了したと宣言することを許されない。
チームは 2 番目のエージェントを引き込む。読み取り専用のレビュアーが、クリーンなコンテキストウィンドウでビルダーの成果物を確認する。ビルダー/レビュアーパターンをスタック上の一段上に持ち上げた形だ。
PostToolUse: 書き込みのたびのマイクロ検証
エージェントのフロントマター内で宣言されたフックは、そのエージェントが実行しているときのみ発火する。スコープは自動的に設定される。ESLint はフロントエンドビルダーに属し、Ruff は Python ビルダーに属し、互いに衝突しない。
Black と mypy を接続した Python エージェント:
# .claude/agents/python-builder.md
---
name: python-builder
description: Build Python modules with automatic formatting and type checking
model: sonnet
hooks:
PostToolUse:
- matcher: "Write|Edit"
hooks:
- type: command
command: 'black "$CLAUDE_TOOL_INPUT_FILE_PATH" && mypy "$CLAUDE_TOOL_INPUT_FILE_PATH" --ignore-missing-imports'
---
You are a Python builder agent. Write clean, typed Python code.
Your hooks automatically format with Black and check types with mypy.メリットはスコープだ。これらのフックはエージェントに属している。プロジェクトレベルの設定には何も漏れない。オーケストレーターが Task ツールを通じてこのエージェントを起動すると、バリデーションも一緒についてくる。
マイクロは構文とフォーマットを捕捉する。書き込まれなかったファイルは捕捉できない。それには Stop フックが必要だ。
Stop フック: 完了前のマクロ検証
エージェントのフロントマターの Stop フックは SubagentStop イベントになる。このスクリプトは必要な出力ファイルがすべて存在し、求められたコンテンツが含まれているかを確認する:
#!/bin/bash
# .claude/scripts/validate-output.sh
# Validates that agent output meets structural requirements
INPUT=$(cat)
STOP_HOOK_ACTIVE=$(echo "$INPUT" | jq -r '.stop_hook_active // false')
if [ "$STOP_HOOK_ACTIVE" = "true" ]; then
exit 0
fi
# Check that required files exist
REQUIRED_FILES=("src/components/index.ts" "src/components/Button.tsx")
MISSING=""
for file in "${REQUIRED_FILES[@]}"; do
if [ ! -f "$file" ]; then
MISSING="$MISSING $file"
fi
done
if [ -n "$MISSING" ]; then
echo "{\"decision\": \"block\", \"reason\": \"Missing required files:$MISSING\"}"
exit 0
fi
# Check that index.ts contains exports
if ! grep -q "export" src/components/index.ts; then
echo "{\"decision\": \"block\", \"reason\": \"index.ts has no exports. Add barrel exports for all components.\"}"
exit 0
fi
exit 0そしてエージェント自体に接続する:
---
name: component-builder
description: Build component libraries with output validation
hooks:
PostToolUse:
- matcher: "Write|Edit"
hooks:
- type: command
command: 'npx prettier --write "$CLAUDE_TOOL_INPUT_FILE_PATH"'
Stop:
- hooks:
- type: command
command: "bash .claude/scripts/validate-output.sh"
---これで両方の階層が有効になる。各書き込みがフォーマットされる。エージェントの停止が許可される前に出力全体が採点される。Stop フックがブロックすれば、チェックが最終的にパスするまでエージェントは動き続ける。
読み取り専用バリデーターエージェント
3 番目の階層はファイルに触れられないレビュアーだ。disallowedTools がツール層でそれを強制する:
# .claude/agents/output-validator.md
---
name: output-validator
description: Validate agent output without modifying files. Use after builder agents complete.
model: haiku
disallowedTools: Write, Edit, NotebookEdit
---
You are a read-only validator. Your job:
1. Read all files the builder created or modified
2. Verify exports, type safety, and error handling
3. Run the test suite with Bash
4. Report issues as a list. Do NOT fix anything.
If all checks pass, say "Validation passed" with a summary.
If issues exist, list each one with file path and line reference.このエージェントにはファイル書き込みができない。読み取りと報告だけだ。タスクの依存関係を通じてビルダーとペアにする:
TaskCreate(subject="Build auth module", description="...")
TaskCreate(subject="Validate auth module", description="Run output-validator on src/auth/")
TaskUpdate(taskId="2", addBlockedBy=["1"])各階層の使い分け
マイクロのみ(PostToolUse)は、品質基準がリンティングで始まり終わる、小規模でタイトなタスクに適している。オーバーヘッドは低く、フィードバックは即座だ。
マイクロ + マクロ(PostToolUse + Stop)は、構造的な形を持つ複数のファイルを出荷するエージェントに向いている。Stop フックはリンターが決して捕捉しないものを捕まえる: 書き込まれなかったファイル、半分しか完成していないロジック、レッドのテストスイート。
3 つの階層すべては、間違いが許されないコードパスに属する。機械的なチェックが地道な作業を処理する。独立したレビュアーが、ビルダー自身のフックでは不可能だった第 2 の意見を提供する。
最もよく使うエージェントでマイクロ階層から始める。エージェントが未完成の成果物を渡してきた瞬間に Stop フックを追加する。成果物全体が正しくまとまっているかを重視するようになったら、各ファイルがパースするだけでなく、レビュアーを呼び込む。エージェント設定は CLAUDE.md に保持しても、プロジェクトに合わせて .claude/agents/ 以下に独立したファイルとして置いても構わない。
単一エージェントを超えて
自己チェックとチームチェックは代替手段ではなく、スタックとして考える。品質バグの約 90% は、レビュアーがファイルを開く前に、埋め込まれた PostToolUse フックと Stop スクリプトによって処理される。レビュアーに残るのは統合とアーキテクチャであり、フックがすでに飲み込んだリントエラーではない。
設定をやめて、構築を始めよう。
AIオーケストレーション付きSaaSビルダーテンプレート。