並行実行アーキテクチャ
概要: 複数のIssue/タスクを同時並行で実行するシステムアーキテクチャです。DAG(有向非巡回グラフ)による依存関係管理、Git Worktreeによるブランチ分離、バッティング回避機構により、効率的な並列作業を実現します。
対象読者: アーキテクト / 実装者 所要時間: 15分 前提知識: Agent階層システム
設計原則
並行実行システムは以下の5原則に基づいて設計されています:
- Claude Code Task Tool 必須: すべてのタスクは Claude Code の Task tool を使用
- 衝突回避: Git マージコンフリクトと作業の重複を防止
- 透明性: すべてのワーカーの活動状況をリアルタイムで可視化
- スケーラビリティ: 3人以上のワーカーが同時作業可能
- 監査可能性: すべての並列作業活動を記録
システムアーキテクチャ
レイヤー構成
┌─────────────────────────────────────────────────────────┐
│ Worker Interface Layer │
│ (Human Developers + AI Agents) │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Task Orchestration Layer │
│ • Task Queue Management │
│ • Worker Registration & Tracking │
│ • Claude Code Task Tool Wrapper │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Coordination Layer │
│ • Task Claim/Release Protocol │
│ • Conflict Detection & Prevention │
│ • Progress Monitoring │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Git Workflow Layer │
│ • Worktree Management │
│ • Branch Isolation │
│ • Merge Coordination │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Storage & State Layer │
│ • GitHub Projects V2 (Task Board) │
│ • GitHub Repository (Code) │
│ • Lock Files (.task-locks/) │
└─────────────────────────────────────────────────────────┘
Task Orchestration Layer
TaskOrchestrator
タスクキューの管理とワーカーへの割り当てを担当。
// agents/coordination/TaskOrchestrator.ts
class TaskOrchestrator {
private queue: PriorityQueue<Task>;
private activeWorkers: Map<WorkerId, WorkerState>;
async enqueueTask(task: Task): Promise<void> {
// タスクをキューに追加(優先度順)
this.queue.enqueue(task, task.priority);
}
async assignTask(workerId: WorkerId): Promise<Task | null> {
// ワーカーに適切なタスクを割り当て
const availableTasks = await this.getAvailableTasks(workerId);
return availableTasks[0] || null;
}
async getAvailableTasks(workerId: WorkerId): Promise<Task[]> {
// 依存関係とファイル競合を考慮
const worker = this.activeWorkers.get(workerId);
return this.queue.filter(task =>
this.canAssign(task, worker)
);
}
}
Task構造
interface Task {
id: string;
type: 'issue' | 'pr' | 'refactor' | 'test' | 'doc';
priority: 1 | 2 | 3 | 4 | 5; // 1 = highest
dependencies: string[]; // task IDs
estimatedDuration: number; // minutes
requiredSkills: string[];
assignedTo?: WorkerId;
status: 'pending' | 'claimed' | 'in_progress' | 'completed' | 'failed';
metadata: {
issueNumber?: number;
branchName?: string;
files: string[]; // Files this task will modify
};
}
DAG(有向非巡回グラフ)による依存関係管理
DAG構築
async buildDAG(tasks: Task[]): Promise<DAG> {
// 1. ノード作成
const nodes = tasks.map(task => ({
id: task.id,
task
}));
// 2. エッジ作成(依存関係)
const edges: Edge[] = [];
for (const task of tasks) {
for (const depId of task.dependencies) {
edges.push({ from: depId, to: task.id });
}
}
// 3. トポロジカルソート
const sorted = this.topologicalSort(nodes, edges);
// 4. 循環依存検出
if (this.hasCyclicDependency(sorted)) {
throw new Error('Circular dependency detected');
}
// 5. レベル算出(並行実行グループ)
const levels = this.computeLevels(sorted, edges);
return { nodes, edges, levels };
}
レベル順実行
async executeLevels(dag: DAG, concurrency: number): Promise<Result[]> {
const results: Result[] = [];
for (const level of dag.levels) {
console.log(`Level ${level.index}: ${level.tasks.length} tasks`);
// 同一レベル内は並行実行
const chunks = this.chunkArray(level.tasks, concurrency);
for (const chunk of chunks) {
const chunkResults = await Promise.all(
chunk.map(task => this.executeTask(task))
);
results.push(...chunkResults);
}
}
return results;
}
DAG例
Issue #270の分解:
task-1: Firebase Auth修正
dependencies: []
priority: 1
task-2: E2Eテスト追加
dependencies: [task-1]
priority: 2
task-3: ドキュメント更新
dependencies: [task-1, task-2]
priority: 3
DAG構造:
Level 1: [task-1] ← 並行度1
Level 2: [task-2] ← task-1完了後
Level 3: [task-3] ← task-1,2完了後
task-1 → task-2 → task-3
Git Worktree分離
Worktree戦略
各ワーカーは独自の Git worktree を使用して完全な分離を実現。
# Worktree自動作成
async function setupWorktree(task: Task): Promise<string> {
const worktreePath = `.worktrees/${task.id}`;
const branchName = `${task.type}/${task.metadata.issueNumber}-${task.id}`;
// Worktree作成
await exec(`git worktree add ${worktreePath} -b ${branchName}`);
// Worktree固有設定
await exec(`cd ${worktreePath} && git config user.name "${worker.name}"`);
return worktreePath;
}
ディレクトリ構造
Autonomous-Operations/
├── .git/ # Main Git directory
├── .worktrees/ # Worktree root
│ ├── task-001/ # Worker 1's worktree
│ │ └── [full repo]
│ ├── task-002/ # Worker 2's worktree
│ │ └── [full repo]
│ └── task-003/ # Worker 3's worktree
│ └── [full repo]
├── src/ # Main working directory
└── [other files]
ブランチ命名規則
<type>/<issue-number>-<task-id>-<description>
例:
- fix/456-task-001-auth-bug
- feat/789-task-002-add-oauth
- refactor/101-task-003-cleanup-utils
type の種類:
fix- バグ修正feat- 新機能refactor- リファクタリングtest- テスト追加docs- ドキュメントchore- その他
バッティング回避メカニズム
1. ファイルレベルの排他制御
const conflictDetector = new ConflictDetector();
// タスク割り当て前にチェック
const hasConflict = await conflictDetector.check(task, activeWorkers);
if (hasConflict) {
// タスクを待機キューへ
await taskQueue.defer(task);
} else {
// 安全に割り当て
await assignTask(task, worker);
}
衝突検出ロジック:
function detectFileConflicts(task: Task, activeTasks: Task[]): boolean {
const taskFiles = new Set(task.metadata.files);
for (const activeTask of activeTasks) {
const activeFiles = new Set(activeTask.metadata.files);
const overlap = intersection(taskFiles, activeFiles);
if (overlap.size > 0) {
return true; // 衝突検出
}
}
return false;
}
2. Lock File管理
.task-locks/構造:
.task-locks/
├── task-001.lock # Task-specific lock
├── task-002.lock
├── shared/
│ ├── package.json.lock # Shared file locks
│ └── tsconfig.json.lock
└── cleanup.sh # Expired lock cleanup script
Lock File形式:
// .task-locks/task-123.lock
{
"taskId": "task-123",
"workerId": "worker-alice",
"workerType": "human",
"claimedAt": "2025-10-10T03:00:00Z",
"lockedFiles": [
"src/auth/login.ts",
"tests/auth/login.test.ts"
],
"branchName": "fix/456-task-001-auth-bug",
"expiresAt": "2025-10-10T04:00:00Z"
}
3. 共有リソースの保護
Critical Files(排他ロック必須):
package.jsonpackage-lock.jsontsconfig.json.github/workflows/*.yml
戦略:
- 共有ファイルを変更するタスクは1つずつ実行
- 他のタスクは解放されるまで待機
Task Claim Protocol
タスク取得フロー
1. Worker requests available tasks
↓
2. Orchestrator checks file conflicts
↓
3. If no conflicts: Create lock file
↓
4. Assign task to worker
↓
5. Worker claims task (status = 'claimed')
↓
6. Worker starts work (status = 'in_progress')
↓
7. Worker completes/fails (status = 'completed'/'failed')
↓
8. Release lock file
実装
class TaskClaimProtocol {
async claimTask(workerId: WorkerId): Promise<Task | null> {
// 1. 利用可能タスク取得
const availableTasks = await this.orchestrator.getAvailableTasks(workerId);
if (availableTasks.length === 0) {
return null;
}
const task = availableTasks[0];
// 2. ファイル衝突チェック
const hasConflict = await this.detectConflicts(task);
if (hasConflict) {
return null;
}
// 3. ロックファイル作成
await this.lockManager.acquireLock(task, workerId);
// 4. タスク割り当て
task.assignedTo = workerId;
task.status = 'claimed';
await this.orchestrator.updateTask(task);
return task;
}
async releaseTask(taskId: string): Promise<void> {
// ロック解放
await this.lockManager.releaseLock(taskId);
// タスク状態更新
const task = await this.orchestrator.getTask(taskId);
task.status = 'completed';
await this.orchestrator.updateTask(task);
}
}
進捗モニタリング
リアルタイム進捗表示
🚀 Claude Code Agent並行実行システム起動
📍 セッションID: session-1759552488828
🖥️ デバイス: MacBook Pro 16-inch
✅ Issue #270 登録完了 (Agent: CodeGenAgent, Priority: 1)
✅ Issue #240 登録完了 (Agent: CodeGenAgent, Priority: 1)
🎯 並行実行開始...
✅ 依存関係チェック完了(循環依存なし)
📊 進捗: 完了 0/2 | 実行中 2 | 待機中 0 | 失敗 0
[12:34:56] ⏳ [issue-270] 実行中... (CodeGenAgent)
[12:34:58] ⏳ [issue-240] 実行中... (CodeGenAgent)
[12:35:20] ✅ [issue-240] 完了 (22秒)
[12:35:35] ✅ [issue-270] 完了 (39秒)
📊 進捗: 完了 2/2 | 実行中 0 | 待機中 0 | 失敗 0
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📋 並行実行最終レポート
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🆔 セッションID: session-1759552488828
🖥️ デバイス: MacBook Pro 16-inch
⏱️ 総実行時間: 39秒
📊 タスク統計:
- 総タスク数: 2
- 完了: 2 ✅
- 失敗: 0 ❌
- 成功率: 100.0%
ProgressMonitor実装
class ProgressMonitor {
async getWorkerProgress(workerId: WorkerId): Promise<Progress> {
const task = await this.getCurrentTask(workerId);
return {
taskId: task.id,
currentStep: task.currentStep,
stepsCompleted: task.stepsCompleted,
totalSteps: task.totalSteps,
percentComplete: (task.stepsCompleted / task.totalSteps) * 100,
estimatedTimeRemaining: this.estimateTimeRemaining(task),
lastUpdated: new Date()
};
}
async getAllProgress(): Promise<Map<WorkerId, Progress>> {
const workers = await this.registry.getActiveWorkers();
const progress = new Map();
for (const worker of workers) {
progress.set(worker.id, await this.getWorkerProgress(worker.id));
}
return progress;
}
}
実行モード
モード1: 疑似実行(デフォルト)
npm run agents:parallel:exec -- --issues=270,240 --concurrency=2
特徴:
- Task tool API未使用
- 実行ログのみ生成
- デバッグ・テスト用
モード2: Task tool統合
USE_TASK_TOOL=true npm run agents:parallel:exec -- --issues=270
特徴:
- Claude Code Task tool API使用
- 実際のAgent実行
- 本番運用モード
モード3: Worktree分離
USE_WORKTREE=true npm run agents:parallel:exec -- --issues=276
特徴:
- Issue単位でWorktree自動作成
- ブランチ完全分離
- バッティング完全回避
ワークフロー例
シナリオ: 3人のワーカーが並列作業
ワーカー:
- Alice (Human Developer)
- Bob (AI Agent - CodeGen)
- Charlie (AI Agent - Review)
タスク:
- Task 1: Fix auth bug (files:
src/auth/login.ts) - Task 2: Add OAuth (files:
src/auth/oauth.ts) - Task 3: Update docs (files:
docs/AUTH.md)
フロー:
T=0:
Alice: claim-task → Task 1 assigned → Setup worktree → Lock files
Bob: claim-task → Task 2 assigned → Setup worktree → Lock files
Charlie: claim-task → Task 3 assigned → Setup worktree → Lock files
T=5min:
Alice: [Working] fix/456-task-001 (Progress: 40%)
Bob: [Working] feat/789-task-002 (Progress: 60%)
Charlie: [Working] docs/101-task-003 (Progress: 80%)
T=10min:
Alice: [Working] fix/456-task-001 (Progress: 70%)
Bob: [Completed] feat/789-task-002 → Create PR → Auto-merge
Charlie: [Completed] docs/101-task-003 → Create PR → Auto-merge
T=15min:
Alice: [Completed] fix/456-task-001 → Rebase main → Create PR
Bob: [Idle] Ready for next task
Charlie: [Idle] Ready for next task
T=20min:
Alice: [PR Merged] → Cleanup worktree → Release lock
Bob: claim-task → Task 4 assigned
Charlie: claim-task → Task 5 assigned
マージ調整
マージ戦略
- 順次マージ: タスク完了順に main へマージ
- Rebase 優先: マージ前に main を rebase
- Conflict Resolution: 自動検出 → 人間介入
- Post-Merge Cleanup: worktree 削除、lock 解除
自動化フロー
async function completeTask(task: Task): Promise<void> {
// 1. Fetch latest main
await exec('git fetch origin main');
// 2. Rebase on main
await exec('git rebase origin/main');
// 3. Run tests
await exec('npm test');
// 4. Create PR
const pr = await createPullRequest(task);
// 5. Auto-merge if checks pass
if (await allChecksPass(pr)) {
await mergePR(pr);
}
// 6. Cleanup
await cleanupWorktree(task);
await releaseLock(task);
}
パフォーマンス最適化
並行度の決定
function calculateOptimalConcurrency(tasks: Task[]): number {
// CPUコア数
const cpuCores = os.cpus().length;
// 依存関係グラフの最大幅
const maxWidth = this.calculateGraphWidth(tasks);
// 最適並行度 = min(CPUコア数, グラフ最大幅)
return Math.min(cpuCores, maxWidth, 10); // 上限10
}
キャッシュ戦略
class TaskCache {
private cache = new Map<string, Task>();
async getTask(taskId: string): Promise<Task> {
if (this.cache.has(taskId)) {
return this.cache.get(taskId)!;
}
const task = await this.fetchFromDB(taskId);
this.cache.set(taskId, task);
return task;
}
invalidate(taskId: string): void {
this.cache.delete(taskId);
}
}
トラブルシューティング
Issue 1: Worktree競合
症状:
fatal: 'worktrees/issue-270' already exists
解決策:
# 既存worktree確認
git worktree list
# 不要worktree削除
git worktree remove ~/Dev/worktrees/autonomous-operations/issue-270
# 自動クリーンアップ
git worktree prune
Issue 2: 依存関係循環検出
症状:
Error: Circular dependency detected: 300 → 270 → 300
解決策:
# Issue本文から依存記述削除
gh issue edit 300 --body "依存: #270のみ"
# または循環依存無視(非推奨)
npm run agents:parallel:exec -- --issues=300 --ignore-deps
関連ドキュメント
- システム全体像 - 全体構成
- Agent階層システム - Agent構造
- 組織設計原則 - 5原則実装
- Agent運用マニュアル - 運用ガイド
次のステップ
- GitHub as OS - GitHub機能の活用方法を学ぶ
- Agent運用マニュアル - 実際の運用方法を理解する
最終更新: 2025-10-10 バージョン: 2.0.0 管理者: AI Operations Lead