第6章 Harnessの機能 — 各要素の役割と使い方

第1章〜第5章で述べた原理を、実際のツールではどう実装しているのか。本章ではClaude Codeを主な例として、各機能がアーキテクチャ図のどの層に対応し、確率的制御と決定論的制御のどちらに属するかを明示しながら解説する。各機能を実際の開発プロセスでどう組み合わせるかは、第7章で述べる。

6.1 機能の全体マップ

Harnessを構成する機能は、第2章で述べた「確率的制御」と「決定論的制御」の二つの領域に分かれる。

確率的制御の側には、テキストとしてコンテキストウィンドウに注入される3つの機能がある。CLAUDE.md(プロジェクト全体の前提と構成を伝える)、Rules(行動規則と禁止事項を定義する)、Skills(再利用可能なワークフロー(作業の流れ)を手順として渡す)。いずれもモデルの判断に「影響を与える」ものであり、遵守を保証するものではない。

決定論的制御の側には、Hooksがある。モデルの動作中の特定イベント(ツール使用前、完了宣言時など)にスクリプト実行を紐づけ、条件を満たさなければ動作を差し戻す。モデルの外側でコードとして動くため、スキップされることがない。なお、モデルがファイルを読み書きしたり外部サービスと通信したりする能力自体は、MCP(Model Context Protocol)というプロトコルが提供しており、Hooksはこのツール実行を監視する役割を担う。

さらに、これらの機能を横断する仕組みとして、Agents(エージェント分割)がある。一つのモデルが一つのコンテキストウィンドウで全作業を担うのではなく、タスクを分割して別のモデルインスタンス(Worker)に委任する。Leadエージェントが全体を統括し、Workerエージェントが個別のタスクを実行する。Worker定義は確率的制御(自然言語テキスト)だが、Workerの起動自体はTaskツールによる決定論的なプロセス呼び出しであり、両方の性質を持つ。

これらの機能が組み合わさって、一つのHarnessを構成する。

Harness Context Engineering(確率的制御) CLAUDE.md プロジェクト全体の指示 Rules 行動規則・禁止事項 Skills 再利用可能なワークフロー定義 → すべてテキストとしてコンテキストに注入 → モデルへの「影響」(遵守は保証されない) Architectural Constraints(決定論的制御) Hooks — ライフサイクルイベントに紐づくスクリプト実行 → コードとして実行される → モデルへの「強制」(遵守が保証される) Agents(タスク分割・並列実行) Worker定義 役割と指示(確率的制御) Task起動 別インスタンスの呼び出し(決定論的) → 確率的制御と決定論的制御の両方を含む → コンテキスト分離による容量問題の回避

以下の6.2〜6.6で、各機能を個別に解説する。それぞれについて、アーキテクチャ上の位置(第4章の構造図のどこに当たるか)、制御の種類(確率的か決定論的か)、実践例、そして限界を述べる。

6.2 CLAUDE.md — プロジェクトの「地図」

アーキテクチャ上の位置: Context Engineering層。コンテキストウィンドウに注入されるテキスト。

制御の種類: 確率的制御

CLAUDE.mdは、セッション開始時に自動的にコンテキストウィンドウに読み込まれるMarkdownファイルだ。プロジェクトルートに配置する。

第1章で述べたように、モデルはステートレスであり、セッションを開始するたびに「このプロジェクトは何か」を一から理解し直す必要がある。CLAUDE.mdはその最初の手がかりになる。人間が新しいプロジェクトに参加したとき、まず全体像を把握するためにREADMEを読むのと同じだ。

何を書くか: CLAUDE.mdの役割は「プロジェクトの地図」であり、モデルが最初に読んで全体像を把握するための情報を記述する。具体的には、プロジェクトの目的、ディレクトリ構成と各ディレクトリの役割、参照すべきファイルの所在、作業上の前提条件だ。

実践例: プロジェクトの案内板として使う

# プロジェクト概要

レシピデータを構造化してネットワーク可視化するプロジェクト。

## ディレクトリ構成
- docs/     — 仕様書、進捗
- data/     — 入力データ(生レシピテキスト)
- output/   — 生成されたYAMLとHTML
- scripts/  — 検証・変換スクリプト

## 作業の前提
- 仕様変更は必ず docs/spec.md に記録する
- data/ 内のファイルは読み取り専用として扱う

