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
This commit is contained in:
Tom Boucher
2026-07-06 15:18:23 -04:00
parent d01eec4358
commit e3262d94d3
19 changed files with 2357 additions and 9 deletions

View File

@@ -0,0 +1,85 @@
{
"id": "claude-orchestration",
"role": "feature",
"version": "1.7.0-rc.3",
"title": "Claude orchestration (Workflow backend)",
"description": "Default-off, BETA, claude-only capability that adopts Claude Code's Workflow tool (the engine behind /effort ultracode) as an optional parallel-execution backend for the GSD loop. When the runtime exposes the Workflow tool and claude_orchestration.execution_backend resolves to 'workflow', execute-phase emits a generated Workflow script (waves -> parallel() barriers, plans -> agent({ agentType: 'gsd-executor', isolation: 'worktree' }), files_modified overlap -> separate sequential stages, resumeFromRunId wired to the phase run id, shared token budget) that composes the SAME gsd-executor agent and worktree isolation the inline path uses, restoring the parallelism + plan-checker + verifier that the #853 backgrounded-agent nesting limitation forces inline on Claude Code. Also folds the ultraplan plan-offload under one runtime gate (plan:* surface). On any runtime lacking the Workflow tool, or when the capability is disabled, behaviour is byte-identical to today (inline/manual dispatch). Detection + emission live in gsd-core/bin/lib/claude-orchestration.cjs (pure, fail-closed). Mirrors the existing gsd-ultraplan-phase BETA-isolation posture.",
"tier": "full",
"requires": [],
"engines": {
"gsd": ">=1.7.0"
},
"runtimeCompat": {
"supported": [
"claude"
],
"unsupported": []
},
"skills": [],
"agents": [],
"hooks": [],
"commands": [
{
"family": "claude-orchestration",
"module": "claude-orchestration-command-router.cjs",
"router": "routeClaudeOrchestrationCommand",
"subcommands": [
"detect-backend",
"emit-workflow"
]
}
],
"activationKey": "claude_orchestration.enabled",
"config": {
"claude_orchestration.enabled": {
"type": "boolean",
"default": false,
"description": "Master toggle for the Claude orchestration capability. Default-off + BETA: the Workflow-tool execution backend and the ultraplan plan-offload surface are inert unless this is true. When false, loop behaviour is byte-identical to a non-Claude runtime (inline/manual dispatch)."
},
"claude_orchestration.execution_backend": {
"type": "enum",
"values": [
"auto",
"workflow",
"inline"
],
"default": "auto",
"description": "Which execute-phase dispatch backend to use when the capability is enabled. 'auto' (default) activates the Workflow backend only when the runtime is Claude AND the Workflow tool is detected AND the Agent SDK meets claude_orchestration.min_agent_sdk_version; otherwise it falls back to inline. 'workflow' forces the Workflow backend when the tool is present AND the Agent SDK meets the floor (still fails closed to inline if the tool is absent or the SDK is too old — the floor applies in both modes). 'inline' forces today's manual one-agent-per-message dispatch regardless of tool availability."
},
"claude_orchestration.min_agent_sdk_version": {
"type": "string",
"default": "0.3.149",
"description": "Minimum Agent SDK version required to activate the Workflow backend under execution_backend='auto'. Defaults to 0.3.149 (the release that introduced the Workflow tool). Raise to pin a higher floor; the detection seam fails closed to inline for any runtime reporting an older or unknown version."
}
},
"steps": [],
"contributions": [
{
"point": "execute:wave:post",
"into": "executor",
"fragment": {
"path": "fragments/execute-wave-post.md"
},
"produces": [],
"consumes": [
"PLAN.md"
],
"when": "claude_orchestration.enabled",
"onError": "skip"
},
{
"point": "plan:post",
"into": "planner",
"fragment": {
"path": "fragments/plan-post.md"
},
"produces": [],
"consumes": [
"CONTEXT.md"
],
"when": "claude_orchestration.enabled",
"onError": "skip"
}
],
"gates": []
}

View File

