fix(worktree): executor agents verify and fix branch base on Windows

When EnterWorktree creates a branch from main instead of the current HEAD
(a known issue on Windows), executor agents now detect the mismatch and
reset their branch base to the correct commit before starting work.

- execute-phase: capture EXPECTED_BASE before spawning, inject
  <worktree_branch_check> block into executor prompts
- execute-plan: document Pattern A worktree_branch_check requirement
- quick.md: inject worktree_branch_check into executor prompt
- diagnose-issues: inject worktree_branch_check into debugger prompts
- settings: add workflow.use_worktrees option so Windows users can
  disable worktree isolation via /gsd:settings without editing files

Closes #1510

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-04-03 11:12:36 -04:00
parent 9b5458d1ff
commit 9b3e08926e
5 changed files with 57 additions and 3 deletions

View File

@@ -88,6 +88,7 @@ This runs in parallel - all gaps investigated simultaneously.
```bash
AGENT_SKILLS_DEBUGGER=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" agent-skills gsd-debugger 2>/dev/null)
EXPECTED_BASE=$(git rev-parse HEAD)
```
**Spawn debug agents in parallel:**
@@ -96,7 +97,7 @@ For each gap, fill the debug-subagent-prompt template and spawn:
```
Task(
prompt=filled_debug_subagent_prompt + "\n\n<files_to_read>\n- {phase_dir}/{phase_num}-UAT.md\n- .planning/STATE.md\n</files_to_read>\n${AGENT_SKILLS_DEBUGGER}",
prompt=filled_debug_subagent_prompt + "\n\n<worktree_branch_check>\nFIRST ACTION: run git merge-base HEAD {EXPECTED_BASE} — if result differs from {EXPECTED_BASE}, run git reset --soft {EXPECTED_BASE} to correct the branch base (fixes Windows EnterWorktree creating branches from main).\n</worktree_branch_check>\n\n<files_to_read>\n- {phase_dir}/{phase_num}-UAT.md\n- .planning/STATE.md\n</files_to_read>\n${AGENT_SKILLS_DEBUGGER}",
subagent_type="gsd-debugger",
${USE_WORKTREES !== "false" ? 'isolation="worktree",' : ''}
description="Debug: {truth_short}"

View File

@@ -244,6 +244,11 @@ Execute each selected wave in sequence. Within a wave: parallel if `PARALLELIZAT
**Worktree mode** (`USE_WORKTREES` is not `false`):
Before spawning, capture the current HEAD:
```bash
EXPECTED_BASE=$(git rev-parse HEAD)
```
```
Task(
subagent_type="gsd-executor",
@@ -256,6 +261,29 @@ Execute each selected wave in sequence. Within a wave: parallel if `PARALLELIZAT
Commit each task atomically. Create SUMMARY.md. Update STATE.md and ROADMAP.md.
</objective>
<worktree_branch_check>
FIRST ACTION before any other work: verify this worktree's branch is based on the correct commit.
Run:
```bash
ACTUAL_BASE=$(git merge-base HEAD {EXPECTED_BASE})
CURRENT_HEAD=$(git rev-parse HEAD)
```
If `ACTUAL_BASE` != `{EXPECTED_BASE}` (i.e. the worktree branch was created from an older
base such as `main` instead of the feature branch HEAD), rebase onto the correct base:
```bash
git rebase --onto {EXPECTED_BASE} $(git rev-parse --abbrev-ref HEAD~1 2>/dev/null || git rev-parse HEAD^) HEAD 2>/dev/null || true
# If rebase fails or is a no-op, reset the branch to start from the correct base:
git reset --soft {EXPECTED_BASE}
```
If `ACTUAL_BASE` == `{EXPECTED_BASE}`: the branch base is correct, proceed immediately.
This check fixes a known issue on Windows where `EnterWorktree` creates branches from
`main` instead of the current feature branch HEAD.
</worktree_branch_check>
<parallel_execution>
You are running as a PARALLEL executor agent. Use --no-verify on all git
commits to avoid pre-commit hook contention with other agents. The

View File

