Skip to content

Subagent architecture: orchestrator + isolated phase agents #126

@VincentShipsIt

Description

@VincentShipsIt

Context

Inspired by Vercel open-agents subagent pattern. Current pipeline uses a single shared mutable PipelineContext across all phases with no context isolation. Toolset scoping relies on CLI flags (--disallowedTools, --sandbox).

Proposed architecture

ORCHESTRATOR (lightweight, Sonnet-tier)
├── PLANNER subagent (read-only tools, Opus)
├── REVIEWER subagent (read-only tools, Sonnet)
├── EXECUTOR subagent (read/write tools, Claude/Codex CLI)
└── VERIFIER subagent (read-only tools, Sonnet)

Each subagent:

  • Gets fresh, scoped context (plan output + repo files only)
  • Has toolset enforced structurally, not via CLI flags
  • Returns summary to orchestrator — internal tool calls stay isolated
  • Can be retried with clean context (no accumulated state)

Benefits

  • Context isolation → no cross-phase state contamination
  • Cheaper orchestrator → routes, never reads 200 files
  • Better retry → discard failed subagent context, spawn fresh
  • Provider flexibility → each subagent can be different provider/model

Trigger conditions (do when)

  • Adding new phase or provider that needs clean isolation
  • Context tokens becoming expensive (>200k per run)
  • Retry bugs traceable to accumulated context mutation
  • Moving pipeline to cloud runtime
  • Multi-pipeline concurrency needs

Current state

  • PipelineContext = single mutable object, mutated by all 14+ cross-phase handler calls
  • Toolset scoping hardcoded in buildClaudeCommand per-phase
  • Dead phaseHints.allowedTools field exists but isn't wired up
  • Tool registry exists in packages/agents/src/tools/registry.ts but only for OpenRouter harness

Incremental path — shipped ✅

  1. Freeze read-only context snapshots per pipeline phase #127 — Freeze read-only context snapshots per phase ✅ closed
  2. Wire up declarative toolset scoping via provider config #128 — Wire up declarative toolset scoping via provider config ✅ closed
  3. Reset phase-specific context fields between pipeline transitions #129 — Reset phase-specific context fields between transitions ✅ closed

Full subagent refactor — deferred

  1. Consume snapshotPhaseInput in runProviderPhase #135 — Consume snapshotPhaseInput in runProviderPhase
  2. Split PipelineContext into orchestrator state and phase payload #136 — Split PipelineContext into orchestrator state and phase payload
  3. Replace direct cross-phase handler calls with orchestrator dispatch loop #137 — Replace direct cross-phase handler calls with orchestrator dispatch loop
  4. Per-phase context factory: fresh context per invocation #138 — Per-phase context factory
  5. Typed phase result contracts between pipeline phases #139 — Typed phase result contracts between pipeline phases

Epic — do not implement full refactor until trigger conditions are met.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request
    No fields configured for Feature.

    Projects

    Status

    Deferred

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions