Files
msd-core/docs/explanation/claude-orchestration-capability.md
Tom Boucher e3262d94d3 feat(capabilities): add claude-orchestration capability (Workflow backend) (#1143)
Default-off, BETA, claude-only capability adopting Claude Code's Workflow tool
(/effort ultracode, Agent SDK >= v0.3.149) as an optional parallel-execution
backend for the GSD loop. Restores the wave parallelism + plan-checker + verifier
that #853 forces inline on Claude Code, and folds gsd-ultraplan-phase under one
runtime gate.

- Pure fail-closed core (src/claude-orchestration.cts): detectWorkflowBackend
  (gate ladder: enabled -> Claude -> backend != inline -> nested+background host
  -> valid Agent SDK -> SDK >= floor; every miss degrades to inline) and
  emitWorkflowScript (waves -> parallel() barriers, plans -> gsd-executor +
  worktree, files_modified overlap -> separate stages, resumeFromRunId, budget).
  All interpolated identifiers validated script-safe; briefs JSON-quoted.
- claude-orchestration command family (gsd-tools claude-orchestration
  detect-backend|emit-workflow) for orchestrator invocation.
- Two gated loop contributions at wired points (execute:wave:post, plan:post);
  federated config keys (enabled/execution_backend/min_agent_sdk_version).
- ADR-1143 implementation amendment; CONTEXT.md glossary entry; explanation doc.

On any runtime lacking the Workflow tool, behaviour is byte-identical to today.

closes #1143
2026-07-06 15:18:23 -04:00

4.7 KiB

Claude orchestration capability (BETA)

Explanation — why this capability exists and how it fits the loop. For the step-by-step, see the capability reference; for the design record, see ADR-1143.

The problem

GSD's execute-phase is wave-based: plans carry a wave number, waves run sequentially, and plans within a wave run in parallel when their files_modified sets don't overlap. On most runtimes GSD realizes that by fanning out one backgrounded gsd-executor agent (in a worktree) per plan.

On Claude Code that fan-out degrades. Backgrounded agents on Claude Code have no Agent/Task tool, so they cannot nest subagents (#853). The autonomous loop therefore falls back to inline sequential execution — and with it silently drops wave parallelism, the plan-checker, and the verifier — on the one runtime most GSD users run.

Claude Code ships an orchestration primitive that sidesteps exactly this: the Workflow tool (the engine behind /effort ultracode, Agent SDK ≥ v0.3.149). A Workflow script is the orchestrator — it runs from the main loop and spawns subagents itself via agent(), parallel() (barrier), pipeline(), and phase(), with isolation: 'worktree', a shared token budget, and resumeFromRunId.

The capability

claude-orchestration is a default-off, BETA, claude-only capability that adopts the Workflow tool as an optional, runtime-gated parallel-execution backend, and folds the existing gsd-ultraplan-phase plan-offload under the same gate. It is blocked-on-nothing now that the ADR-857 capability system is released.

  • role: feature, runtimeCompat.supported: ["claude"], tier: full.
  • activationKey: claude_orchestration.enabled — default false. Nothing changes until you opt in.
  • Registers at two wired loop points: execute:wave:post (into the executor) and plan:post (into the planner). Both are onError: skip and gated by the enabled key.

How it decides whether to activate

Detection is a pure, fail-closed function — detectWorkflowBackend. The Workflow backend activates only when every gate passes; any miss degrades to inline (today's behaviour):

  1. claude_orchestration.enabled is true.
  2. The runtime is Claude (the Workflow tool is Claude / Agent SDK-specific).
  3. claude_orchestration.execution_backend is auto or workflow (not inline).
  4. The host descriptor advertises dispatch.nested and dispatch.background (the nesting-capable Claude-Code shape — a proxy for Workflow-tool presence, meaningful only after gate 2).
  5. The Agent SDK reports a valid semver version.
  6. That version is >= claude_orchestration.min_agent_sdk_version (default 0.3.149). A pre-release of the floor (e.g. 0.3.149-rc.1) compares below the GA release per SemVer, so the preview backend stays off.

What the executor runs when the backend is active

emitWorkflowScript maps the phase's wave/plan model onto Workflow primitives:

GSD concept Workflow primitive
Wave parallel() stage barrier
Plan agent(brief, { agentType: 'gsd-executor', isolation: 'worktree' })
files_modified overlap forces the plans into separate sequential stages
Phase run id resumeFromRunId("<id>")
Phase token cap budget(<tokens>)

Because the emitted script composes the same gsd-executor agent and worktree isolation the inline path uses, it produces the same SUMMARY.md artifacts and commits — the only difference is the execution vehicle.

The fallback contract

On any runtime lacking the Workflow tool — or when the capability is disabled, the SDK is too old, or detection fails for any reason — execute-phase proceeds with the standard inline wave dispatch. This is a release gate, not a nicety: a regression test asserts the inline fallback on every non-capable combination, so the capability is default-off and low-risk by construction.

BETA scope (v1)

The first slice ships detection + emission + declarative ultraplan ownership. The emitter is exercised at the contract level (structure, overlap splitting, resume, budget, anti-injection). End-to-end execution through the Workflow tool is verifiable only inside Claude Code with the tool present. Full install-profile migration of the gsd-ultraplan-phase skill into the capability's skills[] array is a follow-up (it touches the cluster/profile machinery); for v1 the manifest declares ultraplan ownership at plan:post and the existing skill's own runtime gate continues to no-op on non-Claude runtimes.