mybook

第9章 — Workflow: オーケストラの指揮者

60ファイルのリファクタリング

「全 API ルートの認証方式を JWT から OAuth に移行して」

CTO からの指示は明快だったが、影響範囲は広大だった。60ファイル、200箇所以上の変更。一つの Claude Code セッションで処理するにはコンテキストが足りない。一つずつ手動で指示するのは現実的ではない。

「これは Workflow の出番だ」とミサキ。

Workflow とは

Workflow は、複数のサブエージェントの実行をスクリプトで制御する仕組みだ。JavaScript で書かれた台本に従い、エージェントを並列に走らせたり、順序立てて連鎖させたりできる。

Loading diagram...

Workflow の4つの構成要素

要素説明用途
agent()サブエージェントを1体起動調査、変換、検証
parallel()複数タスクを同時実行(バリア付き)全結果が必要なとき
pipeline()各アイテムを段階的に処理ファイルごとの変換
phase()進捗グループの切り替えUI表示と整理

pipeline vs parallel: 正しい選択

Workflow 設計で最も重要な判断が「pipeline を使うか、parallel を使うか」だ。

Loading diagram...

pipeline: デフォルトの選択

各アイテムが独立に処理できるなら pipeline が最適。アイテム A がステージ3にいる間に、アイテム B はまだステージ1にいてよい。

// 60ファイルを並列にリファクタリング
const results = await pipeline(
  files,
  // ステージ1: 各ファイルを分析
  (file) => agent(`Analyze ${file} for auth patterns`, {
    label: `analyze:${file}`,
    phase: 'Analyze'
  }),
  // ステージ2: 変換
  (analysis, file) => agent(`Refactor ${file}: ${analysis}`, {
    label: `refactor:${file}`,
    phase: 'Refactor',
    isolation: 'worktree'
  })
)

parallel: バリアが必要なとき

全結果を集めてから次の処理をしたい場合のみ parallel を使う。

// 全レビューを集めてから重複排除
const allFindings = await parallel(
  dimensions.map(d => () =>
    agent(d.prompt, { schema: FINDINGS_SCHEMA })
  )
)
const deduped = dedup(allFindings.flat())

WARNING

parallel はバリア(全完了を待つ)のため、最も遅いタスクに全体が引きずられる。pipeline なら各アイテムが独立に進むので、壁時計時間が最短になる。迷ったら pipeline を選べ。

実践: 大規模リファクタリング Workflow

ユウキが JWT → OAuth 移行のために書いた Workflow:

export const meta = {
  name: 'auth-migration',
  description: 'JWT 認証を OAuth に移行する',
  phases: [
    { title: 'Discover', detail: '影響ファイルを特定' },
    { title: 'Migrate', detail: '各ファイルを変換' },
    { title: 'Verify', detail: 'テストと監査' },
  ],
}
 
// Phase 1: 影響範囲の特定
phase('Discover')
const discovery = await agent(
  'grep で JWT 関連のパターンを検索し、影響ファイルの一覧を返せ',
  { schema: { type: 'object', properties: {
    files: { type: 'array', items: { type: 'string' } }
  }}}
)
 
log(`${discovery.files.length} ファイルを発見`)
 
// Phase 2: 各ファイルを並列に変換
phase('Migrate')
const results = await pipeline(
  discovery.files,
  // 分析
  (file) => agent(
    `${file} の JWT 認証パターンを分析し、OAuth への変換計画を立てよ`,
    { label: `plan:${file}`, phase: 'Migrate', effort: 'low' }
  ),
  // 変換(worktree で隔離)
  (plan, file) => agent(
    `${file} を以下の計画に従って変換せよ: ${plan}`,
    { label: `migrate:${file}`, phase: 'Migrate', isolation: 'worktree' }
  )
)
 
// Phase 3: 検証
phase('Verify')
const testResult = await agent('pnpm test を実行し、結果を報告せよ')
const auditResult = await agent(
  '変更されたファイルのセキュリティ監査を実施せよ',
  { agentType: 'security-auditor' }
)
 
return { migrated: results.filter(Boolean).length, testResult, auditResult }

Workflow の品質パターン

敵対的検証(Adversarial Verify)

各発見事項を独立した「反論者」に検証させる。

Loading diagram...
// 3人の独立した検証者で多数決
const votes = await parallel(
  Array.from({ length: 3 }, () => () =>
    agent(
      `この発見を反駁せよ: ${finding.description}。
       不確かなら refuted=true とせよ`,
      { schema: VERDICT_SCHEMA }
    )
  )
)
const confirmed = votes.filter(Boolean)
  .filter(v => !v.refuted).length >= 2

Loop-until-dry

未知の数の問題を発見するとき、何も見つからないラウンドが K 回続くまで繰り返す。

const seen = new Set()
let dryRounds = 0
 
while (dryRounds < 2) {
  const found = await agent(
    'まだ見つかっていないバグを探せ',
    { schema: BUGS_SCHEMA }
  )
  const fresh = found.bugs.filter(b => !seen.has(b.id))
 
  if (fresh.length === 0) {
    dryRounds++
    continue
  }
 
  dryRounds = 0
  fresh.forEach(b => seen.add(b.id))
  log(`${seen.size} 件のバグを発見`)
}

完全性批評(Completeness Critic)

最後に「何が見落とされているか」を問う専門エージェントを走らせる。

const critic = await agent(
  `以下の分析結果を見て、欠けている観点を指摘せよ:
   ${JSON.stringify(allResults)}
   - 調査されていないファイル種別はないか
   - 検証されていない主張はないか
   - 見落とされているエッジケースはないか`,
  { label: 'completeness-critic' }
)

Effort の段階的制御

Workflow 内では、各エージェントの effort(推論の深さ)を段階的に制御できる。

Loading chart...
// 探索は安く
agent('ファイルを探せ', { effort: 'low' })
 
// 分析は中程度
agent('コードを分析せよ', { effort: 'medium' })
 
// 実装は深く
agent('リファクタリングせよ', { effort: 'high' })
 
// 検証は最も深く
agent('セキュリティ監査せよ', { effort: 'xhigh' })

ユウキの振り返り

60ファイルの移行は、Workflow なしなら3日かかると見積もられていた。Workflow を使って4時間で完了した。

「Workflow は"オーケストラの指揮者"だ。各楽器(エージェント)は優秀だけど、指揮者がいなければ交響曲にはならない。スクリプトという楽譜があって初めて、複雑な仕事が調和する」

ミサキは最後にこう付け加えた。

「でもね、最も大事なハーネスがまだ残ってる。セキュリティ——すべての仕組みの土台になるものよ」

次の章では、ハーネスエンジニアリングにおけるセキュリティ設計を深掘りする。