@@ -0,0 +1,59 @@
# Claude orchestration — Workflow execution backend (BETA)
> Injected at `execute:wave:post` `into: executor` only when
> `claude_orchestration.enabled` is true. Default-off; `onError: skip`.
## When this contribution is active
The Claude orchestration capability is **default-off and BETA**. It activates only
when ALL of the following hold:
1. `claude_orchestration.enabled` is `true` in `.planning/config.json`, AND
2. the active runtime is **Claude Code** (the Workflow tool is Claude / Agent
SDK-specific), AND
3. `claude_orchestration.execution_backend` resolves to `workflow` — either
explicitly, or via `auto` — **and** the Agent SDK version is
`>= claude_orchestration.min_agent_sdk_version` (default `0.3.149`). The SDK
floor applies in both `auto` and `workflow` modes (fail-closed: a pre-release
or older SDK never activates the preview backend).
Detection is fail-closed: any miss degrades to **inline, manual, one-agent-per-
message dispatch** — exactly today's behaviour. On a non-Claude runtime this
contribution is a no-op.
## What the executor does when the Workflow backend is active
Instead of the orchestrator fanning out one `Agent(subagent_type=gsd-executor,
isolation=worktree, run_in_background=true)` per message (which on Claude Code
cannot nest further subagents — #853 — and so degrades to sequential inline
execution), execute-phase **emits a generated Workflow script** and lets the main
loop orchestrate it:
- **waves → `parallel()` barriers** — each wave is one barrier; the next wave
waits for the previous to complete.
- **plans → `agent(brief, { agentType: 'gsd-executor', isolation: 'worktree' })`**
— the SAME executor agent and worktree isolation the inline path uses, so the
produced `SUMMARY.md` and commits are identical.
- **`files_modified` overlap → separate sequential stages** — two plans that
touch the same file are placed in different stages within the wave (the same
overlap rule execute-phase already applies inline).
- **`resumeFromRunId`** — wired to the phase run id, so an interrupted phase
resumes without re-running completed plans.
- **`budget(tokens)`** — a shared token pool across the whole phase when the
orchestrator passes a `budgetTokens` value to `emitWorkflowScript` (it is a
function parameter, not a config key; the orchestrator decides the budget).
The emitter is a pure function exposed through the capability command surface:
`gsd-tools claude-orchestration emit-workflow --waves <manifest.json> --run-id <id>
[--phase-dir <dir>] [--budget <n>]` (or `require('gsd-core/bin/lib/claude-orchestration.cjs').emitWorkflowScript`
directly). It maps the phase's wave/plan manifest to the Workflow script string
and never invokes the Workflow tool itself; the orchestrator runs the emitted
script. Use `gsd-tools claude-orchestration detect-backend` to resolve whether
the Workflow backend should activate for the current runtime.
## Fallback contract
If detection resolves to `inline` (tool absent, SDK too old, runtime not Claude,
or the capability disabled), execute-phase MUST proceed with the standard inline
wave dispatch. The executor MUST NOT assume parallelism, a shared budget, or
resume-from-run-id semantics in that mode.

View File

@@ -0,0 +1,28 @@
# Claude orchestration — ultraplan plan-offload ownership (BETA)
> Injected at `plan:post` `into: planner` only when
> `claude_orchestration.enabled` is true. Default-off; `onError: skip`.
## Ownership declaration
The `gsd-ultraplan-phase` plan-offload surface (offloading GSD's plan phase to
Claude Code's ultraplan cloud) is **owned by this capability**, not by a
standalone BETA skill. Both surfaces share one runtime gate
(`claude_orchestration.enabled`), one BETA boundary, and one Claude-Code-only
detection seam.
## When the planner should consider ultraplan offload
When this contribution is active (capability enabled, Claude Code runtime), the
planner MAY offer the `/gsd-ultraplan-phase` path as an alternative to local
`/gsd-plan-phase` for phases where cloud-assisted planning adds value. This is
advisory, not mandatory — the stable local planner remains the default.
## Fallback contract
If the capability is disabled, or the runtime is not Claude Code, ultraplan
offload is **not surfaced** and the planner proceeds with the standard local
`/gsd-plan-phase`. The `gsd-ultraplan-phase` command itself remains installed
(its own runtime gate already no-ops on non-Claude runtimes); this contribution
only governs whether the capability manifest advertises it as part of the
orchestration surface.