実際の場面: セッションを再開したとき、モデルは「このプロジェクトで何をしていたか」を一切覚えていない(第1章)。CLAUDE.mdに「docs/progress.mdに現在の進捗が記録されている」と書いてあれば、モデルはまずprogress.mdを読みに行く。書いていなければ、モデルはディレクトリを手当たり次第に探索するか、ユーザーに「何をすればいいですか」と聞くことになる。CLAUDE.mdは「セッション再開時に最初に読む案内板」として最も効果を発揮する。

何を書かないか: 行動規則や禁止事項はCLAUDE.mdに書かない。それはRules(6.3)の役割だ。具体的な作業手順もCLAUDE.mdに書かない。それはSkills(6.4)の役割だ。CLAUDE.mdに書くのは「何があるか」であり、「何をすべきか」や「何をしてはいけないか」ではない。

この区別が重要な理由は、コンテキストウィンドウの性質にある。CLAUDE.mdはセッション開始時に一度読み込まれるが、会話が長くなるにつれて、コンテキストウィンドウの中で古い情報として影響力が薄れていく(第1章のauto-compact)。つまりCLAUDE.mdは「セッション序盤に効果が強く、終盤には弱くなる」性質を持つ。全体像の把握はセッション序盤に必要なのでCLAUDE.mdに適している。一方、作業中ずっと守るべきルールは、別の仕組み(Rules、Hooks)に委ねる方が確実だ。

なぜ確率的制御なのか: CLAUDE.mdはテキストとしてモデルに渡されるだけであり、「data/内のファイルは読み取り専用」と書いてあっても、モデルが書き込んでしまう可能性はゼロではない。重要度の高い制約は、後述のHooksで補強する必要がある。

6.3 Rules — 行動規則の定義

アーキテクチャ上の位置: Context Engineering層。CLAUDE.mdと同様にコンテキストに注入される。

制御の種類: 確率的制御(ただしCLAUDE.mdより特化された指示)

Rulesは .claude/rules/ ディレクトリに配置するMarkdownファイルで、モデルの行動規則を定義する。CLAUDE.mdがプロジェクト全体の「地図」なら、Rulesは「交通ルール」にあたる。

なぜCLAUDE.mdと分けるのか: CLAUDE.mdには「何があるか」を書き、Rulesには「何をすべきか、何をしてはいけないか」を書く。情報の性質が異なるので、ファイルを分ける。もう一つの理由は管理上の利便性だ。Rulesは複数ファイルに分割できるため、「作業規則」「ファイル管理」「問題対応」のようにテーマごとに整理できる。プロジェクトが成長してルールが増えても、関連するルールだけを見つけて修正すればよい。

実践例: 作業規則と禁止事項

# ファイル: .claude/rules/workflow.md

## 実行原則
- 作業開始前に必ず docs/progress.md を読み、現在の状態を確認する
- 1つのPhaseが完了するたびに progress.md を更新する

## 禁止事項
- spec.md に記載されていない機能を独自判断で追加しない
- 既存のテストを削除しない
- 作業対象外のディレクトリを変更しない
# ファイル: .claude/rules/problem-handling.md

## 問題を発見した場合
- 作業を中断し、logs/issues.md に記録する
- 自己判断で修正せず、ユーザーに報告する

Rulesの書き方のコツ: ルールは「なぜそうするのか」の理由を添えると効果が上がる。「data/内のファイルを変更しない」だけでなく「data/内のファイルは入力の原本であり、変更すると再現性が失われるため、変更しない」と書く。モデルは理由を理解した上で判断するので、理由があると「例外的に変更してよいか」の判断が適切になる。逆に理由なしのルールは、モデルが「この状況では当てはまらない」と解釈してスキップしやすい。

実際の場面: データ分析のプロジェクトで、モデルがoutput/に結果を書き出した後「完了です」と報告したが、progress.mdを更新し忘れていた。次のセッションでモデルはprogress.mdを読み、「まだ未完了」と判断して同じ作業をやり直した。Rulesに「1つのPhaseが完了するたびに必ずprogress.mdを更新する」と書いておけば、多くの場合この問題は防げる。ただし、「多くの場合」であって「常に」ではない——これが確率的制御の本質だ。100%の保証が必要なら、Hooks(6.5)で補強する。

確率的制御の限界が表れる場面: Rulesに「spec.mdにない機能を追加するな」と書いても、モデルが「これは改善だ」と解釈して追加してしまうことがある。これは「ルールを無視した」のではなく、「ルールの解釈が人間と異なった」という確率的処理の結果だ。人間同士でも「余計なことをするな」と言ったのに「良かれと思って」やってしまうことがあるが、それと同じ構造だ。

