* fix(#1521): resolve own runtime + worktrees-off for all non-Claude installs Generalizes the Codex-only #1515/#1519 fix to every non-Claude runtime, and wires it into the real install path (where it was previously dead-on-arrival). Root causes: 1. The runtime-default stamping lived only in `_applyRuntimeRewrites`, but the installer emits `gsd-core/workflows/*.md` via `copyWithPathReplacement`, which never calls it — so a real `--codex`/`--cursor`/etc. install emitted `--default claude` and worktrees-on. RUNTIME mis-resolved to claude and the workflow ran executors unisolated against the main checkout. (#1515/#1519 were also dead-on-arrival in real installs; this repairs them.) 2. Only `case 'codex'` was stamped; every other non-Claude runtime kept the Claude default. Fix: - New `_stampNonClaudeRuntimeDefaults(content, runtime)` (single shared helper) stamps `--default <runtime>` + `use_worktrees=false` for every `runtime != claude`; called from both `_applyRuntimeRewrites` and, crucially, `copyWithPathReplacement` in bin/install.js (the real workflow emit path). - Generalize the fail-closed worktree guard `= codex` -> `!= claude` in execute-phase/quick/diagnose-issues (worktree isolation is Claude-Code-only). - Flip manager/autonomous inline-vs-background gating to `codex -> background, everything-else -> inline` (research: only Codex can background-nest the pipeline's subagents; all others run inline, which they support). Worktree-capability determination is research-backed (official docs for all 14 non-Claude runtimes: none honor GSD's isolation="worktree" mechanism, only Codex background-nests). New end-to-end real-install test asserts the EMITTED workflow is stamped — the regression guard that would have caught the dead-on-arrival bug. Closes #1521 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013vX5eUtWa2wsZEyeMf5i3r * chore(#1521): backfill changeset PR number (#1537) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013vX5eUtWa2wsZEyeMf5i3r --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -61,7 +61,7 @@ fi
|
||||
|
||||
When `--only` is set, also set `FROM_PHASE` to the same value so existing filter logic applies.
|
||||
|
||||
When `--interactive` is set, discuss runs inline with questions (not auto-answered). On runtimes where a backgrounded agent can spawn subagents, plan and execute are dispatched as background agents — keeping the main context lean (only discuss conversations accumulate) and enabling overlap. On Claude Code, where a backgrounded agent cannot nest subagents, plan and execute run inline to preserve worktree isolation and independent verification, so they run sequentially and their work accumulates in the main context. Either way, user input is preserved on all design decisions.
|
||||
When `--interactive` is set, discuss runs inline with questions (not auto-answered). On Codex, where a backgrounded agent can still spawn subagents, plan and execute are dispatched as background agents — keeping the main context lean (only discuss conversations accumulate) and enabling overlap. On every other runtime (Claude Code and all other non-Codex runtimes), backgrounded agents cannot reliably nest subagents, so plan and execute run inline to preserve worktree isolation and independent verification, and phases run sequentially with their work accumulating in the main context. Either way, user input is preserved on all design decisions.
|
||||
|
||||
When `PLAN_STRATEGY=converge`, the planning step MUST invoke the plan-review convergence workflow instead of `gsd-plan-phase`. `--cross-ai` is an alias for `--converge`. Forward `CONVERGENCE_ARGS` exactly as parsed so reviewer flags and `--max-cycles N` retain the same meaning as they have on `/gsd:plan-review-convergence`.
|
||||
|
||||
@@ -111,7 +111,7 @@ Display startup banner:
|
||||
If `ONLY_PHASE` is set, display: `Single phase mode: Phase ${ONLY_PHASE}`
|
||||
Else if `FROM_PHASE` is set, display: `Starting from phase ${FROM_PHASE}`
|
||||
If `TO_PHASE` is set, display: `Stopping after phase ${TO_PHASE}`
|
||||
If `INTERACTIVE` is set, display: `Mode: Interactive (discuss inline, plan+execute in background)`
|
||||
If `INTERACTIVE` is set, display: `Mode: Interactive (discuss inline, plan+execute inline — background on Codex only)`
|
||||
If `PLAN_STRATEGY` is `converge`, display: `Planning: Plan-review convergence enabled`
|
||||
|
||||
</step>
|
||||
@@ -357,27 +357,13 @@ UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1)
|
||||
|
||||
**3b. Plan**
|
||||
|
||||
**If `INTERACTIVE` is set:** Background dispatch is only safe where a backgrounded agent can still spawn subagents. On Claude Code a backgrounded agent has no `Agent`/`Task` tool, so the plan-checker never runs and `workflow.plan_check` silently degrades to a self-check. Resolve the runtime first:
|
||||
**If `INTERACTIVE` is set:** Background dispatch is only safe on a runtime where a backgrounded agent can still nest the pipeline's subagents (plan-checker / worktree executors / verifier). Among supported runtimes only **Codex** (`spawn_agent`) can do this; Claude Code's backgrounded agents have no `Agent`/`Task` tool, and every other runtime either prohibits nested subagents or disables them by default. So run **inline** everywhere except Codex, which is dispatched in the background. Resolve the runtime first:
|
||||
|
||||
```bash
|
||||
RUNTIME=$(gsd_run query config-get runtime --default claude --raw 2>/dev/null || echo "claude")
|
||||
```
|
||||
|
||||
- **On Claude Code (`RUNTIME` is `claude`):** Run plan **inline** (do NOT background) so the plan-checker runs. The next phase's discuss does not overlap planning here — correctness over overlap.
|
||||
|
||||
- If `PLAN_STRATEGY=converge`:
|
||||
|
||||
```
|
||||
Skill(skill="gsd-plan-review-convergence", args="${PHASE_NUM} ${CONVERGENCE_ARGS}")
|
||||
```
|
||||
|
||||
- Otherwise (local planning):
|
||||
|
||||
```
|
||||
Skill(skill="gsd-plan-phase", args="${PHASE_NUM}")
|
||||
```
|
||||
|
||||
- **On other runtimes:** Dispatch plan as a background agent to keep the main context lean. While plan runs, the workflow can immediately start discussing the next phase (see step 4).
|
||||
- **If `RUNTIME` is `codex`:** Dispatch plan as a background agent to keep the main context lean. While plan runs, the workflow can immediately start discussing the next phase (see step 4).
|
||||
|
||||
- If `PLAN_STRATEGY=converge`, print: `◆ Spawning background plan-convergence loop for phase ${PHASE_NUM}... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)`
|
||||
|
||||
@@ -401,6 +387,20 @@ RUNTIME=$(gsd_run query config-get runtime --default claude --raw 2>/dev/null ||
|
||||
|
||||
Store the agent task_id. After discuss for the next phase completes (or if no next phase), wait for the plan agent to finish before proceeding to execute.
|
||||
|
||||
- **Otherwise (Claude Code or any other non-Codex runtime):** Run plan **inline** (do NOT background) so the plan-checker runs. The next phase's discuss does not overlap planning here — correctness over overlap.
|
||||
|
||||
- If `PLAN_STRATEGY=converge`:
|
||||
|
||||
```
|
||||
Skill(skill="gsd-plan-review-convergence", args="${PHASE_NUM} ${CONVERGENCE_ARGS}")
|
||||
```
|
||||
|
||||
- Otherwise (local planning):
|
||||
|
||||
```
|
||||
Skill(skill="gsd-plan-phase", args="${PHASE_NUM}")
|
||||
```
|
||||
|
||||
**If `INTERACTIVE` is NOT set (default):** Run plan inline.
|
||||
|
||||
If `PLAN_STRATEGY=converge`, run the convergence loop:
|
||||
@@ -419,19 +419,13 @@ Verify plan produced output — re-run `init phase-op` and check `has_plans`. If
|
||||
|
||||
**3c. Execute**
|
||||
|
||||
**If `INTERACTIVE` is set:** Wait for the plan agent to complete (if not already) and verify plans exist. Background dispatch is only safe where a backgrounded agent can still spawn subagents. On Claude Code a backgrounded agent has no `Agent`/`Task` tool, so the per-plan worktree-isolated executors and the verifier never run (`workflow.use_worktrees` and `workflow.verifier` silently degrade). Resolve the runtime first:
|
||||
**If `INTERACTIVE` is set:** Wait for the plan agent to complete (if not already) and verify plans exist. Background dispatch is only safe on a runtime where a backgrounded agent can still nest the pipeline's subagents (plan-checker / worktree executors / verifier). Among supported runtimes only **Codex** (`spawn_agent`) can do this; Claude Code's backgrounded agents have no `Agent`/`Task` tool, and every other runtime either prohibits nested subagents or disables them by default. So run **inline** everywhere except Codex, which is dispatched in the background. Resolve the runtime first:
|
||||
|
||||
```bash
|
||||
RUNTIME=$(gsd_run query config-get runtime --default claude --raw 2>/dev/null || echo "claude")
|
||||
```
|
||||
|
||||
- **On Claude Code (`RUNTIME` is `claude`):** Run execute **inline** (do NOT background) so worktree isolation and verification run:
|
||||
|
||||
```
|
||||
Skill(skill="gsd-execute-phase", args="${PHASE_NUM} --no-transition")
|
||||
```
|
||||
|
||||
- **On other runtimes:** Dispatch execute as a background agent:
|
||||
- **If `RUNTIME` is `codex`:** Dispatch execute as a background agent:
|
||||
|
||||
```
|
||||
Agent(
|
||||
@@ -443,6 +437,12 @@ Agent(
|
||||
|
||||
Store the agent task_id. The workflow can now start discussing the next phase while this phase executes in the background. Before starting post-execution routing for this phase, wait for the execute agent to complete.
|
||||
|
||||
- **Otherwise (Claude Code or any other non-Codex runtime):** Run execute **inline** (do NOT background) so worktree isolation and verification run:
|
||||
|
||||
```
|
||||
Skill(skill="gsd-execute-phase", args="${PHASE_NUM} --no-transition")
|
||||
```
|
||||
|
||||
**If `INTERACTIVE` is NOT set (default):** Run execute inline as before.
|
||||
|
||||
```
|
||||
@@ -656,12 +656,12 @@ Check for blockers in the Blockers/Concerns section. If blockers are found, go t
|
||||
|
||||
If incomplete phases remain: proceed to next phase, loop back to execute_phase.
|
||||
|
||||
**Interactive mode overlap:** When `INTERACTIVE` is set, the iterate step enables pipeline parallelism **on runtimes where a backgrounded agent can spawn subagents** (on Claude Code, plan/execute run inline — see 3b/3c — so there is no overlap and phases run sequentially):
|
||||
**Interactive mode overlap:** When `INTERACTIVE` is set, the iterate step enables pipeline parallelism **on Codex** (on every other runtime, plan/execute run inline — see 3b/3c — so there is no overlap and phases run sequentially):
|
||||
1. After discuss completes for Phase N, dispatch plan+execute as background agents
|
||||
2. Immediately start discuss for Phase N+1 (the next incomplete phase) while Phase N builds
|
||||
3. Before starting plan for Phase N+1, wait for Phase N's execute agent to complete and handle its post-execution routing (verification, gap closure, etc.)
|
||||
|
||||
This means the user is always answering discuss questions (lightweight, interactive) while the heavy work (planning, code generation) runs in the background. The main context only accumulates discuss conversations — plan and execute contexts are isolated in their agents. (On Claude Code, plan and execute run inline, so they run sequentially and their work accumulates in the main context.)
|
||||
This means the user is always answering discuss questions (lightweight, interactive) while the heavy work (planning, code generation) runs in the background. The main context only accumulates discuss conversations — plan and execute contexts are isolated in their agents. (On Claude Code and all other non-Codex runtimes, plan and execute run inline, so they run sequentially and their work accumulates in the main context.)
|
||||
|
||||
If all phases complete, proceed to lifecycle step.
|
||||
|
||||
@@ -873,9 +873,9 @@ When any phase operation fails or a blocker is detected, present 3 options via A
|
||||
- [ ] `--to N` handle_blocker resume message preserves --to flag
|
||||
- [ ] `--to N` skips lifecycle when not all milestone phases complete
|
||||
- [ ] `--interactive` runs discuss inline via gsd-discuss-phase (asks questions, waits for user)
|
||||
- [ ] `--interactive` dispatches plan and execute as background agents on runtimes that support nested background dispatch; runs them inline on Claude Code
|
||||
- [ ] `--interactive` enables pipeline parallelism (discuss Phase N+1 while Phase N builds) on runtimes with background dispatch; phases run sequentially on Claude Code
|
||||
- [ ] `--interactive` main context only accumulates discuss conversations on runtimes with background dispatch (on Claude Code, inline plan/execute also accumulate)
|
||||
- [ ] `--interactive` dispatches plan and execute as background agents on Codex (the only runtime where a backgrounded agent can nest subagents); runs them inline on all other runtimes
|
||||
- [ ] `--interactive` enables pipeline parallelism (discuss Phase N+1 while Phase N builds) on Codex; phases run sequentially on all other runtimes
|
||||
- [ ] `--interactive` main context only accumulates discuss conversations on Codex (on all other runtimes, inline plan/execute also accumulate)
|
||||
- [ ] `--interactive` waits for background agents before post-execution routing
|
||||
- [ ] `--interactive` compatible with `--only`, `--from`, and `--to` flags
|
||||
- [ ] `--converge` routes planning through `gsd-plan-review-convergence`
|
||||
|
||||
@@ -61,8 +61,8 @@ gaps = [
|
||||
_GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="$HOME/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
|
||||
USE_WORKTREES=$(gsd_run query config-get workflow.use_worktrees --raw 2>/dev/null || echo "true")
|
||||
RUNTIME=$(gsd_run query config-get runtime --default claude --raw 2>/dev/null || echo "claude")
|
||||
if [ "$RUNTIME" = "codex" ] && [ "$USE_WORKTREES" != "false" ]; then
|
||||
echo "FATAL: Codex worktree isolation is unsupported. Set workflow.use_worktrees=false or use a runtime with Agent isolation=\"worktree\" support." >&2
|
||||
if [ "$RUNTIME" != "claude" ] && [ "$USE_WORKTREES" != "false" ]; then
|
||||
echo "FATAL: git worktree isolation (isolation=\"worktree\") is unsupported on runtime '$RUNTIME' — it would run executor agents unisolated against the main checkout. Set workflow.use_worktrees=false." >&2
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
@@ -96,8 +96,8 @@ USE_WORKTREES=$(gsd_run query config-get workflow.use_worktrees --raw 2>/dev/nul
|
||||
EXECUTOR_STALL_INTERVAL_MINUTES=$(gsd_run query config-get executor.stall_detect_interval_minutes 2>/dev/null || echo "5")
|
||||
EXECUTOR_STALL_THRESHOLD_MINUTES=$(gsd_run query config-get executor.stall_threshold_minutes 2>/dev/null || echo "10")
|
||||
|
||||
if [ "$RUNTIME" = "codex" ] && [ "$USE_WORKTREES" != "false" ]; then
|
||||
echo "FATAL: Codex execute-phase worktree isolation is unsupported. Set workflow.use_worktrees=false or use a runtime with Agent isolation=\"worktree\" support." >&2
|
||||
if [ "$RUNTIME" != "claude" ] && [ "$USE_WORKTREES" != "false" ]; then
|
||||
echo "FATAL: git worktree isolation (isolation=\"worktree\") is unsupported on runtime '$RUNTIME' — it would run executor agents unisolated against the main checkout. Set workflow.use_worktrees=false." >&2
|
||||
exit 1
|
||||
fi
|
||||
# Sweep orphaned locked worktrees from prior crashed sessions before spawning executors (#3707).
|
||||
@@ -113,7 +113,7 @@ if [ "$RUNTIME" = "claude" ] && [ "$USE_WORKTREES" != "false" ]; then
|
||||
fi
|
||||
fi
|
||||
```
|
||||
Codex maps subagents to `spawn_agent`, which has no direct Codex mapping for Claude Code's `isolation="worktree"` parameter. Failing closed prevents main-checkout edits while the workflow believes agents are isolated.
|
||||
`isolation="worktree"` is a Claude-Code-specific agent primitive; no other runtime can honor it (Codex maps subagents to `spawn_agent`, others prohibit or omit worktree binding). Failing closed prevents main-checkout edits while the workflow believes agents are isolated.
|
||||
|
||||
If the project uses git submodules, worktree isolation is unsafe **only when a plan touches a submodule path** — the executor commit protocol cannot correctly handle submodule commits inside isolated worktrees. The previous behavior unconditionally disabled worktree isolation whenever `.gitmodules` existed, which penalised every plan in a submodule project even when the plan was nowhere near a submodule. Compute submodule paths once and intersect them per-plan with the plan's declared `files_modified` frontmatter.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<purpose>
|
||||
|
||||
Interactive command center for managing a milestone from a single terminal. Shows a dashboard of all phases with visual status, dispatches discuss inline and plan/execute as background agents, and loops back to the dashboard after each action. Enables parallel phase work from one terminal.
|
||||
Interactive command center for managing a milestone from a single terminal. Shows a dashboard of all phases with visual status, dispatches discuss inline and runs plan/execute inline (backgrounded only on Codex), and loops back to the dashboard after each action. Enables parallel phase work from one terminal.
|
||||
|
||||
</purpose>
|
||||
|
||||
@@ -45,7 +45,7 @@ Display startup banner:
|
||||
{milestone_version} — {milestone_name}
|
||||
{phase_count} phases · {completed_count} complete
|
||||
|
||||
✓ Discuss → inline ◆ Plan/Execute → background
|
||||
✓ Discuss → inline ◆ Plan/Execute → inline (background on Codex)
|
||||
Dashboard auto-refreshes when background work is active.
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
```
|
||||
@@ -221,8 +221,8 @@ Go to exit step.
|
||||
|
||||
When the user selects a compound option, behavior depends on the runtime — the Plan Phase N / Execute Phase N handlers below resolve it via `gsd_run query config-get runtime`:
|
||||
|
||||
- **On Claude Code:** a backgrounded agent cannot nest the pipeline's subagents, so run the chosen plan/execute step(s) **inline** via their handlers below (in order), then run the inline discuss. There is no overlap.
|
||||
- **On other runtimes:** **Spawn all background agents first** (plan/execute) — dispatch them in parallel using the Plan Phase N / Execute Phase N handlers below — then run the inline discuss; the background agents continue while you discuss.
|
||||
- **On Codex:** **Spawn all background agents first** (plan/execute) — dispatch them in parallel using the Plan Phase N / Execute Phase N handlers below — then run the inline discuss; the background agents continue while you discuss.
|
||||
- **Otherwise (Claude Code or any other non-Codex runtime):** a backgrounded agent cannot reliably nest the pipeline's subagents, so run the chosen plan/execute step(s) **inline** via their handlers below (in order), then run the inline discuss. There is no overlap.
|
||||
|
||||
Inline discuss:
|
||||
|
||||
@@ -244,27 +244,13 @@ After discuss completes, loop back to dashboard step.
|
||||
|
||||
### Plan Phase N
|
||||
|
||||
Planning runs autonomously. **First resolve the runtime.** On Claude Code a backgrounded agent has no `Agent`/`Task` tool, so it cannot spawn the plan-checker the pipeline relies on — backgrounding it there silently turns `workflow.plan_check` into a self-check. So run plan **inline** on Claude Code, and **background** it only on runtimes where a backgrounded agent can still nest subagents.
|
||||
Planning runs autonomously. **First resolve the runtime.** Background dispatch is only safe on a runtime where a backgrounded agent can still nest the pipeline's subagents (plan-checker / worktree executors / verifier). Among supported runtimes only **Codex** (`spawn_agent`) can do this; Claude Code's backgrounded agents have no `Agent`/`Task` tool, and every other runtime either prohibits nested subagents or disables them by default. So run **inline** everywhere except Codex, which is dispatched in the background.
|
||||
|
||||
```bash
|
||||
RUNTIME=$(gsd_run query config-get runtime --default claude --raw 2>/dev/null || echo "claude")
|
||||
```
|
||||
|
||||
**If `RUNTIME` is `claude` (Claude Code):** Run plan inline so the plan-checker and quality gates actually run — do NOT wrap it in `Agent(run_in_background=true, …)`:
|
||||
|
||||
```
|
||||
Skill(skill="gsd-plan-phase", args="{N} --auto {manager_flags.plan}")
|
||||
```
|
||||
|
||||
Display while it runs:
|
||||
|
||||
```
|
||||
◆ Planning Phase {N}: {phase_name}... (runs inline so the plan-checker runs — the dashboard resumes when it returns, ~1–5 min; expected, not a freeze)
|
||||
```
|
||||
|
||||
Then loop back to dashboard step.
|
||||
|
||||
**If `RUNTIME` is not `claude` (e.g. Codex):** Spawn a background agent that delegates to the Skill pipeline with any configured flags:
|
||||
**If `RUNTIME` is `codex`:** Spawn a background agent that delegates to the Skill pipeline with any configured flags:
|
||||
|
||||
```
|
||||
Agent(
|
||||
@@ -286,7 +272,7 @@ Important: You are running in the background. Do NOT use AskUserQuestion — mak
|
||||
)
|
||||
```
|
||||
|
||||
> **ORCHESTRATOR RULE — NON-CLAUDE RUNTIME**: After calling Agent() above with `run_in_background=true`, do NOT do any planning work for this phase independently. Return to the dashboard immediately and wait for the background agent to report back. Only resume planning-related work when the subagent result is available.
|
||||
> **ORCHESTRATOR RULE — CODEX RUNTIME**: After calling Agent() above with `run_in_background=true`, do NOT do any planning work for this phase independently. Return to the dashboard immediately and wait for the background agent to report back. Only resume planning-related work when the subagent result is available.
|
||||
|
||||
Display:
|
||||
|
||||
@@ -296,29 +282,29 @@ Display:
|
||||
|
||||
Loop back to dashboard step.
|
||||
|
||||
### Execute Phase N
|
||||
|
||||
Execution runs autonomously. **First resolve the runtime.** On Claude Code a backgrounded agent has no `Agent`/`Task` tool, so it cannot spawn the per-plan worktree-isolated executors or the verifier — backgrounding it there silently disables `workflow.use_worktrees` isolation and `workflow.verifier`. So run execute **inline** on Claude Code, and **background** it only on runtimes where a backgrounded agent can still nest subagents.
|
||||
|
||||
```bash
|
||||
RUNTIME=$(gsd_run query config-get runtime --default claude --raw 2>/dev/null || echo "claude")
|
||||
```
|
||||
|
||||
**If `RUNTIME` is `claude` (Claude Code):** Run execute inline so worktree isolation and the verifier actually run — do NOT wrap it in `Agent(run_in_background=true, …)`:
|
||||
**Otherwise (Claude Code or any other non-Codex runtime):** Run plan inline so the plan-checker and quality gates actually run — do NOT wrap it in `Agent(run_in_background=true, …)`:
|
||||
|
||||
```
|
||||
Skill(skill="gsd-execute-phase", args="{N} {manager_flags.execute}")
|
||||
Skill(skill="gsd-plan-phase", args="{N} --auto {manager_flags.plan}")
|
||||
```
|
||||
|
||||
Display while it runs:
|
||||
|
||||
```
|
||||
◆ Executing Phase {N}: {phase_name}... (runs inline so worktree isolation and verification run — the dashboard resumes when it returns; expected, not a freeze)
|
||||
◆ Planning Phase {N}: {phase_name}... (runs inline so the plan-checker runs — the dashboard resumes when it returns, ~1–5 min; expected, not a freeze)
|
||||
```
|
||||
|
||||
Then loop back to dashboard step.
|
||||
|
||||
**If `RUNTIME` is not `claude` (e.g. Codex):** Spawn a background agent that delegates to the Skill pipeline with any configured flags:
|
||||
### Execute Phase N
|
||||
|
||||
Execution runs autonomously. **First resolve the runtime.** Background dispatch is only safe on a runtime where a backgrounded agent can still nest the pipeline's subagents (plan-checker / worktree executors / verifier). Among supported runtimes only **Codex** (`spawn_agent`) can do this; Claude Code's backgrounded agents have no `Agent`/`Task` tool, and every other runtime either prohibits nested subagents or disables them by default. So run **inline** everywhere except Codex, which is dispatched in the background.
|
||||
|
||||
```bash
|
||||
RUNTIME=$(gsd_run query config-get runtime --default claude --raw 2>/dev/null || echo "claude")
|
||||
```
|
||||
|
||||
**If `RUNTIME` is `codex`:** Spawn a background agent that delegates to the Skill pipeline with any configured flags:
|
||||
|
||||
```
|
||||
Agent(
|
||||
@@ -340,7 +326,7 @@ Important: You are running in the background. Do NOT use AskUserQuestion — mak
|
||||
)
|
||||
```
|
||||
|
||||
> **ORCHESTRATOR RULE — NON-CLAUDE RUNTIME**: After calling Agent() above with `run_in_background=true`, do NOT do any execution work for this phase independently. Return to the dashboard immediately and wait for the background agent to report back. Only resume execution-related work when the subagent result is available.
|
||||
> **ORCHESTRATOR RULE — CODEX RUNTIME**: After calling Agent() above with `run_in_background=true`, do NOT do any execution work for this phase independently. Return to the dashboard immediately and wait for the background agent to report back. Only resume execution-related work when the subagent result is available.
|
||||
|
||||
Display:
|
||||
|
||||
@@ -350,6 +336,20 @@ Display:
|
||||
|
||||
Loop back to dashboard step.
|
||||
|
||||
**Otherwise (Claude Code or any other non-Codex runtime):** Run execute inline so worktree isolation and the verifier actually run — do NOT wrap it in `Agent(run_in_background=true, …)`:
|
||||
|
||||
```
|
||||
Skill(skill="gsd-execute-phase", args="{N} {manager_flags.execute}")
|
||||
```
|
||||
|
||||
Display while it runs:
|
||||
|
||||
```
|
||||
◆ Executing Phase {N}: {phase_name}... (runs inline so worktree isolation and verification run — the dashboard resumes when it returns; expected, not a freeze)
|
||||
```
|
||||
|
||||
Then loop back to dashboard step.
|
||||
|
||||
</step>
|
||||
|
||||
<step name="background_completion">
|
||||
@@ -422,8 +422,8 @@ Display final status with progress bar:
|
||||
- [ ] Dependency resolution: blocked phases show which deps are missing
|
||||
- [ ] Recommendations prioritize: execute > plan > discuss
|
||||
- [ ] Discuss phases run inline via Skill() — interactive questions work
|
||||
- [ ] Plan phases spawn background Task agents — return to dashboard immediately
|
||||
- [ ] Execute phases spawn background Task agents — return to dashboard immediately
|
||||
- [ ] Plan phases run inline (or as background Task agents on Codex) — dashboard resumes when complete
|
||||
- [ ] Execute phases run inline (or as background Task agents on Codex) — dashboard resumes when complete
|
||||
- [ ] Dashboard refreshes pick up changes from background agents via disk state
|
||||
- [ ] Background agent completion triggers notification and dashboard refresh
|
||||
- [ ] Background agent errors present retry/skip options
|
||||
|
||||
@@ -139,8 +139,8 @@ Parse JSON for: `planner_model`, `executor_model`, `checker_model`, `verifier_mo
|
||||
```bash
|
||||
USE_WORKTREES=$(gsd_run query config-get workflow.use_worktrees --raw 2>/dev/null || echo "true")
|
||||
RUNTIME=$(gsd_run query config-get runtime --default claude --raw 2>/dev/null || echo "claude")
|
||||
if [ "$RUNTIME" = "codex" ] && [ "$USE_WORKTREES" != "false" ]; then
|
||||
echo "FATAL: Codex worktree isolation is unsupported. Set workflow.use_worktrees=false or use a runtime with Agent isolation=\"worktree\" support." >&2
|
||||
if [ "$RUNTIME" != "claude" ] && [ "$USE_WORKTREES" != "false" ]; then
|
||||
echo "FATAL: git worktree isolation (isolation=\"worktree\") is unsupported on runtime '$RUNTIME' — it would run executor agents unisolated against the main checkout. Set workflow.use_worktrees=false." >&2
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user