From 71180983a01f62735e843815da377a1f0e743aaf Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Fri, 14 Aug 2026 16:03:48 -0400 Subject: [PATCH] fix(#3423): standardize on , retire the files_to_read emit tag (#3432) * fix(#3423): standardize on required_reading, retire files_to_read emit tag * test(#3423): flip tag assertions, extend consistency guard to spawner surfaces * fix(#3423): sweep capabilities fragments, regen registry+skills, anchor executor test * chore(#3423): acknowledge tag-rename emitted ripples and workflow growth * chore(#3423): broaden emitted-ripple acknowledgment to all embedders * chore(#3423): settle emitted-drift acks post-rebase (merge 3004/1689-owned keys) * chore(#3423): drop stale ripple acks, ack execute-phase growth * chore(#3423): restore pristine 3004 fragment, keep only consumed appends * chore(#3423): backfill changeset pr number * chore(#3423): settle emitted-drift acks post-merge (move code-review-fix ripple into 3190, tag-rename ripples into 3191/3297) * chore(#3423): re-arm 3324 ack for execute-phase.md tag-rename ripple * fix(#3423): trim 8 bytes from execute-phase model note to hold ADR-857 margin, re-arm 3370 ack for net +4 growth --------- Co-authored-by: sim --- .changeset/quick-quails-march.md | 5 + bin/install.js | 2 +- .../fragments/execute-wave-pre.md | 2 +- .../pattern-mapper/fragments/plan-pre.md | 4 +- capabilities/research/fragments/plan-pre.md | 4 +- commands/gsd/code-review.md | 2 +- commands/gsd/execute-phase.md | 2 +- commands/gsd/new-milestone.md | 2 +- commands/gsd/quick.md | 2 +- commands/gsd/verify-work.md | 2 +- docs/AGENTS.md | 2 + gsd-core/bin/lib/capability-registry.cjs | 12 +- gsd-core/references/planner-reviews.md | 2 +- gsd-core/templates/discussion-log.md | 2 +- gsd-core/workflows/ai-integration-phase.md | 16 +-- gsd-core/workflows/code-review-fix.md | 8 +- gsd-core/workflows/code-review.md | 6 +- gsd-core/workflows/diagnose-issues.md | 2 +- gsd-core/workflows/eval-review.md | 4 +- gsd-core/workflows/execute-phase.md | 10 +- gsd-core/workflows/ingest-docs.md | 2 +- gsd-core/workflows/new-milestone.md | 12 +- gsd-core/workflows/new-project.md | 28 ++-- gsd-core/workflows/plan-phase.md | 14 +- gsd-core/workflows/quick.md | 8 +- .../quick/steps/plan-checker-loop.md | 8 +- .../quick/steps/quick-verification.md | 4 +- .../workflows/quick/steps/research-phase.md | 4 +- gsd-core/workflows/secure-phase.md | 2 +- gsd-core/workflows/ui-phase.md | 10 +- gsd-core/workflows/ui-review.md | 4 +- gsd-core/workflows/validate-phase.md | 2 +- gsd-core/workflows/verify-work.md | 12 +- skills/gsd-code-review/SKILL.md | 2 +- skills/gsd-execute-phase/SKILL.md | 2 +- skills/gsd-new-milestone/SKILL.md | 2 +- skills/gsd-quick/SKILL.md | 2 +- skills/gsd-verify-work/SKILL.md | 2 +- src/runtime-artifact-conversion.cts | 2 +- ...gent-required-reading-consistency.test.cjs | 44 ++++++ tests/context-enrichment.test.cjs | 10 +- tests/edge-probe-planner-contract.test.cjs | 12 +- .../2658-trae-instruction-file-path.json | 6 +- ...004-codex-adapter-collaboration-vocab.json | 132 +++++++++--------- .../3132-retired-status-vocab.json | 4 +- ...0-code-review-fix-auto-rewrite-review.json | 2 +- .../3191-unanchored-grep-sites.json | 2 +- .../3297-planphase-gaps-next-up-scope.json | 2 +- .../3370-execute-phase-gate-conflation.json | 2 +- .../3423-required-reading.json | 28 ++++ tests/executor-mvp-tdd-section.test.cjs | 20 +-- tests/init.test.cjs | 12 +- tests/quick-commit-boundary.test.cjs | 6 +- 53 files changed, 289 insertions(+), 206 deletions(-) create mode 100644 .changeset/quick-quails-march.md create mode 100644 tests/emitted-drift-acks/3423-required-reading.json diff --git a/.changeset/quick-quails-march.md b/.changeset/quick-quails-march.md new file mode 100644 index 000000000..87768979b --- /dev/null +++ b/.changeset/quick-quails-march.md @@ -0,0 +1,5 @@ +--- +type: Changed +pr: 3432 +--- +**Agent required-reading enforcement now actually fires** — spawner workflows and commands emitted `` while agents gate on ``, so the "you MUST Read every listed file" clause never triggered; the canonical tag is now `` everywhere (46 spawn blocks across 24 workflows), with a repo guard banning the legacy tag so the two vocabularies can never drift apart again. (#3423) diff --git a/bin/install.js b/bin/install.js index d6542486d..173a6d783 100755 --- a/bin/install.js +++ b/bin/install.js @@ -4014,7 +4014,7 @@ Typed mapping (agent_type-capable schema only): to \`spawn_agent\` when the runtime/tool supports it. Omit missing, empty, inherited, or unsupported values; do not invent one-off effort literals in workflow prose. -- \`fork_context: false\` by default — GSD agents load their own context via \`\` blocks +- \`fork_context: false\` by default — GSD agents load their own context via \`\` blocks - \`task_name\` — required by the collaboration schema; provide a descriptive name for each spawned task - \`fork_turns\` — optional parameter controlling turn-forking depth; coexists with \`fork_context\` (not a replacement) - \`Task(isolation="worktree")\` / \`Agent(isolation="worktree")\` → no direct \`spawn_agent\` mapping, diff --git a/capabilities/claude-orchestration/fragments/execute-wave-pre.md b/capabilities/claude-orchestration/fragments/execute-wave-pre.md index f5041b245..d85f57b89 100644 --- a/capabilities/claude-orchestration/fragments/execute-wave-pre.md +++ b/capabilities/claude-orchestration/fragments/execute-wave-pre.md @@ -110,7 +110,7 @@ them at this step, from data it already has in-context from `discover_and_group_ - **`id`** — the plan id from `PLAN_INDEX`, e.g. `"01-01"`. - **`brief`** — MUST carry the same task content as step 3's inline `Agent()` - prompt (the ``/``/``/ + prompt (the ``/``/``/ `` block, with `{plan_number}`/`{phase_number}`/ `{phase_name}` substituted) — a short summary here would NOT reproduce step 3's behavior and would violate the "identical artifacts" contract. diff --git a/capabilities/pattern-mapper/fragments/plan-pre.md b/capabilities/pattern-mapper/fragments/plan-pre.md index eca9f14d9..2d431f553 100644 --- a/capabilities/pattern-mapper/fragments/plan-pre.md +++ b/capabilities/pattern-mapper/fragments/plan-pre.md @@ -3,10 +3,10 @@ **Phase directory:** {phase_dir} **Padded phase:** {padded_phase} - + - {context_path} (USER DECISIONS from /gsd:discuss-phase) - {research_path} (Technical Research) - + **Output file:** {phase_dir}/{padded_phase}-PATTERNS.md diff --git a/capabilities/research/fragments/plan-pre.md b/capabilities/research/fragments/plan-pre.md index ab08ebcfc..7875d794b 100644 --- a/capabilities/research/fragments/plan-pre.md +++ b/capabilities/research/fragments/plan-pre.md @@ -3,11 +3,11 @@ Research how to implement Phase {phase_number}: {phase_name} Answer: "What do I need to know to PLAN this phase well?" - + - {context_path} (USER DECISIONS from /gsd:discuss-phase) - {requirements_path} (Project requirements) - {state_path} (Project decisions and history) - + ${AGENT_SKILLS_RESEARCHER} diff --git a/commands/gsd/code-review.md b/commands/gsd/code-review.md index 0ea00b503..64c2036ea 100644 --- a/commands/gsd/code-review.md +++ b/commands/gsd/code-review.md @@ -41,7 +41,7 @@ Optional flags parsed from $ARGUMENTS: - `--depth=VALUE` — Depth override (quick|standard|deep). If provided, overrides workflow.code_review_depth config. - `--files=file1,file2,...` — Explicit file list override. Has highest precedence for file scoping per D-08. When provided, workflow skips SUMMARY.md extraction and git diff fallback entirely. -Context files (CLAUDE.md, SUMMARY.md, phase state) are resolved inside the workflow via `gsd-tools query init.phase-op` and delegated to agent via `` blocks. +Context files (CLAUDE.md, SUMMARY.md, phase state) are resolved inside the workflow via `gsd-tools query init.phase-op` and delegated to agent via `` blocks. diff --git a/commands/gsd/execute-phase.md b/commands/gsd/execute-phase.md index 5f0ed2c87..1d9e6038f 100644 --- a/commands/gsd/execute-phase.md +++ b/commands/gsd/execute-phase.md @@ -56,7 +56,7 @@ Phase: $ARGUMENTS - If none of these tokens appear, run the standard full-phase execution flow with no flag-specific filtering - Do not infer that a flag is active just because it is documented in this prompt -Context files are resolved inside the workflow via `gsd-tools query init.execute-phase` and per-subagent `` blocks. +Context files are resolved inside the workflow via `gsd-tools query init.execute-phase` and per-subagent `` blocks. diff --git a/commands/gsd/new-milestone.md b/commands/gsd/new-milestone.md index 607cac18b..5783c710c 100644 --- a/commands/gsd/new-milestone.md +++ b/commands/gsd/new-milestone.md @@ -36,7 +36,7 @@ Brownfield equivalent of new-project. Project exists, PROJECT.md has history. Ga Milestone name: $ARGUMENTS (optional - will prompt if not provided) -Project and milestone context files are resolved inside the workflow (`init new-milestone`) and delegated via `` blocks where subagents are used. +Project and milestone context files are resolved inside the workflow (`init new-milestone`) and delegated via `` blocks where subagents are used. diff --git a/commands/gsd/quick.md b/commands/gsd/quick.md index 3a5b4361f..35b89b57d 100644 --- a/commands/gsd/quick.md +++ b/commands/gsd/quick.md @@ -46,7 +46,7 @@ Granular flags are composable: `--discuss --research --validate` gives the same $ARGUMENTS -Context files are resolved inside the workflow (`init quick`) and delegated via `` blocks. +Context files are resolved inside the workflow (`init quick`) and delegated via `` blocks. diff --git a/commands/gsd/verify-work.md b/commands/gsd/verify-work.md index 78c901592..a6487bd4d 100644 --- a/commands/gsd/verify-work.md +++ b/commands/gsd/verify-work.md @@ -30,7 +30,7 @@ Phase: $ARGUMENTS (optional) - If provided: Test specific phase (e.g., "4") - If not provided: Check for active sessions or prompt for phase -Context files are resolved inside the workflow (`init verify-work`) and delegated via `` blocks. +Context files are resolved inside the workflow (`init verify-work`) and delegated via `` blocks. diff --git a/docs/AGENTS.md b/docs/AGENTS.md index 613b58a48..a77c91470 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -8,6 +8,8 @@ GSD uses a multi-agent architecture where thin orchestrators (workflow files) spawn specialized agents with fresh context windows. Each agent has a focused role, limited tool access, and produces specific artifacts. +**Required reading (#3423):** the canonical spawn-block tag is `` on BOTH sides — orchestrators emit it, and gating agents enforce it ("you MUST use the Read tool to load every file listed there before performing any other actions"). The legacy `` emit-tag is retired and banned repo-wide by `tests/agent-required-reading-consistency.test.cjs`, because a mismatched pair silently disarms the enforcement clause. + ### Agent Categories > The table below covers the **21 primary agents** detailed in this section. Thirteen additional shipped agents (pattern-mapper, debug-session-manager, code-reviewer, code-fixer, ai-researcher, domain-researcher, eval-planner, eval-auditor, framework-selector, intel-updater, doc-classifier, doc-synthesizer, mempalace-curator) have concise stubs in the [Advanced and Specialized Agents](#advanced-and-specialized-agents) section below. For the authoritative 34-agent roster, see [`docs/INVENTORY.md`](INVENTORY.md) and the `agents/` directory. diff --git a/gsd-core/bin/lib/capability-registry.cjs b/gsd-core/bin/lib/capability-registry.cjs index 6ec6cd305..20d2a6c66 100644 --- a/gsd-core/bin/lib/capability-registry.cjs +++ b/gsd-core/bin/lib/capability-registry.cjs @@ -697,7 +697,7 @@ const capabilities = { "into": "executor", "fragment": { "path": "fragments/execute-wave-pre.md", - "inline": "# Claude orchestration — Workflow execution backend (BETA)\n\n> Injected at `execute:wave:pre` `into: executor` only when\n> `claude_orchestration.enabled` is true. Default-off; `onError: skip`.\n\n## When this contribution is active\n\nThe Claude orchestration capability is **default-off and BETA**. It activates only\nwhen ALL of the following hold:\n\n1. `claude_orchestration.enabled` is `true` in `.planning/config.json`, AND\n2. the active runtime is **Claude Code** (the Workflow tool is Claude / Agent\n SDK-specific), AND\n3. `claude_orchestration.execution_backend` resolves to `workflow` — either\n explicitly, or via `auto` — **and** the Agent SDK version is\n `>= claude_orchestration.min_agent_sdk_version` (default `0.3.149`). The SDK\n floor applies in both `auto` and `workflow` modes (fail-closed: a pre-release\n or older SDK never activates the preview backend).\n\nDetection is fail-closed: any miss degrades to **inline, manual, one-agent-per-\nmessage dispatch** — exactly today's behaviour. On a non-Claude runtime this\ncontribution is a no-op.\n\n## Why `execute:wave:pre` (not `execute:wave:post`)\n\nThis is a **dispatch-backend selector** — it decides HOW a wave's executor agents\nare spawned. That decision has to be made BEFORE the wave's `Agent()` calls in\n`execute-phase.md` step 3, not after the wave has already finished (#2285). The\ncapability previously registered at `execute:wave:post`, which fires only after\nworktree merge/post-merge tests/tracking updates — by then the wave was already\ndispatched inline, so the contribution was structurally unable to change how\ndispatch happened. This fragment is injected at the point that actually precedes\ndispatch.\n\n## What the orchestrator does when the Workflow backend is active\n\nBefore spawning executor agents for the current wave (execute-phase.md step 3),\nresolve the dispatch backend through the single composed CLI seam:\n\n```bash\ngsd-tools claude-orchestration resolve-wave-dispatch \\\n --waves \"$WAVE_MANIFEST_PATH\" --run-id \"$PHASE_RUN_ID\" \\\n --runtime \"$RUNTIME\" \\\n --phase-dir \"$PHASE_DIR\" --raw\n```\n\n`--agent-sdk-version` is no longer passed here (#2590). The router resolves the\ninstalled Agent SDK version itself; see **Agent SDK version** below. The former\n`${AGENT_SDK_VERSION:+--agent-sdk-version \"$AGENT_SDK_VERSION\"}` line was also\n**shell-dependent**: zsh does not word-split unquoted parameter expansions, so it\ncollapsed to a SINGLE argv element there, `argValue()` never matched, and the run\nfailed into `agent_sdk_version_unknown` — indistinguishable from genuinely\nunknown. Pass `--agent-sdk-version ` explicitly only to pin a version.\n\nThis composes `detectWorkflowBackend` (the gate ladder above) with\n`emitWorkflowScript` (the wave→plan mapping below) in ONE call — the pure\nfunction backing it is `resolveWaveDispatch` in\n`gsd-core/bin/lib/claude-orchestration.cjs`. Response shape:\n`{ backend: 'inline'|'workflow', reason, script?, summary? }`.\n\n### Manifest construction (`$WAVE_MANIFEST_PATH`, `$PHASE_RUN_ID`, `$PHASE_DIR`)\n\nThese are NOT pre-existing execute-phase.md variables — the orchestrator builds\nthem at this step, from data it already has in-context from `discover_and_group_plans`\n(the `PLAN_INDEX` JSON) and step 2.5 (the per-plan `USE_WORKTREES_FOR_PLAN` decision):\n\n1. **`$PHASE_DIR`** — reuse `{phase_dir}` from the `INIT` bundle (already loaded\n in the `initialize` step). No new value needed.\n\n2. **`$PHASE_RUN_ID`** — a stable identifier for THIS phase-execution attempt, so\n `resumeFromRunId` can resume an interrupted run without re-dispatching plans\n the Workflow tool already completed. Construct it deterministically —\n `execute-{phase_number}-{phase_slug}` — from `INIT`'s `phase_number`/`phase_slug`\n (both are already validated identifiers used elsewhere in this workflow, so\n they satisfy `emitWorkflowScript`'s `isScriptableIdentifier` check). Do NOT\n mint a new random id per wave — the SAME `$PHASE_RUN_ID` is reused for every\n wave in the phase so the Workflow tool can correctly track cross-wave resume\n state.\n\n3. **`$WAVE_MANIFEST_PATH`** — a fresh temp file for THIS wave's manifest (one\n wave = one `waves` array with a single entry, matching the wave-by-wave\n dispatch loop; do not batch multiple waves into one manifest — waves are\n dispatched in wave order, not all at once):\n\n ```bash\n WAVE_MANIFEST_PATH=$(mktemp \"${TMPDIR:-/tmp}/gsd-wave-dispatch-XXXXXX\") && mv \"$WAVE_MANIFEST_PATH\" \"$WAVE_MANIFEST_PATH.json\" && WAVE_MANIFEST_PATH=\"$WAVE_MANIFEST_PATH.json\"\n ```\n\n Then **use the Write tool** (not a bash/jq pipeline — the orchestrator already\n has every field parsed in-context) to write the manifest JSON to\n `$WAVE_MANIFEST_PATH`:\n\n ```json\n {\n \"waves\": [\n {\n \"id\": \"wave-{N}\",\n \"plans\": [\n {\n \"id\": \"{plan_id}\",\n \"brief\": \"{the SAME ... prompt block step 3 builds for this plan's inline Agent() call}\",\n \"files_modified\": [\"{from PLAN_INDEX.plans[].files_modified for this plan}\"],\n \"use_worktree\": {true unless step 2.5 set USE_WORKTREES_FOR_PLAN=false for this plan}\n }\n ]\n }\n ]\n }\n ```\n\n - **`id`** — the plan id from `PLAN_INDEX`, e.g. `\"01-01\"`.\n - **`brief`** — MUST carry the same task content as step 3's inline `Agent()`\n prompt (the ``/``/``/\n `` block, with `{plan_number}`/`{phase_number}`/\n `{phase_name}` substituted) — a short summary here would NOT reproduce\n step 3's behavior and would violate the \"identical artifacts\" contract.\n - **`files_modified`** — copy verbatim from the plan's `PLAN_INDEX` entry.\n - **`use_worktree`** — `true` for every plan UNLESS step 2.5's per-plan\n worktree gate (`execute-phase/steps/per-plan-worktree-gate.md`) set\n `USE_WORKTREES_FOR_PLAN=false` for that plan (submodule-touching plan, or\n project-level `USE_WORKTREES=false`) — in which case pass `false` here so\n `emitWorkflowScript` omits `isolation: \"worktree\"` for that plan (#2772 /\n #2285 finding 1). **Never** hardcode `true` — that would force worktree\n isolation on a plan the inline path explicitly keeps out of worktrees.\n\n4. **`$AGENT_SDK_VERSION`** — no longer built here; the router resolves it.\n\n**Agent SDK version:** the orchestrator has no *bash-computable* way to\nintrospect the live Agent SDK version — but the router runs in Node, so it\nresolves the version itself (#2590), in this order:\n\n1. an explicit `--agent-sdk-version ` (pin a version),\n2. `GSD_AGENT_SDK_VERSION`,\n3. the **installed** `@anthropic-ai/claude-agent-sdk` package version, read from\n its `package.json` on disk by walking `node_modules` up the tree. (Read\n directly rather than via `require.resolve`: the SDK's `exports` map does not\n expose `./package.json`, so `require.resolve` throws\n `ERR_PACKAGE_PATH_NOT_EXPORTED`.)\n\nPreviously nothing computed this at all, so gate 5 returned\n`agent_sdk_version_unknown` on **every** automated run and the Workflow backend\ncould never activate — while `gsd-tools capability state` still reported the\ncapability `active: true`. Fail-closed is preserved: when no version can be\nresolved, gate 5 still declines to `inline`. What changed is that a resolvable\nversion is now actually found, so a genuinely-too-old SDK reports\n`agent_sdk_version_below_floor` — the truthful reason — instead of `unknown`.\n\n**If `backend == \"workflow\"`:** run the emitted `script` via the Workflow tool\nfor THIS wave instead of the per-message `Agent()` loop in step 3. The script\ncomposes the SAME `gsd-executor` agent type the inline path uses, with\nworktree isolation applied PER PLAN from the manifest's `use_worktree` field\n(see `emitWorkflowScript`):\n\n- **waves → one or more sequential `parallel()` barriers** — each wave is a\n barrier group; when plans within a wave share `files_modified`, they are split\n into separate sequential stages within that wave's barrier.\n- **plans → `agent(brief, { agentType: 'gsd-executor', isolation: 'worktree' })`**\n when `use_worktree` is not `false`, or `agent(brief, { agentType: 'gsd-executor' })`\n (no isolation) when it is — so the produced `SUMMARY.md` and commits are\n identical to inline dispatch, INCLUDING the inline path's submodule safety\n gate (#2772 / #2285 finding 1).\n- **`files_modified` overlap → separate sequential stages** — the same overlap\n rule execute-phase already applies inline (step 1 of the wave loop).\n- **`resumeFromRunId`** — **pass `summary.resumeRunId` as the Workflow tool's\n `resumeFromRunId` INPUT when you invoke the tool.** It is a tool parameter,\n not a script function; the script deliberately does not call it (#2590 — doing\n so threw \"resumeFromRunId is not defined\" and rejected the entire script).\n Omitting it from the tool invocation silently regresses phase-resume to a\n no-op: an interrupted phase re-runs completed plans.\n\n### After the run: manifest bridge into the merge chain (#3302)\n\nThe single Workflow tool call replaces step 3's per-plan `Agent()` loop — which also\nmeans step 3's manifest bookkeeping (creation + per-agent recording) does NOT happen on\nthis path. The orchestrator MUST bridge the run's per-agent results into the SAME\nmanifest-scoped merge chain inline dispatch uses, before steps 4–5.8, which then run\nunchanged:\n\n1. **Create the manifest BEFORE invoking the tool** (this is step 3's creation block,\n which this path skips). When ANY plan in the wave has `use_worktree` not `false`:\n\n ```bash\n if [ -z \"${WAVE_WORKTREE_MANIFEST:-}\" ]; then\n M=$(mktemp \"${TMPDIR:-/tmp}/gsd-worktree-wave-XXXXXX\") && mv \"$M\" \"$M.json\" && WAVE_WORKTREE_MANIFEST=\"$M.json\" || exit 1 # XXXXXX must be path-final on BSD/macOS (#1520)\n # Persist the dispatch-time orchestrator worktree root so wave-cleanup pins back\n # to the orchestrator's OWN worktree (#630), exactly as inline dispatch does.\n ORCH_ROOT=$(git rev-parse --show-toplevel)\n ORCH_ROOT=\"$ORCH_ROOT\" MANIFEST=\"$WAVE_WORKTREE_MANIFEST\" node -e 'const fs=require(\"fs\");fs.writeFileSync(process.env.MANIFEST,JSON.stringify({orchestrator_root:process.env.ORCH_ROOT||null,worktrees:[]})+\"\\n\")'\n export WAVE_WORKTREE_MANIFEST\n fi\n ```\n\n2. **Invoke the Workflow tool with the emitted script and\n `resumeFromRunId: summary.resumeRunId`.** The script top-level `return`s one entry\n per dispatched plan: `{ plan, expects_worktree, metadata }`. `metadata` is that\n plan's executor `` JSON (`{agent_id, worktree_path, branch,\n expected_base}` — captured by the executor itself per\n `agents/gsd-executor.md`), or `null` when the agent's result carried none\n (interrupted agent, resumed-from-cache plan, or a non-worktree plan).\n\n3. **Record every worktree plan** exactly as inline dispatch does at step 3's\n \"After each `Agent()` returns\" — one `worktree.record-agent` per returned entry\n with `expects_worktree: true` and complete metadata:\n\n ```bash\n gsd_run query worktree.record-agent --manifest \"$WAVE_WORKTREE_MANIFEST\" \\\n --agent-id \"\" --path \"\" \\\n --branch \"\" --base \"\" \\\n --files \"\"\n ```\n\n The verb's write-strict validation applies as inline: on a non-zero exit or any\n missing field, stop and ask for recovery — do not append an under-populated entry.\n\n4. **HALT on uncapturable metadata — never a silently-empty manifest (#3302).**\n After recording, the manifest must hold one entry per `expects_worktree: true`\n outcome (`summary.worktreePlans` from `resolve-wave-dispatch` is the expected\n count). Any shortfall — a `null` `metadata`, a missing/empty field, or a count\n mismatch — means commits are stranded on their `worktree-wf_*` branches and\n `worktree.cleanup-wave` would merge nothing while the phase looks green. STOP the\n phase with the failing plan id and the recovery hint below; do NOT run\n `worktree.cleanup-wave` and do NOT proceed to step 4.\n\n **Recovery hint:** the unmerged `worktree-wf_*` branch still holds the work. Recover\n the missing metadata from the run's per-agent result journal (`journal.jsonl` — one\n `{\"type\":\"result\",…}` line per agent — in the Workflow run's transcript dir), re-run\n `worktree.record-agent` by hand, then re-run cleanup. If the journal cannot be\n recovered either, merge the branch manually after review — never discard it.\n\n5. **Resume (`resumeFromRunId`).** Cached/resumed agents do not re-emit their final\n messages, so a previously-completed plan can return with `metadata: null`. Recover\n that plan's metadata from the ORIGINAL run's journal (same hint as above). If it\n cannot be recovered, fail loudly per rule 4 — a resumed run must never report\n success over silently-dropped agent work.\n\n6. **Non-worktree plans** (`expects_worktree: false` — `use_worktree: false` in the\n manifest): they ran without isolation; their commits are already on the main working\n tree. No record-agent entry, no manifest write.\n\nWith the manifest populated, steps 4–5.8 (wait/completion bookkeeping, step 5.5's\nmanifest-scoped `worktree.cleanup-wave`, post-merge gate, tracking update) run\nUNCHANGED — the Workflow backend replaces HOW agents are spawned and returns their\nmetadata; the merge chain itself is the inline path's own, now with real input.\n\n**If `backend == \"inline\"`** (any gate miss, or `resolve-wave-dispatch` itself\nunavailable/erroring): proceed to step 3's standard per-message `Agent()`\ndispatch — the default, byte-identical-to-today path. `onError: skip` on this\ncontribution means a `resolve-wave-dispatch` command failure is treated exactly\nlike an `inline` result, never as a fatal wave error.\n\n## Fallback contract\n\nDetection is fail-closed end-to-end: capability disabled, non-Claude runtime,\n`execution_backend:\"inline\"`, missing/incapable host descriptor, unknown or\nbelow-floor Agent SDK version, or an `emitWorkflowScript` failure on a malformed\nwave manifest — ANY of these degrades to `backend:\"inline\"` and execute-phase's\nstandard inline dispatch (step 3) runs unmodified. The Workflow backend never\npartially activates; the executor MUST NOT assume parallelism, a shared budget,\nor resume-from-run-id semantics when `backend == \"inline\"`.\n" + "inline": "# Claude orchestration — Workflow execution backend (BETA)\n\n> Injected at `execute:wave:pre` `into: executor` only when\n> `claude_orchestration.enabled` is true. Default-off; `onError: skip`.\n\n## When this contribution is active\n\nThe Claude orchestration capability is **default-off and BETA**. It activates only\nwhen ALL of the following hold:\n\n1. `claude_orchestration.enabled` is `true` in `.planning/config.json`, AND\n2. the active runtime is **Claude Code** (the Workflow tool is Claude / Agent\n SDK-specific), AND\n3. `claude_orchestration.execution_backend` resolves to `workflow` — either\n explicitly, or via `auto` — **and** the Agent SDK version is\n `>= claude_orchestration.min_agent_sdk_version` (default `0.3.149`). The SDK\n floor applies in both `auto` and `workflow` modes (fail-closed: a pre-release\n or older SDK never activates the preview backend).\n\nDetection is fail-closed: any miss degrades to **inline, manual, one-agent-per-\nmessage dispatch** — exactly today's behaviour. On a non-Claude runtime this\ncontribution is a no-op.\n\n## Why `execute:wave:pre` (not `execute:wave:post`)\n\nThis is a **dispatch-backend selector** — it decides HOW a wave's executor agents\nare spawned. That decision has to be made BEFORE the wave's `Agent()` calls in\n`execute-phase.md` step 3, not after the wave has already finished (#2285). The\ncapability previously registered at `execute:wave:post`, which fires only after\nworktree merge/post-merge tests/tracking updates — by then the wave was already\ndispatched inline, so the contribution was structurally unable to change how\ndispatch happened. This fragment is injected at the point that actually precedes\ndispatch.\n\n## What the orchestrator does when the Workflow backend is active\n\nBefore spawning executor agents for the current wave (execute-phase.md step 3),\nresolve the dispatch backend through the single composed CLI seam:\n\n```bash\ngsd-tools claude-orchestration resolve-wave-dispatch \\\n --waves \"$WAVE_MANIFEST_PATH\" --run-id \"$PHASE_RUN_ID\" \\\n --runtime \"$RUNTIME\" \\\n --phase-dir \"$PHASE_DIR\" --raw\n```\n\n`--agent-sdk-version` is no longer passed here (#2590). The router resolves the\ninstalled Agent SDK version itself; see **Agent SDK version** below. The former\n`${AGENT_SDK_VERSION:+--agent-sdk-version \"$AGENT_SDK_VERSION\"}` line was also\n**shell-dependent**: zsh does not word-split unquoted parameter expansions, so it\ncollapsed to a SINGLE argv element there, `argValue()` never matched, and the run\nfailed into `agent_sdk_version_unknown` — indistinguishable from genuinely\nunknown. Pass `--agent-sdk-version ` explicitly only to pin a version.\n\nThis composes `detectWorkflowBackend` (the gate ladder above) with\n`emitWorkflowScript` (the wave→plan mapping below) in ONE call — the pure\nfunction backing it is `resolveWaveDispatch` in\n`gsd-core/bin/lib/claude-orchestration.cjs`. Response shape:\n`{ backend: 'inline'|'workflow', reason, script?, summary? }`.\n\n### Manifest construction (`$WAVE_MANIFEST_PATH`, `$PHASE_RUN_ID`, `$PHASE_DIR`)\n\nThese are NOT pre-existing execute-phase.md variables — the orchestrator builds\nthem at this step, from data it already has in-context from `discover_and_group_plans`\n(the `PLAN_INDEX` JSON) and step 2.5 (the per-plan `USE_WORKTREES_FOR_PLAN` decision):\n\n1. **`$PHASE_DIR`** — reuse `{phase_dir}` from the `INIT` bundle (already loaded\n in the `initialize` step). No new value needed.\n\n2. **`$PHASE_RUN_ID`** — a stable identifier for THIS phase-execution attempt, so\n `resumeFromRunId` can resume an interrupted run without re-dispatching plans\n the Workflow tool already completed. Construct it deterministically —\n `execute-{phase_number}-{phase_slug}` — from `INIT`'s `phase_number`/`phase_slug`\n (both are already validated identifiers used elsewhere in this workflow, so\n they satisfy `emitWorkflowScript`'s `isScriptableIdentifier` check). Do NOT\n mint a new random id per wave — the SAME `$PHASE_RUN_ID` is reused for every\n wave in the phase so the Workflow tool can correctly track cross-wave resume\n state.\n\n3. **`$WAVE_MANIFEST_PATH`** — a fresh temp file for THIS wave's manifest (one\n wave = one `waves` array with a single entry, matching the wave-by-wave\n dispatch loop; do not batch multiple waves into one manifest — waves are\n dispatched in wave order, not all at once):\n\n ```bash\n WAVE_MANIFEST_PATH=$(mktemp \"${TMPDIR:-/tmp}/gsd-wave-dispatch-XXXXXX\") && mv \"$WAVE_MANIFEST_PATH\" \"$WAVE_MANIFEST_PATH.json\" && WAVE_MANIFEST_PATH=\"$WAVE_MANIFEST_PATH.json\"\n ```\n\n Then **use the Write tool** (not a bash/jq pipeline — the orchestrator already\n has every field parsed in-context) to write the manifest JSON to\n `$WAVE_MANIFEST_PATH`:\n\n ```json\n {\n \"waves\": [\n {\n \"id\": \"wave-{N}\",\n \"plans\": [\n {\n \"id\": \"{plan_id}\",\n \"brief\": \"{the SAME ... prompt block step 3 builds for this plan's inline Agent() call}\",\n \"files_modified\": [\"{from PLAN_INDEX.plans[].files_modified for this plan}\"],\n \"use_worktree\": {true unless step 2.5 set USE_WORKTREES_FOR_PLAN=false for this plan}\n }\n ]\n }\n ]\n }\n ```\n\n - **`id`** — the plan id from `PLAN_INDEX`, e.g. `\"01-01\"`.\n - **`brief`** — MUST carry the same task content as step 3's inline `Agent()`\n prompt (the ``/``/``/\n `` block, with `{plan_number}`/`{phase_number}`/\n `{phase_name}` substituted) — a short summary here would NOT reproduce\n step 3's behavior and would violate the \"identical artifacts\" contract.\n - **`files_modified`** — copy verbatim from the plan's `PLAN_INDEX` entry.\n - **`use_worktree`** — `true` for every plan UNLESS step 2.5's per-plan\n worktree gate (`execute-phase/steps/per-plan-worktree-gate.md`) set\n `USE_WORKTREES_FOR_PLAN=false` for that plan (submodule-touching plan, or\n project-level `USE_WORKTREES=false`) — in which case pass `false` here so\n `emitWorkflowScript` omits `isolation: \"worktree\"` for that plan (#2772 /\n #2285 finding 1). **Never** hardcode `true` — that would force worktree\n isolation on a plan the inline path explicitly keeps out of worktrees.\n\n4. **`$AGENT_SDK_VERSION`** — no longer built here; the router resolves it.\n\n**Agent SDK version:** the orchestrator has no *bash-computable* way to\nintrospect the live Agent SDK version — but the router runs in Node, so it\nresolves the version itself (#2590), in this order:\n\n1. an explicit `--agent-sdk-version ` (pin a version),\n2. `GSD_AGENT_SDK_VERSION`,\n3. the **installed** `@anthropic-ai/claude-agent-sdk` package version, read from\n its `package.json` on disk by walking `node_modules` up the tree. (Read\n directly rather than via `require.resolve`: the SDK's `exports` map does not\n expose `./package.json`, so `require.resolve` throws\n `ERR_PACKAGE_PATH_NOT_EXPORTED`.)\n\nPreviously nothing computed this at all, so gate 5 returned\n`agent_sdk_version_unknown` on **every** automated run and the Workflow backend\ncould never activate — while `gsd-tools capability state` still reported the\ncapability `active: true`. Fail-closed is preserved: when no version can be\nresolved, gate 5 still declines to `inline`. What changed is that a resolvable\nversion is now actually found, so a genuinely-too-old SDK reports\n`agent_sdk_version_below_floor` — the truthful reason — instead of `unknown`.\n\n**If `backend == \"workflow\"`:** run the emitted `script` via the Workflow tool\nfor THIS wave instead of the per-message `Agent()` loop in step 3. The script\ncomposes the SAME `gsd-executor` agent type the inline path uses, with\nworktree isolation applied PER PLAN from the manifest's `use_worktree` field\n(see `emitWorkflowScript`):\n\n- **waves → one or more sequential `parallel()` barriers** — each wave is a\n barrier group; when plans within a wave share `files_modified`, they are split\n into separate sequential stages within that wave's barrier.\n- **plans → `agent(brief, { agentType: 'gsd-executor', isolation: 'worktree' })`**\n when `use_worktree` is not `false`, or `agent(brief, { agentType: 'gsd-executor' })`\n (no isolation) when it is — so the produced `SUMMARY.md` and commits are\n identical to inline dispatch, INCLUDING the inline path's submodule safety\n gate (#2772 / #2285 finding 1).\n- **`files_modified` overlap → separate sequential stages** — the same overlap\n rule execute-phase already applies inline (step 1 of the wave loop).\n- **`resumeFromRunId`** — **pass `summary.resumeRunId` as the Workflow tool's\n `resumeFromRunId` INPUT when you invoke the tool.** It is a tool parameter,\n not a script function; the script deliberately does not call it (#2590 — doing\n so threw \"resumeFromRunId is not defined\" and rejected the entire script).\n Omitting it from the tool invocation silently regresses phase-resume to a\n no-op: an interrupted phase re-runs completed plans.\n\n### After the run: manifest bridge into the merge chain (#3302)\n\nThe single Workflow tool call replaces step 3's per-plan `Agent()` loop — which also\nmeans step 3's manifest bookkeeping (creation + per-agent recording) does NOT happen on\nthis path. The orchestrator MUST bridge the run's per-agent results into the SAME\nmanifest-scoped merge chain inline dispatch uses, before steps 4–5.8, which then run\nunchanged:\n\n1. **Create the manifest BEFORE invoking the tool** (this is step 3's creation block,\n which this path skips). When ANY plan in the wave has `use_worktree` not `false`:\n\n ```bash\n if [ -z \"${WAVE_WORKTREE_MANIFEST:-}\" ]; then\n M=$(mktemp \"${TMPDIR:-/tmp}/gsd-worktree-wave-XXXXXX\") && mv \"$M\" \"$M.json\" && WAVE_WORKTREE_MANIFEST=\"$M.json\" || exit 1 # XXXXXX must be path-final on BSD/macOS (#1520)\n # Persist the dispatch-time orchestrator worktree root so wave-cleanup pins back\n # to the orchestrator's OWN worktree (#630), exactly as inline dispatch does.\n ORCH_ROOT=$(git rev-parse --show-toplevel)\n ORCH_ROOT=\"$ORCH_ROOT\" MANIFEST=\"$WAVE_WORKTREE_MANIFEST\" node -e 'const fs=require(\"fs\");fs.writeFileSync(process.env.MANIFEST,JSON.stringify({orchestrator_root:process.env.ORCH_ROOT||null,worktrees:[]})+\"\\n\")'\n export WAVE_WORKTREE_MANIFEST\n fi\n ```\n\n2. **Invoke the Workflow tool with the emitted script and\n `resumeFromRunId: summary.resumeRunId`.** The script top-level `return`s one entry\n per dispatched plan: `{ plan, expects_worktree, metadata }`. `metadata` is that\n plan's executor `` JSON (`{agent_id, worktree_path, branch,\n expected_base}` — captured by the executor itself per\n `agents/gsd-executor.md`), or `null` when the agent's result carried none\n (interrupted agent, resumed-from-cache plan, or a non-worktree plan).\n\n3. **Record every worktree plan** exactly as inline dispatch does at step 3's\n \"After each `Agent()` returns\" — one `worktree.record-agent` per returned entry\n with `expects_worktree: true` and complete metadata:\n\n ```bash\n gsd_run query worktree.record-agent --manifest \"$WAVE_WORKTREE_MANIFEST\" \\\n --agent-id \"\" --path \"\" \\\n --branch \"\" --base \"\" \\\n --files \"\"\n ```\n\n The verb's write-strict validation applies as inline: on a non-zero exit or any\n missing field, stop and ask for recovery — do not append an under-populated entry.\n\n4. **HALT on uncapturable metadata — never a silently-empty manifest (#3302).**\n After recording, the manifest must hold one entry per `expects_worktree: true`\n outcome (`summary.worktreePlans` from `resolve-wave-dispatch` is the expected\n count). Any shortfall — a `null` `metadata`, a missing/empty field, or a count\n mismatch — means commits are stranded on their `worktree-wf_*` branches and\n `worktree.cleanup-wave` would merge nothing while the phase looks green. STOP the\n phase with the failing plan id and the recovery hint below; do NOT run\n `worktree.cleanup-wave` and do NOT proceed to step 4.\n\n **Recovery hint:** the unmerged `worktree-wf_*` branch still holds the work. Recover\n the missing metadata from the run's per-agent result journal (`journal.jsonl` — one\n `{\"type\":\"result\",…}` line per agent — in the Workflow run's transcript dir), re-run\n `worktree.record-agent` by hand, then re-run cleanup. If the journal cannot be\n recovered either, merge the branch manually after review — never discard it.\n\n5. **Resume (`resumeFromRunId`).** Cached/resumed agents do not re-emit their final\n messages, so a previously-completed plan can return with `metadata: null`. Recover\n that plan's metadata from the ORIGINAL run's journal (same hint as above). If it\n cannot be recovered, fail loudly per rule 4 — a resumed run must never report\n success over silently-dropped agent work.\n\n6. **Non-worktree plans** (`expects_worktree: false` — `use_worktree: false` in the\n manifest): they ran without isolation; their commits are already on the main working\n tree. No record-agent entry, no manifest write.\n\nWith the manifest populated, steps 4–5.8 (wait/completion bookkeeping, step 5.5's\nmanifest-scoped `worktree.cleanup-wave`, post-merge gate, tracking update) run\nUNCHANGED — the Workflow backend replaces HOW agents are spawned and returns their\nmetadata; the merge chain itself is the inline path's own, now with real input.\n\n**If `backend == \"inline\"`** (any gate miss, or `resolve-wave-dispatch` itself\nunavailable/erroring): proceed to step 3's standard per-message `Agent()`\ndispatch — the default, byte-identical-to-today path. `onError: skip` on this\ncontribution means a `resolve-wave-dispatch` command failure is treated exactly\nlike an `inline` result, never as a fatal wave error.\n\n## Fallback contract\n\nDetection is fail-closed end-to-end: capability disabled, non-Claude runtime,\n`execution_backend:\"inline\"`, missing/incapable host descriptor, unknown or\nbelow-floor Agent SDK version, or an `emitWorkflowScript` failure on a malformed\nwave manifest — ANY of these degrades to `backend:\"inline\"` and execute-phase's\nstandard inline dispatch (step 3) runs unmodified. The Workflow backend never\npartially activates; the executor MUST NOT assume parallelism, a shared budget,\nor resume-from-run-id semantics when `backend == \"inline\"`.\n" }, "produces": [], "consumes": [ @@ -2797,7 +2797,7 @@ const capabilities = { }, "fragment": { "path": "fragments/plan-pre.md", - "inline": "\n**Phase:** {phase_number} - {phase_name}\n**Phase directory:** {phase_dir}\n**Padded phase:** {padded_phase}\n\n\n- {context_path} (USER DECISIONS from /gsd:discuss-phase)\n- {research_path} (Technical Research)\n\n\n**Output file:** {phase_dir}/{padded_phase}-PATTERNS.md\n\nExtract the list of files to be created/modified from CONTEXT.md and RESEARCH.md. For each file, classify by role and data flow, find the closest existing analog in the codebase, extract concrete code excerpts, and produce PATTERNS.md.\n\n" + "inline": "\n**Phase:** {phase_number} - {phase_name}\n**Phase directory:** {phase_dir}\n**Padded phase:** {padded_phase}\n\n\n- {context_path} (USER DECISIONS from /gsd:discuss-phase)\n- {research_path} (Technical Research)\n\n\n**Output file:** {phase_dir}/{padded_phase}-PATTERNS.md\n\nExtract the list of files to be created/modified from CONTEXT.md and RESEARCH.md. For each file, classify by role and data flow, find the closest existing analog in the codebase, extract concrete code excerpts, and produce PATTERNS.md.\n\n" }, "produces": [ "PATTERNS.md" @@ -3201,7 +3201,7 @@ const capabilities = { }, "fragment": { "path": "fragments/plan-pre.md", - "inline": "\nResearch how to implement Phase {phase_number}: {phase_name}\nAnswer: \"What do I need to know to PLAN this phase well?\"\n\n\n\n- {context_path} (USER DECISIONS from /gsd:discuss-phase)\n- {requirements_path} (Project requirements)\n- {state_path} (Project decisions and history)\n\n\n${AGENT_SKILLS_RESEARCHER}\n\n\n**Phase description:** {phase_description}\n**Phase requirement IDs (MUST address):** {phase_req_ids}\n\n**Project instructions:** Read ./CLAUDE.md or ./.claude/CLAUDE.md if either exists; follow project-specific guidelines.\n**Project skills:** Check .claude/skills/ or .agents/skills/ directory if either exists. Read SKILL.md files and account for project skill patterns.\n\n\n\nWrite to: {phase_dir}/{phase_num}-RESEARCH.md\n\n" + "inline": "\nResearch how to implement Phase {phase_number}: {phase_name}\nAnswer: \"What do I need to know to PLAN this phase well?\"\n\n\n\n- {context_path} (USER DECISIONS from /gsd:discuss-phase)\n- {requirements_path} (Project requirements)\n- {state_path} (Project decisions and history)\n\n\n${AGENT_SKILLS_RESEARCHER}\n\n\n**Phase description:** {phase_description}\n**Phase requirement IDs (MUST address):** {phase_req_ids}\n\n**Project instructions:** Read ./CLAUDE.md or ./.claude/CLAUDE.md if either exists; follow project-specific guidelines.\n**Project skills:** Check .claude/skills/ or .agents/skills/ directory if either exists. Read SKILL.md files and account for project skill patterns.\n\n\n\nWrite to: {phase_dir}/{phase_num}-RESEARCH.md\n\n" }, "produces": [ "RESEARCH.md" @@ -3989,7 +3989,7 @@ const byLoopPoint = { }, "fragment": { "path": "fragments/plan-pre.md", - "inline": "\nResearch how to implement Phase {phase_number}: {phase_name}\nAnswer: \"What do I need to know to PLAN this phase well?\"\n\n\n\n- {context_path} (USER DECISIONS from /gsd:discuss-phase)\n- {requirements_path} (Project requirements)\n- {state_path} (Project decisions and history)\n\n\n${AGENT_SKILLS_RESEARCHER}\n\n\n**Phase description:** {phase_description}\n**Phase requirement IDs (MUST address):** {phase_req_ids}\n\n**Project instructions:** Read ./CLAUDE.md or ./.claude/CLAUDE.md if either exists; follow project-specific guidelines.\n**Project skills:** Check .claude/skills/ or .agents/skills/ directory if either exists. Read SKILL.md files and account for project skill patterns.\n\n\n\nWrite to: {phase_dir}/{phase_num}-RESEARCH.md\n\n" + "inline": "\nResearch how to implement Phase {phase_number}: {phase_name}\nAnswer: \"What do I need to know to PLAN this phase well?\"\n\n\n\n- {context_path} (USER DECISIONS from /gsd:discuss-phase)\n- {requirements_path} (Project requirements)\n- {state_path} (Project decisions and history)\n\n\n${AGENT_SKILLS_RESEARCHER}\n\n\n**Phase description:** {phase_description}\n**Phase requirement IDs (MUST address):** {phase_req_ids}\n\n**Project instructions:** Read ./CLAUDE.md or ./.claude/CLAUDE.md if either exists; follow project-specific guidelines.\n**Project skills:** Check .claude/skills/ or .agents/skills/ directory if either exists. Read SKILL.md files and account for project skill patterns.\n\n\n\nWrite to: {phase_dir}/{phase_num}-RESEARCH.md\n\n" }, "produces": [ "RESEARCH.md" @@ -4023,7 +4023,7 @@ const byLoopPoint = { }, "fragment": { "path": "fragments/plan-pre.md", - "inline": "\n**Phase:** {phase_number} - {phase_name}\n**Phase directory:** {phase_dir}\n**Padded phase:** {padded_phase}\n\n\n- {context_path} (USER DECISIONS from /gsd:discuss-phase)\n- {research_path} (Technical Research)\n\n\n**Output file:** {phase_dir}/{padded_phase}-PATTERNS.md\n\nExtract the list of files to be created/modified from CONTEXT.md and RESEARCH.md. For each file, classify by role and data flow, find the closest existing analog in the codebase, extract concrete code excerpts, and produce PATTERNS.md.\n\n" + "inline": "\n**Phase:** {phase_number} - {phase_name}\n**Phase directory:** {phase_dir}\n**Padded phase:** {padded_phase}\n\n\n- {context_path} (USER DECISIONS from /gsd:discuss-phase)\n- {research_path} (Technical Research)\n\n\n**Output file:** {phase_dir}/{padded_phase}-PATTERNS.md\n\nExtract the list of files to be created/modified from CONTEXT.md and RESEARCH.md. For each file, classify by role and data flow, find the closest existing analog in the codebase, extract concrete code excerpts, and produce PATTERNS.md.\n\n" }, "produces": [ "PATTERNS.md" @@ -4209,7 +4209,7 @@ const byLoopPoint = { "into": "executor", "fragment": { "path": "fragments/execute-wave-pre.md", - "inline": "# Claude orchestration — Workflow execution backend (BETA)\n\n> Injected at `execute:wave:pre` `into: executor` only when\n> `claude_orchestration.enabled` is true. Default-off; `onError: skip`.\n\n## When this contribution is active\n\nThe Claude orchestration capability is **default-off and BETA**. It activates only\nwhen ALL of the following hold:\n\n1. `claude_orchestration.enabled` is `true` in `.planning/config.json`, AND\n2. the active runtime is **Claude Code** (the Workflow tool is Claude / Agent\n SDK-specific), AND\n3. `claude_orchestration.execution_backend` resolves to `workflow` — either\n explicitly, or via `auto` — **and** the Agent SDK version is\n `>= claude_orchestration.min_agent_sdk_version` (default `0.3.149`). The SDK\n floor applies in both `auto` and `workflow` modes (fail-closed: a pre-release\n or older SDK never activates the preview backend).\n\nDetection is fail-closed: any miss degrades to **inline, manual, one-agent-per-\nmessage dispatch** — exactly today's behaviour. On a non-Claude runtime this\ncontribution is a no-op.\n\n## Why `execute:wave:pre` (not `execute:wave:post`)\n\nThis is a **dispatch-backend selector** — it decides HOW a wave's executor agents\nare spawned. That decision has to be made BEFORE the wave's `Agent()` calls in\n`execute-phase.md` step 3, not after the wave has already finished (#2285). The\ncapability previously registered at `execute:wave:post`, which fires only after\nworktree merge/post-merge tests/tracking updates — by then the wave was already\ndispatched inline, so the contribution was structurally unable to change how\ndispatch happened. This fragment is injected at the point that actually precedes\ndispatch.\n\n## What the orchestrator does when the Workflow backend is active\n\nBefore spawning executor agents for the current wave (execute-phase.md step 3),\nresolve the dispatch backend through the single composed CLI seam:\n\n```bash\ngsd-tools claude-orchestration resolve-wave-dispatch \\\n --waves \"$WAVE_MANIFEST_PATH\" --run-id \"$PHASE_RUN_ID\" \\\n --runtime \"$RUNTIME\" \\\n --phase-dir \"$PHASE_DIR\" --raw\n```\n\n`--agent-sdk-version` is no longer passed here (#2590). The router resolves the\ninstalled Agent SDK version itself; see **Agent SDK version** below. The former\n`${AGENT_SDK_VERSION:+--agent-sdk-version \"$AGENT_SDK_VERSION\"}` line was also\n**shell-dependent**: zsh does not word-split unquoted parameter expansions, so it\ncollapsed to a SINGLE argv element there, `argValue()` never matched, and the run\nfailed into `agent_sdk_version_unknown` — indistinguishable from genuinely\nunknown. Pass `--agent-sdk-version ` explicitly only to pin a version.\n\nThis composes `detectWorkflowBackend` (the gate ladder above) with\n`emitWorkflowScript` (the wave→plan mapping below) in ONE call — the pure\nfunction backing it is `resolveWaveDispatch` in\n`gsd-core/bin/lib/claude-orchestration.cjs`. Response shape:\n`{ backend: 'inline'|'workflow', reason, script?, summary? }`.\n\n### Manifest construction (`$WAVE_MANIFEST_PATH`, `$PHASE_RUN_ID`, `$PHASE_DIR`)\n\nThese are NOT pre-existing execute-phase.md variables — the orchestrator builds\nthem at this step, from data it already has in-context from `discover_and_group_plans`\n(the `PLAN_INDEX` JSON) and step 2.5 (the per-plan `USE_WORKTREES_FOR_PLAN` decision):\n\n1. **`$PHASE_DIR`** — reuse `{phase_dir}` from the `INIT` bundle (already loaded\n in the `initialize` step). No new value needed.\n\n2. **`$PHASE_RUN_ID`** — a stable identifier for THIS phase-execution attempt, so\n `resumeFromRunId` can resume an interrupted run without re-dispatching plans\n the Workflow tool already completed. Construct it deterministically —\n `execute-{phase_number}-{phase_slug}` — from `INIT`'s `phase_number`/`phase_slug`\n (both are already validated identifiers used elsewhere in this workflow, so\n they satisfy `emitWorkflowScript`'s `isScriptableIdentifier` check). Do NOT\n mint a new random id per wave — the SAME `$PHASE_RUN_ID` is reused for every\n wave in the phase so the Workflow tool can correctly track cross-wave resume\n state.\n\n3. **`$WAVE_MANIFEST_PATH`** — a fresh temp file for THIS wave's manifest (one\n wave = one `waves` array with a single entry, matching the wave-by-wave\n dispatch loop; do not batch multiple waves into one manifest — waves are\n dispatched in wave order, not all at once):\n\n ```bash\n WAVE_MANIFEST_PATH=$(mktemp \"${TMPDIR:-/tmp}/gsd-wave-dispatch-XXXXXX\") && mv \"$WAVE_MANIFEST_PATH\" \"$WAVE_MANIFEST_PATH.json\" && WAVE_MANIFEST_PATH=\"$WAVE_MANIFEST_PATH.json\"\n ```\n\n Then **use the Write tool** (not a bash/jq pipeline — the orchestrator already\n has every field parsed in-context) to write the manifest JSON to\n `$WAVE_MANIFEST_PATH`:\n\n ```json\n {\n \"waves\": [\n {\n \"id\": \"wave-{N}\",\n \"plans\": [\n {\n \"id\": \"{plan_id}\",\n \"brief\": \"{the SAME ... prompt block step 3 builds for this plan's inline Agent() call}\",\n \"files_modified\": [\"{from PLAN_INDEX.plans[].files_modified for this plan}\"],\n \"use_worktree\": {true unless step 2.5 set USE_WORKTREES_FOR_PLAN=false for this plan}\n }\n ]\n }\n ]\n }\n ```\n\n - **`id`** — the plan id from `PLAN_INDEX`, e.g. `\"01-01\"`.\n - **`brief`** — MUST carry the same task content as step 3's inline `Agent()`\n prompt (the ``/``/``/\n `` block, with `{plan_number}`/`{phase_number}`/\n `{phase_name}` substituted) — a short summary here would NOT reproduce\n step 3's behavior and would violate the \"identical artifacts\" contract.\n - **`files_modified`** — copy verbatim from the plan's `PLAN_INDEX` entry.\n - **`use_worktree`** — `true` for every plan UNLESS step 2.5's per-plan\n worktree gate (`execute-phase/steps/per-plan-worktree-gate.md`) set\n `USE_WORKTREES_FOR_PLAN=false` for that plan (submodule-touching plan, or\n project-level `USE_WORKTREES=false`) — in which case pass `false` here so\n `emitWorkflowScript` omits `isolation: \"worktree\"` for that plan (#2772 /\n #2285 finding 1). **Never** hardcode `true` — that would force worktree\n isolation on a plan the inline path explicitly keeps out of worktrees.\n\n4. **`$AGENT_SDK_VERSION`** — no longer built here; the router resolves it.\n\n**Agent SDK version:** the orchestrator has no *bash-computable* way to\nintrospect the live Agent SDK version — but the router runs in Node, so it\nresolves the version itself (#2590), in this order:\n\n1. an explicit `--agent-sdk-version ` (pin a version),\n2. `GSD_AGENT_SDK_VERSION`,\n3. the **installed** `@anthropic-ai/claude-agent-sdk` package version, read from\n its `package.json` on disk by walking `node_modules` up the tree. (Read\n directly rather than via `require.resolve`: the SDK's `exports` map does not\n expose `./package.json`, so `require.resolve` throws\n `ERR_PACKAGE_PATH_NOT_EXPORTED`.)\n\nPreviously nothing computed this at all, so gate 5 returned\n`agent_sdk_version_unknown` on **every** automated run and the Workflow backend\ncould never activate — while `gsd-tools capability state` still reported the\ncapability `active: true`. Fail-closed is preserved: when no version can be\nresolved, gate 5 still declines to `inline`. What changed is that a resolvable\nversion is now actually found, so a genuinely-too-old SDK reports\n`agent_sdk_version_below_floor` — the truthful reason — instead of `unknown`.\n\n**If `backend == \"workflow\"`:** run the emitted `script` via the Workflow tool\nfor THIS wave instead of the per-message `Agent()` loop in step 3. The script\ncomposes the SAME `gsd-executor` agent type the inline path uses, with\nworktree isolation applied PER PLAN from the manifest's `use_worktree` field\n(see `emitWorkflowScript`):\n\n- **waves → one or more sequential `parallel()` barriers** — each wave is a\n barrier group; when plans within a wave share `files_modified`, they are split\n into separate sequential stages within that wave's barrier.\n- **plans → `agent(brief, { agentType: 'gsd-executor', isolation: 'worktree' })`**\n when `use_worktree` is not `false`, or `agent(brief, { agentType: 'gsd-executor' })`\n (no isolation) when it is — so the produced `SUMMARY.md` and commits are\n identical to inline dispatch, INCLUDING the inline path's submodule safety\n gate (#2772 / #2285 finding 1).\n- **`files_modified` overlap → separate sequential stages** — the same overlap\n rule execute-phase already applies inline (step 1 of the wave loop).\n- **`resumeFromRunId`** — **pass `summary.resumeRunId` as the Workflow tool's\n `resumeFromRunId` INPUT when you invoke the tool.** It is a tool parameter,\n not a script function; the script deliberately does not call it (#2590 — doing\n so threw \"resumeFromRunId is not defined\" and rejected the entire script).\n Omitting it from the tool invocation silently regresses phase-resume to a\n no-op: an interrupted phase re-runs completed plans.\n\n### After the run: manifest bridge into the merge chain (#3302)\n\nThe single Workflow tool call replaces step 3's per-plan `Agent()` loop — which also\nmeans step 3's manifest bookkeeping (creation + per-agent recording) does NOT happen on\nthis path. The orchestrator MUST bridge the run's per-agent results into the SAME\nmanifest-scoped merge chain inline dispatch uses, before steps 4–5.8, which then run\nunchanged:\n\n1. **Create the manifest BEFORE invoking the tool** (this is step 3's creation block,\n which this path skips). When ANY plan in the wave has `use_worktree` not `false`:\n\n ```bash\n if [ -z \"${WAVE_WORKTREE_MANIFEST:-}\" ]; then\n M=$(mktemp \"${TMPDIR:-/tmp}/gsd-worktree-wave-XXXXXX\") && mv \"$M\" \"$M.json\" && WAVE_WORKTREE_MANIFEST=\"$M.json\" || exit 1 # XXXXXX must be path-final on BSD/macOS (#1520)\n # Persist the dispatch-time orchestrator worktree root so wave-cleanup pins back\n # to the orchestrator's OWN worktree (#630), exactly as inline dispatch does.\n ORCH_ROOT=$(git rev-parse --show-toplevel)\n ORCH_ROOT=\"$ORCH_ROOT\" MANIFEST=\"$WAVE_WORKTREE_MANIFEST\" node -e 'const fs=require(\"fs\");fs.writeFileSync(process.env.MANIFEST,JSON.stringify({orchestrator_root:process.env.ORCH_ROOT||null,worktrees:[]})+\"\\n\")'\n export WAVE_WORKTREE_MANIFEST\n fi\n ```\n\n2. **Invoke the Workflow tool with the emitted script and\n `resumeFromRunId: summary.resumeRunId`.** The script top-level `return`s one entry\n per dispatched plan: `{ plan, expects_worktree, metadata }`. `metadata` is that\n plan's executor `` JSON (`{agent_id, worktree_path, branch,\n expected_base}` — captured by the executor itself per\n `agents/gsd-executor.md`), or `null` when the agent's result carried none\n (interrupted agent, resumed-from-cache plan, or a non-worktree plan).\n\n3. **Record every worktree plan** exactly as inline dispatch does at step 3's\n \"After each `Agent()` returns\" — one `worktree.record-agent` per returned entry\n with `expects_worktree: true` and complete metadata:\n\n ```bash\n gsd_run query worktree.record-agent --manifest \"$WAVE_WORKTREE_MANIFEST\" \\\n --agent-id \"\" --path \"\" \\\n --branch \"\" --base \"\" \\\n --files \"\"\n ```\n\n The verb's write-strict validation applies as inline: on a non-zero exit or any\n missing field, stop and ask for recovery — do not append an under-populated entry.\n\n4. **HALT on uncapturable metadata — never a silently-empty manifest (#3302).**\n After recording, the manifest must hold one entry per `expects_worktree: true`\n outcome (`summary.worktreePlans` from `resolve-wave-dispatch` is the expected\n count). Any shortfall — a `null` `metadata`, a missing/empty field, or a count\n mismatch — means commits are stranded on their `worktree-wf_*` branches and\n `worktree.cleanup-wave` would merge nothing while the phase looks green. STOP the\n phase with the failing plan id and the recovery hint below; do NOT run\n `worktree.cleanup-wave` and do NOT proceed to step 4.\n\n **Recovery hint:** the unmerged `worktree-wf_*` branch still holds the work. Recover\n the missing metadata from the run's per-agent result journal (`journal.jsonl` — one\n `{\"type\":\"result\",…}` line per agent — in the Workflow run's transcript dir), re-run\n `worktree.record-agent` by hand, then re-run cleanup. If the journal cannot be\n recovered either, merge the branch manually after review — never discard it.\n\n5. **Resume (`resumeFromRunId`).** Cached/resumed agents do not re-emit their final\n messages, so a previously-completed plan can return with `metadata: null`. Recover\n that plan's metadata from the ORIGINAL run's journal (same hint as above). If it\n cannot be recovered, fail loudly per rule 4 — a resumed run must never report\n success over silently-dropped agent work.\n\n6. **Non-worktree plans** (`expects_worktree: false` — `use_worktree: false` in the\n manifest): they ran without isolation; their commits are already on the main working\n tree. No record-agent entry, no manifest write.\n\nWith the manifest populated, steps 4–5.8 (wait/completion bookkeeping, step 5.5's\nmanifest-scoped `worktree.cleanup-wave`, post-merge gate, tracking update) run\nUNCHANGED — the Workflow backend replaces HOW agents are spawned and returns their\nmetadata; the merge chain itself is the inline path's own, now with real input.\n\n**If `backend == \"inline\"`** (any gate miss, or `resolve-wave-dispatch` itself\nunavailable/erroring): proceed to step 3's standard per-message `Agent()`\ndispatch — the default, byte-identical-to-today path. `onError: skip` on this\ncontribution means a `resolve-wave-dispatch` command failure is treated exactly\nlike an `inline` result, never as a fatal wave error.\n\n## Fallback contract\n\nDetection is fail-closed end-to-end: capability disabled, non-Claude runtime,\n`execution_backend:\"inline\"`, missing/incapable host descriptor, unknown or\nbelow-floor Agent SDK version, or an `emitWorkflowScript` failure on a malformed\nwave manifest — ANY of these degrades to `backend:\"inline\"` and execute-phase's\nstandard inline dispatch (step 3) runs unmodified. The Workflow backend never\npartially activates; the executor MUST NOT assume parallelism, a shared budget,\nor resume-from-run-id semantics when `backend == \"inline\"`.\n" + "inline": "# Claude orchestration — Workflow execution backend (BETA)\n\n> Injected at `execute:wave:pre` `into: executor` only when\n> `claude_orchestration.enabled` is true. Default-off; `onError: skip`.\n\n## When this contribution is active\n\nThe Claude orchestration capability is **default-off and BETA**. It activates only\nwhen ALL of the following hold:\n\n1. `claude_orchestration.enabled` is `true` in `.planning/config.json`, AND\n2. the active runtime is **Claude Code** (the Workflow tool is Claude / Agent\n SDK-specific), AND\n3. `claude_orchestration.execution_backend` resolves to `workflow` — either\n explicitly, or via `auto` — **and** the Agent SDK version is\n `>= claude_orchestration.min_agent_sdk_version` (default `0.3.149`). The SDK\n floor applies in both `auto` and `workflow` modes (fail-closed: a pre-release\n or older SDK never activates the preview backend).\n\nDetection is fail-closed: any miss degrades to **inline, manual, one-agent-per-\nmessage dispatch** — exactly today's behaviour. On a non-Claude runtime this\ncontribution is a no-op.\n\n## Why `execute:wave:pre` (not `execute:wave:post`)\n\nThis is a **dispatch-backend selector** — it decides HOW a wave's executor agents\nare spawned. That decision has to be made BEFORE the wave's `Agent()` calls in\n`execute-phase.md` step 3, not after the wave has already finished (#2285). The\ncapability previously registered at `execute:wave:post`, which fires only after\nworktree merge/post-merge tests/tracking updates — by then the wave was already\ndispatched inline, so the contribution was structurally unable to change how\ndispatch happened. This fragment is injected at the point that actually precedes\ndispatch.\n\n## What the orchestrator does when the Workflow backend is active\n\nBefore spawning executor agents for the current wave (execute-phase.md step 3),\nresolve the dispatch backend through the single composed CLI seam:\n\n```bash\ngsd-tools claude-orchestration resolve-wave-dispatch \\\n --waves \"$WAVE_MANIFEST_PATH\" --run-id \"$PHASE_RUN_ID\" \\\n --runtime \"$RUNTIME\" \\\n --phase-dir \"$PHASE_DIR\" --raw\n```\n\n`--agent-sdk-version` is no longer passed here (#2590). The router resolves the\ninstalled Agent SDK version itself; see **Agent SDK version** below. The former\n`${AGENT_SDK_VERSION:+--agent-sdk-version \"$AGENT_SDK_VERSION\"}` line was also\n**shell-dependent**: zsh does not word-split unquoted parameter expansions, so it\ncollapsed to a SINGLE argv element there, `argValue()` never matched, and the run\nfailed into `agent_sdk_version_unknown` — indistinguishable from genuinely\nunknown. Pass `--agent-sdk-version ` explicitly only to pin a version.\n\nThis composes `detectWorkflowBackend` (the gate ladder above) with\n`emitWorkflowScript` (the wave→plan mapping below) in ONE call — the pure\nfunction backing it is `resolveWaveDispatch` in\n`gsd-core/bin/lib/claude-orchestration.cjs`. Response shape:\n`{ backend: 'inline'|'workflow', reason, script?, summary? }`.\n\n### Manifest construction (`$WAVE_MANIFEST_PATH`, `$PHASE_RUN_ID`, `$PHASE_DIR`)\n\nThese are NOT pre-existing execute-phase.md variables — the orchestrator builds\nthem at this step, from data it already has in-context from `discover_and_group_plans`\n(the `PLAN_INDEX` JSON) and step 2.5 (the per-plan `USE_WORKTREES_FOR_PLAN` decision):\n\n1. **`$PHASE_DIR`** — reuse `{phase_dir}` from the `INIT` bundle (already loaded\n in the `initialize` step). No new value needed.\n\n2. **`$PHASE_RUN_ID`** — a stable identifier for THIS phase-execution attempt, so\n `resumeFromRunId` can resume an interrupted run without re-dispatching plans\n the Workflow tool already completed. Construct it deterministically —\n `execute-{phase_number}-{phase_slug}` — from `INIT`'s `phase_number`/`phase_slug`\n (both are already validated identifiers used elsewhere in this workflow, so\n they satisfy `emitWorkflowScript`'s `isScriptableIdentifier` check). Do NOT\n mint a new random id per wave — the SAME `$PHASE_RUN_ID` is reused for every\n wave in the phase so the Workflow tool can correctly track cross-wave resume\n state.\n\n3. **`$WAVE_MANIFEST_PATH`** — a fresh temp file for THIS wave's manifest (one\n wave = one `waves` array with a single entry, matching the wave-by-wave\n dispatch loop; do not batch multiple waves into one manifest — waves are\n dispatched in wave order, not all at once):\n\n ```bash\n WAVE_MANIFEST_PATH=$(mktemp \"${TMPDIR:-/tmp}/gsd-wave-dispatch-XXXXXX\") && mv \"$WAVE_MANIFEST_PATH\" \"$WAVE_MANIFEST_PATH.json\" && WAVE_MANIFEST_PATH=\"$WAVE_MANIFEST_PATH.json\"\n ```\n\n Then **use the Write tool** (not a bash/jq pipeline — the orchestrator already\n has every field parsed in-context) to write the manifest JSON to\n `$WAVE_MANIFEST_PATH`:\n\n ```json\n {\n \"waves\": [\n {\n \"id\": \"wave-{N}\",\n \"plans\": [\n {\n \"id\": \"{plan_id}\",\n \"brief\": \"{the SAME ... prompt block step 3 builds for this plan's inline Agent() call}\",\n \"files_modified\": [\"{from PLAN_INDEX.plans[].files_modified for this plan}\"],\n \"use_worktree\": {true unless step 2.5 set USE_WORKTREES_FOR_PLAN=false for this plan}\n }\n ]\n }\n ]\n }\n ```\n\n - **`id`** — the plan id from `PLAN_INDEX`, e.g. `\"01-01\"`.\n - **`brief`** — MUST carry the same task content as step 3's inline `Agent()`\n prompt (the ``/``/``/\n `` block, with `{plan_number}`/`{phase_number}`/\n `{phase_name}` substituted) — a short summary here would NOT reproduce\n step 3's behavior and would violate the \"identical artifacts\" contract.\n - **`files_modified`** — copy verbatim from the plan's `PLAN_INDEX` entry.\n - **`use_worktree`** — `true` for every plan UNLESS step 2.5's per-plan\n worktree gate (`execute-phase/steps/per-plan-worktree-gate.md`) set\n `USE_WORKTREES_FOR_PLAN=false` for that plan (submodule-touching plan, or\n project-level `USE_WORKTREES=false`) — in which case pass `false` here so\n `emitWorkflowScript` omits `isolation: \"worktree\"` for that plan (#2772 /\n #2285 finding 1). **Never** hardcode `true` — that would force worktree\n isolation on a plan the inline path explicitly keeps out of worktrees.\n\n4. **`$AGENT_SDK_VERSION`** — no longer built here; the router resolves it.\n\n**Agent SDK version:** the orchestrator has no *bash-computable* way to\nintrospect the live Agent SDK version — but the router runs in Node, so it\nresolves the version itself (#2590), in this order:\n\n1. an explicit `--agent-sdk-version ` (pin a version),\n2. `GSD_AGENT_SDK_VERSION`,\n3. the **installed** `@anthropic-ai/claude-agent-sdk` package version, read from\n its `package.json` on disk by walking `node_modules` up the tree. (Read\n directly rather than via `require.resolve`: the SDK's `exports` map does not\n expose `./package.json`, so `require.resolve` throws\n `ERR_PACKAGE_PATH_NOT_EXPORTED`.)\n\nPreviously nothing computed this at all, so gate 5 returned\n`agent_sdk_version_unknown` on **every** automated run and the Workflow backend\ncould never activate — while `gsd-tools capability state` still reported the\ncapability `active: true`. Fail-closed is preserved: when no version can be\nresolved, gate 5 still declines to `inline`. What changed is that a resolvable\nversion is now actually found, so a genuinely-too-old SDK reports\n`agent_sdk_version_below_floor` — the truthful reason — instead of `unknown`.\n\n**If `backend == \"workflow\"`:** run the emitted `script` via the Workflow tool\nfor THIS wave instead of the per-message `Agent()` loop in step 3. The script\ncomposes the SAME `gsd-executor` agent type the inline path uses, with\nworktree isolation applied PER PLAN from the manifest's `use_worktree` field\n(see `emitWorkflowScript`):\n\n- **waves → one or more sequential `parallel()` barriers** — each wave is a\n barrier group; when plans within a wave share `files_modified`, they are split\n into separate sequential stages within that wave's barrier.\n- **plans → `agent(brief, { agentType: 'gsd-executor', isolation: 'worktree' })`**\n when `use_worktree` is not `false`, or `agent(brief, { agentType: 'gsd-executor' })`\n (no isolation) when it is — so the produced `SUMMARY.md` and commits are\n identical to inline dispatch, INCLUDING the inline path's submodule safety\n gate (#2772 / #2285 finding 1).\n- **`files_modified` overlap → separate sequential stages** — the same overlap\n rule execute-phase already applies inline (step 1 of the wave loop).\n- **`resumeFromRunId`** — **pass `summary.resumeRunId` as the Workflow tool's\n `resumeFromRunId` INPUT when you invoke the tool.** It is a tool parameter,\n not a script function; the script deliberately does not call it (#2590 — doing\n so threw \"resumeFromRunId is not defined\" and rejected the entire script).\n Omitting it from the tool invocation silently regresses phase-resume to a\n no-op: an interrupted phase re-runs completed plans.\n\n### After the run: manifest bridge into the merge chain (#3302)\n\nThe single Workflow tool call replaces step 3's per-plan `Agent()` loop — which also\nmeans step 3's manifest bookkeeping (creation + per-agent recording) does NOT happen on\nthis path. The orchestrator MUST bridge the run's per-agent results into the SAME\nmanifest-scoped merge chain inline dispatch uses, before steps 4–5.8, which then run\nunchanged:\n\n1. **Create the manifest BEFORE invoking the tool** (this is step 3's creation block,\n which this path skips). When ANY plan in the wave has `use_worktree` not `false`:\n\n ```bash\n if [ -z \"${WAVE_WORKTREE_MANIFEST:-}\" ]; then\n M=$(mktemp \"${TMPDIR:-/tmp}/gsd-worktree-wave-XXXXXX\") && mv \"$M\" \"$M.json\" && WAVE_WORKTREE_MANIFEST=\"$M.json\" || exit 1 # XXXXXX must be path-final on BSD/macOS (#1520)\n # Persist the dispatch-time orchestrator worktree root so wave-cleanup pins back\n # to the orchestrator's OWN worktree (#630), exactly as inline dispatch does.\n ORCH_ROOT=$(git rev-parse --show-toplevel)\n ORCH_ROOT=\"$ORCH_ROOT\" MANIFEST=\"$WAVE_WORKTREE_MANIFEST\" node -e 'const fs=require(\"fs\");fs.writeFileSync(process.env.MANIFEST,JSON.stringify({orchestrator_root:process.env.ORCH_ROOT||null,worktrees:[]})+\"\\n\")'\n export WAVE_WORKTREE_MANIFEST\n fi\n ```\n\n2. **Invoke the Workflow tool with the emitted script and\n `resumeFromRunId: summary.resumeRunId`.** The script top-level `return`s one entry\n per dispatched plan: `{ plan, expects_worktree, metadata }`. `metadata` is that\n plan's executor `` JSON (`{agent_id, worktree_path, branch,\n expected_base}` — captured by the executor itself per\n `agents/gsd-executor.md`), or `null` when the agent's result carried none\n (interrupted agent, resumed-from-cache plan, or a non-worktree plan).\n\n3. **Record every worktree plan** exactly as inline dispatch does at step 3's\n \"After each `Agent()` returns\" — one `worktree.record-agent` per returned entry\n with `expects_worktree: true` and complete metadata:\n\n ```bash\n gsd_run query worktree.record-agent --manifest \"$WAVE_WORKTREE_MANIFEST\" \\\n --agent-id \"\" --path \"\" \\\n --branch \"\" --base \"\" \\\n --files \"\"\n ```\n\n The verb's write-strict validation applies as inline: on a non-zero exit or any\n missing field, stop and ask for recovery — do not append an under-populated entry.\n\n4. **HALT on uncapturable metadata — never a silently-empty manifest (#3302).**\n After recording, the manifest must hold one entry per `expects_worktree: true`\n outcome (`summary.worktreePlans` from `resolve-wave-dispatch` is the expected\n count). Any shortfall — a `null` `metadata`, a missing/empty field, or a count\n mismatch — means commits are stranded on their `worktree-wf_*` branches and\n `worktree.cleanup-wave` would merge nothing while the phase looks green. STOP the\n phase with the failing plan id and the recovery hint below; do NOT run\n `worktree.cleanup-wave` and do NOT proceed to step 4.\n\n **Recovery hint:** the unmerged `worktree-wf_*` branch still holds the work. Recover\n the missing metadata from the run's per-agent result journal (`journal.jsonl` — one\n `{\"type\":\"result\",…}` line per agent — in the Workflow run's transcript dir), re-run\n `worktree.record-agent` by hand, then re-run cleanup. If the journal cannot be\n recovered either, merge the branch manually after review — never discard it.\n\n5. **Resume (`resumeFromRunId`).** Cached/resumed agents do not re-emit their final\n messages, so a previously-completed plan can return with `metadata: null`. Recover\n that plan's metadata from the ORIGINAL run's journal (same hint as above). If it\n cannot be recovered, fail loudly per rule 4 — a resumed run must never report\n success over silently-dropped agent work.\n\n6. **Non-worktree plans** (`expects_worktree: false` — `use_worktree: false` in the\n manifest): they ran without isolation; their commits are already on the main working\n tree. No record-agent entry, no manifest write.\n\nWith the manifest populated, steps 4–5.8 (wait/completion bookkeeping, step 5.5's\nmanifest-scoped `worktree.cleanup-wave`, post-merge gate, tracking update) run\nUNCHANGED — the Workflow backend replaces HOW agents are spawned and returns their\nmetadata; the merge chain itself is the inline path's own, now with real input.\n\n**If `backend == \"inline\"`** (any gate miss, or `resolve-wave-dispatch` itself\nunavailable/erroring): proceed to step 3's standard per-message `Agent()`\ndispatch — the default, byte-identical-to-today path. `onError: skip` on this\ncontribution means a `resolve-wave-dispatch` command failure is treated exactly\nlike an `inline` result, never as a fatal wave error.\n\n## Fallback contract\n\nDetection is fail-closed end-to-end: capability disabled, non-Claude runtime,\n`execution_backend:\"inline\"`, missing/incapable host descriptor, unknown or\nbelow-floor Agent SDK version, or an `emitWorkflowScript` failure on a malformed\nwave manifest — ANY of these degrades to `backend:\"inline\"` and execute-phase's\nstandard inline dispatch (step 3) runs unmodified. The Workflow backend never\npartially activates; the executor MUST NOT assume parallelism, a shared budget,\nor resume-from-run-id semantics when `backend == \"inline\"`.\n" }, "produces": [], "consumes": [ diff --git a/gsd-core/references/planner-reviews.md b/gsd-core/references/planner-reviews.md index 47f6557f6..da8f52088 100644 --- a/gsd-core/references/planner-reviews.md +++ b/gsd-core/references/planner-reviews.md @@ -7,7 +7,7 @@ Triggered when orchestrator sets Mode to `reviews`. Replanning from scratch with **Execution contract:** REVIEWS.md is audit trail and feedback input, not a second execution contract. /gsd:execute-phase primarily consumes PLAN.md plus the normal phase context. Every current actionable review finding must therefore be incorporated into the relevant PLAN.md or explicitly deferred/rejected in that PLAN.md. ### Step 1: Load REVIEWS.md -Read the reviews file from ``. Parse: +Read the reviews file from ``. Parse: - Per-reviewer feedback (strengths, concerns, suggestions) - Consensus Summary (agreed concerns = highest priority to address) - Divergent Views (investigate, make a judgment call) diff --git a/gsd-core/templates/discussion-log.md b/gsd-core/templates/discussion-log.md index 37cd86692..978c08bd5 100644 --- a/gsd-core/templates/discussion-log.md +++ b/gsd-core/templates/discussion-log.md @@ -4,7 +4,7 @@ Template for `.planning/phases/XX-name/{phase_num}-DISCUSSION-LOG.md` — audit **Purpose:** Software audit trail for decision-making. Captures all options considered, not just the selected one. Separate from CONTEXT.md which is the implementation artifact consumed by downstream agents. -**NOT for LLM consumption.** This file should never be referenced in `` blocks or agent prompts. +**NOT for LLM consumption.** This file should never be referenced in `` blocks or agent prompts. ## Format diff --git a/gsd-core/workflows/ai-integration-phase.md b/gsd-core/workflows/ai-integration-phase.md index 2351ee4ae..c87022888 100644 --- a/gsd-core/workflows/ai-integration-phase.md +++ b/gsd-core/workflows/ai-integration-phase.md @@ -112,10 +112,10 @@ Select the right AI framework for Phase {phase_number}: {phase_name} Goal: {phase_goal} - + {context_path if exists} {requirements_path if exists} - + Phase: {phase_number} — {phase_name} @@ -161,10 +161,10 @@ Before editing, verify the section you are about to write is still a template pl - + {ai_spec_path} {context_path if exists} - + framework: {primary_framework} @@ -196,11 +196,11 @@ Before editing, verify the section you are about to write is still a template pl - + {ai_spec_path} {context_path if exists} {requirements_path if exists} - + system_type: {system_type} @@ -227,11 +227,11 @@ Write Sections 5, 6, and 7 of AI-SPEC.md AI-SPEC.md now contains domain context (Section 1b) — use it as your rubric starting point. - + {ai_spec_path} {context_path if exists} {requirements_path if exists} - + system_type: {system_type} diff --git a/gsd-core/workflows/code-review-fix.md b/gsd-core/workflows/code-review-fix.md index 6a0a902d5..4d27eb69e 100644 --- a/gsd-core/workflows/code-review-fix.md +++ b/gsd-core/workflows/code-review-fix.md @@ -207,9 +207,9 @@ Use Agent() to spawn agent: ```text Agent(subagent_type="gsd-code-fixer", model="{FIXER_MODEL}", prompt=" - + ${REVIEW_PATH} - + phase_dir: ${PHASE_DIR} @@ -329,9 +329,9 @@ ${AGENT_SKILLS_REVIEWER}") echo "Issues remain. Applying fixes for iteration ${ITERATION}..." Agent(subagent_type="gsd-code-fixer", model="{FIXER_MODEL}", prompt=" - + ${REVIEW_PATH} - + phase_dir: ${PHASE_DIR} diff --git a/gsd-core/workflows/code-review.md b/gsd-core/workflows/code-review.md index a93fd3d80..30f040e6d 100644 --- a/gsd-core/workflows/code-review.md +++ b/gsd-core/workflows/code-review.md @@ -443,7 +443,7 @@ else fi ``` -Build files_to_read block for agent: +Build required_reading block for agent: ```bash FILES_TO_READ="" for file in "${REVIEW_FILES[@]}"; do @@ -498,9 +498,9 @@ Print: `◆ Spawning code reviewer... (runs in a subagent — no output until it ``` Agent(subagent_type="gsd-code-reviewer", model="{REVIEWER_MODEL}", prompt=" - + ${FILES_TO_READ} - + ${STRUCTURAL_FINDINGS_BLOCK} diff --git a/gsd-core/workflows/diagnose-issues.md b/gsd-core/workflows/diagnose-issues.md index df82a702c..ac0b2c43d 100644 --- a/gsd-core/workflows/diagnose-issues.md +++ b/gsd-core/workflows/diagnose-issues.md @@ -159,7 +159,7 @@ placeholder, not a shell variable. ``` Agent( - prompt=filled_debug_subagent_prompt + "\n\n" + WORKTREE_GUARD + "\n\n\n- {phase_dir}/{phase_num}-UAT.md\n- {state_path}\n\n${AGENT_SKILLS_DEBUGGER}", + prompt=filled_debug_subagent_prompt + "\n\n" + WORKTREE_GUARD + "\n\n\n- {phase_dir}/{phase_num}-UAT.md\n- {state_path}\n\n${AGENT_SKILLS_DEBUGGER}", subagent_type="gsd-debugger", {harnessFlag} description="Debug: {truth_short}" diff --git a/gsd-core/workflows/eval-review.md b/gsd-core/workflows/eval-review.md index c2577fed1..f2ce62917 100644 --- a/gsd-core/workflows/eval-review.md +++ b/gsd-core/workflows/eval-review.md @@ -91,11 +91,11 @@ Conduct evaluation coverage audit of Phase {phase_number}: {phase_name} {If no AI-SPEC: "Audit against general AI eval best practices."} - + - {summary_paths} - {plan_paths} - {ai_spec_path if exists} - + ai_spec_path: {ai_spec_path or "none"} diff --git a/gsd-core/workflows/execute-phase.md b/gsd-core/workflows/execute-phase.md index 4630fb6ef..0b7244656 100644 --- a/gsd-core/workflows/execute-phase.md +++ b/gsd-core/workflows/execute-phase.md @@ -91,7 +91,7 @@ Parse JSON for: `executor_model`, `verifier_model`, `commit_docs`, `parallelizat `section_manifest` (#2932) gates the three `steps/*.md` reads below: read a step file only when its `id` is in `section_manifest.included` (equivalently, its path is in `section_manifest.read`); skip it — without reading — when its `id` is in `section_manifest.excluded`. When `section_manifest` is `null` (degraded: manifest artifact missing/unreadable), read all three unconditionally — the safe superset. -**Model resolution:** If `executor_model` is `"inherit"`, omit the `model=` parameter from all `Agent()` calls — do NOT pass `model="inherit"` to Agent. Omitting the `model=` parameter causes Claude Code to inherit the current orchestrator model automatically. Only set `model=` when `executor_model` is an explicit model name (e.g., `"claude-sonnet-5"`, `"claude-opus-4-8"`). +**Model resolution:** If `executor_model` is `"inherit"`, omit the `model=` parameter from all `Agent()` calls — do NOT pass `model="inherit"` to Agent. Omitting the `model=` parameter causes Claude Code to inherit the orchestrator model automatically. Only set `model=` when `executor_model` is an explicit model name (e.g., `"claude-sonnet-5"`, `"claude-opus-4-8"`). @~/.claude/gsd-core/references/execute-phase-response-language.md @@ -742,7 +742,7 @@ increases monotonically across waves. `{status}` is `complete` (success), ${CONTEXT_WINDOW < 200000 ? '' : '- `~/.claude/gsd-core/references/executor-examples.md`'} - + Read these files at execution start using the Read tool. First resolve repo root so every path is anchored: \`PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)\` @@ -757,7 +757,7 @@ increases monotonically across waves. `{status}` is `complete` (success), ` : ''} - ${PROJECT_ROOT}/CLAUDE.md (Project instructions, if exists — follow project-specific guidelines and coding conventions) - ${PROJECT_ROOT}/.claude/skills/ or ${PROJECT_ROOT}/.agents/skills/ (Project skills, if either exists — list skills, read SKILL.md for each, follow relevant rules during implementation) - + ${AGENT_SKILLS} @@ -1301,7 +1301,7 @@ Check must_haves against actual codebase. Cross-reference requirement IDs from PLAN frontmatter against REQUIREMENTS.md — every ID MUST be accounted for. Create VERIFICATION.md. - + Read these files before verification: - {phase_dir}/*-PLAN.md (All plans — understand intent, check must_haves) - {phase_dir}/*-SUMMARY.md (All summaries — cross-reference claimed vs actual) @@ -1310,7 +1310,7 @@ ${CONTEXT_WINDOW >= 500000 ? `- {phase_dir}/*-CONTEXT.md (User decisions — ver - {phase_dir}/*-RESEARCH.md (Known pitfalls — check for traps) - Prior VERIFICATION.md files from earlier phases (regression check) ` : ''} - + ${VERIFIER_SKILLS}", subagent_type="gsd-verifier", diff --git a/gsd-core/workflows/ingest-docs.md b/gsd-core/workflows/ingest-docs.md index e6a81341b..164141746 100644 --- a/gsd-core/workflows/ingest-docs.md +++ b/gsd-core/workflows/ingest-docs.md @@ -62,7 +62,7 @@ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi Parse `project_exists`, `planning_exists`, `has_git`, `git_worktree_root`, `in_nested_subdir`, `project_path` from INIT. -**Absolute path fields (#2376):** INIT also carries `requirements_path`, `roadmap_path`, `state_path`, `intel_dir`, and `conflicts_path` — all anchored on `project_root`, not the orchestrator's own cwd. Use these (not bare `.planning/...` literals) whenever building ``/output paths for a spawned subagent, since that subagent's own cwd may differ from the orchestrator's. +**Absolute path fields (#2376):** INIT also carries `requirements_path`, `roadmap_path`, `state_path`, `intel_dir`, and `conflicts_path` — all anchored on `project_root`, not the orchestrator's own cwd. Use these (not bare `.planning/...` literals) whenever building ``/output paths for a spawned subagent, since that subagent's own cwd may differ from the orchestrator's. **Auto-detect MODE** if not set: - `planning_exists: true` → `MODE=merge` diff --git a/gsd-core/workflows/new-milestone.md b/gsd-core/workflows/new-milestone.md index f933906c3..fd808c7fa 100644 --- a/gsd-core/workflows/new-milestone.md +++ b/gsd-core/workflows/new-milestone.md @@ -351,9 +351,9 @@ Focus ONLY on what's needed for the NEW features. {QUESTION} - + - {project_path} (Project context) - + ${AGENT_SKILLS_RESEARCHER} @@ -390,12 +390,12 @@ After all 4 complete, spawn synthesizer: Agent(prompt=" Synthesize research outputs into SUMMARY.md. - + - {research_dir}/STACK.md - {research_dir}/FEATURES.md - {research_dir}/ARCHITECTURE.md - {research_dir}/PITFALLS.md - + ${AGENT_SKILLS_SYNTHESIZER} @@ -518,13 +518,13 @@ gsd_run query commit "docs: define milestone v[X.Y] requirements" --files .plann ```text Agent(prompt=" - + - {project_path} - {requirements_path} - {research_dir}/SUMMARY.md (if exists) - {config_path} - {milestones_path} - + ${AGENT_SKILLS_ROADMAPPER} diff --git a/gsd-core/workflows/new-project.md b/gsd-core/workflows/new-project.md index 6fd251824..142c89b93 100644 --- a/gsd-core/workflows/new-project.md +++ b/gsd-core/workflows/new-project.md @@ -752,9 +752,9 @@ Subsequent: Research what's needed to add [target features] to an existing [doma What's the standard 2025 stack for [domain]? - + - {project_path} (Project context and goals) - + ${AGENT_SKILLS_RESEARCHER} @@ -796,9 +796,9 @@ Subsequent: How do [target features] typically work? What's expected behavior? What features do [domain] products have? What's table stakes vs differentiating? - + - {project_path} (Project context) - + ${AGENT_SKILLS_RESEARCHER} @@ -836,9 +836,9 @@ Subsequent: How do [target features] integrate with existing [domain] architectu How are [domain] systems typically structured? What are major components? - + - {project_path} (Project context) - + ${AGENT_SKILLS_RESEARCHER} @@ -876,9 +876,9 @@ Subsequent: What are common mistakes when adding [target features] to [domain]? What do [domain] projects commonly get wrong? Critical mistakes? - + - {project_path} (Project context) - + ${AGENT_SKILLS_RESEARCHER} @@ -912,12 +912,12 @@ Agent(prompt=" Synthesize research outputs into SUMMARY.md. - + - {research_dir}/STACK.md - {research_dir}/FEATURES.md - {research_dir}/ARCHITECTURE.md - {research_dir}/PITFALLS.md - + ${AGENT_SKILLS_SYNTHESIZER} @@ -1161,12 +1161,12 @@ Spawn gsd-roadmapper agent with path references: Agent(prompt=" - + - {project_path} (Project context) - {requirements_path} (v1 Requirements) - {research_dir}/SUMMARY.md (Research findings - if exists) - {config_path} (Granularity and mode settings) - + ${AGENT_SKILLS_ROADMAPPER} @@ -1262,9 +1262,9 @@ Use AskUserQuestion: User feedback on roadmap: [user's notes] - + - {roadmap_path} (Current roadmap to revise) - + ${AGENT_SKILLS_ROADMAPPER} diff --git a/gsd-core/workflows/plan-phase.md b/gsd-core/workflows/plan-phase.md index 8a2a2daf3..82dc0576d 100644 --- a/gsd-core/workflows/plan-phase.md +++ b/gsd-core/workflows/plan-phase.md @@ -100,7 +100,7 @@ Parse JSON for: `researcher_model`, `planner_model`, `checker_model`, `research_ **If `response_language` is set:** All user-facing orchestrator output MUST be in `{response_language}`; technical terms, code, paths, and subagent prompts stay in English. Pass `response_language: {value}` into every spawned subagent prompt. -**File paths (for blocks):** `state_path`, `roadmap_path`, `requirements_path`, `context_path`, `research_path`, `verification_path`, `uat_path`, `reviews_path`. These are null if files don't exist. +**File paths (for blocks):** `state_path`, `roadmap_path`, `requirements_path`, `context_path`, `research_path`, `verification_path`, `uat_path`, `reviews_path`. These are null if files don't exist. **If `planning_exists` is false:** Error — run `/gsd:new-project` first. @@ -699,7 +699,7 @@ Planner prompt: **Phase:** {phase_number} **Mode:** {standard | gap_closure | reviews} - + - {state_path} (Project State) - {roadmap_path} (Roadmap) - {requirements_path} (Requirements) @@ -723,7 +723,7 @@ ${CONTEXT_WINDOW >= 500000 ? ` - CONTEXT.md, SUMMARY.md, and LEARNINGS.md from any phases listed in the current phase's "Depends on:" field in ROADMAP.md (regardless of recency — explicit dependencies always load, deduplicated against the 3 most recent) - Skip all other prior phases to stay within context budget ` : ''} - + ${API_SURFACE_PATH ? ` **API Surface (HINT — may be incomplete):** When \`intel.enabled\` is true, \`${API_SURFACE_PATH}\` lists symbols extracted from the codebase by regex/JS analysis. Prefer symbols listed there when referencing existing code. This surface is regex/JS-derived and MAY BE INCOMPLETE — a symbol's absence means *unknown*, not *nonexistent*. Never treat the surface as exhaustive. If you reference a symbol that is not in the surface and this phase creates it, list it under "Artifacts this phase produces". @@ -978,14 +978,14 @@ Checker prompt: **Phase Goal:** {goal from ROADMAP} **Mode:** {standard | gap_closure | reviews} - + - {PHASE_DIR}/*-PLAN.md (Plans to verify) - {roadmap_path} (Roadmap) - {requirements_path} (Requirements) - {context_path} (USER DECISIONS from /gsd:discuss-phase) - {research_path} (Technical Research — includes Validation Architecture) - {reviews_path} (Cross-AI Review Feedback - if --reviews; verify actionable findings are represented in PLAN.md) - + ${AGENT_SKILLS_CHECKER} @@ -1112,10 +1112,10 @@ Revision prompt: **Phase:** {phase_number} **Mode:** revision - + - {PHASE_DIR}/*-PLAN.md (Existing plans) - {context_path} (USER DECISIONS from /gsd:discuss-phase) - + ${AGENT_SKILLS_PLANNER} diff --git a/gsd-core/workflows/quick.md b/gsd-core/workflows/quick.md index db52251cd..9c4d3c6dc 100644 --- a/gsd-core/workflows/quick.md +++ b/gsd-core/workflows/quick.md @@ -313,12 +313,12 @@ Agent( **Directory:** ${QUICK_DIR} **Description:** ${DESCRIPTION} - + - ${STATE_PATH} (Project State) - ./CLAUDE.md or ./.claude/CLAUDE.md (if exists — follow project-specific guidelines) ${DISCUSS_MODE ? '- ' + QUICK_DIR + '/' + quick_id + '-CONTEXT.md (User decisions — locked, do not revisit)' : ''} ${RESEARCH_MODE ? '- ' + QUICK_DIR + '/' + quick_id + '-RESEARCH.md (Research findings — use to inform implementation choices)' : ''} - + ${AGENT_SKILLS_PLANNER} @@ -446,12 +446,12 @@ fi \`\`\` ` : ''} - + - ${QUICK_DIR}/${quick_id}-PLAN.md (Plan) - ${STATE_PATH} (Project state) - ./CLAUDE.md or ./.claude/CLAUDE.md (Project instructions, if exists) - .claude/skills/ or .agents/skills/ (Project skills, if either exists — list skills, read SKILL.md for each, follow relevant rules during implementation) - + ${AGENT_SKILLS_EXECUTOR} diff --git a/gsd-core/workflows/quick/steps/plan-checker-loop.md b/gsd-core/workflows/quick/steps/plan-checker-loop.md index c475f7f47..1685062a9 100644 --- a/gsd-core/workflows/quick/steps/plan-checker-loop.md +++ b/gsd-core/workflows/quick/steps/plan-checker-loop.md @@ -18,9 +18,9 @@ Checker prompt: **Mode:** quick-full **Task Description:** ${DESCRIPTION} - + - ${QUICK_DIR}/${quick_id}-PLAN.md (Plan to verify) - + ${AGENT_SKILLS_CHECKER} @@ -74,9 +74,9 @@ Revision prompt: **Mode:** quick-full (revision) - + - ${QUICK_DIR}/${quick_id}-PLAN.md (Existing plan) - + ${AGENT_SKILLS_PLANNER} diff --git a/gsd-core/workflows/quick/steps/quick-verification.md b/gsd-core/workflows/quick/steps/quick-verification.md index 28d490412..41b1314d6 100644 --- a/gsd-core/workflows/quick/steps/quick-verification.md +++ b/gsd-core/workflows/quick/steps/quick-verification.md @@ -17,9 +17,9 @@ Agent( Task directory: ${QUICK_DIR} Task goal: ${DESCRIPTION} - + - ${QUICK_DIR}/${quick_id}-PLAN.md (Plan) - + ${AGENT_SKILLS_VERIFIER} diff --git a/gsd-core/workflows/quick/steps/research-phase.md b/gsd-core/workflows/quick/steps/research-phase.md index f390bd2ae..ddf164487 100644 --- a/gsd-core/workflows/quick/steps/research-phase.md +++ b/gsd-core/workflows/quick/steps/research-phase.md @@ -30,12 +30,12 @@ Agent( **Task:** ${DESCRIPTION} **Output:** ${QUICK_DIR}/${quick_id}-RESEARCH.md - + - ${STATE_PATH} (Project state — what's already built) - ${PROJECT_PATH} (Project context) - ./CLAUDE.md or ./.claude/CLAUDE.md (if exists — project-specific guidelines) ${DISCUSS_MODE ? '- ' + QUICK_DIR + '/' + quick_id + '-CONTEXT.md (User decisions — research should align with these)' : ''} - + ${AGENT_SKILLS_PLANNER} diff --git a/gsd-core/workflows/secure-phase.md b/gsd-core/workflows/secure-phase.md index acfedc3a1..4c0fa0159 100644 --- a/gsd-core/workflows/secure-phase.md +++ b/gsd-core/workflows/secure-phase.md @@ -115,7 +115,7 @@ Print: `◆ Spawning security auditor... (runs in a subagent — no output until ``` Agent( prompt="Read ~/.claude/agents/gsd-security-auditor.md for instructions.\n\n" + - "{PLAN, SUMMARY, impl files, SECURITY.md}" + + "{PLAN, SUMMARY, impl files, SECURITY.md}" + "{threat register}" + "asvs_level: {SECURITY_ASVS}, block_on: {SECURITY_BLOCK_ON}" + "Never modify implementation files. Verify mitigations exist — do not scan for new threats. Escalate implementation gaps. Return a structured verdict only — do NOT write SECURITY.md (the orchestrator owns the file write)." + diff --git a/gsd-core/workflows/ui-phase.md b/gsd-core/workflows/ui-phase.md index af05cc904..ddde71bfd 100644 --- a/gsd-core/workflows/ui-phase.md +++ b/gsd-core/workflows/ui-phase.md @@ -132,14 +132,14 @@ Create UI design contract for Phase {phase_number}: {phase_name} Answer: "What visual and interaction contracts does this phase need?" - + - {state_path} (Project State) - {roadmap_path} (Roadmap) - {requirements_path} (Requirements) - {context_path} (USER DECISIONS from /gsd:discuss-phase) - {research_path} (Technical Research — stack decisions) - {SKETCH_FINDINGS_PATH} (Sketch Findings — validated design decisions, CSS patterns, visual direction from /gsd:sketch, if exists) - + ${AGENT_SKILLS_UI} @@ -155,7 +155,7 @@ padded_phase: {padded_phase} ``` -Omit null file paths from ``. +Omit null file paths from ``. @@ -205,11 +205,11 @@ Validate UI design contract for Phase {phase_number}: {phase_name} Check all 6 dimensions. Return APPROVED or BLOCKED. - + - {phase_dir}/{padded_phase}-UI-SPEC.md (UI Design Contract — PRIMARY INPUT) - {context_path} (USER DECISIONS — check compliance) - {research_path} (Technical Research — check stack alignment) - + ${AGENT_SKILLS_UI_CHECKER} diff --git a/gsd-core/workflows/ui-review.md b/gsd-core/workflows/ui-review.md index cd580b22a..c0c376f36 100644 --- a/gsd-core/workflows/ui-review.md +++ b/gsd-core/workflows/ui-review.md @@ -84,12 +84,12 @@ Conduct 6-pillar visual audit of Phase {phase_number}: {phase_name} {If no UI-SPEC: "Audit against abstract 6-pillar standards."} - + - {summary_paths} (Execution summaries) - {plan_paths} (Execution plans — what was intended) - {ui_spec_path} (UI Design Contract — audit baseline, if exists) - {context_path} (User decisions, if exists) - + ${AGENT_SKILLS_UI_REVIEWER} diff --git a/gsd-core/workflows/validate-phase.md b/gsd-core/workflows/validate-phase.md index 4701066b5..a3f75caa3 100644 --- a/gsd-core/workflows/validate-phase.md +++ b/gsd-core/workflows/validate-phase.md @@ -110,7 +110,7 @@ Print: `◆ Spawning nyquist auditor... (runs in a subagent — no output until ``` Agent( prompt="Read ~/.claude/agents/gsd-nyquist-auditor.md for instructions.\n\n" + - "{PLAN, SUMMARY, impl files, VALIDATION.md}" + + "{PLAN, SUMMARY, impl files, VALIDATION.md}" + "{gap list}" + "{framework, config, commands}" + "Never modify impl files. Max 3 debug iterations. Escalate impl bugs." + diff --git a/gsd-core/workflows/verify-work.md b/gsd-core/workflows/verify-work.md index cff12a6bb..c98d854e0 100644 --- a/gsd-core/workflows/verify-work.md +++ b/gsd-core/workflows/verify-work.md @@ -704,11 +704,11 @@ Agent( **Phase:** {phase_number} **Mode:** gap_closure - + - {phase_dir}/{phase_num}-UAT.md (UAT with diagnoses) - {state_path} (Project State) - {roadmap_path} (Roadmap) - + ${AGENT_SKILLS_PLANNER} @@ -769,9 +769,9 @@ Agent( **Phase:** {phase_number} **Phase Goal:** Close diagnosed gaps from UAT - + - {phase_dir}/*-PLAN.md (Plans to verify) - + ${AGENT_SKILLS_CHECKER} @@ -813,9 +813,9 @@ Agent( **Phase:** {phase_number} **Mode:** revision - + - {phase_dir}/*-PLAN.md (Existing plans) - + ${AGENT_SKILLS_PLANNER} diff --git a/skills/gsd-code-review/SKILL.md b/skills/gsd-code-review/SKILL.md index d7f87b321..0743fe103 100644 --- a/skills/gsd-code-review/SKILL.md +++ b/skills/gsd-code-review/SKILL.md @@ -41,7 +41,7 @@ Optional flags parsed from $ARGUMENTS: - `--depth=VALUE` — Depth override (quick|standard|deep). If provided, overrides workflow.code_review_depth config. - `--files=file1,file2,...` — Explicit file list override. Has highest precedence for file scoping per D-08. When provided, workflow skips SUMMARY.md extraction and git diff fallback entirely. -Context files (CLAUDE.md, SUMMARY.md, phase state) are resolved inside the workflow via `gsd-tools query init.phase-op` and delegated to agent via `` blocks. +Context files (CLAUDE.md, SUMMARY.md, phase state) are resolved inside the workflow via `gsd-tools query init.phase-op` and delegated to agent via `` blocks. diff --git a/skills/gsd-execute-phase/SKILL.md b/skills/gsd-execute-phase/SKILL.md index 27ed6b394..d5bf1392d 100644 --- a/skills/gsd-execute-phase/SKILL.md +++ b/skills/gsd-execute-phase/SKILL.md @@ -55,7 +55,7 @@ Phase: $ARGUMENTS - If none of these tokens appear, run the standard full-phase execution flow with no flag-specific filtering - Do not infer that a flag is active just because it is documented in this prompt -Context files are resolved inside the workflow via `gsd-tools query init.execute-phase` and per-subagent `` blocks. +Context files are resolved inside the workflow via `gsd-tools query init.execute-phase` and per-subagent `` blocks. diff --git a/skills/gsd-new-milestone/SKILL.md b/skills/gsd-new-milestone/SKILL.md index 9ee777b4f..aecac14ce 100644 --- a/skills/gsd-new-milestone/SKILL.md +++ b/skills/gsd-new-milestone/SKILL.md @@ -36,7 +36,7 @@ Brownfield equivalent of new-project. Project exists, PROJECT.md has history. Ga Milestone name: $ARGUMENTS (optional - will prompt if not provided) -Project and milestone context files are resolved inside the workflow (`init new-milestone`) and delegated via `` blocks where subagents are used. +Project and milestone context files are resolved inside the workflow (`init new-milestone`) and delegated via `` blocks where subagents are used. diff --git a/skills/gsd-quick/SKILL.md b/skills/gsd-quick/SKILL.md index 2cec5ebff..157f9dc0d 100644 --- a/skills/gsd-quick/SKILL.md +++ b/skills/gsd-quick/SKILL.md @@ -46,7 +46,7 @@ Granular flags are composable: `--discuss --research --validate` gives the same $ARGUMENTS -Context files are resolved inside the workflow (`init quick`) and delegated via `` blocks. +Context files are resolved inside the workflow (`init quick`) and delegated via `` blocks. diff --git a/skills/gsd-verify-work/SKILL.md b/skills/gsd-verify-work/SKILL.md index f49fba482..4bdffdf0a 100644 --- a/skills/gsd-verify-work/SKILL.md +++ b/skills/gsd-verify-work/SKILL.md @@ -30,7 +30,7 @@ Phase: $ARGUMENTS (optional) - If provided: Test specific phase (e.g., "4") - If not provided: Check for active sessions or prompt for phase -Context files are resolved inside the workflow (`init verify-work`) and delegated via `` blocks. +Context files are resolved inside the workflow (`init verify-work`) and delegated via `` blocks. diff --git a/src/runtime-artifact-conversion.cts b/src/runtime-artifact-conversion.cts index 175f5fa4f..c8e10d45e 100644 --- a/src/runtime-artifact-conversion.cts +++ b/src/runtime-artifact-conversion.cts @@ -1648,7 +1648,7 @@ Typed mapping (agent_type-capable schema only): to \`spawn_agent\` when the runtime/tool supports it. Omit missing, empty, inherited, or unsupported values; do not invent one-off effort literals in workflow prose. -- \`fork_context: false\` by default — GSD agents load their own context via \`\` blocks +- \`fork_context: false\` by default — GSD agents load their own context via \`\` blocks - \`task_name\` — required by the collaboration schema; provide a descriptive name for each spawned task - \`fork_turns\` — optional parameter controlling turn-forking depth; coexists with \`fork_context\` (not a replacement) - \`Task(isolation="worktree")\` / \`Agent(isolation="worktree")\` → no direct \`spawn_agent\` mapping, diff --git a/tests/agent-required-reading-consistency.test.cjs b/tests/agent-required-reading-consistency.test.cjs index f79ea4423..0d9cf9704 100644 --- a/tests/agent-required-reading-consistency.test.cjs +++ b/tests/agent-required-reading-consistency.test.cjs @@ -206,5 +206,49 @@ describe('debugger agent references bug patterns', () => { ); }); }); + +// ─── Emit-Side Parity (F8 #3423 / epic #1891) ─────────────────────────────── +// The agent-side ban above is half the retirement. Spawner workflows and +// commands must not EMIT the legacy tag either: a block sent to +// an agent whose gate reads never fires the MUST-Read clause +// (the ui-review → gsd-ui-auditor instance: a score produced against a baseline +// the auditor was never required to open). This sweep pins the workflow-side +// emit tag to the agent-side gate tag — the two vocabularies cannot drift again. + +function listMarkdownRecursive(dir) { + const out = []; + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) out.push(...listMarkdownRecursive(full)); + else if (entry.isFile() && entry.name.endsWith('.md')) out.push(full); + } + return out; +} + +describe('READING: no legacy blocks in spawner surfaces', () => { + const SPAWNER_DIRS = [ + path.join(__dirname, '..', 'gsd-core', 'workflows'), + path.join(__dirname, '..', 'commands'), + path.join(__dirname, '..', 'gsd-core', 'references'), + path.join(__dirname, '..', 'gsd-core', 'templates'), + path.join(__dirname, '..', 'capabilities'), // fragments emit spawn blocks too (#3423 blocker) + ]; + const files = SPAWNER_DIRS.flatMap((d) => listMarkdownRecursive(d)).sort(); + + test('spawner surfaces enumerated (guard is not scanning nothing)', () => { + assert.ok(files.length > 100, `expected a large spawner surface, found ${files.length}`); + }); + + for (const file of files) { + const rel = path.relative(path.join(__dirname, '..'), file); + test(`${rel} does not contain `, () => { + const content = fs.readFileSync(file, 'utf-8'); + assert.ok( + !content.includes('') && !content.includes(''), + `${rel} still emits the legacy tag — migrate to (#3423)` + ); + }); + } +}); }); } diff --git a/tests/context-enrichment.test.cjs b/tests/context-enrichment.test.cjs index ffa58398b..80b1608d4 100644 --- a/tests/context-enrichment.test.cjs +++ b/tests/context-enrichment.test.cjs @@ -63,14 +63,14 @@ describe('execute-phase.md context enrichment', () => { test('verifier prompt includes files_to_read block', () => { const content = fs.readFileSync(EXECUTE_WORKFLOW_PATH, 'utf-8'); assert.ok( - content.includes(''), - 'execute-phase.md should contain opening tag' + content.includes(''), + 'execute-phase.md should contain opening tag' ); assert.ok( - content.includes(''), - 'execute-phase.md should contain closing tag' + content.includes(''), + 'execute-phase.md should contain closing tag' ); - const verifierSection = content.substring(content.lastIndexOf('')); + const verifierSection = content.substring(content.lastIndexOf('')); assert.ok( verifierSection.includes('PLAN.md'), 'verifier files_to_read should reference PLAN.md' diff --git a/tests/edge-probe-planner-contract.test.cjs b/tests/edge-probe-planner-contract.test.cjs index 9aa45485b..468058530 100644 --- a/tests/edge-probe-planner-contract.test.cjs +++ b/tests/edge-probe-planner-contract.test.cjs @@ -32,17 +32,17 @@ function extractDownstreamConsumerBlock(content) { return content.slice(start, end + ''.length); } -// Extract the planner block that contains {UI_SPEC_PATH} -// There are multiple blocks in plan-phase.md; we need the one +// Extract the planner block that contains {UI_SPEC_PATH} +// There are multiple blocks in plan-phase.md; we need the one // at ~line 890-912 inside the planning_context markdown block. function extractPlannerFilesBlock(content) { let pos = 0; while (true) { - const start = content.indexOf('', pos); + const start = content.indexOf('', pos); if (start === -1) return ''; - const end = content.indexOf('', start); + const end = content.indexOf('', start); if (end === -1) return ''; - const block = content.slice(start, end + ''.length); + const block = content.slice(start, end + ''.length); if (block.includes('{UI_SPEC_PATH}')) { return block; } @@ -80,7 +80,7 @@ test('RR-01: plan-phase.md resolves phase *-SPEC.md (excluding AI/UI variants) i assert.match( filesBlock, /[{]SPEC_PATH[}]/, - 'The planner block (containing {UI_SPEC_PATH}) must also contain {SPEC_PATH}' + 'The planner block (containing {UI_SPEC_PATH}) must also contain {SPEC_PATH}' ); }); diff --git a/tests/emitted-drift-acks/2658-trae-instruction-file-path.json b/tests/emitted-drift-acks/2658-trae-instruction-file-path.json index 05c4c5106..b71bd706c 100644 --- a/tests/emitted-drift-acks/2658-trae-instruction-file-path.json +++ b/tests/emitted-drift-acks/2658-trae-instruction-file-path.json @@ -22,7 +22,7 @@ "gsd-core/workflows/update.md": "#2658: same CLAUDE.md replacement-target change as checkpoints.md above (bare directory '.trae/rules/' -> concrete file '.trae/rules/rules.md').", "skills/gsd-ns-project/skills/profile-user/SKILL.md": "#2658: derived (via commands/gsd/profile-user.md, which mentions CLAUDE.md) through convertClaudeToTraeMarkdown; same replacement-target change as checkpoints.md above.", "skills/gsd-ns-review/skills/code-review/SKILL.md": "#2658: derived (via commands/gsd/code-review.md, which mentions CLAUDE.md) through convertClaudeToTraeMarkdown; same replacement-target change as checkpoints.md above.", - "ingest-docs.md": "#2658: runtime-detection block gained a `/.trae/` path-based line and a `TRAE_CONFIG_DIR` env-var fallback line (the same trae-detection gap found in new-project.md, fixed here too since it is the identical defect in a sibling workflow).", - "new-project.md": "#2658: runtime-detection block gained a `/.trae/` path-based line and a `TRAE_CONFIG_DIR` env-var fallback line, so trae resolves to RUNTIME=trae instead of falling through to the claude default." + "ingest-docs.md": "#2658: runtime-detection block gained a `/.trae/` path-based line and a `TRAE_CONFIG_DIR` env-var fallback line (the same trae-detection gap found in new-project.md, fixed here too since it is the identical defect in a sibling workflow). — #3423 append (epic #1891 F8): also grew with the -> tag rename (15 chars/block, tag-token-only delta).", + "new-project.md": "#2658: runtime-detection block gained a `/.trae/` path-based line and a `TRAE_CONFIG_DIR` env-var fallback line, so trae resolves to RUNTIME=trae instead of falling through to the claude default. — #3423 append (epic #1891 F8): also grew with the -> tag rename (15 chars/block, tag-token-only delta)." } -} +} \ No newline at end of file diff --git a/tests/emitted-drift-acks/3004-codex-adapter-collaboration-vocab.json b/tests/emitted-drift-acks/3004-codex-adapter-collaboration-vocab.json index efd075215..ae3217cc0 100644 --- a/tests/emitted-drift-acks/3004-codex-adapter-collaboration-vocab.json +++ b/tests/emitted-drift-acks/3004-codex-adapter-collaboration-vocab.json @@ -1,76 +1,76 @@ { "version": 1, "paths": { - ".agents/skills/gsd-add-tests/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-ai-integration-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-audit-fix/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-audit-milestone/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-audit-uat/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-autonomous/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-capture/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-cleanup/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", + ".agents/skills/gsd-add-tests/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-ai-integration-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-audit-fix/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-audit-milestone/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-audit-uat/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-autonomous/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-capture/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-cleanup/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", ".agents/skills/gsd-code-review/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-complete-milestone/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-config/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-debug/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-discuss-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-docs-update/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-eval-review/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", + ".agents/skills/gsd-complete-milestone/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-config/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-debug/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-discuss-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-docs-update/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-eval-review/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", ".agents/skills/gsd-execute-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-explore/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-extract-learnings/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-fast/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-forensics/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-graphify/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-health/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-help/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-import/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-inbox/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-ingest-docs/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-manager/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-map-codebase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-mempalace-capture/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-mempalace-recall/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-milestone-summary/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-mvp-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", + ".agents/skills/gsd-explore/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-extract-learnings/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-fast/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-forensics/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-graphify/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-health/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-help/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-import/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-inbox/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-ingest-docs/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-manager/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-map-codebase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-mempalace-capture/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-mempalace-recall/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-milestone-summary/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-mvp-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", ".agents/skills/gsd-new-milestone/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-new-project/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-next/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-ns-context/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-ns-ideate/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-ns-manage/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-ns-project/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-ns-review/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-ns-workflow/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-onboard/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-pause-work/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-plan-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-plan-review-convergence/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-pr-branch/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-profile-user/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-progress/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", + ".agents/skills/gsd-new-project/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-next/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-ns-context/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-ns-ideate/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-ns-manage/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-ns-project/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-ns-review/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-ns-workflow/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-onboard/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-pause-work/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-plan-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-plan-review-convergence/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-pr-branch/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-profile-user/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-progress/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", ".agents/skills/gsd-quick/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-resume-work/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-review/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-review-backlog/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-secure-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-settings/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-ship/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-sketch/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-spec-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-spike/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-stats/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-surface/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-thread/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-ui-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-ui-review/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-ultraplan-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-undo/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-update/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-validate-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", + ".agents/skills/gsd-resume-work/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-review/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-review-backlog/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-secure-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-settings/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-ship/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-sketch/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-spec-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-spike/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-stats/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-surface/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-thread/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-ui-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-ui-review/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-ultraplan-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-undo/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-update/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-validate-phase/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", ".agents/skills/gsd-verify-work/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-workspace/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.", - ".agents/skills/gsd-workstreams/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple." + ".agents/skills/gsd-workspace/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta.", + ".agents/skills/gsd-workstreams/SKILL.md": "#3004: Codex adapter builder (getCodexSkillAdapterHeader in bin/install.js) changed collaboration-tool vocabulary \u2014 wait(ids)\u2192wait_agent, gated close_agent, added task_name+fork_turns. Every Codex SKILL.md embeds this adapter block, so all ripple.#3423 append (epic #1891 F8): body also moved with the -> rename in its embedded workflow/command/capability sources (the skills-from-commands rule expects a commands/gsd change this diff does not carry) \u2014 deliberate, tag-token-only delta." } } diff --git a/tests/emitted-drift-acks/3132-retired-status-vocab.json b/tests/emitted-drift-acks/3132-retired-status-vocab.json index 2d1f453eb..8f05578ea 100644 --- a/tests/emitted-drift-acks/3132-retired-status-vocab.json +++ b/tests/emitted-drift-acks/3132-retired-status-vocab.json @@ -1,6 +1,6 @@ { "version": 1, "paths": { - "ui-phase.md": "#3132: realigned resolution loop and write-back format from covered/backstop-as-status to resolved+verification." + "ui-phase.md": "#3132: realigned resolution loop and write-back format from covered/backstop-as-status to resolved+verification. — #3423 append (epic #1891 F8): also grew with the -> tag rename (15 chars/block, tag-token-only delta)." } -} +} \ No newline at end of file diff --git a/tests/emitted-drift-acks/3190-code-review-fix-auto-rewrite-review.json b/tests/emitted-drift-acks/3190-code-review-fix-auto-rewrite-review.json index f22f09126..ad46f5428 100644 --- a/tests/emitted-drift-acks/3190-code-review-fix-auto-rewrite-review.json +++ b/tests/emitted-drift-acks/3190-code-review-fix-auto-rewrite-review.json @@ -1,6 +1,6 @@ { "version": 1, "paths": { - "code-review-fix.md": "#3190: the --auto convergence loop rewrote REVIEW.md every re-review iteration but never recommitted it (committed REVIEW.md stayed at iteration 1, contradicting the committed REVIEW-FIX.md), and the commit-fix step's two inline frontmatter validators exported REVIEW_PATH into a node -e body that reads process.env.FIX_REPORT_PATH — so HAS_STATUS/FIX_FRONTMATTER were always empty and REVIEW-FIX.md was never committed at all. The fix renames the exported env var to FIX_REPORT_PATH at both validator sites, stages the converged REVIEW.md alongside REVIEW-FIX.md in the single --auto docs commit (guarded on AUTO_MODE so non-auto single-pass runs are untouched), and removes the spent .iterN.md backups on successful convergence (retained on degradation for post-mortem). Growth is the deployed contract for those three coupled fixes plus inline rationale comments; the regression test is tests/code-review-fix-pipeline-regression.test.cjs." + "code-review-fix.md": "#3190: the --auto convergence loop rewrote REVIEW.md every re-review iteration but never recommitted it (committed REVIEW.md stayed at iteration 1, contradicting the committed REVIEW-FIX.md), and the commit-fix step's two inline frontmatter validators exported REVIEW_PATH into a node -e body that reads process.env.FIX_REPORT_PATH — so HAS_STATUS/FIX_FRONTMATTER were always empty and REVIEW-FIX.md was never committed at all. The fix renames the exported env var to FIX_REPORT_PATH at both validator sites, stages the converged REVIEW.md alongside REVIEW-FIX.md in the single --auto docs commit (guarded on AUTO_MODE so non-auto single-pass runs are untouched), and removes the spent .iterN.md backups on successful convergence (retained on degradation for post-mortem). Growth is the deployed contract for those three coupled fixes plus inline rationale comments; the regression test is tests/code-review-fix-pipeline-regression.test.cjs. — #3423 append (epic #1891 F8): also grew with the -> tag rename (15 chars/block, tag-token-only delta; no prose changed)." } } diff --git a/tests/emitted-drift-acks/3191-unanchored-grep-sites.json b/tests/emitted-drift-acks/3191-unanchored-grep-sites.json index c6b6ffb0f..11fa1690c 100644 --- a/tests/emitted-drift-acks/3191-unanchored-grep-sites.json +++ b/tests/emitted-drift-acks/3191-unanchored-grep-sites.json @@ -1,6 +1,6 @@ { "version": 1, "paths": { - "code-review.md": "#3191: +711 bytes. The two remaining unanchored `git log --grep=\"${PADDED_PHASE}\"` diff-base derivations (spawn_reviewer; Tier-3 was anchored in #2989) now use the anchored '[Pp]hase N([^[:alnum:]_]|$)' with --extended-regexp, and the #2989 site's trailing \\b — not a POSIX ERE token, silently matching nothing on macOS regex(3) — is replaced by the POSIX class; spawn_reviewer also gains Tier-3's parent-exists guard. The fallow structural-pre-pass.md fragment (not size-measured; hash ripple explained by its own committed change) carries the same anchoring. Supersedes the spent 2989-code-review-anchored-diff-base.json fragment." + "code-review.md": "#3191: +711 bytes. The two remaining unanchored `git log --grep=\"${PADDED_PHASE}\"` diff-base derivations (spawn_reviewer; Tier-3 was anchored in #2989) now use the anchored '[Pp]hase N([^[:alnum:]_]|$)' with --extended-regexp, and the #2989 site's trailing \\b — not a POSIX ERE token, silently matching nothing on macOS regex(3) — is replaced by the POSIX class; spawn_reviewer also gains Tier-3's parent-exists guard. The fallow structural-pre-pass.md fragment (not size-measured; hash ripple explained by its own committed change) carries the same anchoring. Supersedes the spent 2989-code-review-anchored-diff-base.json fragment. — #3423 append (epic #1891 F8): also grew 9 bytes with the -> tag rename (3 tag tokens, +3 bytes each; tag-token-only delta, no prose changed)." } } diff --git a/tests/emitted-drift-acks/3297-planphase-gaps-next-up-scope.json b/tests/emitted-drift-acks/3297-planphase-gaps-next-up-scope.json index 0deb1910f..865b3b451 100644 --- a/tests/emitted-drift-acks/3297-planphase-gaps-next-up-scope.json +++ b/tests/emitted-drift-acks/3297-planphase-gaps-next-up-scope.json @@ -1,6 +1,6 @@ { "version": 1, "paths": { - "plan-phase.md": "#3297: the bash preamble now captures --gaps planning mode into GAPS_MODE and derives GAPS_EXEC_FLAG (empty or --gaps-only), and the Next Up command substitutes ${GAPS_EXEC_FLAG} into /gsd:execute-phase {X} so a completed --gaps planning run hands off execute-phase's matching gap-closure scope (--gaps-only) instead of the whole-phase run — the literal fix for the mode-blind handoff, plus the six-line gap-mode capture/derive block and the one-paragraph rendering note that tells the agent how to substitute the flag. Standard and --reviews runs leave the flag empty, so their rendered Next Up is byte-identical to before. Growth is the write side of the fix, not incidental prose. Supersedes the spent #3218 fragment (merged into next), which also named plan-phase.md and would otherwise double-ack the same path." + "plan-phase.md": "#3297: the bash preamble now captures --gaps planning mode into GAPS_MODE and derives GAPS_EXEC_FLAG (empty or --gaps-only), and the Next Up command substitutes ${GAPS_EXEC_FLAG} into /gsd:execute-phase {X} so a completed --gaps planning run hands off execute-phase's matching gap-closure scope (--gaps-only) instead of the whole-phase run — the literal fix for the mode-blind handoff, plus the six-line gap-mode capture/derive block and the one-paragraph rendering note that tells the agent how to substitute the flag. Standard and --reviews runs leave the flag empty, so their rendered Next Up is byte-identical to before. Growth is the write side of the fix, not incidental prose. Supersedes the spent #3218 fragment (merged into next), which also named plan-phase.md and would otherwise double-ack the same path. — #3423 append (epic #1891 F8): also grew 21 bytes with the -> tag rename (7 tag tokens, +3 bytes each; tag-token-only delta, no prose changed)." } } diff --git a/tests/emitted-drift-acks/3370-execute-phase-gate-conflation.json b/tests/emitted-drift-acks/3370-execute-phase-gate-conflation.json index b1036062c..b1d9e3d53 100644 --- a/tests/emitted-drift-acks/3370-execute-phase-gate-conflation.json +++ b/tests/emitted-drift-acks/3370-execute-phase-gate-conflation.json @@ -1,7 +1,7 @@ { "version": 1, "paths": { - "execute-phase.md": "#3370: the step-3 executor-routing line now also cites #3370 — the checkpoint gate rule itself lives in the execute-phase/steps/per-plan-executor-routing.md fragment (loaded per plan in every isolation mode immediately before the dispatch prompt is composed), the same keep-the-host-lean pattern #1689/#3417 used, because the host sits under the frozen ADR-857 Phase 6 ceiling (≤93400). Net growth is 6 bytes (93386 -> 93392): the routing citation only; the rule text, which forbids the orchestrator from composing dispatch text that refuses or overrides auto-approval for the default gate=\"blocking\" (only blocking-human always surfaces), is in the fragment. Supersedes the spent #3324 fragment (merged into next), which also named execute-phase.md and would otherwise double-ack the same path.", + "execute-phase.md": "#3370: the step-3 executor-routing line now also cites #3370 — the checkpoint gate rule itself lives in the execute-phase/steps/per-plan-executor-routing.md fragment (loaded per plan in every isolation mode immediately before the dispatch prompt is composed), the same keep-the-host-lean pattern #1689/#3417 used, because the host sits under the frozen ADR-857 Phase 6 ceiling (≤93400). Net growth is 6 bytes (93386 -> 93392): the routing citation only; the rule text, which forbids the orchestrator from composing dispatch text that refuses or overrides auto-approval for the default gate=\"blocking\" (only blocking-human always surfaces), is in the fragment. Supersedes the spent #3324 fragment (merged into next), which also named execute-phase.md and would otherwise double-ack the same path. — #3423 append (epic #1891 F8): grew 12 bytes with the -> tag rename (4 tag tokens, +3 bytes each), then trimmed 8 bytes of redundant prose (dropped 'current' from the model-inheritance note; #3478's growth had left only 8 bytes of ADR-857 margin) to stay under the Phase 6 margin ceiling; net +4 bytes against the #3370 baseline.", "execute-plan.md": "#3370: the Pattern A dispatch prompt spec gained the gate-semantics clause (gate=\"blocking\" (the default) is auto-approvable in auto-mode per the executor's own checkpoint protocol, gate=\"blocking-human\" always surfaces to a human; add no instruction overriding that protocol), closing the identically-shaped dispatch-time gap on the single-plan path named in the issue. Growth ~248 bytes (38913 -> 39161, still under the DEFAULT 40 KiB ceiling). Supersedes the spent #2652 fragment (merged into next), which also named execute-plan.md and would otherwise double-ack the same path." } } diff --git a/tests/emitted-drift-acks/3423-required-reading.json b/tests/emitted-drift-acks/3423-required-reading.json new file mode 100644 index 000000000..2d69f49c3 --- /dev/null +++ b/tests/emitted-drift-acks/3423-required-reading.json @@ -0,0 +1,28 @@ +{ + "version": 1, + "paths": { + "ai-integration-phase.md": { + "reason": "#3423 (epic #1891 F8): +bytes are the -> tag rename (15 chars per block); no prose added or rewritten. No tier crossed." + }, + "diagnose-issues.md": "#3423 (epic #1891 F8): +6 bytes are the -> tag rename (2 tag tokens, +3 bytes each); no prose added or rewritten. No tier crossed.", + "eval-review.md": { + "reason": "#3423 (epic #1891 F8): +bytes are the -> tag rename (15 chars per block); no prose added or rewritten. No tier crossed." + }, + "new-milestone.md": { + "reason": "#3423 (epic #1891 F8): +bytes are the -> tag rename (15 chars per block); no prose added or rewritten. No tier crossed." + }, + "quick.md": "#3423 (epic #1891 F8): +12 bytes are the -> tag rename (4 tag tokens, +3 bytes each); no prose added or rewritten. No tier crossed.", + "secure-phase.md": { + "reason": "#3423 (epic #1891 F8): +bytes are the -> tag rename (15 chars per block); no prose added or rewritten. No tier crossed." + }, + "ui-review.md": { + "reason": "#3423 (epic #1891 F8): +bytes are the -> tag rename (15 chars per block); no prose added or rewritten. No tier crossed." + }, + "validate-phase.md": { + "reason": "#3423 (epic #1891 F8): +bytes are the -> tag rename (15 chars per block); no prose added or rewritten. No tier crossed." + }, + "verify-work.md": { + "reason": "#3423 (epic #1891 F8): +bytes are the -> tag rename (15 chars per block); no prose added or rewritten. No tier crossed." + } + } +} diff --git a/tests/executor-mvp-tdd-section.test.cjs b/tests/executor-mvp-tdd-section.test.cjs index 3cacacac9..bd3fabbb5 100644 --- a/tests/executor-mvp-tdd-section.test.cjs +++ b/tests/executor-mvp-tdd-section.test.cjs @@ -193,17 +193,21 @@ describe('bug #3099: absolute-path safety guidance in gsd-executor.md', () => { ); }); - test('execute-phase prompt anchors subagent file paths to project_root before files_to_read (#280)', () => { - const filesIdx = executePhaseSrc.indexOf(''); - assert.ok(filesIdx !== -1, 'files_to_read block not found in execute-phase.md'); + test('execute-phase prompt anchors subagent file paths to project_root before required_reading (#280)', () => { + // Anchor on the dispatch's PROJECT_ROOT computation, then require the + // nearest block to open just before it — the executor + // must be told to compute the root BEFORE reading the listed files + // (#3423 note: execute-phase carries several such blocks, so a bare + // indexOf on the tag can anchor to the wrong one). + const prIdx = executePhaseSrc.indexOf('PROJECT_ROOT=$(git rev-parse --show-toplevel'); + assert.ok(prIdx !== -1, 'executor dispatch must compute PROJECT_ROOT in the prompt'); + const filesIdx = executePhaseSrc.lastIndexOf('', prIdx); + assert.ok(filesIdx !== -1, 'required_reading block not found before the PROJECT_ROOT computation'); + assert.ok(prIdx - filesIdx < 1800, 'required_reading block must sit adjacent to the PROJECT_ROOT computation'); const dispatchSnippet = executePhaseSrc.slice(filesIdx, filesIdx + 1800); - assert.ok( - dispatchSnippet.includes('PROJECT_ROOT=$(git rev-parse --show-toplevel'), - 'executor dispatch must compute PROJECT_ROOT in the prompt before file reads', - ); assert.ok( dispatchSnippet.includes('${PROJECT_ROOT}/'), - 'executor files_to_read paths must be anchored to ${PROJECT_ROOT}/', + 'executor required_reading paths must be anchored to ${PROJECT_ROOT}/', ); }); diff --git a/tests/init.test.cjs b/tests/init.test.cjs index 788ca065d..c86742938 100644 --- a/tests/init.test.cjs +++ b/tests/init.test.cjs @@ -2878,7 +2878,7 @@ describe('#2376 — init.* path fields resolve when process cwd differs from --c // allow-test-rule: source-text-is-the-product (see #2376) // - // Checks verbatim presence of the exact edited /output blocks + // Checks verbatim presence of the exact edited /output blocks // rather than scanning the whole file for absence of the old literals: several // of those literals (e.g. .planning/PROJECT.md, .planning/config.json) remain // legitimately elsewhere in this file in orchestrator-local bash/doc-table @@ -2889,17 +2889,17 @@ describe('#2376 — init.* path fields resolve when process cwd differs from --c const content = fs.readFileSync(wfPath, 'utf8'); assert.ok(content.includes( - '\n- {research_dir}/STACK.md\n- {research_dir}/FEATURES.md\n- {research_dir}/ARCHITECTURE.md\n- {research_dir}/PITFALLS.md\n' + '\n- {research_dir}/STACK.md\n- {research_dir}/FEATURES.md\n- {research_dir}/ARCHITECTURE.md\n- {research_dir}/PITFALLS.md\n' ), 'research-synthesizer spawn must read from {research_dir}, not bare .planning/research/*.md literals'); assert.ok(content.includes('Write to: {research_dir}/SUMMARY.md'), 'research-synthesizer spawn must write to {research_dir}/SUMMARY.md, not a bare literal'); assert.ok(content.includes( - '\n- {project_path} (Project context)\n- {requirements_path} (v1 Requirements)\n- {research_dir}/SUMMARY.md (Research findings - if exists)\n- {config_path} (Granularity and mode settings)\n' + '\n- {project_path} (Project context)\n- {requirements_path} (v1 Requirements)\n- {research_dir}/SUMMARY.md (Research findings - if exists)\n- {config_path} (Granularity and mode settings)\n' ), 'roadmapper spawn must read from {project_path}/{requirements_path}/{research_dir}/{config_path}, not bare .planning literals'); assert.ok(content.includes( - '\n - {roadmap_path} (Current roadmap to revise)\n ' + '\n - {roadmap_path} (Current roadmap to revise)\n ' ), 'roadmapper revision spawn must read {roadmap_path}, not a bare .planning/ROADMAP.md literal'); }); @@ -2909,13 +2909,13 @@ describe('#2376 — init.* path fields resolve when process cwd differs from --c const content = fs.readFileSync(wfPath, 'utf8'); assert.ok(content.includes( - '\n- {research_dir}/STACK.md\n- {research_dir}/FEATURES.md\n- {research_dir}/ARCHITECTURE.md\n- {research_dir}/PITFALLS.md\n' + '\n- {research_dir}/STACK.md\n- {research_dir}/FEATURES.md\n- {research_dir}/ARCHITECTURE.md\n- {research_dir}/PITFALLS.md\n' ), 'research-synthesizer spawn must read from {research_dir}, not bare .planning/research/*.md literals'); assert.ok(content.includes('Write to: {research_dir}/SUMMARY.md'), 'research-synthesizer spawn must write to {research_dir}/SUMMARY.md, not a bare literal'); assert.ok(content.includes( - '\n- {project_path}\n- {requirements_path}\n- {research_dir}/SUMMARY.md (if exists)\n- {config_path}\n- {milestones_path}\n' + '\n- {project_path}\n- {requirements_path}\n- {research_dir}/SUMMARY.md (if exists)\n- {config_path}\n- {milestones_path}\n' ), 'roadmapper spawn must read from {project_path}/{requirements_path}/{research_dir}/{config_path}/{milestones_path}, not bare .planning literals'); }); diff --git a/tests/quick-commit-boundary.test.cjs b/tests/quick-commit-boundary.test.cjs index 18660148c..eef126e95 100644 --- a/tests/quick-commit-boundary.test.cjs +++ b/tests/quick-commit-boundary.test.cjs @@ -174,8 +174,8 @@ describe('quick.md pre-dispatch PLAN.md commit (#2432)', () => { const executorTask = content.indexOf('subagent_type="gsd-executor"'); assert.ok(executorTask !== -1, 'executor Task() spawn must exist'); // Find the files_to_read block near the executor spawn - const filesBlock = content.lastIndexOf('', executorTask); - const filesBlockEnd = content.indexOf('', filesBlock); + const filesBlock = content.lastIndexOf('', executorTask); + const filesBlockEnd = content.indexOf('', filesBlock); const filesContent = content.slice(filesBlock, filesBlockEnd); assert.ok( filesContent.includes('QUICK_DIR') || filesContent.includes('.planning/quick'), @@ -219,7 +219,7 @@ describe('quick.md pre-dispatch PLAN.md commit (#2432)', () => { 'executor prompt must materialize PLAN.md from git show : when absent (#1265)' ); assert.ok( - executorPrompt.indexOf('git show') < executorPrompt.indexOf(''), + executorPrompt.indexOf('git show') < executorPrompt.indexOf(''), 'PLAN.md materialization must be a first action before files_to_read can prime paths (#1265)' ); });