この限界への対処は二通りある。一つはルールをより具体的に書くこと——「機能を追加するな」ではなく「spec.mdのタスク一覧に記載されていない作業を行わない。改善提案がある場合はissues.mdに記録し、実行しない」のように、曖昧さを減らす。もう一つは、Hooks(6.5)で決定論的に検証すること——ルールで意図を伝え、Hooksで実際に守られたか確認する二重構造だ。

6.4 Skills — 再利用可能なワークフロー(作業の流れ)定義

アーキテクチャ上の位置: Context Engineering層。呼び出し時にコンテキストに注入される。

制御の種類: 確率的制御

Skillsは .claude/skills/ ディレクトリに配置するワークフロー(作業の流れ)定義で、Claude Codeの拡張の中心的な仕組みだ。各Skillはフォルダとして構成され、SKILL.md を核に、テンプレートやスクリプトなどのサポートファイルをバンドルできる。

CLAUDE.md、Rules との違い: CLAUDE.mdは「このプロジェクトは何か」、Rulesは「常に守るべきルール」を定義する。どちらもセッション全体を通じて効いている。Skillsは違う。Skillsは「特定の作業をどう進めるか」の手順書であり、呼び出されたときだけコンテキストに注入される。常時読み込まれるCLAUDE.mdやRulesと比べて、必要な場面でだけ登場する点が異なる。

料理に例えると、CLAUDE.mdは「このキッチンの配置図」、Rulesは「衛生管理の基本ルール」、Skillsは「この料理のレシピ」にあたる。レシピは必要なときに取り出して参照し、作り終えたら棚に戻す。

Skillsの特徴: /スキル名 でユーザーが手動で呼び出せるだけでなく、タスクの内容に基づいてClaudeが自動的に発動させることもできる。ディレクトリ構成でスクリプトやテンプレートをバンドルでき、YAML frontmatterで名前と説明を定義する。

実践例: セットアップSkillと実行Skill

# ディレクトリ構成
.claude/skills/
  setup/
    SKILL.md          ← メインの指示(必須)
    templates/        ← テンプレートファイル
  execute/
    SKILL.md
    scripts/
      validate.sh     ← Skillから呼び出せるスクリプト
# ファイル: .claude/skills/setup/SKILL.md

---
name: setup
description: プロジェクトの初期セットアップを行う。proposal.mdに基づいてspec.md、progress.md等を生成する。
---

## 手順
1. docs/proposal.md を読む
2. proposal.md の内容に基づいて以下のファイルを生成する:
   - docs/spec.md(仕様書)
   - docs/progress.md(進捗管理)
   - CLAUDE.md(プロジェクト指示)
3. 生成完了後「/setup 完了」と報告して停止する

## 禁止事項
- 実装(コードの記述・実行)に入らないこと
# ファイル: .claude/skills/execute/SKILL.md

---
name: execute
description: spec.mdに従ってタスクを実行する。progress.mdで進捗を管理する。
---

## 手順
1. docs/progress.md を読み、現在のPhaseと未完了タスクを確認する
2. docs/spec.md を読み、タスクの詳細仕様を確認する
3. 未完了タスクを順番に実行する
4. 各タスク完了後に progress.md を更新する
5. Phase完了後に git commit する

呼び出し方: ターミナルで /setup/execute と入力すると、SKILL.mdの内容がコンテキストに注入される。また、description フィールドの内容に基づいて、ユーザーが明示的に呼ばなくてもClaudeが適切なタイミングで自動的にSkillを選択・適用することがある。

スクリプトのバンドル: Skillsのディレクトリには、SKILL.mdだけでなくスクリプトやテンプレートを同梱できる。上の例で execute/scripts/validate.sh が入っているのはこのためだ。SKILL.mdの手順の中で「validate.shを実行して結果を確認する」と書いておけば、確率的制御(手順のテキスト)が決定論的制御(スクリプトの実行)を呼び出す形になる。Skillsの中に二つの制御を統合できるのは、実用上の大きな利点だ。

実際の場面: 対話の中で重要な結論が出たとき、それをファイルに書き出さないとauto-compactで失われる(第1章)。「重要な結論が出たら書き出せ」とRulesに書くだけでは、書き出し先やフォーマットが毎回バラバラになる。Skillとして「書き出し先はdocs/progress.mdの該当Phaseに追記、フォーマットは『結論: 内容、根拠: 理由』」と定義しておけば、書き出しの手順が標準化される。Skillsは「何をするか」だけでなく「どうするか」の一貫性を提供する。

