← ブログに戻る

ハーネスエンジニアリング、Fowler実物の3節

この記事を含む総合ガイド Claude Code 実戦運用ガイド

「ハーネスエンジニアリング」を新語だと思っていた時期があります。AGENTS.md を書いたり、hooks を設定したり、新しい足場を組み上げていく仕事だと。Martin Fowler の Harness engineering for coding agent users (2026-04-02) を読み直したのは今週です。読み終えて、自分がこの3年で書いてきた pre-pushcheck-built-pages.mjs に、Fowler が名前を付けてくれただけだと気づきました。

この記事は、Fowler の原文にある3つの節を順番に読み、それぞれ自分の kenimoto-dev リポジトリで対応する装置を棚卸ししたログです。書いてみて分かったのは、ハーネスは「これから作るもの」ではなく、「既にあるものを見つけて、足りないところに 1 個ずつ足すもの」だということです。

Fowler の3節と kenimoto-dev リポジトリの既存装置の対応

Fowler の定義: Agent = Model + Harness

まず Fowler が Harness をどう定義しているかを、原文の言葉で確認します。

Agent = Model + Harness

これだけです。エージェントを構成する要素のうち「モデルそのもの以外の全部」がハーネス、という広い定義です。定義が広いので、記事本体は「じゃあその全部を、どんな軸で分けて論じるか」の話に費やされます。Fowler は自分の記事の中で複数の切り口を提示していますが、私が読み直して「ここが実装者にとって効く」と感じた3節を選んで並べます。

  • 1節目: Feedforward vs Feedback (Guides と Sensors)
  • 2節目: Computational vs Inferential
  • 3節目: Harnessability

3節目の Harnessability が、この記事の中心にある概念です。「ハーネスはコードベースに埋まっている」という主張の出どころはここです。ですが 3節目だけを読むと文脈が抜けるので、1節目と 2節目を先に置きます。

1節: Guides と Sensors (Feedforward vs Feedback)

Fowler は Harness を大きく 2 種類に分けます。原文の表現でいうと Guides は「anticipate the agent’s behaviour and aim to steer it before it acts」、Sensors は「observe after the agent acts and help it self-correct」です。前者はフィードフォワード制御、後者はフィードバック制御に対応します。

具体例に落とすと、AGENTS.md やスキル定義、コードのコメント、命名規約は Guides です。エージェントがコードを書き始める前に「こういう風に書け」と伝えるものはすべてここに入ります。一方、linter、型チェッカー、テスト、AI コードレビューは Sensors です。書いたあとで「そこはおかしい」と返してやり直させるものたち。

Fowler が強調しているのは、Guides だけでも Sensors だけでも足りない、両方が要る、という点です。Guides は事前に伝えられる情報の量に限界があるし、Sensors だけだと「間違えてから直す」の繰り返しでコストが膨らむ。両方を組み合わせて初めて steering loop が閉じます。

私の repo で対応する装置を並べてみます。

Guides実装
プロジェクト側の指針CLAUDE.md (デザインルールと記事の型の 2 節、絵文字禁止・裏の取れない一人称を禁じ手として明記)
執筆スキル.claude/skills/ (SKILL.md の description が発火条件)
記事の型の正本docs/article-formats.md (解説型 vs 実測型の判定基準)
Sensors実装
型チェッカーtsconfig.jsonastro/tsconfigs/strict を extends して strict: true
ビルド時のページ検査scripts/check-built-pages.mjs (216 行、6 ルール、646 ページに実行)
push の直前検査scripts/git-hooks/pre-push (HEAD が main でなければ拒否)

書き出してみると、Guides と Sensors がだいたい 1:1 で並んでいます。棚卸しをする前は「Guides ばかりで Sensors が薄い」と自己認識していたのですが、実際に数えたら思ったより Sensors 側が育っていました。過去の自分が痛い目に遭うたびに 1 本ずつ書いた check-built-pages.mjs のルール (後述) が、少しずつ積み上がっていたからです。

2節: Computational と Inferential

Sensors は 2 種類にさらに分けられます。Fowler の言い方は Computational (deterministic and fast, run by the CPU) と Inferential (LLM ベース、slower and more expensive; results are more non-deterministic) です。

Computational は linter、型チェック、テスト、正規表現、diff。ミリ秒〜秒で結果が返り、再実行すれば同じ結果が出ます。Inferential は AI コードレビュー、意味的な妥当性判定、命名の一貫性チェック。時間もコストもかかり、同じ入力でも結果が揺れます。

