Claude Code や Codex といった AI コーディングエージェントを現場に投入する開発者が増えるなか、「ハーネスエンジニアリング」という新しい実践領域が注目を集めている。逆瀬川氏(@gyakuse)が公開したまとめ記事(読了 54 分)から、要点を紹介する。

そもそも「ハーネス」とは何か

「ハーネス(harness)」とは、もともと馬具の意味だ。馬の力を人間が制御して活かすための装具一式 — 手綱、鞍、轡(くつわ)などを指す。馬がどれだけ優秀でも、ハーネスなしでは暴走するだけで仕事にならない。

ソフトウェアの世界では「テストハーネス」という用語がすでにある。テスト対象のコードを「つなぎ止めて」、入力を与え、出力を検証する枠組みのことだ。テスト対象そのものではなく、テスト対象を正しく動かすための外側の仕組みを指す。

AI コーディングエージェントにおける「ハーネス」もこれと同じ発想だ。AI エージェント(= 馬)は強力だが、そのままでは暴走する。古いドキュメントを信じてしまう、リンターのルールを勝手に緩和する、前のセッションで何をしたか忘れる。エージェントを制御し、安定した成果を引き出すための外側の仕組み全体がハーネスであり、それを設計・構築する技術がハーネスエンジニアリングだ。

具体的にハーネスを構成する要素は、大きく 3 つの層に分けられる:

  1. 入力層 — エージェントに何を読ませ、何を読ませないかを制御する(AGENTS.md の設計、リポジトリの衛生管理、セッション間の状態引き継ぎ)
  2. 実行制御層 — エージェントの作業中にリアルタイムで品質を強制する(リンター・フォーマッターの自動実行、計画と実行の分離)
  3. 検証層 — エージェントの出力が正しいことを確認する(E2E テスト、プリコミットチェック)

核心的な洞察は「ハーネスがモデルより重要」という点だ。Morph の分析によると、同じモデルでもハーネスを変えると SWE-bench スコアが 22 ポイント変動するのに対し、モデルの交換では 1 ポイントしか変わらない。開発者の責任は「正しいコードを書く」から「エージェントが確実に正しいコードを生産する環境を設計する」へとシフトしている。

7 つの主要トピック

1. リポジトリ衛生 〈入力層〉

「衛生(hygiene)」は、ソフトウェア開発で「不要物や汚染を取り除き、健全な状態を保つ」という意味で使われる慣用表現だ(「コードハイジーン」「ブランチハイジーン」なども同様)。ここでは、リポジトリ内に古くなったドキュメントや不正確な情報が溜まらないよう清潔に保つことを指す。人間なら「このメモ、古そうだな」と判断できるが、エージェントは 3 ヶ月前のメモも最新のコードも同じ「事実」として読んでしまう。だから情報の鮮度管理が重要になる。

  • 実行可能なアーティファクト(コード、テスト、設定)を優先する
  • 説明的ドキュメントは腐敗しやすいため最小化する
  • ADR(Architecture Decision Records)で決定履歴を保全する
  • テストはドキュメントより腐敗に強い

最大の敵は「説明的ドキュメントの腐敗」だ。エージェントは「3 ヶ月前のメモ」と「現在の真実」を区別できないため、古い情報が存在するだけで性能が低下する。ハーネスの入力層として、エージェントが読む情報の鮮度と正確性を保つことが最初のステップになる。

2. 決定論的ツールで品質を強制する 〈実行制御層〉

「決定論的(deterministic)」とは、同じ入力に対して毎回必ず同じ結果を返すという意味だ。リンターやフォーマッターがその典型で、たとえば「未使用の変数がある」というコードを渡せば、何度実行しても必ず同じ警告を返す。気分や文脈によって判断が揺れることがない。

対照的に、LLM は非決定論的だ。同じコードを渡しても、実行するたびにチェックの粒度や指摘内容がブレる。「インデントを揃えて」と指示しても、ある時はスペース 2 つ、別の時はタブで揃えるかもしれない。