確率的制御の限界: ただし、SKILL.md自体の指示に対する遵守は確率的である。「validate.shを実行せよ」と書いてあっても、モデルがスキップする可能性はゼロではない。手順5の「Phase完了後にgit commitする」が飛ばされる事例は、第9章の移植テストで実証的に確認されている。Skillsだけでは手順遵守を保証できないからこそ、次のHooks(6.5)が必要になる。

6.5 Hooks — 決定論的制御の実装

アーキテクチャ上の位置: Architectural Constraints層。オーケストレーション層のイベントループ内で動作。

制御の種類: 決定論的制御

Hooksは .claude/settings.json で定義する。モデルの動作中の特定イベント(ツール使用前、ツール使用後、タスク完了宣言時など)に、シェルスクリプトの実行を紐づける。

6.2〜6.4との根本的な違い: CLAUDE.md、Rules、Skillsはすべてテキストとしてコンテキストウィンドウに入り、モデルの確率的な生成プロセスに「影響を与える」ものだった。Hooksは違う。Hooksはモデルの生成プロセスの外側で動くコードであり、モデルがスキップする手段を持たない。第2章で述べた「確率的制御と決定論的制御」の区別が、ここで具体的な実装として現れる。

第4章の基盤構造図で言えば、CLAUDE.md・Rules・Skillsはコンテキストウィンドウの中に入る要素であり、Hooksはイベントループの③(PreToolUse)や⑦(Stop)に位置する要素だ。

Hookが発動するタイミング: Hookは3種類のイベントに紐づけられる。

PreToolUse — モデルがツール(ファイル書き込み、コード実行など)を使おうとした瞬間に発動する。ツール実行の前にスクリプトが走り、exit 1を返せばツール実行自体がブロックされる。「やろうとしたことを止める」ゲートだ。

PostToolUse — ツール実行の直後に発動する。実行結果を検証し、問題があればモデルにフィードバックを返す。「やったことを確認する」チェックポイントだ。

Stop — モデルが「タスク完了です」と宣言した瞬間に発動する。完了条件を検証し、未達であればモデルに差し戻す。第2章で述べた「間違った完了を阻止するゲート」の実装そのものだ。

実践例: Stop Hook(タスク完了前の検証)

{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "command": "bash .claude/hooks/check_completion.sh"
      }
    ]
  }
}
# ファイル: .claude/hooks/check_completion.sh

#!/bin/bash

errors=""

# progress.md が更新されているか確認
if ! git diff --name-only HEAD | grep -q "progress.md"; then
  errors="${errors}progress.md が更新されていません。\n"
fi

# git commit がされているか確認
if [ -n "$(git status --porcelain)" ]; then
  errors="${errors}コミットされていない変更があります。\n"
fi

if [ -n "$errors" ]; then
  echo "以下の問題があります:"
  echo -e "$errors"
  echo "これらを解決してから完了してください。"
  exit 1  # 完了を拒否 → モデルに差し戻し
fi

exit 0  # 完了を許可

実際の場面: 6.3のRulesで「必ずprogress.mdを更新せよ」と書いたが、確率的制御なのでスキップされることがあった。上のStop Hookを設定すれば、progress.mdが更新されていない状態では完了できない。モデルが「忘れた」としても、Hookが差し戻すので、モデルは自分でprogress.mdを更新してから完了する。Rulesだけでは「多くの場合」守られるが、Hookを加えると「常に」守られる。これが確率的制御と決定論的制御の実用上の違いだ。

なぜこれが決定論的なのか: このスクリプトの実行にモデルは関与しない。git diffgit status は通常のプログラムとして動作し、条件分岐は100%正確だ。exit 1が返されればモデルの完了宣言は必ず却下される。モデルにこのチェックを「スキップ」する手段はない。

実践例: PreToolUse Hook(危険な操作の防止)

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "bash .claude/hooks/check_write_permission.sh \"$TOOL_INPUT\""
      }
    ]
  }
}

この例では、モデルがファイルに書き込もうとするたびに、書き込み先が許可されたディレクトリかどうかをスクリプトが検証する。Rulesにも「data/への書き込み禁止」を書いているが、Hooksで二重に守ることで確実性が担保される。Rulesはモデルに「なぜ書き込んではいけないか」を理解させ、Hooksは「理解に関係なく物理的に阻止する」。意図の伝達と行動の強制を分けることで、両方の利点を得る。

Hooksの設計原則 — 「検出と報告」: Hooksの役割は問題の自動修正ではなく、問題の検出とユーザーへの報告だ。Stop Hookが「progress.mdが更新されていません」と報告したとき、モデルに差し戻されたモデルは自分でprogress.mdを更新しようとする。しかし、Hookがモデルの代わりにprogress.mdを書き換えるわけではない。判断と修正はモデル(または人間)が行い、Hookは「条件を満たしていない」という事実だけを確実に検出する。

