本文へスキップ

ハーネスエンジニアリング入門: 60行の自作エージェントでClaude Codeの中身を理解する

ハーネスエンジニアリングとは何かを馬具のたとえと3層の進化で整理し、Python約60行の最小ハーネスを自作して、エージェントループ・ツール実行・ガードレールの仕組みをコードで理解します。

SHAYOUWORLD 更新 約11分

Claude Code も Codex CLI も Cursor も、その正体は LLM の周りに組まれた「ハーネス」だ。本稿では、まずハーネスとハーネスエンジニアリングという言葉を短く整理し、そのうえで Python 約60行で動くハーネスを実際に書いて、Claude Code の中で毎日起きていることをコードのレベルで理解する。読み終わる頃には、while ループ1個とツール2個が「エージェント」と呼ばれるものの骨格だと腹落ちしているはずだ。

この記事を3行で

  • LLM単体は「テキストを1回受けて1回返す」だけ。ファイルも読めずコマンドも打てない。それを仕事する存在に変える外側の機構がハーネス
  • 心臓部は約25行の while ループ。「モデルに聞く → ツール要求を実行 → 結果を見せてまた聞く」を stop_reason が変わるまで回すだけ
  • 自作ハーネスと Claude Code の差分(コンテキスト管理・権限・メモリ)を見ると、普段触っている設定項目の意味が全部つながる

1. ハーネスとは何か: 馬具のたとえと3層の進化

英語の “harness” は 馬具 のことだ。馬そのものは強力でも、車を引かせるには胴体に巻く帯、手綱、車との連結金具がなければ仕事にならない。AI の文脈でも同じで、LLM を仕事させるための 周辺装置の総体 をハーネスと呼ぶ。中身はシステムプロンプト、ツール(MCP を含む)、コンテキスト管理、メモリ、エージェントループ、ガードレールやログといった部品だ。

つまりハーネスエンジニアリングとは、「LLM を中心に置いて、周りの装置をどう設計するかの工学」である。プロンプトの言い回しを磨くのとも、文脈に入れる情報を選ぶのとも、別の階層の話になる。AIエンジニアリングの主役は、この数年で次のように移ってきた。

  1. 2022-2024
    プロンプト工学
    何を聞くか。Few-shot、Chain-of-Thought、ロール設計など、1回の指示文を磨き上げる。
  2. 2025
    コンテキスト工学
    何を見せるか。RAG、履歴圧縮、CLAUDE.md / AGENTS.md など、文脈ウィンドウに何を詰めるかを設計する。
  3. 2026
    ハーネス工学
    どう動かすか。ツール、メモリ、ループ制御、承認ゲート、観測まで含めた周辺装置を設計する。
3つは置き換わるのではなく積み上がる。ハーネス工学の中にも、プロンプトとコンテキストの設計はサブセットとして残る。

違いを一言でいえば、プロンプト工学が1ターン内の指示文を扱うのに対し、ハーネス工学はセッション全体から運用のライフサイクルまでを扱う。失敗の症状も違う。前者は「指示通りに動かない」として現れ、後者は「ループの暴走」「トークンの浪費」「無断の破壊操作」「何が起きたか追えない」として現れる。症状の取り違えも起きやすく、プロンプトのせいだと思って文言を磨いていたら実はメモリが古い情報を返していた、モデルのせいだと思って高いモデルに替えたら実はハーネスに再試行もログもなかった、というのが典型だ。

この言葉が広まった背景には、「賢いモデル + 貧弱なハーネス」は「ふつうのモデル + 良いハーネス」に負ける、という経験則がある。解説記事では、Vercel がツールを約8割削って成功率を80%から100%に上げた例や、LangChain が同じモデルのままハーネスの変更だけで Terminal Bench 2.0 の順位を下位から上位5位に上げた例が引かれている(いずれも各記事が引用する報告値で、本サイトでは再現していない)。

そして、普段使っている Claude Code / Codex CLI / Cursor も、それぞれ設計思想の違うハーネスだ。CLAUDE.md、ツールの許可、サブエージェント、hooks といった、普段「設定」と呼んでいるもののほとんどが、ハーネスの構成要素にあたる。

2. なぜ「書いて」理解するのか

上のような部品名は、解説を読めば覚えられる。だが「モデルがツールを使う」と言われたとき、実際にワイヤ上で何が起きているかをイメージできる人は少ない。

