🐎

Claude Code を安定運用するために『ハーネス』を育てる

に公開

TL;DR

  • Claude Code を「賢いモデル」として使うだけでは、出力は安定しない
  • モデルの周りに置く "ハーネス(馬具)" = ガイドとセンサーをプロジェクトに合わせて育てるのが効く
  • 実プロジェクトで運用している 2つの制御点 を紹介する
    • ① 入口CLAUDE.md / .claude/rules/ の2階層化(常時 / 条件付き / 指示型の3チャネルで注入)
    • ② 計算型ハーネス内の推論型ジャッジpre-commit × Claude CLI で 意味的整合性 をコミット時にジャッジする
  • 「ツールを増やす」のではなく 「制御点をどこに置くか」 で考えるとブレない

参考: Birgitta Böckeler, Harness Engineering for Coding Agent Users


1. ハーネスとは何か

利用者が触れるのは「ハーネス」だけ

私たちは LLM の 利用者 であって、モデルメーカーではない。学習データ・重み・確率分布はブラックボックスで、こちらからは触れない。利用者ができるのは、LLM の周りに 入口 / 道具立て / 出口 / ループ という制御点を置くことだけだ。これらの総体が ハーネス(馬具) である。

なぜ二重化するのか

LLM は 非決定的で、コンテキストを知らず、トークン単位で思考する。だからハーネスの仕事は「確率的に良い結果が出やすい状況を作ること」に尽きる。100% の制御は目指さない。代わりに ガイド(事前)+ センサー(事後) で二重化することで実用化する。

本記事で扱う2つの制御点

トピック ハーネス上の位置づけ
CLAUDE.md / .claude/rules の運用 ガイド(事前注入):人間可読の方針をモデルに事前注入
pre-commit × Claude CLI 計算型ハーネスの中に推論型ジャッジを埋める / Left Shift

補足:道具立て(許可ツール・MCP・サブエージェント等)も重要だが、本記事では入口と出口にフォーカスする。


2. ① CLAUDE.md / .claude/rules の運用(入口を整える)

結論

プロジェクト固有の判断・前提を Claude に常時注入する。
膨らみは 「骨格 + 条件付き注入」 で抑える。

課題

CLAUDE.md を増やすと、毎回トークン代を払いながら 「いま使われない情報」も常時注入 してしまう。文脈ウィンドウを圧迫し、コンテキスト密度(いまのタスクに効く情報の割合)が下がる。

一方、LLM には 不確実なときでも「分からない」と言わず、もっともらしい答えを返す傾向 がある[1]。変化の速い領域(クラウドサービスの仕様、ライブラリの最新仕様など)では、学習時点の古い知識を自信ありげに提示してしまう 誤情報リスクが高い。「公式を確認しろ」という姿勢を 常に効かせたい ニーズもある。

やったこと

  1. CLAUDE.md は「常に効くべき骨格」に絞る
    • コア原則・主要スタック・参照ドキュメント表だけにスリム化
  2. 詳細はトピック別ルールに分割.claude/rules/ 配下に置き、対象パスに応じた条件付き注入にする
    • 開発プロセス / 品質ゲート / インフラ / 自律性 / セキュリティコンテキスト / API 仕様整合性 など
  3. 公式情報を強制するガイド
    • 「仕様・制限・最新情報が関わる場合は公式を Web 検索する」「検索した場合は参照元を明示する」を明文化し、推測回答を抑制
  4. 2階層 CLAUDE.md で住み分け
    • グローバル(~/.claude/CLAUDE.md)= 姿勢
    • プロジェクト(./CLAUDE.md.claude/rules/)= コンテキスト

2階層の役割分担

個人(~/.claude/CLAUDE.md)— "姿勢" を作る

プロジェクトを跨いで効くべき行動規範を書く。たとえばこういうものだ。

  • 誠実性:不明は「不明」と明示する。事実・推測・意見を混同しない。推測には推測と明記する
  • 同僚としての関わり方:より良い案に気付いたら割り込んで提案する。反論形式で展開しない。指摘は押し付けではなく提案として伝える
  • 前提の検証:指摘を評価するとき、論理の整合性より先に 前提・仮定の妥当性 を問う
  • 技術質問の作法:仕様・制限・最新情報は公式を確認する。検索したら参照元を明示する。短期的に楽な案と長期的に健全な案を区別する
  • リスク提示の様式:条件を具体化する。可能なら発生確率(高・中・低)を示す

「公式情報を確認する」「不明と明示する」のような姿勢ルールは、嘘の事前抑制(feedforward) として効く。出力後にチェックするより、出力前に「自信がないなら検索しろ」と内発化させる方が安い。

プロジェクト(./CLAUDE.md.claude/rules/)— "コンテキスト" を渡す

そのプロジェクトでしか通用しない事実を書く。

  • システム概要・アーキテクチャ:ドメイン / 主要スタック / サービス構成
  • 参照ドキュメント表:どこに何があるか・docs/CLAUDE.md / .claude/rules の住み分け
  • プロジェクト固有のコア原則:「最小の変更で目的を達成する」「『将来のため』は拡張の理由にならない」など、設計判断の優先順位
  • 暗黙の前提:観測済みの実害事象、利用可能な基盤(リトライ機構など)、社内運用上の制約
  • レビューエージェント向け注意事項:プロジェクトの技術スタックと既存基盤を踏まえた指摘を出させるための前提共有

注入の3チャネル

プロジェクト固有の前提をモデルに渡す手段は、用途に応じて3つに分けられる。

チャネル 仕組み 何を載せるか
① 常時注入 CLAUDE.md 骨格・コア原則・参照表
② 条件付き注入 .claude/rules/paths: マッチ トピック別の詳細ルール
③ 指示型注入 プロンプトで「以下を Read せよ」と命じる 状況依存で動的に引かせるドキュメント