Hooksを使いすぎないこと: Hooksは強力だが、すべてをHooksで制御しようとすると、モデルの自由度が失われる。ファイルの書き込みを全面禁止すれば安全だが、モデルは何も作れなくなる。第5章で述べたように、確率的制御の柔軟さはそれ自体が能力であり、すべてを決定論的に固めてしまえばその能力を殺すことになる。Hooksで固めるのは「壊れたら取り返しがつかない操作」——入力データの上書き、テストの削除、本番環境への反映——に限定し、それ以外はRulesによる確率的制御で十分だ。

MCP(Model Context Protocol)— ツール実行の基盤: Hooksは「ツール使用を監視する」仕組みだ。では、そもそもモデルがファイルを読み書きしたり外部サービスと通信したりできるのはなぜか。MCP(Model Context Protocol)というプロトコルが、「モデルの外側のプログラム」を標準化された方法で接続しているからだ。モデル単体はテキストを生成することしかできない(第1章)。MCPがモデルに「手足」を提供し、Hooksがその「手足」の動きを監視する——この組み合わせが、能力と安全性を両立させる。MCPの詳細は本稿の射程を超えるため深入りしない。押さえておくべきは一点だけだ。モデルが「どのツールをいつ呼ぶか」の判断は確率的であり、ツールが呼ばれた後の実行は決定論的——Skillsと同じ「判断は確率的、実行は決定論的」の構造を持つ。

6.6 Agents — タスクの分割と並列実行

アーキテクチャ上の位置: オーケストレーション層。確率的制御(Worker定義)と決定論的制御(Taskツール起動)の両方にまたがる。

制御の種類: 複合型(確率的+決定論的)

これまで解説してきた6.2〜6.5の機能は、いずれも一つのモデルインスタンスが一つのコンテキストウィンドウの中で作業することを前提としていた。Agentsはこの前提を拡張する。一つのモデル(Lead)が別のモデルインスタンス(Worker)を起動し、タスクを委任する仕組みだ。

なぜAgentsが必要か — コンテキストの限界: 第1章で述べたように、コンテキストウィンドウには物理的な上限がある。一つのセッションですべてのPhaseを処理しようとすると、Phase 1の文脈がPhase 3の途中でauto-compactされて消える危険がある。また、複数のPhaseが独立して実行可能な場合、逐次処理は非効率だ。

Agentsはこの問題に対してコンテキストの分離というアプローチで対処する。各Workerは独立したコンテキストウィンドウを持つ。Lead(親エージェント)がタスクの概要と必要な情報をWorkerに渡し、Workerは自分専用のコンテキストの中で作業する。Workerのコンテキストが溢れても、Leadのコンテキストには影響しない。

ここで重要なのは、「コンテキストの分離」が何を意味するかだ。従来のソフトウェアにおける並列処理では、スレッド(メモリ空間を共有する並列実行単位)とプロセス(メモリ空間が独立した並列実行単位)の区別が設計上の重要な判断だった。スレッドは共有メモリを通じて互いに干渉しうるため、排他制御(ロック)が必要になる。プロセスはメモリレベルでは干渉しないが、ファイルやネットワークなどの共有資源を通じた連携には別の設計が必要だ。

Agentsにおけるコンテキストの分離は、このプロセスモデルに近い。各Workerのコンテキストウィンドウは独立しており、あるWorkerの文脈が別のWorkerの生成プロセスに干渉することはない。LLMの世界では「コンテキストウィンドウ」がスレッドにとっての「メモリ空間」に相当する。この分離があるからこそ、各Workerは自分の担当タスクに集中でき、他のWorkerの作業による文脈汚染やauto-compactの影響を受けない。

ただし、ファイルシステムは共有されている。これは従来のプロセスモデルでもプロセス間がファイルやパイプを通じて通信できるのと同じだ。Worker間の連携はこの共有ファイルシステムを介して行われるが、コンテキストレベルでの干渉は起きない——この区別が、Agents設計の核心にある。

現在、Claude Codeにおける Agentsの実装には二つの仕組みがある。Task Tool / Subagents(階層型の委任モデル)とAgent Teams(チーム型の協調モデル)だ。両者はコンテキスト分離という基本原理を共有しつつ、Worker間の連携方式が根本的に異なる。

#### 6.6.1 Task Tool / Subagents — 階層型の委任