だからこそ、機械的に判定できるルール(構文エラー、未使用変数、フォーマット)は LLM に任せず、決定論的ツールに委ねるのが原則だ。

ここで重要なのが「ほぼ毎回」と「例外なく毎回」の差だ。CLAUDE.md に「リンターを実行せよ」と書くだけでは前者にとどまる。コンテキストウィンドウの消費が進むと、エージェントはリンターの存在を忘れてしまうからだ。Claude Code の Hook(特定のライフサイクルイベントで自動実行されるスクリプト)で強制すれば後者になる。

Claude Code Hooks の 4 パターン

パターンイベント用途
Safety GatesPreToolUse破壊的コマンド(rm -rf)のブロック、機密ファイルの編集禁止
Quality LoopsPostToolUseファイル編集後のリンター自動実行 → JSON で結果注入 → 自己修正ループ
Completion GatesStopエージェント完了宣言時にテスト実行、通るまで停止させない
Observability全イベントエージェントの意図と結果の監視・ログ記録

最も強力なのは Quality Loops だ。PostToolUse Hook でリンター・型チェッカーを自動実行し、エラーを hookSpecificOutput.additionalContext として JSON で返す。エージェントはこのフィードバックを受けて即座に自己修正する。このループがファイル書き込みのたびに繰り返される。

言語別の推奨スタック:

言語PostToolUseプリコミットカスタムルール
TypeScriptBiome + Oxlinttsc + ESLinteslint-plugin-local-rules
PythonRuff check/formatRuff + mypyast-grep
Gogofumpt + golangci-lint同左ast-grep

リンター設定の保護も重要だ。エージェントがリンターエラーに直面すると、コードを修正するのではなくリンター設定を変更してエラーを消そうとすることが頻繁に観察される。PreToolUse Hook で設定ファイルの編集をブロックし、git commit --no-verify の実行を禁止することで、エージェントがルールを迂回する道を構造的に塞ぐ。

エラーメッセージを修正指示にする

OpenAI チームの巧みな手法として、カスタムリンターのエラーメッセージに「何が間違っているか」だけでなく「どう修正するか」まで含めるアプローチがある。エージェントはリンターエラーを無視できない(CI が通らないため)が、ドキュメントは無視できる。だからルールの説明はエラーメッセージの中に書く:

ERROR: ServiceA は Infrastructure レイヤーに直接依存できません
  src/services/ServiceA.ts:42
  WHY: 依存方向違反 (ADR-007 参照)
  FIX: Provider インターフェースを Domain 層に定義し、
       Infrastructure 層で実装してください

3. AGENTS.md / CLAUDE.md は「道しるべ」に徹する 〈入力層〉

AGENTS.md や CLAUDE.md は、エージェント起動時に最初に読み込まれる指示書だ。ここに詳細な説明を長々と書きたくなるが、それは逆効果になる。情報が多すぎるとエージェントのコンテキストを圧迫し、肝心の作業に使える余裕が減る。

原文ではこれをポインタ設計と呼んでいる。指示書自体に内容を書くのではなく、「詳しくはこのファイルを見よ」と参照先だけを示す設計だ。C 言語のポインタが値そのものではなくアドレスを持つのと同じ発想で、指示書は情報の「置き場所」を指し示す道しるべに徹する。

  • 50 行以下を目標にする(IFScale の研究では 150〜200 指示の時点で primacy bias — 先頭の指示が優先され後半が無視される傾向 — が顕著になり性能が劣化し始める)
  • 詳細は別ファイル(Skills、.claude/rules/)に分離し、参照のみ記述する
  • 記述的説明ではなくルーティング指示(「○○については docs/xx.md を参照」)に集中する
  • ポインタが指す先が消えれば 404 相当のエラーが起き、腐敗が機械的に検出可能になる(説明的ドキュメントの腐敗は沈黙のうちに進行する)

4. 計画と実行の分離 〈実行制御層〉

  • 計画段階を人間がレビューする
  • 一度に複数機能に取り組まない
  • テストで完了を検証する

