Merge branch 'next' into fix/1941-quick-worktree-stale-base
This commit is contained in:
@@ -306,6 +306,8 @@
|
||||
"capability-writer.cjs",
|
||||
"check-command-router.cjs",
|
||||
"cjs-command-router-adapter.cjs",
|
||||
"claude-orchestration-command-router.cjs",
|
||||
"claude-orchestration.cjs",
|
||||
"cli-exit.cjs",
|
||||
"cli-skew-check.cjs",
|
||||
"clock.cjs",
|
||||
|
||||
@@ -86,3 +86,39 @@ These existing multi-model features (`execute-phase` `cross_ai_delegation`, the
|
||||
- **Neutral:** no effect on non-Claude runtimes by construction; no behavior change until explicitly enabled.
|
||||
|
||||
> **Governance note:** This ADR is a *draft design* accompanying feature request #1143. Per CONTRIBUTING, it is PR'd only after the issue receives `approved-feature`, and the capability is implemented only after #857 is released.
|
||||
|
||||
## Amendment (2026-07-06): BETA v1 implementation landed
|
||||
|
||||
#857 is **released** (CLOSED); the capability infrastructure is live. The BETA v1
|
||||
of this capability has shipped as `capabilities/claude-orchestration/` with the
|
||||
scope agreed in the Decision, refined to the lowest-risk first slice:
|
||||
|
||||
- **Detection + emission** live as pure, fail-closed functions in
|
||||
`gsd-core/bin/lib/claude-orchestration.cjs` (source `src/claude-orchestration.cts`):
|
||||
`detectWorkflowBackend` (gate ladder: enabled → Claude runtime →
|
||||
execution_backend ≠ inline → host dispatch nested+background → valid Agent SDK
|
||||
→ SDK ≥ `claude_orchestration.min_agent_sdk_version`, default `0.3.149`) and
|
||||
`emitWorkflowScript` (waves → `parallel()` stage barriers, plans →
|
||||
`agent({ agentType: 'gsd-executor', isolation: 'worktree' })`, `files_modified`
|
||||
overlap → separate sequential stages, `resumeFromRunId` wired to the phase run
|
||||
id, shared `budget(tokens)` pool). All interpolated values are validated as
|
||||
script-safe identifiers or JSON-quoted (review Finding 1).
|
||||
- **Loop registration** is at the two **wired** points the loop host contract
|
||||
actually renders: `execute:wave:post into:executor` (Workflow-backend guidance)
|
||||
and `plan:post into:planner` (ultraplan ownership declaration). `execute:wave:pre`
|
||||
and `execute:pre` are declared in the contract but **not wired** today, so the
|
||||
capability registers at `wave:post` (the constraint `external-job` also documents).
|
||||
- **Config** is federated (`claude_orchestration.enabled` default false /
|
||||
`activationKey`, `execution_backend` enum `auto|workflow|inline` default `auto`,
|
||||
`min_agent_sdk_version`); the keys live only in the registry, so uninstall
|
||||
removes them cleanly.
|
||||
- **ultraplan ownership** is declared in the manifest (`plan:post` contribution);
|
||||
full install-profile migration of the `gsd-ultraplan-phase` skill into the
|
||||
capability's `skills[]` is deferred to a follow-up (it triggers the CLUSTERS /
|
||||
profile membership gate and is a heavier, install-machinery change).
|
||||
|
||||
Status remains **Proposed** — the BETA is default-off and the end-to-end Workflow
|
||||
execution path (actual orchestration via the Workflow tool inside Claude Code) is
|
||||
not verifiable outside that runtime. The capability is structurally complete and
|
||||
tested at the contract level; flipping to Accepted follows maintainer sign-off on
|
||||
the E2E behaviour once exercised on Claude Code with the Workflow tool present.
|
||||
|
||||
@@ -80,6 +80,14 @@ Cross-cutting steps (a, b, c) are applied by the descriptor pipeline for the app
|
||||
5. **Codex** — fold the `.toml` sidecar into the descriptor (or declare it an explicit companion artifact); the `.md` + `.toml` must both reach parity.
|
||||
6. **Delete the inline loop** once every runtime is green; remove the now-dead `isKimi`/minimal special-casing that referenced it.
|
||||
|
||||
### Cutover progress (#1575)
|
||||
|
||||
- **Step 0 (parity harness):** shipped in `tests/issue-1575-agent-descriptor-parity.test.cjs`. Asserts `applySurface` output is byte-identical to `installRuntimeArtifacts` for all descriptor-driven runtimes. Covers stale-cleanup convergence (pre-existing legacy `.agent.md` pruned correctly).
|
||||
- **Step 1 (trivial converters):** cursor, windsurf, augment, trae, codebuddy — install-path cutover complete (PR #1438); surface-path parity shipped (#1575: `applySurface` now builds `agentCtx` and passes it to `kind.stage()` for agents, applying path-rewrite + attribution + converter + normalize).
|
||||
- **Step 2 (scope-aware):** copilot and antigravity — cutover complete (#1575: declared `agents` kind in `capability.json`, added to `_DESCRIPTOR_AGENTS_RUNTIMES`, copilot `.agent.md` rename handled in both `_copyStaged` and `_syncGsdDir`).
|
||||
- **Cline:** deferred — rules-only local branch + local/global complication not handled by the descriptor-driven path.
|
||||
- **Remaining:** steps 3–6 (config-reading, no-converter, codex, inline-loop deletion).
|
||||
|
||||
## Risks / trade-offs
|
||||
|
||||
- **Silent install regression** across ~15 runtimes is the dominant risk; the byte-for-byte golden gate is the mitigation, and per-runtime sequencing bounds the blast radius of any single step.
|
||||
|
||||
94
docs/explanation/claude-orchestration-capability.md
Normal file
94
docs/explanation/claude-orchestration-capability.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# Claude orchestration capability (BETA)
|
||||
|
||||
> **Explanation** — *why this capability exists and how it fits the loop.* For the
|
||||
> step-by-step, see the [capability reference](../reference/capability-matrix.md);
|
||||
> for the design record, see [ADR-1143](../adr/1143-claude-orchestration-capability.md).
|
||||
|
||||
## 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.
|
||||
|
||||
[#853]: https://github.com/open-gsd/gsd-core/issues/853
|
||||
[#1143]: https://github.com/open-gsd/gsd-core/issues/1143
|
||||
171
docs/how-to/enable-claude-orchestration-workflow-backend.md
Normal file
171
docs/how-to/enable-claude-orchestration-workflow-backend.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# How to enable and use the Claude orchestration backend (BETA)
|
||||
|
||||
Run GSD's execute-phase waves through Claude Code's Workflow tool (`/effort ultracode`, Agent SDK ≥ v0.3.149) instead of the default one-agent-per-message dispatch, and fold the `gsd-ultraplan-phase` plan-offload under the same gate. On Claude Code this restores the wave parallelism that backgrounded-agent nesting (#853) otherwise forces inline.
|
||||
|
||||
> **BETA.** This capability tracks a Claude Code preview surface. It is default-off, fail-closed, and Claude-only. Every detection miss degrades silently to today's inline behaviour — enabling it can never break the loop. See the [explanation doc](../explanation/claude-orchestration-capability.md) for the why, and [ADR-1143](../adr/1143-claude-orchestration-capability.md) for the design.
|
||||
|
||||
**What you need:**
|
||||
- GSD installed with the `full` profile (the capability is `tier: full`).
|
||||
- **Claude Code** with the Workflow tool available (Agent SDK ≥ `0.3.149`). On any other runtime the capability is an explicit no-op — you can flip the switch safely, nothing happens.
|
||||
- A GSD project with at least one planned phase (you need a wave/plan manifest to emit a script for).
|
||||
|
||||
---
|
||||
|
||||
## Step 1 — Enable the capability
|
||||
|
||||
The capability ships disabled. Turn on the master switch inside your GSD project:
|
||||
|
||||
```bash
|
||||
gsd-tools query config-set claude_orchestration.enabled true
|
||||
```
|
||||
|
||||
That single key gates everything — both the Workflow-backend hook at `execute:wave:post` and the ultraplan ownership declaration at `plan:post`. All other `claude_orchestration.*` keys are optional refinements.
|
||||
|
||||
Verify it took:
|
||||
|
||||
```bash
|
||||
gsd-tools query config-get claude_orchestration.enabled
|
||||
# → true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 2 — Check whether your runtime qualifies
|
||||
|
||||
Detection is fail-closed: the Workflow backend activates only when **every** gate opens. Before relying on it, confirm your runtime reports as capable:
|
||||
|
||||
```bash
|
||||
gsd-tools claude-orchestration detect-backend \
|
||||
--runtime claude \
|
||||
--agent-sdk-version 1.2.0
|
||||
```
|
||||
|
||||
You will get one of two results:
|
||||
|
||||
| `backend` | `available` | Meaning |
|
||||
|-----------|-------------|---------|
|
||||
| `workflow` | `true` | Every gate passed — the emitter will produce a Workflow script the orchestrator can run. |
|
||||
| `inline` | `false` | A gate failed. The `reason` field tells you which: `capability_disabled`, `runtime_not_claude`, `backend_inline`, `workflow_tool_unavailable`, `agent_sdk_version_unknown`, or `agent_sdk_version_below_floor`. |
|
||||
|
||||
> **The CLI is a simulation harness, not a probe.** `detect-backend` assumes a capable host descriptor unless you pass `--no-nested-dispatch`. It exists so you (and the orchestrator) can ask "given these facts, would the backend activate?" The real detection the loop uses is the pure `detectWorkflowBackend` function, called with the live host descriptor.
|
||||
|
||||
### If detection returns `inline`
|
||||
|
||||
Work through the `reason`:
|
||||
|
||||
- **`runtime_not_claude`** — you are on Codex / Cursor / opencode / etc. The Workflow tool is Claude-specific; there is nothing to enable here. Your loop is unchanged.
|
||||
- **`agent_sdk_version_below_floor`** — upgrade Claude Code / the Agent SDK to at least `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 and will not activate.
|
||||
- **`workflow_tool_unavailable`** — your host descriptor does not advertise nested + background dispatch. This is unusual on Claude Code; if you see it, the Workflow tool is not present in this session.
|
||||
- **`agent_sdk_version_unknown`** — the version could not be determined. Supply it explicitly via `--agent-sdk-version`.
|
||||
|
||||
### Pin a higher floor (optional)
|
||||
|
||||
If you want to gate the BETA behind a newer Agent SDK than the default:
|
||||
|
||||
```bash
|
||||
gsd-tools query config-set claude_orchestration.min_agent_sdk_version 1.0.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 3 — Choose the execution backend
|
||||
|
||||
`claude_orchestration.execution_backend` controls how aggressively the backend is used once detection passes:
|
||||
|
||||
| Value | Behaviour |
|
||||
|-------|-----------|
|
||||
| `auto` (default) | Use the Workflow backend **if** detection passes; otherwise inline. The safe, recommended value. |
|
||||
| `workflow` | Force the Workflow backend when the tool is present (still fails closed to inline if the tool is absent or the SDK is too old — the floor applies in both modes). |
|
||||
| `inline` | Force today's manual one-agent-per-message dispatch, even on a capable Claude Code runtime. Use this to A/B compare or to temporarily retire the BETA. |
|
||||
|
||||
Switch with:
|
||||
|
||||
```bash
|
||||
gsd-tools query config-set claude_orchestration.execution_backend workflow
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 4 — Emit a Workflow script for a phase
|
||||
|
||||
With the capability enabled and detection passing, generate the Workflow script for a phase's wave/plan manifest. The manifest is the wave/plan model execute-phase already builds:
|
||||
|
||||
```json
|
||||
{
|
||||
"waves": [
|
||||
{
|
||||
"id": "w1",
|
||||
"plans": [
|
||||
{ "id": "p1", "brief": "Implement the foo module", "files_modified": ["src/foo.cts"] },
|
||||
{ "id": "p2", "brief": "Wire the bar seam", "files_modified": ["src/bar.cts"] }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Emit the script:
|
||||
|
||||
```bash
|
||||
gsd-tools claude-orchestration emit-workflow \
|
||||
--waves .planning/phases/01-foo/waves.json \
|
||||
--run-id phase-01-foo \
|
||||
--phase-dir .planning/phases/01-foo \
|
||||
--budget 500000
|
||||
```
|
||||
|
||||
The output is a generated Workflow script that maps GSD's model 1:1 onto Workflow primitives:
|
||||
|
||||
- **waves → sequential `parallel()` barriers** (split into separate stages within a wave when `files_modified` overlap),
|
||||
- **plans → `agent(brief, { agentType: "gsd-executor", isolation: "worktree" })`** — the **same** executor agent and worktree isolation the inline path uses,
|
||||
- **`resumeFromRunId("<run-id>")`** wired to the phase run id,
|
||||
- **`budget(<tokens>)`** — a shared token pool across the whole phase (omit `--budget` to skip).
|
||||
|
||||
Because the script composes the same `gsd-executor` agent + worktree isolation + `SUMMARY.md` artifact as the inline path, the artifacts and commits it produces are identical — only the execution vehicle differs.
|
||||
|
||||
### Run the emitted script
|
||||
|
||||
Feed the emitted script to Claude Code's Workflow tool (`/effort ultracode`, or an Agent SDK `Workflow` invocation). The orchestrator runs it; each `agent()` call spawns a `gsd-executor` in its own worktree, waves barrier between each other, and `resumeFromRunId` lets an interrupted phase resume without re-running completed plans.
|
||||
|
||||
---
|
||||
|
||||
## Step 5 — Ultraplan plan-offload
|
||||
|
||||
Enabling the capability also folds `gsd-ultraplan-phase` under the same runtime gate. When the capability is on, the planner may offer the `/gsd-ultraplan-phase` path (offload plan-phase to Claude Code's ultraplan cloud) as an alternative to local `/gsd-plan-phase`. This is advisory — the stable local planner remains the default.
|
||||
|
||||
If the capability is off, or the runtime is not Claude Code, ultraplan offload is not surfaced and `/gsd-plan-phase` runs as normal.
|
||||
|
||||
---
|
||||
|
||||
## Disabling
|
||||
|
||||
To turn the capability off and return to byte-identical inline behaviour:
|
||||
|
||||
```bash
|
||||
gsd-tools query config-set claude_orchestration.enabled false
|
||||
```
|
||||
|
||||
Or force inline dispatch while leaving the capability otherwise on:
|
||||
|
||||
```bash
|
||||
gsd-tools query config-set claude_orchestration.execution_backend inline
|
||||
```
|
||||
|
||||
Either step is sufficient — no uninstall or resurface needed. The federated config keys live only in the capability registry, so they vanish cleanly if the capability is ever removed.
|
||||
|
||||
---
|
||||
|
||||
## What is and is not wired in BETA v1
|
||||
|
||||
**Working today:**
|
||||
- Detection (`detectWorkflowBackend` / `gsd-tools claude-orchestration detect-backend`) — fail-closed, tested across every gate.
|
||||
- Emission (`emitWorkflowScript` / `gsd-tools claude-orchestration emit-workflow`) — waves→barriers, overlap→stages, resume, budget, anti-injection.
|
||||
- The contribution fragments at `execute:wave:post` and `plan:post` (gated, `onError: skip`).
|
||||
- Inline fallback on every non-capable combination (regression-tested).
|
||||
|
||||
**Not yet wired (follow-ups):**
|
||||
- `execute-phase.md` does not yet auto-branch to emit-and-run the Workflow script. Today you emit the script explicitly (Step 4) and run it via the Workflow tool. Automatic dispatch inside the loop is the next milestone.
|
||||
- The plan-checker and verifier still run inline — this capability delivers the parallel-execution backend, not those gates.
|
||||
- Full install-profile migration of the `gsd-ultraplan-phase` skill into the capability's `skills[]` (it is currently declared in the manifest; the skill's own runtime gate continues to no-op on non-Claude runtimes).
|
||||
|
||||
If a preview-API change breaks detection, the capability degrades to inline; it cannot destabilise the core loop.
|
||||
@@ -44,7 +44,7 @@ Core package and are stamped with the package version at release (per
|
||||
ADR-1244 D6). They are not subject to the consent or integrity-pin flow applied
|
||||
to third-party capabilities.
|
||||
|
||||
### Feature capabilities (role: feature) — 18
|
||||
### Feature capabilities (role: feature) — 19
|
||||
|
||||
Feature capabilities extend what the loop does — contributing research,
|
||||
planning, execution, verification, or ship artefacts at the loop extension
|
||||
@@ -55,6 +55,7 @@ points.
|
||||
| `ai-integration` | feature | full | `>=1.6.0` | `plan:pre` | step | first-party |
|
||||
| `assumption-delta` | feature | full | `>=1.6.0` | `plan:pre` | contribution | first-party |
|
||||
| `audit` | feature | full | `>=1.6.0` | — | — | first-party |
|
||||
| `claude-orchestration` | feature | full | `>=1.7.0` | `plan:post`, `execute:wave:post` | contribution | first-party |
|
||||
| `code-review` | feature | full | `>=1.6.0` | `execute:post` | step | first-party |
|
||||
| `drift` | feature | full | `>=1.6.0` | `plan:pre`, `execute:wave:post` | gate | first-party |
|
||||
| `external-job` | feature | full | `>=1.7.0` | `plan:post`, `execute:wave:post` | contribution | first-party |
|
||||
|
||||
Reference in New Issue
Block a user