Task Tool / Subagentsは、Leadが一方向的にWorkerにタスクを委任する階層型のモデルだ。Workerは与えられたタスクを独立して実行し、結果をLeadに返す。Worker同士は直接やり取りしない。

Lead-Worker構造: ワークフロー(作業の流れ)では、以下のような役割分担を定義する。

Lead(統括エージェント)
  ├── spec.mdとprogress.mdを読み、全体状況を把握する
  ├── 各Phaseのタスクを適切なWorkerに割り当てる
  ├── Workerの結果を受け取り、agent_log.mdに記録する
  └── 全Phaseの完了を確認し、報告する

Worker A(前処理担当)
  ├── 入力データの正規化・クリーニング
  └── 結果をoutput/に書き出す

Worker B(構造化担当)
  ├── 正規化済みデータからノード・エッジを抽出
  └── YAML形式で書き出す

Worker定義ファイル: Worker定義は .claude/agents/ ディレクトリにMarkdownファイルとして配置する。中身は自然言語の指示であり、6.3のRulesや6.4のSkillsと同じく確率的制御だ。

# ファイル: .claude/agents/preprocessor.md

あなたは前処理担当のWorkerです。

## 責務
- data/raw/ のテキストファイルを読み込む
- 不要な空白・改行の正規化を行う
- 処理結果を data/normalized/ に書き出す

## 制約
- data/raw/ のファイルは読み取り専用。変更しない
- エラーが発生した場合、logs/issues.md に記録して停止する

実際の場面: 社内イベントの企画を一人で進めると、会場手配の途中でケータリングの見積もりに切り替え、戻ったら会場候補のどこまで調べたか忘れている。スケジュール調整に入ると、今度は予算の内訳が曖昧になる。人間のチームでも「会場担当」「食事担当」「スケジュール担当」を分ける方が効率的だ。Agentsも同じで、各Workerに担当を割り振れば、各Workerは自分の仕事だけに集中できる。Leadは「予算総額を超えていないか」「日程に矛盾がないか」といった全体の整合性だけを確認する。一つのモデルがすべてを抱え込むより、仕事を分けた方がそれぞれの精度が上がる。

Taskツールによる起動: Claude CodeではTaskツールを使ってWorkerを起動する。Leadが「このタスクをWorker Aに任せよ」と判断すると、Taskツールが新しいモデルインスタンスを生成し、Worker定義と必要なコンテキストを渡して実行する。Claude Codeでは最大10のWorkerを並列に起動できる。

ここに確率的制御と決定論的制御の二面性がある。Leadが「どのWorkerにどのタスクを割り当てるか」の判断は確率的だ。しかし、Taskツールが呼ばれた後のWorkerインスタンスの生成は決定論的なプロセスだ——新しいプロセスが確実に起動し、Worker定義が確実に渡される。6.5で述べたMCPと同じく、「判断は確率的、実行は決定論的」という二面性を持つ。

Worker間通信はファイルベース: Task Tool / SubagentsのWorker同士は直接通信しない。コンテキストウィンドウが分離されているため、Worker Aの出力をWorker Bが直接「見る」ことはできない。代わりに、ファイルシステムを介して通信する。Worker Aが output/phase_a_result.yaml に書き出し、Worker Bがそれを読み込む。Leadが「Worker Aの完了を確認してからWorker Bを起動する」ことで、依存関係を管理する。

これは第1章で述べたステートレス性への対処と同じ構造だ。セッション間の文脈をファイルに外部化するのと同様に、Worker間の文脈もファイルに外部化する。原理は同じで、スケールが異なるだけだ。

Agentログの役割: Leadは各Workerの起動・完了・エラーを logs/agent_log.md に記録する。これにより、どのWorkerがいつ何を実行し、どういう結果になったかを追跡できる。人間がセッション後にプロセスを振り返る際の手がかりになる。

# agent_log.md

| 時刻 | エージェント | Phase | 操作 | 結果 |
|------|-------------|-------|------|------|
| 10:01 | Lead | - | Worker A 起動(前処理) | 開始 |
| 10:03 | Worker A | A | data/raw/ 正規化 | 完了(10件処理) |
| 10:03 | Lead | - | Worker B 起動(構造化) | 開始 |
| 10:08 | Worker B | B | ノード・エッジ抽出 | 完了(58ノード, 46エッジ) |

#### 6.6.2 Agent Teams — チーム型の協調

Agent Teamsは、2026年2月にClaude Codeの実験的機能として導入された、Task Tool / Subagentsとは異なるアプローチのマルチエージェント機構だ。

Task Tool / Subagentsが「Lead→Workerへの一方向的な委任」だったのに対し、Agent TeamsはTeammate同士がメッセージを直接やり取りできるピアツーピアの協調モデルを提供する。