「常時 vs 条件付き vs 指示型」を意識的に使い分けると、いまのタスクに効く情報の割合(コンテキスト密度) が上がる。CLAUDE.md に全部書こうとすると、入口は太るがコンテキスト密度は下がる、というジレンマに陥らないで済む。

ハーネス観点で言うと

  • 入口(インプット)への 常時ガイド注入 が主役(§1 の制御点①)
  • 「常時/条件付き/指示型」の3チャネルに分けることで コンテキスト密度 を上げる
  • 「公式情報を確認」型のルールは 嘘の事前抑制(feedforward)

3. ② pre-commit × Claude CLI(計算型ハーネスに推論型ジャッジを埋める)

結論

API 仕様(OpenAPI)の変更時に pre-commit で Claude CLI を起動 し、実装との 意味的整合性 をジャッジする。
RESULT:BLOCK ならコミットを中止。Claude Code セッション内では .claude/rules/api-spec-consistency.md で同観点を二重化する。

きっかけ:構文 lint では落ちない不一致

実プロジェクトで実際に起きた事象を一般化すると

  • API 定義書(OpenAPI)のあるフィールドの pattern が、実装が受理する範囲より 広く 書かれていた
  • 例:定義書では拡張子の大文字小文字どちらも許可、実装は小文字のみ受理
  • 定義書通りに実装したクライアントがランタイムエラー になる種類の不一致
  • OpenAPI lint も型生成もスキーマレベルでは正しく、検出できない
  • 人間のコードレビューでも見落とした

これは「構文ではなく 意味的整合性 の問題」だ。人間がレビュー時に読んで気付くしかない種類の判断 を、AI ジャッジでコミット時点に常駐させたい、というのが出発点だった。

仕組み:pre-commit から Claude CLI を呼ぶ

ポイントは以下

  • 差分があるときだけ起動:API 定義のステージング差分があるときだけ Claude CLI を立ち上げる。毎コミット走らせない
  • 読み取り専用で起動--allowedTools Read,Grep,Glob に絞る。書き込み権限を渡さない(=書き換えられないので副作用が出ない)
  • 末尾タグで機械判定RESULT:BLOCK / RESULT:WARN / RESULT:OK を grep して exit code に変換
  • 緊急時の逃げ道git commit --no-verify で回避可能。最終ジャッジは人間が握る

チェックスクリプトのプロンプト核心部分(抜粋・一般化)

## あなたのタスク
1. 以下の API 定義書を Read ツールで読む:
   - docs/api/*.yaml
2. 以下の実装コードを Read, Grep, Glob ツールで読む:
   - 該当エンドポイントを処理するハンドラ・バリデータ

## チェック観点
- バリデーション仕様(pattern, minLength, maxLength, enum, required)
- リクエスト/レスポンスのフィールド定義、ステータスコード、パスパラメータ

## プロジェクト固有のコンテキスト(指摘対象外)
- 外部発行 ID 等、実装側で検証しない値
- OpenAPI の example の値の差異
- エラーレスポンスの message 文言

## 出力形式
### BLOCK(コミット禁止): 利用者の実装に実害がある不一致
### WARN(警告のみ): 改善が望ましいが実害は低い不一致

## 最終行の判定タグ(厳守)
- BLOCK該当が1件以上: RESULT:BLOCK
- WARN該当のみ:        RESULT:WARN
- 不一致なし:          RESULT:OK

指摘対象外」をプロンプトに含めるのが地味に重要だ。LLM は気を利かせすぎるので、実害のない差分 を明示的に許容しておかないと WARN/BLOCK が多発する。

Claude Code セッション内とも二重化する

pre-commit だけだとコミット時にしか効かない。編集中に Claude Code が定義書と実装の片方だけを直して矛盾を生むケースがあるので、セッション内でも同じ観点を持たせる。

.claude/rules/api-spec-consistency.md の中身(抜粋):

---
paths:
  - "docs/api/**/*.yaml"
  - "<実装コードのパス>/**/*.go"
---

上記パスを修正した場合、API 定義書と実装コードの整合性を確認すること。
<省略>

paths にマッチするファイルを編集すると、フロントマターより後ろの本文が条件付きで注入される。これで 編集中(Claude Code 内)コミット時(Git hook) の二重ガードになる。

ハーネス観点で言うと

  • 計算型ハーネス(Git hook / CI)に推論型ジャッジを埋める という構造の例
  • Left Shift:CI ではなくコミット時に倒すことで、レビュー前に矛盾を潰せる
  • 横展開しやすい候補
    • ADR と実装の整合:ADR の決定事項に反する実装変更を検出
    • SQL マイグレーションのリスクジャッジ:ロック待ち・ダウンタイムリスクを評価
    • Terraform 変更のセキュリティ観点:公開範囲・IAM 緩和の検出
    • 依存ライブラリ更新時のブレーキングチェンジ確認

いずれも「構文 lint では届かない、人間が読んで判断する種類の不一致」が対象だ。


まとめ

  • ハーネス=モデルの周りに置くガイドとセンサー。プロジェクトに合わせて育てる
  • ガイドは 常時 / 条件付き / 指示型 の3チャネルで注入する
  • センサーは 計算型ハーネス(pre-commit / CI)の中に推論型ジャッジを埋める 形で組む
  • 「ツールを増やす」のではなく 「制御点をどこに置くか」 で考えるとブレない

参考

脚注
  1. OpenAI の研究 Why Language Models Hallucinate (2025) によれば、ベンチマークの多くが「棄権 = 不正解 = 0点」型で 推測した方が期待値が高い ため、当てずっぽうでも答える戦略が学習される、という構造的問題。 ↩︎

Discussion