本記事は Zenn にも掲載しています。
本記事はシリーズ「自己学習する開発環境」の第2回です。
- AIが同じミスを二度としない開発環境(全体像)
- 設計書1枚から実装・レビュー・PRまで(本記事)
- AIレビューの指摘を資産化する — 自己学習ループの実装
- Figma to Code を閉ループにする
用語メモ
- オーケストレーター / 指揮者: 自分では実装せず、複数のサブエージェントへの指示出しと結果の確認に専念する役割
- 委譲: 作業を自分でやらず、サブエージェントに任せること
- Contract: フロントエンドとバックエンドが共有する API の型定義・スキーマ
- 凍結: 「以後は変更しない」と決めて確定させること
- バリア: そこまでの作業が全部終わるまで、先へ進めない同期ポイント
- エスカレーション: AI だけで解決できない問題を、人間の判断に引き継ぐこと
実装を AI エージェントに任せると、今度は別の問題が起きます。こちらが把握できない速度でコードが増え、レビューが追いつかないのです。差分を全部読むなら自分で書いたほうが早い。かといって読まずにマージはできない。
筆者のチームでは、これを逆転の発想で解決しました。実装もレビューもテストも全部サブエージェントに任せ、メインセッション(と人間)は判断だけをする体制です。設計書を書いて /workspace-plan orchestrate と打つと、実装 → 6観点レビュー → 修正 → ユニットテスト → 最終ゲート → PR 準備まで進み、人間が登場するのは5つの確認ゲートだけになります。
Claude Code の開発責任者 Boris Cherny は「my job is to write loops(自分の仕事はループを書くことだ)」と言っています1。本記事は、この「ループを書く」を開発フロー全体に適用した実例です。ループエンジニアリングという概念の整理はシリーズ第1回に譲り、ここでは実装の詳細に集中します。
なお、前提となる環境はこうです。
筆者のチームでは、管理画面・ユーザー向けフロントエンド2つ(Next.js)・バックエンド API(NestJS)・Playwright E2E を含むモノレポを運用しており、
.claude/skillsに18個のスキル、.claude/agentsに12個のサブエージェント定義を置いています。
1. 前提: ブランチごとの「一冊のドキュメント」
オーケストレーションの話の前に、その土台となる状態管理から説明します。マルチエージェントの記事では見落とされがちですが、長いフローを回すには、まず「今どこにいるか」をファイルに残せるようにするのが先です。
workspace-plan スキルは、ブランチごとに .claude/workspace/{ブランチ名}/ を切り、5つのドキュメントを置きます。
| ファイル | 役割 |
|---|---|
overview.md |
概要・完成条件(設計書のチェックリストが展開される) |
architecture.md |
アーキテクチャ設計 |
rollout-plan.md |
実装計画とチェックリスト |
worklog.md |
時系列ログ。設計判断の根拠と教訓を記録 |
known-issues.md |
既知の問題・積み残し |
このスキルには、全操作に共通する最重要ルールが1つあります。
1つのタスク/ステップが終わるたびに、その都度ワークスペースドキュメントへ進捗を反映する(作業完了 = ドキュメント更新まで)。 あとでまとめて書く・記憶に頼るのは禁止。
セッションの記憶(コンテキスト)は、セッションが終われば消えます。しかしドキュメントは残ります。このルールがあるおかげで、セッションが切れても・翌日でも・別のマシンでも、status 操作ひとつで「どこまで進んでいて、何が積み残しか」に復帰できます。頭の中の状態をファイルに書き出しておくことこそが、長いループの前提条件です。
親子ワークスペース
エピック(複数チケットをまとめる大きな作業単位)は、親(tracker = 進捗をまとめて見る側)ワークスペースと子ワークスペースに分けます。
ポイントはディレクトリをネストさせないことです。親も子もフラットに並べ、親子関係はドキュメント内の相互リンクで表現します。子が独立したブランチ・PR を持てること、git worktree と競合しないこと、既存の操作(init / status / update)がそのまま使えることが理由です。子の進捗が変わったら親の一覧表へ反映(ロールアップ)し、status <親> で全体をひと目で確認できます。
2. 指揮者パターン — メインセッションは実装しない
orchestrate 操作の大原則はこの一文です。
メインは指揮者に徹する。実装・レビュー・テストを自分で書かない。 必ずサブエージェントに委譲する。
メインセッションがやってよいのは、次の6つだけです。
- 設計書・ワークスペースの読込と把握
- サブエージェントへの指示出し
- 返ってきたサマリの統合・判断
- ワークスペースの更新
- ユーザー確認ゲート
- フローの分岐制御
なぜここまで制限するのか。ひとつは、メインのコンテキストを判断のために取っておきたいからです。実装の生ログ、巨大な diff、テストの失敗出力はトークンの塊で、これをメインに積み上げていくと、フローの後半になるほど判断の質が落ちてコストも跳ね上がります。重い作業をサブエージェントの別コンテキストへ隔離してしまえば、メインに返ってくるのは「サマリ」だけで済みます。
もうひとつは、高価なモデルの思考を「分解」と「検収(返ってきた結果の検品)」にだけ使いたいからです。何をどう分けるか、返ってきた結果は正しいか。結局ここが一番頭を使う仕事で、最上位モデルを充てる価値があるのもここです。
サブエージェント編成(12体)
| 役割 | agent | モデル |
|---|---|---|
| フロントエンド実装 | frontend-implementer |
上位(opus) |
| バックエンド実装 | backend-implementer |
上位(opus) |
| テスト実装 | test-implementer |
上位(opus) |
| FEレビュー: 規約 / 品質 / UX |
fe-review-convention / fe-review-quality / fe-review-ux
|
上位(opus) |
| BEレビュー: 規約 / セキュリティ / 品質 |
be-review-convention / be-review-security / be-review-quality
|
上位(opus) |
| Figma取得 / Storybook撮影 / 視覚比較 |
figma-fetch / storybook-shoot / figma-compare(第4回で詳述) |
取得・撮影は標準(sonnet)、視覚比較は上位(opus) |
モデルの配分方針はシンプルで、コードの読み書きや指摘の判断が要る役はすべて上位モデル、機械的な取得・撮影だけ標準モデルです。指揮者を務めるメインセッションも最上位モデル前提です(筆者のチームでは指揮者系のスキルに「標準モデルで起動されていたら上位モデルへの切り替えを促す。ただし止めはしない」という注意書きを入れています)。トークン消費の内訳もこの表のとおりで、支配的なのは実装3体とレビュー6体(すべて上位モデル)です。
レビューが6体もいるのは、1エージェント=1観点に絞っているからです。「規約もバグもUXも全部見て」と頼むと注意が分散します。観点を絞ったエージェントを並列に走らせ、指摘をメインが統合するほうが、速度は明確に上がりますし、検出の精度も上がると考えています(検出率そのものの比較計測はまだしていません)。
レビューエージェントの定義はたとえばこんな形です(抜粋)。
---
name: fe-review-convention
description: フロントエンド実装を「設計規約準拠」の観点だけで厳格レビューする。
指摘リストだけを返す(修正はしない)。
model: opus
---
あなたはフロントエンド・規約準拠レビュー担当です。他のレビュアー(品質、UX)とは
独立に、**「設計規約に沿っているか」だけ**を厳しく見ます。
**修正はしません。指摘リストだけを返します。**
## 厳格さの方針
- 迷ったら「指摘する」側に倒す
- 各指摘に重要度を付ける: P0=必ず直す / P1=直すべき / P2=改善提案
「修正はしない・指摘だけ返す」も重要な設計です。レビュアーに修正までさせると、指摘の整理(観点間でダブった指摘をまとめる・ぶつかる指摘のどちらを取るか決める)をメインが行う前にコードが変わってしまいます。
もうひとつ地味に効く工夫があります。各エージェントが使うモデルは agent 定義の frontmatter だけに書き、スキル側には一切書かないことです(先の編成表のモデル列は、この frontmatter の model: を集めたものです)。同じ情報を2箇所に書くと、片方だけ更新されて矛盾する「ドリフト」が必ず起きます。チーム全体で「唯一の正(single source of truth)はどこか」をファイル単位で決めておくのは、スキル運用の基本だと考えています。
実装面の補足をひとつ。サブエージェントの起動は Claude Code の Agent ツールで行います(以前は Task という名前でした)。スキルの frontmatter allowed-tools に Agent を含めておくと、起動のたびの許可確認を省けます。ただし allowed-tools は「事前承認」であって利用可否の制御ではありません。委譲できるかどうか自体を決めるのは、サブエージェント定義側の tools 欄に Agent があるかどうかです(ここから省くと、そのエージェントは孫エージェントを起動できません)。
指揮者からサブエージェントへの指示プロンプト
サブエージェントはメインの会話(コンテキスト)を引き継ぎません。そのためフローには「各エージェントには設計書パス・対象範囲・担当の具体ステップを毎回明示的に渡す」というルールがあります。実際の指示は、たとえばこんな形になります(形式は実運用のもの・内容はサンプル)。
あなたは backend-implementer です。以下を実装してください。
- 設計書: .claude/workspace/TICKET-123/orchestration.md(最初に読むこと)
- 対象範囲: 申請APIの新設(POST /applications)。
Contract は packages/shared で凍結済み(変更禁止)
- 対象外(明示): フロントエンド一式・既存APIの改修(「ついで修正」も禁止)
- 完了条件: typecheck green・対象のユニットテスト追加
- 返すもの: 変更ファイル一覧と設計判断の要約だけ(コード全文は返さない)
「返すもの」を絞っているのは、前述のとおりメインのコンテキストを守るためです。この文面を、指揮者が Agent ツールの prompt にそのまま渡してサブエージェントを起動する——それが「委譲」の実体です。
3. orchestrate の3フェーズ — 並列化は「凍結」が前提
フロー全体は3フェーズ構成です。図中の「バリア」は、そこまでの作業が全部揃うまで先へ進めない同期ポイントを指します。
(色分け: 黄=人間の確認ゲート / 青緑=サブエージェントの作業 / 青=指揮者が扱う工程 / 紫=学習系。👤 ゲートは図には定常フローの2箇所のみ描いており、残り3つ — 打ち切り時・P0/P1 を残す判断・Contract 変更時 — は例外分岐で登場します)
Phase 0: 基盤確定(直列)
設計書を読み、ワークスペースを整え、そして共有パッケージの型・API Contract・DB スキーマをここで凍結します。共有物を固めてから、全体計画(フェーズ順・並列トラック・起動するエージェント)をユーザーに提示し、開始の合図を待ちます。
Contract の凍結が、次のフェーズの並列化の前提です。ここを固めずに BE/FE を並列で走らせると、後から型が変わって FE が丸ごと手戻りします。
Phase 1: BE/FE 2トラック並列
Contract 確定後、BE と FE は互いに独立です(FE は Contract の型にのみ依存し、BE の内部実装には依存しません)。そこで2トラックを並列で進めます。各トラックの中では「実装 → 3観点レビュー → 修正 → ユニットテスト」を順番に流し、同じ種類の工程はひとまとめにして同時に起動します(レビューは最大 BE3 + FE3 = 6体同時)。
トラック内が直列なのは同一ファイルを触るから、トラック間が並列なのはディレクトリが分かれているから。この判断は早見表としてスキルに固定してあります(抜粋)。
| 工程 | 並列/直列 | 根拠 |
|---|---|---|
| 共有 Contract・DBスキーマの確定 | 直列(バリア) | FE/BE 双方の前提。競合しやすいので単独確定 |
| BE実装 ↔ FE実装 | 並列 | FEはContract型のみ依存。別ディレクトリ |
| レビュー(BE3+FE3観点) | 並列 | 読み取り専用・副作用なし |
| 修正ループ | トラック内は直列 | 同一ファイル編集の競合回避 |
| 最終ゲート | 直列(バリア) | 全トラックが終わってから、アプリ横断のデグレを検知 |
迷ったら直列に倒す(安全側)、もルールに含めています。
Phase 2: 収束・最終ゲート・PR(直列)
両トラックが揃ったら、変更していないアプリも含めて全アプリの typecheck とユニットテストを実行します。今回触っていないアプリを省略しないのは、共有パッケージ経由で他のアプリの型が壊れたり、既存機能が壊れたり(デグレ)していないかを検知するためです。1つでも落ちたら PR には進まず、該当の implementer に差し戻します。
ゲートを抜けたら、運用メトリクスの記録と retrospective(学習の反映)を行い、ユーザーの承認を得てから commit / PR を作成します。この retrospective が環境を学習させる仕組みの入口なのですが、それは第3回のテーマです。
ルールには「事故」が刻まれている
このフロー定義を読むと、ところどころに妙に具体的な注意書きがあります。たとえば:
- 「共有パッケージの Contract を変更したら必ずビルドし直すこと。古い dist のままだとバックエンドが起動時にクラッシュする既知事故あり」
- 「Phase 1 の途中で Contract 変更が必要になったら Phase 0 に戻して確定し直し、FE トラックへ再同期する(手戻りをユーザーに共有する)」
これらは全部、実際に踏んだ事故です。エージェントがミスするたびに、同じミスが起きないようフロー定義側へ恒久修正を入れる。ハーネスエンジニアリングの基本動作を、フロー定義ファイルに対して続けてきた結果がこの「妙な具体性」です。
4. レビュー修正ループの収束ルール — Verifier は「止まり方」まで設計する
ここが本記事で一番伝えたい部分です。この章では、レビューと収束判定を担う検証の仕組み全体を Verifier(評価器) と呼びます。
AI にレビューと修正のループを回させるとき、最大の事故は「動かないこと」ではありません。収束しないループと、収束したフリです。修正が別の問題を生み、それを直すと元の問題が再発する。あるいは3周回った挙句「概ね対応済みです」と報告してくる。放置すると、トークンだけ溶けて品質は上がりません。
そこで、レビュー修正ループには目安ではなく強制ルールとして収束条件を定義しています。
① 上限3周のハードリミット。 周回は回数で数えます(周N = N回目の差し戻し修正 + N+1回目のレビュー。たとえば周1は「1回目の修正と、その確認の2回目レビュー」までを指します)。3周で P0/P1 が消えなければ続行せず、残指摘リストを添えてユーザーにエスカレーションします。
② 指摘台帳。 各周の終わりに、全指摘を連番ID・観点・重要度・状態(open/fixed/wontfix)の台帳として worklog に記録します。再レビュー時は前周の台帳をエージェントに渡し、「同じ指摘か別の指摘か」の判定を ID で行います。台帳がないと、言い回しが変わっただけの同一指摘を「新しい指摘」と数えてしまい、収束判定ができません。
実物の台帳はこんな形です(ワークログから抜粋・マスキング済み)。
### 指摘台帳(周1・連番ID/観点/重要度/状態)
- BE-P0-1 [security] メール確認APIが、トークン内のユーザーとURL側のアカウントを
突き合わせておらず、他人のアカウントを確認できてしまう。open → 要修正
- BE-P1-1 [security+quality] 確認処理が「読んでから更新」の2段階で、同時実行に
弱い(条件付き update 1回に置き換える)。open → 要修正
- BE-P1-3 [convention] 同じ定数配列を2ファイルに二重定義。open → 要修正
- BE-P2-2 [convention] 新規メソッドが RORO(引数・戻り値をオブジェクトに統一する規約)逸脱。→ 修正(軽微)
③ 停滞検知。 前の周から P0/P1 の残数が減っていなければ、上限前でも即エスカレーションします。同じアプローチの繰り返しは解決しません。
④ 振動検知。 同一指摘(台帳IDで判定)が2周連続で残る、または修正が A↔B の往復(片方を直すともう片方が壊れる)になったら「振動」とみなし、その場で打ち切ります。
⑤ 抜け道封じ。 打ち切りを「概ね対応済み」「実用上問題なし」などに言い換えて完了報告することを禁止します。未解決の P0/P1 は known-issues に記録した上でユーザー判断を仰ぐ。P1 を残したまま先へ進む判断ができるのはユーザーだけで、指揮者(AI)の独断では許しません。ついでに言うと、重要度の降格(P1→P2)もユーザー承認事項です。降格は握り潰しの温床になるからです。
⑤が奇妙に見えるかもしれませんが、実運用では一番重要でした。LLM には「完了と報告したい」方向のバイアスがあります。ルールは性善説で書いてはいけない。「〜を禁止」だけでなく「〜という言い換えを禁止」まで書いて、初めてルールとして機能します。
5. 自分の仕事をループに落とし込む方法
ここまでは筆者のチームの話でした。とはいえ、この型自体はうちのモノレポ専用のものではありません。自分の業務に当てはめるとしたらどうなるか、手順に分解してみます。
起動は設計書1枚
orchestrate の入力は、テンプレートに沿った設計書1枚です。章立てはこうなっています。
# オーケストレーション設計書: TICKET-123 {タイトル}
## 1. ゴール / 背景
## 2. 対象範囲(スコープ) ← どのパッケージ・アプリを触るか
## 3. 対象外(明示) ← ここに書いたものは実装させない
## 4. フェーズ順 / 並列方針
## 5. バックエンド詳細 ← API一覧・認可要件・マイグレーション要否
## 6. フロントエンド詳細 ← 対象画面・Figma URL・参考画面
## 7. テスト方針 ← unit必須 / e2e要否
## 8. 完成条件(チェックリスト) ← overview.md に展開され最終判定に使われる
## 9. 決定事項 / 制約
## 10. 懸念・未確定 ← 着手前に指揮者が確認する
この設計書は §1 の5ファイルとは別の入力用ドキュメントで、ワークスペース内(.claude/workspace/{ブランチ名}/orchestration.md)か設計書置き場(docs/plans/)に置き、パスを渡して起動します。完成条件は起動時に overview.md へ展開されます。
書くうえで一番重要なのは「2. 対象範囲」と「3. 対象外」です。ここがエージェントへの指示の境界になります。対象外を明示しないと、エージェントは「ついでに直しておきました」をやります。善意のスコープ外実装は、レビューコストを静かに膨らませる事故です。
一般化した4ステップ
自分のタスクをループのワークフローに落とすときの手順です。
Step 1: 工程を「直列必須」と「並列可能」に分ける。 判断基準は2つだけです。同じファイル・成果物を触るか。前工程の確定が前提か。両方 No なら並列にできます。並列化の前に「凍結すべき共有物」(型・スキーマ・規約・用語集)を特定するのがコツです。
Step 2: 各工程を「実装系」と「検証系」のエージェントに割り当てる。 検証系は観点を1つに絞ると精度が上がります。「全部見て」は「何も見ない」とほぼ同義です。
Step 3: 人間の確認ゲートを置く場所を決める。 筆者のチームでは、前章の収束ルール(5項目)とは別に、確認ゲートを5箇所に固定しています。①着手前(全体計画の提示後)②レビュー修正ループの打ち切り時 ③P0/P1 を残して進む判断が必要なとき ④凍結したはずの共有物に変更が必要になったとき ⑤commit/PR の前。逆に言うと、これ以外は AI の判断で連続実行を許しています。ゲートを絞るから自動化が回り、ゲートがあるから安心して任せられる。両方が必要です。
Step 4: ループの「止まり方」を先に設計する。 上限周回数、停滞・振動の定義、エスカレーション先。前章のとおり、ここを設計しないループは事故ります。回し方より止まり方が先です。
開発以外にも同じ型は使えます。たとえばブログ記事の執筆なら「構成案の凍結(Phase 0)→ 本文執筆 ∥ ファクトチェック(Phase 1)→ 推敲レビュー → 修正 → 公開前チェックリスト(Phase 2)」という同型のループが組めます。白状すると、このシリーズ自体もほぼこの型で作っています。構成案を固めてから執筆し、ペルソナの違うレビューエージェントを並列に走らせて、指摘を反映しました。
6. 補足: 並列開発を支える worktree slot 方式
トラックの並列とは別に、ブランチ自体の並列も運用しています。orchestrate を --worktree フラグ付きで起動すると、git worktree(1つのリポジトリから複数の作業ディレクトリを並行して持てる Git 標準機能)で別の作業ツリーを作り、slot 番号を払い出して環境ごと分離します。
分離するのは3つの競合です。①ファイル競合(worktree で別ディレクトリ)②ポート競合(slot × 100 のオフセット)③実行環境競合(Docker Compose のプロジェクト名と DB ボリュームを slot 別に)。さらに起動時に本体(ローカル開発環境)の DB を pg_dump | pg_restore で複製するので、シード投入なしで、普段の開発 DB と同じデータのまま並行作業に入れます。
これで「ブランチAで orchestrate を回しながら、ブランチBの動作確認をする」が1台のマシンで成立します。詳細は別記事にする予定なので、ここでは概要に留めます。
まとめ
指揮者パターンの本質は一文に要約できます。高いモデルの思考は「分解」と「検収」にだけ使い、作業は委譲する。
正直に書いておくと、この体制は安くはありません。レビューだけで上位モデルのエージェントが最大6体、修正ループは最大3周まで回ります。コンテキスト隔離でコストを抑えてはいますが、上位モデル前提の設計であり、安価なモデルに置き換えると「言い換え禁止」のようなメタルールの遵守やレビュー精度から先に劣化します。導入時はまず1タスク流してみて、自分たちの予算感と照らすことをおすすめします。
導入時のチェックリストを置いておきます。
- メインセッションの役割を6つ(把握・指示・統合・記録・ゲート・分岐)に制限しているか
- 並列化の前に「凍結すべき共有物」を特定したか
- レビューエージェントは観点を1つに絞っているか(修正はさせず指摘だけ返させているか)
- ループの上限・停滞・振動・エスカレーションを定義したか
- 「概ね対応済み」のような言い換え完了報告を明文で禁止したか
- 進捗をセッション外のドキュメントに毎ステップ書き残しているか

orchestrate 実行中の様子(再構成イメージ)。Phase 0 で共有物を凍結し、Phase 1 で実装・レビューのワーカーが並列に起動する
さて、このフローの Phase 2 には「retrospective(学習の反映)」というステップがありました。レビューで出た指摘は、そのタスクで直して終わりではありません。次のタスクで同じ指摘が出ないように、環境側へ書き戻されます。次回は、この自己学習ループの実装 — 追記専用ログ・頻出違反ランキング・予防DoD・実測メトリクス — を詳しく見ていきます。
参考リンク
- Loop Engineering入門(suwash)
- Loop Engineeringとは — #ハーネスエンジニアリング(Qiita)
- エンジニアのAgent Loopを整える技術(karamage)
- Claude Codeでハーネスエンジニアリングを実践する(sasadango28)
-
Addy Osmani「Loop Engineering」(https://addyo.substack.com/p/loop-engineering)内で引用された発言。 ↩