Task Tool / Subagents(階層型) Lead Worker A Worker B 委任 結果 委任 結果 Worker同士は互いを知らない (ファイル経由でのみ連携) Agent Teams(チーム型) Team Lead Teammate A Teammate B 全員がメールボックスを通じて メッセージを直接送り合える 共通: コンテキストは分離されている 階層型: Leadが統括。Workerは結果をLeadに返す。     Worker間の連携はファイルシステム経由のみ。 チーム型: メールボックスでピアツーピア通信が可能。

コンテキストは依然として分離されている。 これがAgent Teamsを理解する上で最も重要な点だ。各Teammateは独立したコンテキストウィンドウを持ち、フルのコンテキストを共有することはない。共有されるのは、メールボックスを通じた明示的なメッセージだけだ。

並列処理のアナロジーで整理すると:

モデル従来のソフトウェアLLMエージェント
共有メモリ型(スレッド)メモリ空間を共有。干渉あり該当なし — コンテキスト共有型のAgentsは現時点で存在しない
メッセージパッシング型プロセス間通信(MPI等)Agent Teams — メールボックスで明示的にメッセージ交換
ファイル共有型独立プロセス+共有ファイルTask Tool / Subagents — ファイルシステム経由でのみ連携

Agent Teamsが追加したのは「メッセージパッシング」であり、「コンテキスト共有」ではない。Teammate Aが発見した問題をTeammate Bに直接伝えられるようになったが、Teammate Aのコンテキスト全体がTeammate Bに流れ込むわけではない。送信するメッセージの内容を選択する必要があり、その選択自体は確率的な判断だ。

共有タスクリスト: Agent Teamsではタスクの管理にも新しい仕組みが加わっている。タスクが依存関係のグラフ(DAG: 有向非巡回グラフ)として構造化され、あるタスクが別のタスクをブロックできる。たとえば「タスク3(テスト実行)はタスク1(API実装)とタスク2(認証設定)の両方が完了するまで開始できない」という制約を表現できる。タスクの状態はファイルシステムに永続化され、すべてのTeammateから参照可能だ。

実際の場面: Task Tool / Subagentsのイベント企画の例に戻ると、Agent Teamsではこうなる。会場担当が「300人収容の会場が確保できた」とメッセージを送ると、食事担当がそれを直接受け取り、300人分のケータリング見積もりに着手できる。Task Tool / Subagentsでは、この情報はいったんLeadに戻り、Leadが食事担当に伝え直す必要があった。チームメンバー同士が直接話せるか、全員が上司を経由して話すかの違いだ。

Agent Teamsの制約: Agent Teamsは2026年3月時点でまだ実験的機能であり、いくつかの重要な制約がある。実行にはOpus 4.6以上のモデルが必要で、実験的機能フラグの有効化が前提となる。また、Teammateのトークン消費は個別に発生するため、3つのTeammateを並列に動かすと、単一セッションの3〜4倍のトークンコストがかかる。並列実行による時間短縮とコスト増のトレードオフは、タスクの性質に応じて判断する必要がある。

#### 6.6.3 共通の設計原則

Task Tool / SubagentsとAgent Teamsは実装が異なるが、以下の原則は共通している。

ツール間の実装差異: Agentsの仕組みはツールによって大きく異なる。Claude CodeではTask Tool / SubagentsとAgent Teamsの両方が利用可能だ。Codex CLIでは同等の並列実行機構がなく、逐次実行に書き換える必要がある。Gemini CLIではSubagents(実験的機能)として部分的に対応している。この差異は第9章の移植で詳しく述べる。

確率的制御の限界: Worker / Teammate定義はテキストであり、各エージェントの行動は確率的制御に従う。Worker Aに「data/raw/を変更するな」と書いても、確率的に守られないリスクはある。Workerの行動にも6.5のHooks(PreToolUse)が適用されるため、重要な制約はHooksで二重に守れる。ただし、Leadが「適切なWorkerに適切なタスクを割り振る」判断自体は確率的であり、Hooksでは制御しにくい。ここはSkills(6.4)の中でWorker割り当てのルールを明示的に記述することで精度を上げる。