@@ -72,7 +72,7 @@ grep -n "type=\"checkpoint" .planning/phases/XX-name/{phase}-{plan}-PLAN.md
| Verify-only | B (segmented) | Segments between checkpoints. After none/human-verify → SUBAGENT. After decision/human-action → MAIN |
| Decision | C (main) | Execute entirely in main context |
**Pattern A:** init_agent_tracking → spawn Task(subagent_type="gsd-executor", model=executor_model) with prompt: execute plan at [path], autonomous, all tasks + SUMMARY + commit, follow deviation/auth rules, report: plan name, tasks, SUMMARY path, commit hash → track agent_id → wait → update tracking → report. **Include `isolation="worktree"` only if `workflow.use_worktrees` is not `false`** (read via `config-get workflow.use_worktrees`).
**Pattern A:** init_agent_tracking → capture `EXPECTED_BASE=$(git rev-parse HEAD)` → spawn Task(subagent_type="gsd-executor", model=executor_model) with prompt: execute plan at [path], autonomous, all tasks + SUMMARY + commit, follow deviation/auth rules, report: plan name, tasks, SUMMARY path, commit hash → track agent_id → wait → update tracking → report. **Include `isolation="worktree"` only if `workflow.use_worktrees` is not `false`** (read via `config-get workflow.use_worktrees`). **When using `isolation="worktree"`, include a `<worktree_branch_check>` block in the prompt** instructing the executor to run `git merge-base HEAD {EXPECTED_BASE}` and, if the result differs from `{EXPECTED_BASE}`, reset the branch base with `git reset --soft {EXPECTED_BASE}` before starting work. This corrects a known issue on Windows where `EnterWorktree` creates branches from `main` instead of the feature branch HEAD.
**Pattern B:** Execute segment-by-segment. Autonomous segments: spawn subagent for assigned tasks only (no SUMMARY/commit). Checkpoints: main context. After all segments: aggregate, create SUMMARY, commit. See segment_execution.

View File

@@ -550,6 +550,11 @@ Offer: 1) Force proceed, 2) Abort
**Step 6: Spawn executor**
Capture current HEAD before spawning (used for worktree branch check):
```bash
EXPECTED_BASE=$(git rev-parse HEAD)
```
Spawn gsd-executor with plan reference:
```
@@ -557,6 +562,15 @@ Task(
prompt="
Execute quick task ${quick_id}.
${USE_WORKTREES !== "false" ? `
<worktree_branch_check>
FIRST ACTION before any other work: verify this worktree branch is based on the correct commit.
Run: git merge-base HEAD ${EXPECTED_BASE}
If the result differs from ${EXPECTED_BASE}, run: git reset --soft ${EXPECTED_BASE}
This corrects a known issue on Windows where EnterWorktree creates branches from main instead of the feature branch HEAD.
</worktree_branch_check>
` : ''}
<files_to_read>
- ${QUICK_DIR}/${quick_id}-PLAN.md (Plan)
- .planning/STATE.md (Project state)

View File

@@ -34,6 +34,7 @@ Parse current values (default to `true` if not present):
- `workflow.ui_safety_gate` — prompt to run /gsd:ui-phase before planning frontend phases (default: true if absent)
- `model_profile` — which model each agent uses (default: `balanced`)
- `git.branching_strategy` — branching approach (default: `"none"`)
- `workflow.use_worktrees` — whether parallel executor agents run in worktree isolation (default: `true`)
</step>
<step name="present_settings">
@@ -153,6 +154,15 @@ AskUserQuestion([
{ label: "No (Recommended)", description: "Run smart discuss before each phase — surfaces gray areas and captures decisions." },
{ label: "Yes", description: "Skip discuss in /gsd:autonomous — chain directly to plan. Best for backend/pipeline work where phase descriptions are the spec." }
]
},
{
question: "Use git worktrees for parallel agent isolation?",
header: "Worktrees",
multiSelect: false,
options: [
{ label: "Yes (Recommended)", description: "Each parallel executor runs in its own worktree branch — no conflicts between agents." },
{ label: "No", description: "Disable worktree isolation. Use on platforms where EnterWorktree is broken (e.g. Windows with feature branches). Agents run sequentially on the main working tree." }
]
}
])
```
@@ -176,7 +186,8 @@ Merge new settings into existing config.json:
"text_mode": true/false,
"research_before_questions": true/false,
"discuss_mode": "discuss" | "assumptions",
"skip_discuss": true/false
"skip_discuss": true/false,
"use_worktrees": true/false
},
"git": {
"branching_strategy": "none" | "phase" | "milestone",