本文へスキップ
Edition · Tokyo
入門・導入ガイド · 長く使える

ハーネスを60行で自作する: Claude Codeの中身を理解する最短ルート

Claude Codeの正体である「ハーネス」をPython約60行で自作し、エージェントループ・ツール実行・ガードレールの仕組みをコードで理解します。写経して動かせる最小実装付き。

codeagent.jp編集部 情報確認 約7分
Tags
情報確認
参考リンク
2件
更新性
長く使える
読了目安
約7分
更新管理

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

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

ハーネスエンジニアリング入門では「Claude Code の正体はハーネスである」という話を概念図で整理した。本稿はその実践編だ。Python 約60行で動くハーネスを実際に書いて、Claude Code の中で毎日起きていることをコードのレベルで理解する。読み終わる頃には、while ループ1個とツール2個が「エージェント」と呼ばれるものの骨格だと腹落ちしているはずだ。

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

ハーネスの解説記事を読むと、システムプロンプト・ツール・ループ・ガードレールと部品名は覚えられる。だが「モデルがツールを使う」と言われたとき、実際にワイヤ上で何が起きているかをイメージできる人は少ない。

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

2. 全体像: 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(結果の文脈追記)はすべてハーネス側のコードが行う。

3. コード全文: mini_agent.py

以下が全文だ。pip install anthropicANTHROPIC_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) → … の順で積まれていくことが確認できる。

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

コメント番号ごとに、教科書的なハーネス構成要素との対応を見ていく。

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

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

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

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

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

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

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

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

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

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

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

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

7. まとめ

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

概念の全体地図はハーネスエンジニアリング入門を、自分のハーネス(Claude Code)を育てる具体策は下の関連記事をどうぞ。

関連記事

Primary sources

一次情報・参考リンク

About the author
codeagent.jp編集部

Claude Code / Codex / MCP を個人開発サイト運用と公開MCPサーバー開発で試し、一次情報・検証ログ・失敗例をもとに整理します。

関連して読む