Agentsを使いすぎないこと: Agentsはコンテキスト分離と並列実行を可能にする強力な機能だが、すべてのタスクに必要なわけではない。Workerを起動するたびにコンテキストの受け渡しコストが発生し、Worker間の連携にはファイルI/Oやメッセージングが必要になる。タスクが一つのコンテキストウィンドウに十分収まるなら、Agentsを使わない方がシンプルで効率的だ。第5章で述べた「困ったら入れる」の原則はここでも当てはまる。Agentsの導入が有効なのは、データ量が大きくコンテキスト溢れが予想される場合、独立して並列実行可能なPhaseがある場合、そしてWorkerごとに異なる専門性(前処理、構造化、検証など)を持たせたい場合だ。

6.7 機能の使い分け — 確率的/決定論的の配置

6.2〜6.6で個別に解説した機能を、制御の種類で整理する。

確率的制御(Context Engineering)
  ┃
  ┣━ CLAUDE.md    ── 常時読み込み。プロジェクトの前提。
  ┃                  最も広い範囲に影響するが、最も緩い制御。
  ┃
  ┣━ Rules        ── 常時読み込み。行動規則・禁止事項。
  ┃                  CLAUDE.mdより具体的な指示。
  ┃
  ┗━ Skills       ── 呼び出し時 or 自動発動。ワークフロー(作業の流れ)定義。
                     手順の一貫性を高める。スクリプトもバンドル可能。
                     指示テキスト部分はスキップされうる。

決定論的制御(Architectural Constraints)
  ┃
  ┣━ Hooks        ── イベント駆動。条件チェック。
  ┃                  モデルがスキップできない強制力。
  ┃
  ┗━ ツール実行    ── MCP等を介したファイル操作・外部通信。
                     コードとして確実に実行される。

複合型(確率的 + 決定論的)
  ┃
  ┗━ Agents       ── Worker定義は確率的(自然言語テキスト)。
                     Task起動は決定論的(プロセス生成)。
                     コンテキスト分離と並列実行を提供。

この図を見ると、確率的制御の側に3つの機能があり、決定論的制御の側にHooksとツール実行、そして確率的・決定論的の両方にまたがるAgentsがある。確率的制御が多いのは偶然ではない。AIシステムにおける制御の大部分は確率的であり、決定論的に制御できる部分は限られている。モデルの行動のほとんどは「影響を与える」ことしかできず、「強制する」ことができるのはHooksとツール実行という狭い領域だけだ。

確率的制御の中にもグラデーションがある: 3つの確率的制御は一様ではない。影響力の強さと持続性に差がある。

CLAUDE.mdはセッション全体を通じて影響するが、6.2で述べたように会話が長くなると影響力が薄れる。Rulesも常時読み込みだが、より具体的な指示であるため、モデルが参照する確率はCLAUDE.mdより高い。Skillsは呼び出されたときだけ効くが、手順が明確なので呼び出し直後の遵守率は高い。

つまり、確率的制御の中でも「広く薄く効く」(CLAUDE.md)から「狭く強く効く」(Skills)までのスペクトラムがある。

実践上の設計パターン — 二重構造: 重要な制約は「Rulesに書く+Hooksでも守る」の二重構造にする。Rulesだけだと確率的に破られるリスクがある。Hooksだけだと、なぜその制約があるのかモデルが理解できず、不自然な動作をする可能性がある。両方を組み合わせることで、モデルは制約の意図を理解しつつ(Rules)、万が一忘れても強制される(Hooks)。

具体例で示す。「入力データを変更してはならない」という制約を実装する場合:

Rulesに書く(確率的制御):
  「data/ 内のファイルは入力の原本であり、
   再現性が失われるため変更しない」
  → モデルは「なぜ変更してはいけないか」を理解する
  → 大半のケースでは、これだけで守られる

Hooksで守る(決定論的制御):
  PreToolUse Hook で data/ への Write/Edit を検出し、
  exit 1 で阻止する
  → モデルの理解に関係なく、物理的に書き込みが阻止される
  → Rulesを「忘れた」場合のセーフティネット

この二重構造は、6.3で述べた「意図の伝達と行動の強制を分ける」設計パターンの一般化だ。Rulesが「理由を伝えて行動を促す」(教育的機能)、Hooksが「条件に違反したら止める」(検査的機能)を担う。

判断の基準 — 失敗のコストで決める: どの機能を使うかは、第5章で述べた「失敗のコスト」で判断する。失敗しても大きな問題にならない制約はRulesだけで十分だ。失敗すると取り返しがつかない制約はHooksで補強する。すべてにHooksを設けるのはコストに見合わない。

実用上のポイント: 迷ったら「これが守られなかったとき、どのくらい困るか」を自問する。「文体が揺れる」程度ならRulesで十分。「入力データが上書きされる」なら致命的なのでHooksで守る。この判断を各制約に対して個別に行うのが、Harness設計の中心的な作業だ。