AI-DLC Workflow V2のアーキテクチャ: one core, many harnessesの設計思想
ステージの定義を修正したい。でもハーネスが6つある。6箇所直すの? いいえ、1箇所です。AI-DLC Workflow V2には「修正は1回、反映は全ハーネス」を構造的に保証するビルドの仕組みがあります。その3層構造を整理しましょう。シリーズ第19回。
Series: AI-DLC Workflow V2の解説 (31 articles)
- …
- 19AI-DLC Workflow V2のアーキテクチャ: one core, many harnessesの設計思想 This article
1. はじめに
この記事はAI-DLC Workflow V2(以降V2)シリーズの第19回です。第18回ではCLIコマンドの全体像をユースケース別に整理しました。
今回は視点を変えて、V2を「使う」側ではなく「作っている」側の設計に踏み込みます。その前に、V2が言う「ハーネス」の位置づけを確認しておきましょう。

LLMは推論能力そのもの。コーディングエージェント(Claude Code、Kiroなど)はLLMにツールとコンテキストを加えたもの。そしてAI-DLCのハーネスは、そのエージェントの上に「規律あるライフサイクル」を載せる外層です。今回の記事は、この外層がどのように実装されているかを見ていきます。
今回のゴールは、V2が「1つのソースから6つのハーネスを生成する」仕組み、つまりコア・パッケージング・アーキテクチャを理解することです。V2はClaude Code、Kiro IDE、Kiro CLI、Codex CLI、opencode、GitHub Copilotという6つのハーネスをサポートしていますが、メソドロジー(方法論)の定義は1箇所にしか存在しません。ステージの追加も、エージェントの変更も、
core/ を編集すれば全ハーネスに反映されます。では、この「one core, many harnesses」の設計がなぜ必要だったのか、そしてどのように実現されているのかを見ていきましょう。
2. なぜ「one core」が必要だったのか
まずV2の全体像を確認しましょう。以下の図の「FOUNDATION」セクションにある「パッケージマネージャー」が今回の主題です。

「ツール非依存の単一コア → 多様なハーネスへ」。この一文が示す通り、V2はメソドロジーの定義を1箇所に集約し、そこから各ハーネスへ配信する設計を採っています。
では、なぜこの設計が必要だったのでしょうか。複数のAIコーディングアシスタントをサポートするフレームワークを作るとき、素朴なアプローチは「ハーネスごとに実装を持つ」ことです。しかしこの方法には深刻な問題があります。
ここで重要なのは、V2のメソドロジーが33ステージ・14エージェント・9スコープ・17フック・5センサーという規模であることです。もしこれをハーネスごとに複製していたら、ステージ定義を1つ修正するだけで6箇所の更新が必要になります。
実際に起きる問題を整理すると、次のようになります。
| 問題 | 影響 |
|---|---|
| メソドロジーの分散 | ステージ追加や修正が6倍のコストになる |
| ドリフト(ずれ) | あるハーネスだけ古い定義が残る |
| テストの爆発 | 同じロジックを各ハーネスで個別にテストする必要がある |
| 貢献の障壁 | コントリビュータが複数ハーネスの違いを理解しないと修正できない |
言い換えれば、「メソドロジーは1つ、表示方法だけが異なる」という事実を、リポジトリ構造そのものに反映する必要があったのです。この設計判断が「one core, many harnesses」のアーキテクチャを生みました。
3. 3層アーキテクチャ: core / harness / dist
V2のリポジトリは明確に3つのゾーンに分かれています。以下のスライドが示すように、コントロールプレーン(指揮者 + ワークフローステートマシン)とデータプレーン(ステージ内のエージェント群)は共通で、「ツール固有のビルド」の部分だけが各ハーネスへ分岐します。

この「ツール固有のビルド」を担うのが、これから見ていく3層構造です。