Fowler の主張は、両方が要るです。Computational は速くて確実だが、機械的なパターンでしか動けない。Inferential は遅くて不確実だが、意味を理解する必要のある判断ができる。片方だけでは覆えない領域があります。

私の repo に置いてある Sensors を Computational / Inferential 軸で分類し直します。

種類実装どういう指摘を返すか
Computationaltsc --strict型の不整合をコンパイル時に検出
Computationalcheck-built-pages.mjs ルール A本文 .prose が 300 字未満なら fail
Computationalcheck-built-pages.mjs ルール Brel=canonical の行き先が dist に存在しないと fail
Computationalcheck-built-pages.mjs ルール C<aside> の開閉タグと Markdown 空行の関係が壊れていたら fail
Computationalcheck-built-pages.mjs ルール Dremark-directive に食われた : の残骸を検出
Computationalcheck-built-pages.mjs ルール EUNVERIFIABLE_CLAIMS 正規表現群 (例: \d+社を(支援|見てき|伴走))
Computationalcheck-built-pages.mjs ルール F箇条書き項目が前項依存の接続詞で始まっていたら fail
Computationalpre-pushHEAD が main でなければ push 拒否
Inferential/zenn-review スキルAI Slop / Wit / 導線 / 字数のセルフレビュー
Inferential/avoid-ai-writing-ja-detect「〜だけ」「〜こそ」「〜のみならず」等の AI 文体パターン検出

書いてみて発見だったのは、私の repo の Sensors は 8 対 2 で Computational に偏っている という事実です。Inferential 側はスキル化されているものが 2 個しかない。過去 3 年、私は「まず正規表現で書けるルールから入れる」という選び方をしてきたわけです。Fowler の分類で眺め直すと、Inferential をもう少し増やす余地があると分かります。

Fowler の記事のもう一つの示唆は、Inferential を Computational の代わりに使わないことです。「機械的なパターンで書けるチェックを LLM に任せる」のは、遅くて高くて不安定な選択になる。逆に「意味の一貫性」を正規表現で書こうとすると、書けても保守できないルールの塊になる。適材適所です。

3節: Harnessability — codebase 自体がハーネスを持つ

ここが Fowler の記事で一番味のある節です。原文からの直接引用です。

A codebase written in a strongly typed language naturally has type-checking as a sensor; clearly definable module boundaries afford architectural constraint rules; frameworks like Spring abstract away details the agent doesn’t even have to worry about.

強い型付き言語で書かれたコードベースは、型チェックが Sensor になる。明確なモジュール境界はアーキテクチャ制約のルールを支える。Spring のようなフレームワークは、そもそもエージェントが気にしなくていい詳細を抽象化してくれる。

Fowler がここで言っているのは、ハーネスを「後付けする」だけではなく、コードベースの性質そのものがハーネスを支える (Harnessable にする) ということです。同じ AGENTS.md を書いたとしても、TypeScript strict 相手と JavaScript の any 祭り相手では、エージェントの成功確率がまるで違う。

私の kenimoto-dev はどれくらい Harnessable か、を測ってみます。

観点実測Harnessability への寄与
型付き言語かtsconfig.jsonastro/tsconfigs/strict を extends、strict: true型不整合を Sensor が拾う
モジュール境界25 本の .ts と 118 本の .astrosrc/ 配下のディレクトリ分割 (content/, layouts/, pages/, lib/)エージェントが「どこに書くか」で迷いにくい
フレームワーク規約Astro のファイルシステムルーティング。src/pages/**/*.astro がそのままURLルーティング設定を書かせない
ビルド時の閉じ込めastro build の後段に check-built-pages.mjs (646 ページを検査) を配置壊れた成果物は本番へ出ない

このうち、私自身が最近になって効いていると感じているのが check-built-pages.mjs の 6 ルールです。書いた経緯を並べると、次の性質が見えてきます。

  • A (本文短すぎ): 2026-08-30、remark プラグインが CI で例外を投げた結果、本文ゼロの記事が「デプロイ成功」として本番に出た事故のあと足した
  • B (canonical の行き先不在): 同日、frontmatter の canonical_url を手書きで維持していて、slug を変えた記事が 404 を正規 URL として Google に申告し続けていたのを見つけたあと足した
  • C (囲みの壊れ方 3 種): 2026-09-03、sudoers 記事で <aside> の開閉タグ前後の空行を入れ忘れて、生の **### が読者の画面に出ていた事故のあと足した
  • D (:の残骸): 同日、17:11 のような時刻表記が remark-directive の textDirective として解釈され、.md 644 本中 75 本 192 箇所で空の <div></div> が発生していたのを見つけたあと足した
  • E (裏の取れない一人称): 同日、「12 社の GraphRAG を見てきました」で始まる受託記録ゼロの記事 2 本を発見して削除し、正規表現化した
  • F (前項依存の接続詞): 2026-09-09、自分のまとめの箇条書きで踏んだ