実は、モデルは何も実行していない。モデルがやるのは「bash ツールを ls という引数で呼びたい」と宣言するテキストを返すことだけで、実行するのはハーネス側のコードだ。この一点を体で理解すると、Claude Code の権限ダイアログがなぜあの位置に挟まるのか、hooks がなぜツール呼び出しに介入できるのか、すべて自明になる。だから書く。

3. 全体像: 4ステップのループ

先にこれから作るものの構造を見ておく。ハーネスの心臓部は、この4ステップを完了まで繰り返すループだ。

① Plan — client.messages.create()モデルが次の一手を宣言(LLMの仕事はここだけ)② Tool Call の検出stop_reason == “tool_use” を判定③ Execute — run_tool()subprocess / open() で実際に実行④ Observe — 結果を追記tool_result を messages に積んで①へ戻る緑の3ステップ(②③④)がハーネスの仕事。ここを差し替えるのがハーネスエンジニアリング
最小ハーネスの構造。LLMは Plan(次の一手の宣言)だけを担当し、Tool Call の解釈・Execute・Observe(結果の文脈追記)はすべてハーネス側のコードが行う。

4. コード全文: mini_agent.py

以下が全文だ。pip install anthropic と ANTHROPIC_API_KEY の設定だけで動く。コメントの (1)〜(5) が次章の解剖と対応している。

# mini_agent.py — 最小構成のエージェントハーネス(約60行)
# 使い方: ANTHROPIC_API_KEY を設定して `python mini_agent.py "タスク"`
import json
import subprocess
import sys
from anthropic import Anthropic
client = Anthropic()
# (1) ツール棚: モデルに見せる「使ってよい道具」の宣言
TOOLS = [
{
"name": "bash",
"description": "シェルコマンドを実行し、標準出力と標準エラーを返す。",
"input_schema": {
"type": "object",
"properties": {"command": {"type": "string", "description": "実行するコマンド"}},
"required": ["command"],
},
},
{
"name": "read_file",
"description": "テキストファイルを読んで内容を返す。",
"input_schema": {
"type": "object",
"properties": {"path": {"type": "string", "description": "読むファイルのパス"}},
"required": ["path"],
},
},
]
# (2) システムプロンプト: ハーネスが毎回注入する「前提」
SYSTEM = "あなたはターミナルで作業するコーディングエージェントです。ツールを使ってタスクを完了してください。"
DANGEROUS = ("rm ", "del ", "format", "mkfs", "> /dev/")
def run_tool(name: str, args: dict) -> str:
# (3) ツール実行: モデルは「宣言」するだけで、実行するのはこちら側
if name == "bash":
cmd = args["command"]
if any(word in cmd for word in DANGEROUS): # (4) ガードレール
if input(f"実行しますか? [{cmd}] y/N: ").lower() != "y":
return "ユーザーが実行を拒否しました。"
r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=60)
return (r.stdout + r.stderr)[:5000] or "(出力なし)"
if name == "read_file":
with open(args["path"], encoding="utf-8") as f:
return f.read()[:5000]
return f"未知のツール: {name}"
def agent_loop(task: str) -> str:
messages = [{"role": "user", "content": task}]
while True: # (5) エージェントループ: ここがハーネスの心臓部
resp = client.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
system=SYSTEM,
tools=TOOLS,
messages=messages,
)
messages.append({"role": "assistant", "content": resp.content})
if resp.stop_reason != "tool_use": # ツール要求がなければ完了
return next(b.text for b in resp.content if b.type == "text")
results = []
for block in resp.content:
if block.type == "tool_use":
print(f"[tool] {block.name} {json.dumps(block.input, ensure_ascii=False)[:80]}")
results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": run_tool(block.name, block.input),
})
messages.append({"role": "user", "content": results}) # 結果を文脈に追記
if __name__ == "__main__":
print(agent_loop(sys.argv[1] if len(sys.argv) > 1 else "このディレクトリのファイル一覧を教えて"))

ループ部分の機構(3ターンにわたるツール実行と messages 配列の積み上げ)は、モックを使ったテストで検証済みだ。API呼び出しを差し替えて「bash要求 → read_file要求 → 完了」の3ターンを流すと、tool_result が正しい tool_use_id に紐付き、会話履歴が user → assistant → user(tool_result) → … の順で積まれていくことが確認できる。

5. 解剖: 5つの部品がハーネスの教科書と対応する

複数の解説記事を突き合わせると、ハーネスの部品リストはおおむね11個に収束する。システムプロンプト、ツール、メモリ、コンテキスト管理、ループ、出力パース、状態管理、エラー処理、ガードレール、検証、サブエージェントだ。60行ハーネスが備えているのは、このうちツール、システムプロンプト、ガードレール、ループという骨格の部分にあたる。コメント番号ごとに対応を見ていく。