それぞれの責務を見ていきましょう。
core/ — ハーネス中立の単一ソース
core/ はV2の「何であるか(what)」を定義する場所です。ここに置かれたファイルは特定のハーネスに依存しません。1
2
3
4
5
6
7
8
9
10
11
core/
├── tools/ 36のaidlc-*.tsエンジンツール
├── aidlc-common/ ステージプロトコル + 33ステージファイル + コンダクタ定義
├── agents/ 14エージェント(11ドメイン専門家 + 2レビュアー + コンポーザー)
├── hooks/ 17フレームワークフック
├── knowledge/ エージェントごとの方法論知識
├── memory/ org/team/projectルール + フェーズガードレール
├── scopes/ 9スコープ定義
├── sensors/ 検証マニフェスト
├── skills/ 3セッションスキル
└── templates/ オンボーディングスケルトンここで重要なのは、
core/ のマークダウンファイルが特定のディレクトリ名を直接書かないことです。代わりに {{HARNESS_DIR}} というトークン(置換用の目印)を使います。たとえば「.claude/tools/ にあるファイルを…」と書く代わりに「{{HARNESS_DIR}}/tools/ にあるファイルを…」と記述します。このトークンがビルド時にハーネスごとの正しいパスへ置換されます。harness/<name>/ — 薄いハーネス固有サーフェス
harness/ は各ハーネスが「どう振る舞うか(how)」を定義する薄い層です。各ハーネスのディレクトリには以下のようなファイルが含まれます。manifest.ts— このハーネスがcore/をどう射影するかの宣言skills/aidlc/SKILL.md— ハーネス固有のオーケストレータスキルonboarding.fills.ts— オンボーディングドキュメント(CLAUDE.md や AGENTS.md)の変数settings.jsonや設定ファイルemit.ts(オプション)— 宣言的なマッピングだけでは表現できないハーネス固有の出力
6つのハーネスはそれぞれ
harness/claude/、harness/kiro/、harness/kiro-ide/、harness/codex/、harness/opencode/、harness/copilot/ に存在します。dist/<harness>/ — 生成済み・コミット済み・ドリフト監視
dist/ はユーザーがプロジェクトにコピーする成果物です。手で編集してはいけません。CIのドリフトガードが手編集を検出し、ビルドを失敗させます。各ハーネスの出力先は以下の通りです。
| ハーネス | 出力ディレクトリ |
|---|---|
| Claude Code | dist/claude/.claude/ |
| Kiro IDE | dist/kiro-ide/.kiro/ + AGENTS.md |
| Kiro CLI | dist/kiro/.kiro/ + AGENTS.md |
| Codex CLI | dist/codex/.codex/ + .agents/ + AGENTS.md |
| opencode | dist/opencode/.aidlc/ + .opencode/ + AGENTS.md |
| GitHub Copilot | dist/copilot/.aidlc/ + .github/ + AGENTS.md |
覚えているでしょうか。V2のユーザーインストールは「distツリーをプロジェクトにコピーする」だけです。この単純さは、ビルドパイプラインが複雑さを吸収してくれるからこそ成り立っています。
4. ビルドフロー: package.tsが何をしているか
では、
core/ と harness/ から dist/ がどう生まれるのかを見ていきましょう。bun scripts/package.ts を実行すると、ハーネスごとに5つのステップが走ります。ステップ1: コア射影(COPY core → dist)
manifest.ts の coreDirs に従い、core/<src> を dist/<name>/<harnessDir>/<dst> へコピーします。コピー時に .md ファイル内の {{HARNESS_DIR}} トークンをハーネスのディレクトリ名(.claude、.kiro、.codex、.aidlc)に置換します。ステップ2: ハーネスファイルのコピー(COPY harness → dist)
manifest.ts の harnessFiles に従い、ハーネス固有のファイルをdistツリーに配置します。オーケストレータスキル、設定ファイル、ルールファイルなどがここで配置されます。同じトークン置換が適用されます。ステップ3: ステージグラフのコンパイル
33のステージ定義と9つのスコープ定義から、
stage-graph.json(ステージ間の依存関係グラフ)と scope-grid.json(どのスコープでどのステージが有効か)を生成します。このコンパイル済みデータは dist/ 内にのみ存在し、core/ には含まれません。ステップ4: ランナー生成
aidlc-runner-gen がスコープ別のスキルファイルを自動生成します。各スコープ(enterprise、mvp、feature 等)に対応するランナーが、ステージグラフに基づいて作られます。ステップ5: EMIT(オプション)
宣言的なマッピングでは表現しきれない構造的な出力が必要なハーネスは、
emit.ts を持ちます。Codex CLIは config.toml、hooks.json、エージェントTOMLファイルを、opencodeとGitHub Copilotもそれぞれ固有のファイルをこのステップで生成します。Claude CodeとKiroはこのステップを使いません(宣言的なマッピングだけで完結するため)。ドリフトガード: --check
bun scripts/package.ts --check を実行すると、一時ディレクトリに全ハーネスを生成し、コミット済みの dist/ とバイト単位で比較します。差分があればCI失敗です。つまり「dist/ を手で編集して、core/ の更新を忘れる」という事故を構造的に防止しています。ここで重要なのは、設計原則として許可されたテキスト変換クラスが
{{HARNESS_DIR}} トークンの置換ただ1つであることです。ビルドスクリプトはルールディレクトリ名の書き換え(rulesRename)やティア制御のためのfrontmatter調整も行いますが、これらはメソドロジーの記述内容を変えるものではなく、ハーネスの構造的な差異を吸収する補助処理です。記事本文やステージ定義の文言に対して許可された変換は、あくまでトークン置換のみです。5. manifest.ts: ハーネスの「顔」
各ハーネスの
manifest.ts は HarnessManifest 型を実装します。この型がハーネスの全容を宣言的に定義しています。Claude Codeの例で中身を見ていきましょう。HarnessManifest の構造
各ハーネスの
manifest.ts は HarnessManifest 型を実装します。主要フィールドを抜粋します(実際の型にはプラグイン制御やランナー生成の省略オプションなど追加フィールドがあります)。1
2
3
4
5
6
7
8
9
10
type HarnessManifest = {
name: string; // "claude" — dist/<name>/ のディレクトリ名
harnessDir: string; // ".claude" | ".kiro" | ".codex" | ".aidlc"
tierFlavor: string; // "claude" | "codex" | "kiro" | "opencode" | "copilot"
coreDirs: DirMap[]; // core → dist のディレクトリ射影
harnessFiles: FileMap[];// ハーネス固有ファイルの配置先
onboarding?: {...}; // オンボーディングドキュメント生成設定
rulesRename: string | null; // ルールディレクトリの名前変更
emit: ((ctx) => void) | null; // オプションの出力プラグイン
};Claude Codeのmanifest(具体例)
Claudeのマニフェストは比較的シンプルです。
core/ のディレクトリ名をそのまま使い、名前の変更は行いません。1
2
3
4
5
6
7
8
9
10
11
12
coreDirs: [
{ src: "tools", dst: "tools" },
{ src: "aidlc-common", dst: "aidlc-common" },
{ src: "knowledge", dst: "knowledge" },
{ src: "sensors", dst: "sensors" },
{ src: "scopes", dst: "scopes" },
{ src: "agents", dst: "agents" },
{ src: "hooks", dst: "hooks" },
{ src: "skills/aidlc-session-cost", dst: "skills/aidlc-session-cost" },
{ src: "skills/aidlc-replay", dst: "skills/aidlc-replay" },
{ src: "skills/aidlc-outcomes-pack", dst: "skills/aidlc-outcomes-pack" },
],harnessFiles ではオーケストレータスキル(SKILL.md)、設定ファイル(settings.json)、ルールファイル(rules-aidlc.md)などを配置します。emit は null です。Claude Codeは宣言的なマッピングだけで完結するため、追加の出力プラグインを必要としません。ハーネス間の違い
各ハーネスの差異は
manifest.ts を比較するとわかります。| ハーネス | harnessDir | rulesRename | emit |
|---|---|---|---|
| Claude Code | .claude | null | null |
| Kiro IDE | .kiro | "steering" | null |
| Kiro CLI | .kiro | "steering" | null |
| Codex CLI | .codex | "aidlc-rules" | あり |
| opencode | .aidlc | null | あり |
| GitHub Copilot | .aidlc | null | あり |
rulesRename はルールディレクトリの名前を変更する設定です。Kiroでは rules/ を steering/ に、Codexでは aidlc-rules/ にリネームします。Claude Codeはリネームしません。この違いは各ハーネスが「ルールファイルをどの名前で認識するか」の仕様に由来します。emit を持つ3つのハーネス(Codex、opencode、Copilot)は、宣言的マッピングだけでは表現できない独自のファイル形式を出力する必要があるハーネスです。6. プラグイン機構: ステージを追加する
V2はコアの33ステージに加えて、プラグインによるステージ追加をサポートしています。プラグインは
core/ と同じ構造の「ミニ core」として設計されています。プラグインのディレクトリ構造
リポジトリの
plugins/test-pro/ がリファレンス実装(参照用の見本)です。構造を見てみましょう。1
2
3
4
5
6
7
8
9
10
11
plugins/test-pro/
├── .aidlc-plugin/
│ └── plugin.json 宣言的マニフェスト
├── stages/ 新ステージ定義
├── contributions/ 既存ステージへの追加貢献
├── sensors/ 検証マニフェスト
├── tools/ ツール実装
├── agents/ 新エージェント
├── knowledge/ エージェント知識
├── scopes/ 新スコープ定義
└── tests/ プラグイン固有テストplugin.json — 宣言的な貢献先の定義
plugin.json はプラグインが何を提供するかを宣言します。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"name": "test-pro",
"version": "0.1.0",
"description": "Full-featured testing plugin...",
"dependencies": ["core"],
"aidlc": {
"contributes": {
"stages": "stages/",
"overlays": "contributions/",
"agents": "agents/",
"scopes": "scopes/",
"knowledge": "knowledge/",
"sensors": "sensors/",
"tools": "tools/"
}
}
}contributes フィールドが、プラグインの各ディレクトリがコアのどの概念に対応するかを示します。stages/ は新しいステージを追加し、contributions/(overlays)は既存ステージに追加の貢献を提供します。ビルドとインストール
bun scripts/package.ts はプラグインも処理し、dist/plugins/test-pro/ 以下にハーネスごとのホストプラグイン形式を出力します。ユーザーは dist/plugins/<name>/<harness>/ を自分のプロジェクトにコピーし、harness.json の plugins フィルタで有効化を制御します。プラグインは「追加」の仕組みです。コアのステージを削除したり上書きしたりはできません。既存ステージに新しい貢献(たとえば追加の検証ステップ)を加えたり、ワークフローに新しいステージを挿入したりできます。
7. まとめ
V2のコア・パッケージング・アーキテクチャは、3つの原則で成り立っています。
- 単一ソース: メソドロジーの定義は
core/に1つだけ存在する。6つのハーネスが同じ33ステージ、同じ14エージェント、同じ17フックを共有する - 宣言的マッピング: 各ハーネスの
manifest.tsが射影ルールを宣言する。ビルドスクリプトpackage.tsが5ステップでdist/を生成し、ドリフトガードが差分を許さない - 拡張可能性: プラグイン機構により、コアを変更することなくステージ・エージェント・センサーを追加できる
この設計のおかげで、コントリビュータは
core/ を1箇所修正すれば全ハーネスに反映でき、ハーネス固有の変更は小さな harness/<name>/ に閉じます。ユーザーは dist/<harness>/ をコピーするだけで、その背後の複雑さを意識する必要がありません。Series: AI-DLC Workflow V2の解説 (31 articles)
- …
- 19AI-DLC Workflow V2のアーキテクチャ: one core, many harnessesの設計思想 This article
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article