エージェントにいきなりコードを書かせず、まず計画を出力させて人間が確認する。馬に走り出す前に行き先を確認させるようなものだ。

5. E2E テスト戦略 〈検証層〉

エージェントは自分が書いたコードを「見る」手段がなければ、コンパイルが通っただけで「完了」と宣言する。Anthropic の実験ではブラウザ自動化を導入したことで、コードだけからは見えなかったバグをエージェントが自力で発見・修正するようになった。

各領域ごとの推奨ツール:

アプリタイプ構造化テキストインターフェース推奨ツール
WebアクセシビリティツリーPlaywright CLI / agent-browser
Mobileアクセシビリティツリーmobile-mcp / XcodeBuildMCP
CLI標準出力/エラー出力bats-core / pexpect
APIHTTP レスポンスHurl / Pact
InfrastructurePlan 出力/スキーマterraform test / conftest
AI/ML評価メトリクスlm-evaluation-harness / DeepEval

Web アプリのテストでは、MCP(Model Context Protocol)版 Playwright よりも CLI 版の方がトークン効率が約 4 倍良い(114,000 トークン vs 27,000 トークン)。長いセッションではコンテキスト消費の差が品質に直結する。

ユニバーサル原則は「構造化テキストで検証し、決定論的に実行可能にする」こと。エージェントにテストを生成させ、生成されたテストを CI で決定論的に実行するのが推奨パターンだ。

6. セッション間の状態管理 〈入力層〉

  • 起動ルーティンを標準化する
  • Git ログとコミットメッセージで前回状態を記録する
  • 進捗は JSON で機械的に解析可能な形式にする

エージェントは毎回新しいセッションで起動するため、前回の作業内容を「覚えていない」。入力層として、前回の状態を確実に引き継ぐ仕組みが必要になる。

7. Codex vs Claude Code 〈全層〉

  • Claude Code(作業場型): ローカル環境で直接操作。全ツール(Write/Edit/Bash 等)対応の安定版 Hooks で品質ループを構築可能
  • Codex(密室型): クラウドサンドボックスでの並列実行。2026 年 3 月 26 日の rust-v0.117.0 で実験的 Hooks を導入(Pre/PostToolUse は Bash のみ対応)
  • ハイブリッド構成: Claude Code で計画・設計 → Codex で並列実行 → Claude Code でレビュー
優先事項推奨理由
品質Claude Code 主軸Hooks が全ツール対応の安定版
スループットCodex 主軸非同期サンドボックスでの並列実行
両方Claude Code でハーネス構築 → Codex でスケールハーネスの品質がスケール時の信頼性を決定

フィードバック速度が品質を決定する

フィードバックループの品質は速度に比例する。できるだけ多くのチェックをより速いレイヤーに移動させるのがハーネスエンジニアリングの目標だ。

  1. 最速(ミリ秒): PostToolUse Hook → フォーマッター・リンター自動実行
  2. 速い(秒): プリコミットフック → リンター・型チェック(Lefthook 推奨)
  3. 遅い(分): CI/CD パイプライン → 全テストスイート
  4. 最遅(時間〜日): 人間のコードレビュー

MVH(Minimum Viable Harness)ロードマップ

段階的に導入するためのロードマップ:

  • Week 1: AGENTS.md 作成、プリコミットフック導入、PostToolUse Hook 設定
  • Week 2-4: テスト追加、計画→実行ワークフロー確立、E2E テスト導入
  • Month 2-3: カスタムリンター構築、記述ドキュメント削減
  • Month 3+: 高度なフィードバックループ、複数エージェント管理

まとめ

「コンテキスト内で発見できないものは存在しないのと同じ」であり、「リポジトリ内で発見できる古い情報は最新の真実と区別不可能」。このジレンマを理解した上で、実行可能なアーティファクトと決定論的ツールを中心にハーネスを設計することが、AI コーディングエージェント時代の開発者に求められるスキルだ。

参考