Claude Code の hooks 機能を使って、ツール呼び出しの権限判定をすべてロギングし、そのログを Claude に分析させてハーネスを継続的に改善する仕組みを作りました。
ハーネスの改善を自動化したい
Birgitta Böckeler の Harness engineering for coding agent users では、コーディングエージェントにおけるハーネス(モデル以外のすべて)の制御を2つの方向で整理しています。
- フィードフォワード(ガイド): エージェントが行動する前に望ましい方向へ操舵する。CLAUDE.md やスキル定義、ブートストラップスクリプトなど
- フィードバック(センサー): エージェントの出力を観察し、問題を検出して自己修正させる。リンター、テスト、構造テストなど
そして、問題の観察 → ハーネスの改善 → 再観察というループ(steering loop)を継続的に回すことが重要だとされています。
The human's job in this is to steer the agent by iterating on the harness. Whenever an issue happens multiple times, the feedforward and feedback controls should be improved to make the issue less probable to occur in the future, or even prevent it.
Claude Code のハーネスには settings.json(allow/deny ルール)、CLAUDE.md(行動指針)、hooks(PreToolUse バリデータ)など複数の構成要素があり、継続的に改善していく必要があります。しかし問題が起きるたびに都度修正するのは作業の中断を伴い、負担になります。
そこで、hook イベントのロギング・集計・AI 分析の3層で steering loop を自動化する仕組みを構築し、Claude Code プラグインとして公開しました。
3層アーキテクチャ
Claude Code Harness
|
v
[1] log-hook-event.sh ─── JSONL ログ記録(計装基盤)
|
v
[2] aggregate-hook-logs.sh ─── 集計・事実収集(決定論的処理)
|
v
[3] /tool-use-steering:improve ─── AI による分類・判断・適用(意味的判断による steering)
- ロギング層: 全 hook イベントを JSONL で記録する計装基盤
- 集計層: シェルスクリプトで決定論的にグルーピング
- 分析層: Claude が集計結果を読み、意味的判断で改善候補を分類・提示・適用する steering
各層の役割を明確に分離しているのがポイントです。
ロギング層: steering loop のための計装
Claude Code の hooks は権限判定を含む4つの hook イベント(PreToolUse / PostToolUse / PermissionRequest / PermissionDenied)を提供しています。プラグインの hooks.json で全イベントに log-hook-event.sh を登録し、~/.claude/logs/<session_id>.jsonl に追記します。
実装は disler/claude-code-hooks-mastery の hook イベントを JSON にロギングするパターン(.claude/hooks/ 配下の各スクリプト)を参考にしつつ、以下の点を変えています。
- bash + jq の1スクリプト構成: disler は Python (uv) でイベントごとに別スクリプトを用意していますが、こちらは実行オーバーヘッドを最小化するために bash + jq の1本で全イベントを処理します
- セッション単位のファイル分割: disler はイベント種別ごとにファイルを分けますが、こちらは
<session_id>.jsonlでセッションごとに分けています。並列セッションのログが混ざらず、後述のツール呼び出し単位の集約も自然に書けます - tool_response 本文の除外:
is_errorフラグのみ抽出し本文は捨てています。秘密情報の混入リスクとファイルサイズの抑制のためです
集計層: 決定論的な事実収集
ログをツール呼び出し単位にグルーピングし、統計を出力するシェルスクリプトです。核心は各ツール呼び出しがどの権限フローを辿ったかの導出で、同一コマンドの Pre / Req / Denied / Post イベントの発火パターンから「自動許可」「ユーザー許可」「ユーザー拒否」「自動拒否」の4状態を機械的に分類します。
設計判断として、このスクリプトには改善アクションの判断ロジックを入れていません。 「このコマンドを allow に追加すべきか」といった意思決定は次の分析層に委ねています。この層は純粋に決定論的な処理に徹しています。
分析層: 意味的判断による steering
集計結果を Claude に読み込ませ、改善候補を対話的に適用するスラッシュコマンドです。
/tool-use-steering:improve # 直近14日分を分析
/tool-use-steering:improve 7 # 直近7日分を分析
Claude は集計 JSON を読み、まず各パターンの根本原因を分析します。シグナルから直接アクションに飛ばず、なぜそのパターンが発生しているかを考えてから分類に進む設計です。
たとえばユーザー承認が多いコマンドがあっても、単に allow に追加すればいいとは限りません。gh issue comment のように人間がレビューしてから実行したいコマンドなら、allow ではなく ask に追加して明示的に許可を出す方が適切です。gh api を全て許可するのはリスクがありますが、頻出するパターンがあるならスクリプトに切り出してそのスクリプトだけを許可する方が安全です。
根本原因を踏まえた上で、改善候補をフィードフォワードとフィードバックの2方向に分類します。
- フィードフォワード改善: CLAUDE.md へのルール追加。Claude が繰り返し同じ禁止コマンドを試みている場合、行動指針としてガイドを追加する
- フィードバック改善: settings.json の allow/deny 調整、スクリプト抽出、hook バリデータの修正など
- エラー多発箇所の検出: lint/test/build で繰り返しエラーが発生しているコマンドを特定し、情報提示する。自動修正はしない
また、上記に当てはまらないパターンが見つかった場合は新しいカテゴリとして報告させる仕組みにしており、運用しながらパターンを見出して分析項目を追加していく予定です。
日次の改善ループ
現在は日次のスケジュールで /tool-use-steering:improve 1 を実行し、前日のログから settings.json の調整を対話的に適用しています。14日以上経過したログは自動削除されます。
まとめ
Claude Code の hook イベントをロギングし、集計と AI 分析を組み合わせることで、ハーネスの steering loop を自動化しました。
今回はツール呼び出しの権限判定イベントを起点とした steering loop でしたが、ハーネス改善のデータソースはこれだけではありません。セッションログからの行動パターン分析、コードレビューの指摘傾向、テスト失敗の再発パターンなど、異なる観点からの steering loop も模索していきたいと考えています。
参考
- Harness engineering for coding agent users — Birgitta Böckeler による harness engineering のフレームワーク。フィードフォワード/フィードバック、決定論的/意味的判断の分類と steering loop の概念
- disler/claude-code-hooks-mastery — 全13 hookイベントの包括的な実装パターン集。ログ形式やイベント設計の参考にした
- Hooks - Claude Code — 公式ドキュメント