Blog
ハーネスエンジニアリングについて思考整理
※ Zennの再掲載です。初公開:2026年3月22日。 Zennの元記事
はじめに
こんにちは、 yunoです。 この記事は昨今、巷で話題のハーネスエンジニアリングについて自分なりの思考整理をするための記事です。
※ 私が基本利用しているのがClaude Codeのため、Claude Codeに寄った記述になることをご容赦ください mm
ハーネスエンジニアリングとは
ハーネスエンジニアリングは Mitchell Hashimoto 氏のブログの記載が最古のものとよく記事では見かけます。 その後、OpenAIの記事が出たことでより広がったと考えます。
逆瀬川氏のブログでは「一言で言えばCoding Agentをできるだけ人間の介入なしに自律的に稼働させ、出力を安定させるためのものを指します。」と言及されており、自分なりにより咀嚼した結果、ハーネスエンジニアリングとはハーネスとある通り、AIエージェントに装備を整え制御し、AIエージェントがより効率的に働くことができる環境を構築していくことだと捉えています。
勘所
ハーネスエンジニアリングにおけるポイントは「エージェントにお願いする」のではなく、「仕組みで制御」していく点にあります。 仕組みで制御することでAIの根幹にある「曖昧さ」をなるべく排除し、より信頼性高くエージェントにタスクを遂行させることができます。 ハーネスを整えていくためには以下の点をおさえ、実装・整備していく必要があります。
| ポイント | 概要 |
|---|---|
| 決定的 > 非決定的 | 決定論的ツールで制御できるものは仕組みで制御する |
| リポジトリ衛生 | 機械的に判断可能な情報を中心に置く |
| CLAUDE.md, AGENTS.mdは目次 | プロンプトではなく参照先への道標とする |
| エラーメッセージ = 教育 | エラーに修正手順を含め、エージェントが自律的に修正できるようにする |
| テストを回せる環境整備 | エージェントが自身でテストを実行・修正できる環境を作る |
| フィードバックループ | 検証→修正→再検証のループで品質を自律的に上げる |
| 定期的なスキャン | コードやドキュメントの陳腐化を検知・修正する仕組みを整える |
| 段階的導入 | 既存環境への影響を考慮し、段階的に導入する |
個人的な感想ですが、これらのポイントの半分はそもそも開発する上で整えているような環境構築・整備の話だと感じました。ハーネスエンジニアリングと名前がついてはいるものの、対象が人からAIに変わっただけという側面も大きいように思います。ただ、それ以外にも概念的な話が多く、奥が深いです。
決定的 > 非決定的
AIエージェントの「曖昧さ」をなるべく回避するには、決定論的ツールで制御できるものは決定論的ツールで制御することが基本です。 リントエラーやビルドエラー、型エラー、アーキテクチャテストなどをツールとして導入し、出力されたコードを検証することで確実に品質を担保できます。
Claude Codeであればhooks、pre-commit、CIを用いることで各層で検証することが可能です。 この際に、各フェーズで検知するルールやテストを分けることが重要です。 すべてを編集時に検知していては開発速度が落ち、開発体験が低下します。ここは人間が開発していた時と同様です。
| レイヤー | 実行タイミング | 検知対象 |
|---|---|---|
| hooks | ツール呼び出しごと(~ms) | 危険コマンドの遮断、保護ファイルへの書き込み防止、リント設定の改竄防止 |
| pre-commit | コミット時(~sec) | lint / format検証、型チェック、単体テスト |
| CI | push後(~min) | 統合テスト、ビルド検証、セキュリティスキャン |
また、リントの設定やルール改竄を防止するため、hooksを用いてバイパスや編集ができないように制御することも必要です。
例えば以下のようなPreToolUse hookを設定することで、エージェントがリント設定ファイルを書き換えようとした際に確実にブロックできます。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path // .tool_input.filePath // empty' | grep -qE '\\.(eslintrc|prettierrc|stylelintrc|editorconfig)|biome\\.json' && echo 'リント設定ファイルの直接編集は禁止されています。変更はチームレビューを経てください。' >&2 && exit 2 || exit 0"
}
]
}
]
}
}
このようにhooksは「お願い」ではなく「仕組み」として機能するため、コンテキストウィンドウが逼迫してCLAUDE.mdの指示が忘れられた場合でも確実に制御が効きます。
ただし、すべてを決定的に制御することは現状(2026/03/22時点)では難しいと考えています。
リポジトリ衛生
リポジトリには、コードやリンター設定、テスト、API定義(Swaggerなど)、型定義、ADR(Architecture Decision Records)のような意思決定の履歴など、機械的に正誤を判断できるものを置くのが良いです。
逆に、手書きの説明書やAPI説明書、機能について書かれたドキュメントなどは置かないほうが良いです。エージェントが実装を進める中でコードの変化にドキュメントのメンテナンスが追いつけず腐敗していき、エージェントに混乱をもたらすことになります。
要はコードやテストからわかるものはドキュメントとして置くべきではありません。
実際に業務で導入を行っていますが、一度立ち止まり「このドキュメントはコードや型、リントの設定、テストなどからわからないか?」と考えると、大部分のドキュメントは置かなくてよいことに気づきました。
(私の場合、初期の環境構築手順や会社的な制約など、リポジトリに入れたくはないが記述が必要な内容はGitHubのWiki機能を利用するようにしています。)
CLAUDE.md, AGENTS.mdは目次
今まで、CLAUDE.mdやAGENTS.mdについてよく見られた記事では「アーキテクチャはクリーンアーキテクチャです」や「xxxは禁止です」といったプロンプトが書かれていたと思います。
ハーネスエンジニアリング的には、ADRへのパスやリントルールへの参照、最低限必要なコマンドなどのような目次的な内容を記述するのが良いです。
例えばdocsフォルダがある場合は、docs配下にAGENTS.mdを用意し、ドキュメント群の目次を定義しておくと効果的です。
エラーメッセージ = 教育
OpenAIの記事にありますが、リンターやテストでのエラーメッセージを以下のようなフォーマットで返却することで、エージェントにエラーだけでなく修正方法まで伝えることができます。ツールがエージェントを「教育」しながら開発を進められるため、人間が介入せずにエージェントに実装タスクを遂行させることが可能になります。
ERROR: [何が間違っているか]
[どのファイル:行番号]
WHY: [なぜこのルールがあるか、ADRへのリンク]
FIX: [具体的な修正手順、コード例があれば含む]
EXAMPLE:
// Bad:
import { db } from '../infra/database';
// Good:
import { DatabaseProvider } from '../domain/providers';
テストを回せる環境整備
この内容はハーネスエンジニアリング以前の話ですが、UT・IT・E2Eをローカル内で実行し、エージェントが自身でテストを回せる環境を整える必要があります。 テスト結果に応じて修正を行えるようにし、品質ゲートを構築します。
また、フロントエンドであればChrome DevToolsやブラウザを用いてパフォーマンス検証をエージェント自身に行わせ、改善させるといった活用も効果的です。
フィードバックループ
上記の決定論的ツールでの検知やテストの実行に加え、別エージェントからのレビュー指摘を受けて修正し、再度レビューとツール検証を行う。このフィードバックループを構築することで、人間の介入なしに成果物の品質を上げることができます。
Claude Codeでの具体的なループの例として、PostToolUse hookでファイル編集後に自動でlintを実行し、エラーがあればadditionalContextとしてClaudeに返すことで自動修正を促す仕組みがあります。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path // .tool_input.filePath // empty'); [ -z \"$FILE\" ] && exit 0; RESULT=$(npx eslint --no-warn-ignored \"$FILE\" 2>&1) || { echo '{\"additionalContext\": \"以下のlintエラーを修正してください:\\n'\"$(echo $RESULT | head -20)\"'\"}'; exit 0; }; exit 0"
}
]
}
]
}
}
この仕組みにより、以下のループが人間の介入なしに回り続けます。
- エージェントがファイルを編集する
PostToolUsehookが自動でlintを実行する- エラーがあれば
additionalContextとしてClaudeのコンテキストに注入される - Claudeがエラー内容を受け取り、自律的に修正を行う
- 再び
PostToolUsehookが発火し、修正が正しいか検証される
さらに、別エージェント(サブエージェント)によるコードレビューをこのループに組み込むことで、lint以外の設計上の問題も検知・修正させることが可能です。
定期的なスキャン
定期的なスキャンで陳腐化していくコードやADRなどのドキュメントを修正していく仕組みを整える必要があります。
Claude Codeであればskillsとして定義し、/loopを用いることで定期的にコマンドを実行してスキャンをかけることができます。
コードの陳腐化はフレームワークやパッケージ、ライブラリの進化によって発生します。ベストプラクティスは日々変わるため、そのギャップを検知して修正のIssueを起票し、日々改修・マージしていく必要があります。
ADRとコードに乖離がある場合は、先祖返りに気づいていないか、ADRの更新が漏れているかのいずれかです。このような乖離を検知してIssueにすることで衛生を保つ必要があります。
段階的導入
さまざまな整備が必要ですが、案件で並列に開発が進む場合や既存のリポジトリに導入する場合、すぐには導入できない仕組みも出てきます。 その場合は段階的に導入していきましょう。
例えばリントの設定で、エラーではなくwarningにしておき、一時的に既存のリントエラーが修正されるまでブロックしない、あるいは編集されたファイルのみにブロックをかけ、新しくエージェントが編集・作成するものに関しては確実に制御する、といった方法が取れます。
また、自動承認など、組織のルールによって導入の可否が決まるものもあります。チームや組織の状況に合わせた導入計画が重要です。
まとめ
ハーネスエンジニアリングとは、AIエージェントに装備を整え制御し、効率的に働ける環境を構築していくことです。その核心は「エージェントにお願いする」のではなく「仕組みで制御する」という考え方にあります。
特に重要な原則は以下の3点です。
- 決定的制御を最大化する:hooks → pre-commit → CIの多層防御を構築し、各レイヤーで拾う問題を適切に分離する。実行コストが安い順に、手前で問題を潰す。
- リポジトリを信頼できる唯一の情報源にする:機械的に検証可能な情報(コード、テスト、型定義、リント設定、ADR)をリポジトリに集約し、腐敗しやすい散文的ドキュメントは排除する。
- 自律的な品質向上ループを構築する:エラーメッセージに修正手順を含め、テストを自身で回せる環境を整え、フィードバックループで人間の介入なしに品質を上げ続ける仕組みを作る。
これらの多くは従来の開発でも重要とされてきた原則と共通しています。ハーネスエンジニアリングは、その対象を人からAIエージェントに拡張した実践と言えるでしょう。ただし、AIエージェント特有の「曖昧さ」や「コンテキスト消失」といった課題に対応するため、より仕組みによる強制力が求められる点が異なります。
すべてを一度に導入する必要はありません。段階的に整備しながら、チームとプロジェクトに合った形でハーネスを育てていくことが現実的なアプローチです。