(1) ツール棚 = Tool Registry。 TOOLS はモデルに渡す「メニュー」で、JSON Schema で引数の型まで宣言する。重要なのは、ここに実行コードが1行もないこと。モデルが受け取るのは道具の説明書だけだ。Claude Code の Read / Edit / Bash、MCP サーバーが追加するツールも、ワイヤ上ではこれと同じただの宣言リストにすぎない。

(2) システムプロンプト注入。 ユーザーが書いた覚えのない前提(役割、作業ディレクトリ、規約)を毎リクエスト先頭に積む。Claude Code が起動時に CLAUDE.md や git 状態を読み込んで注入しているのは、この SYSTEM 文字列の豪華版だ。

(3) ツール実行 = ハーネスの専権事項。 run_tool() が subprocess や open() を呼ぶ。モデルの宣言と実行の間にコードが挟まっているからこそ、次の(4)が可能になる。

(4) ガードレール。 危険そうなコマンドだけ input() で人間に確認を求める。たった4行だが、これが Claude Code の権限ダイアログ・permission mode・hooks の原型だ。宣言と実行が分離しているアーキテクチャだから、この位置に任意の検問を挟める。

(5) エージェントループ。 stop_reason が "tool_use" である限り、結果を見せてもう一度モデルに聞く。end_turn が返ったらタスク完了。エージェントの「自律性」の正体は、この繰り返しの中でモデルが毎回「次の一手」を選び直していることだ。

6. ここから Claude Code までの距離

60行ハーネスは動くが、実務で1日使えば破綻する。何が足りないかを並べると、製品ハーネスが積んでいる機構の意味が逆算できる。

60行の自作ハーネス
Claude Code(製品ハーネス)
コンテキスト管理
messages が伸び続け、いずれ上限超過で死ぬ
自動コンパクション、ファイルの部分読み、コンテキスト回復
権限
文字列マッチの確認1個(すり抜け放題)
permission mode、許可リスト、hooks、sandbox 実行
ツール
bash と read_file の2個
編集・検索・Web・サブエージェント + MCP で無限拡張
メモリ
プロセスが終わればすべて忘れる
CLAUDE.md、auto memory でセッション横断の記憶
失敗への備え
タイムアウト60秒のみ。無限ループも止められない
リトライ、コスト管理、ループ検知、チェックポイント
検証
なし(出力を信じるだけ)
テスト実行、型チェック、レビューループとの統合
観測
print でツール名を出すだけ
ターミナルに残る実行ログ
骨格は同じで、差分はすべて「運用の作り込み」。この差分領域こそがハーネスエンジニアリングの主戦場になる。

見ての通り、骨格(ループ+ツール+注入)は60行で再現でき、差分はすべて運用機構だ。OpenAI Codex チームの「Agents aren’t hard; the harness is hard(エージェントは難しくない。ハーネスが難しい)」という言葉は、この差分の作り込みが難しいという意味であって、ループが難しいという意味ではない。

製品ハーネス同士でも、作り込みの方向は違う。同じモデルを使っていても、Claude Code で動かすか Cursor で動かすかで挙動も得意分野も変わる。解説記事での整理をまとめると、おおむね次のようになる。

観点Claude CodeCodex CLICursor
設計思想透明性と制御性。破壊的な操作は明示承認速度重視。ツール呼び出しがモデルAPIに統合IDE 密結合と対話性。差分レビューを承認ゲートにする
コンテキスト戦略関連ファイルを選んで読む。CLAUDE.md を起点に階層展開AGENTS.md を読み、短く起動するコードインデックスとセマンティック検索で必要な箇所を注入
向くタスク長い文脈、複雑なリファクタ、自律実行中粒度の作業の即実行日常のイテレーション、UI 構築

7. 理解が変わる3つのポイント

写経して動かすと、普段の Claude Code の見え方が変わる。効果が大きい順に3つ挙げる。

  1. 権限ダイアログの位置が必然になる。 宣言と実行の間にハーネスのコードが必ず挟まる以上、そこが唯一の検問所だ。「なぜモデルに直接ルールを言い聞かせるより hooks のほうが確実か」の答えもここにある — モデルは宣言しかできず、実行を握っているのはハーネスだから。
  2. コンテキスト管理の切実さがわかる。 messages 配列は1タスクでも驚くほど伸びる。ツール結果を [:5000] で切り詰める1行の意味、そして Claude Code のコンパクションや部分読みが「節約術」ではなく生存条件だと体感できる。
  3. ツール設計がプロンプト設計より効く理由が見える。 モデルの挙動は TOOLS の description に強く引っ張られる。ツールの説明文を1行変えるだけで呼び方が変わる様子は、自作ハーネスなら数分で実験できる。