6 ルール全部が、私が過去に踏んだ地雷の跡地です。 事故のあとに検査を 1 本ずつ足していったら、6 ルール、216 行のスクリプトになっていました。これは「後付けのハーネス」なのですが、astro build のパイプラインに組み込まれたあとは、コードベース側の性質として振る舞います。次に私が同じ地雷を踏もうとすると、Cloudflare のビルドが exit 1 で止まる。私 (と、私のリポジトリで作業するエージェント) は、その事故に「気づく」機会すら奪われる。これが Fowler の言う「codebase に埋まっているハーネス」だと思います。

棚卸しの結果、次に足すべきもの

3節を順に読んで自分の repo に対応させた結果、次に足すべきものが 2 つ見えました。

  1. Inferential 側の Sensor をあと 2〜3 本追加する。現状は AI Slop 検出とレビュー通し1本しかない。「記事全体のロジックの飛躍を LLM が拾う」種類のセンサーがまだ弱い
  2. Guides 側の「執筆前に AGENTS.md 相当を読ませる導線」を明示化するdocs/article-formats.md は正本として置いてあるが、エージェントが記事を書き始める前に必ず読む導線にはなっていない

これは私の repo の話ですが、この棚卸しの手順は他のリポジトリにもそのまま使えます。Fowler の 3節 (Guides/Sensors、Computational/Inferential、Harnessability) を軸にして、既に置いてある装置を分類し、偏りを見つけ、足りない側に 1〜2 本足す。作るのではなく数える作業から入る、ということです。

反論と限界

正直に書いておくべきこと。

Fowler の記事は 2026-04 のもので、モデルとエージェントの前提はこの半年で動いています。特に Inferential Sensors のコスト構造は Sonnet / Haiku の値下げでかなり変わりました。今後 Inferential の比重は上がる方向に振れると思います。

3節を選んだのは私の選び方です。Fowler は他にも Regulation categories (Maintainability / Architecture fitness / Behaviour の 3 分類) や、Timing (「品質は左に寄せる」の議論) など、実装者にとって役立つ節を並べています。私が「3節」に絞ったのは字数の都合と、「棚卸しの軸」として最小限の 3 個を選ぶためです。原文は 8〜9 節あります。

「codebase に埋まっている」は魔法ではない。type-checking がある = 全部の失敗を Sensor が拾ってくれる、ではありません。型は「型の不整合」しか拾わない。ロジックの誤り、命名の一貫性、可読性はすべて別の Sensor が要ります。Fowler も原文で「strongly typed language naturally has type-checking as a sensor」と書いていて、あくまで一種類の Sensor として位置づけています。

まとめ

  • Fowler の定義は「Agent = Model + Harness」。モデル以外の全部がハーネス
  • Fowler が置いた軸は主に 3 つ: Guides vs Sensors、Computational vs Inferential、Harnessability
  • Harnessability = コードベース自体の性質 (型付き、モジュール境界、フレームワーク規約) が Sensor と Guide を支える
  • 私の kenimoto-dev で棚卸ししたら、Sensor は 8:2 で Computational に偏っていて、Inferential 側に足す余地があった
  • 6 ルールの check-built-pages.mjs は全部、事故のあとに 1 本ずつ足した「後付け」だが、ビルドパイプラインに置いた瞬間から「コードベースの性質」に変わる
  • 「新しいハーネスを作る」より、既にあるものを Fowler の 3節で分類し、偏りを 1 本ずつ埋める方が、たぶん近道

check-built-pages.mjs に 6 ルール足すのに 3 週間かかりました。3節で分類するのは今週 15 分で済みました。同じ量の設計を、私は事故 6 件を経てから書いていた。分類軸を先に持っていれば、たぶん 3 件目あたりで「Sensor 側が偏っている」に気づけていたはずです。

関連

ハーネス・エンジニアリング 関連書籍 ハーネス・エンジニアリング ハーネスエンジニアリング 入門 | AGENTS.md 設計・hooks 実装・AIエージェント運用の体系書 書籍ページを見る →