8. 自分のハーネスを見直す5つの観点

構造がわかったら、次は普段使っている製品ハーネスを「設定」ではなく「自分が設計している周辺装置」として見直す。観点は5つある。

  1. システムプロンプト層を階層化したか。 グローバル(~/.claude/CLAUDE.md)・プロジェクト(./CLAUDE.md)・サブパス(.claude/rules/*.md)に分け、@ インポートで読ませる。60行版の SYSTEM 文字列を、用途別に分けて育てるイメージだ。
  2. ツールを削ったか。 前述の Vercel の例のように、多すぎるツールはモデルを迷わせる。MCP サーバーや内蔵ツールを過剰に有効化していないか棚卸しする。
  3. メモリを育てているか。 auto memory や MEMORY.md を放置せず、失敗も成功も書き残して同じミスを潰す。
  4. サーキットブレーカーがあるか。 タイムアウト、再帰の深さ、コスト上限、破壊的な操作の承認ゲート。60行版に欠けていた、無限ループとトークンの浪費への保険だ。
  5. 検証ループが回っているか。 npm run check、テスト、LLM による判定、pre-commit hook など、「出力した」と「正しい」の間に橋を架ける。

ハーネスは一度作って終わりではなく、失敗をルールに変換し続けるラチェット(逆戻りしない歯車)として育てるものだ。このサイト自体も、プロジェクトルールを定義する CLAUDE.md、探索や設計を分担するサブエージェント、破壊的な操作を抑える hooks、外部データをつなぐ MCP という製品ハーネスの上で更新している。CLAUDE.md を一行足すたびに、ツールを一つ削るたびに、hooks を一つ書くたびに、自分のハーネスは少しずつ強くなる。

9. まとめ

  • ハーネスは LLM を仕事させる周辺装置の総体で、ハーネスエンジニアリングはプロンプト工学・コンテキスト工学の上に積み上がる設計領域
  • ハーネスの心臓部は while stop_reason == "tool_use" のループで、約60行あれば動くものが書ける
  • モデルはツールを実行できない。宣言するだけで、実行・検問・記録はすべてハーネス側の仕事
  • 製品ハーネスとの差分はコンテキスト管理・権限・メモリなどの運用機構で、そこがハーネスエンジニアリングの主戦場

自分のハーネス(Claude Code)を育てる具体策は、下の関連記事をどうぞ。

関連記事

関連して読む

この記事の情報・検証メモ
Tags
公開日
情報確認
参考リンク
7件
更新性
長く使える
更新管理

仕様・料金・提供範囲が変わりやすいテーマは、公開日・更新日・情報確認日を分けて管理します。 導入前には必ず記事末尾の一次情報と公式ドキュメントで最新状況を確認してください。

図解を保存・共有

記事の要点を1枚にまとめました。画像は新しいタブで開いて保存できます。

ハーネスエンジニアリング入門: 60行の自作エージェントでClaude Codeの中身を理解する エージェントの心臓部は while ループ1個。書けば構造が腹落ちする ハーネスの最小構成:LLM単体は「テキスト1往復」しかできない装置。ループ・ツール・システムプロンプト・ガードレールが外側の機構。この外側の総体がハーネスで、Claude Codeの正体。 60行の中身:ツール棚の宣言(モデルには実行権がない)。while stop_reason == tool_use のエージェントループ。危険コマンドだけ人間に確認するガードレール。 製品ハーネスとの距離:足りないのはコンテキスト管理・権限体系・メモリ。差分を見るとClaude Codeの設定項目の意味がわかる。ハーネスの難しさは部品数ではなく運用の作り込み。
ハーネスエンジニアリング入門: 60行の自作エージェントでClaude Codeの中身を理解する 記事の要約 2026.07.24 入門・導入ガイド
画像を開く・保存 記事リンクを共有 約11分 / harness-engineering / ai-agent
Primary sources

一次情報・参考リンク

About the author
SHAYOUWORLD

日本の公共データAPIを使うMCPサーバーを作って公開し、ローカルLLMを自分のGPUで測った記録を、一次情報・検証ログ・失敗例とあわせて整理します。