From d1ff0437f1ba1c536bf18e300a51260967bf3b86 Mon Sep 17 00:00:00 2001 From: Tibsfox Date: Sat, 28 Mar 2026 10:11:49 -0700 Subject: [PATCH] feat(config): add workflow.use_worktrees toggle to disable worktree isolation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds `workflow.use_worktrees` config option (default: `true`) that allows users to disable git worktree isolation for executor agents. When set to `false`: - Executor agents run without `isolation="worktree"` - Plans execute sequentially on the main working tree - No worktree merge ordering issues or orphaned worktrees - Normal git hooks run (no --no-verify needed) This provides an escape hatch for solo developers and users who experience worktree merge conflicts, as worktree ordering issues are inherently difficult when parallel agents modify overlapping files. Usage: /gsd:settings → set workflow.use_worktrees to false Or directly: gsd-tools config-set workflow.use_worktrees false Changes: - config.cjs: add workflow.use_worktrees to valid keys - planning-config.md: document the option - execute-phase.md: read config, conditional worktree + sequential mode - execute-plan.md: conditional worktree in Pattern A - quick.md: conditional worktree for quick executor - diagnose-issues.md: conditional worktree for debug agents - 2 new tests (config set + workflow structural check) Closes #1451 Co-Authored-By: Claude Opus 4.6 (1M context) --- get-shit-done/bin/lib/config.cjs | 1 + get-shit-done/references/planning-config.md | 1 + get-shit-done/workflows/diagnose-issues.md | 8 ++++++- get-shit-done/workflows/execute-phase.md | 23 +++++++++++++++++++++ get-shit-done/workflows/execute-plan.md | 2 +- get-shit-done/workflows/quick.md | 6 +++++- tests/config.test.cjs | 10 +++++++++ tests/execute-phase-wave.test.cjs | 16 ++++++++++++++ 8 files changed, 64 insertions(+), 3 deletions(-) diff --git a/get-shit-done/bin/lib/config.cjs b/get-shit-done/bin/lib/config.cjs index 67fe5a6b9..9cfb7dc9f 100644 --- a/get-shit-done/bin/lib/config.cjs +++ b/get-shit-done/bin/lib/config.cjs @@ -22,6 +22,7 @@ const VALID_CONFIG_KEYS = new Set([ 'workflow.discuss_mode', 'workflow.skip_discuss', 'workflow._auto_chain_active', + 'workflow.use_worktrees', 'git.branching_strategy', 'git.phase_branch_template', 'git.milestone_branch_template', 'git.quick_branch_template', 'planning.commit_docs', 'planning.search_gitignored', 'hooks.context_warnings', diff --git a/get-shit-done/references/planning-config.md b/get-shit-done/references/planning-config.md index f8276c761..20ee56f37 100644 --- a/get-shit-done/references/planning-config.md +++ b/get-shit-done/references/planning-config.md @@ -24,6 +24,7 @@ Configuration options for `.planning/` directory behavior. | `git.phase_branch_template` | `"gsd/phase-{phase}-{slug}"` | Branch template for phase strategy | | `git.milestone_branch_template` | `"gsd/{milestone}-{slug}"` | Branch template for milestone strategy | | `git.quick_branch_template` | `null` | Optional branch template for quick-task runs | +| `workflow.use_worktrees` | `true` | Whether executor agents run in isolated git worktrees. Set to `false` to disable worktrees — agents execute sequentially on the main working tree instead. Recommended for solo developers or when worktree merges cause issues. | diff --git a/get-shit-done/workflows/diagnose-issues.md b/get-shit-done/workflows/diagnose-issues.md index ea53fe26e..47f3e09d6 100644 --- a/get-shit-done/workflows/diagnose-issues.md +++ b/get-shit-done/workflows/diagnose-issues.md @@ -55,6 +55,12 @@ gaps = [ +**Read worktree config:** + +```bash +USE_WORKTREES=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" config-get workflow.use_worktrees 2>/dev/null || echo "true") +``` + **Report diagnosis plan to user:** ``` @@ -92,7 +98,7 @@ For each gap, fill the debug-subagent-prompt template and spawn: Task( prompt=filled_debug_subagent_prompt + "\n\n\n- {phase_dir}/{phase_num}-UAT.md\n- .planning/STATE.md\n\n${AGENT_SKILLS_DEBUGGER}", subagent_type="gsd-debugger", - isolation="worktree", + ${USE_WORKTREES !== "false" ? 'isolation="worktree",' : ''} description="Debug: {truth_short}" ) ``` diff --git a/get-shit-done/workflows/execute-phase.md b/get-shit-done/workflows/execute-phase.md index 0bdb11174..f403da146 100644 --- a/get-shit-done/workflows/execute-phase.md +++ b/get-shit-done/workflows/execute-phase.md @@ -68,6 +68,14 @@ AGENT_SKILLS=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" agent-skills Parse JSON for: `executor_model`, `verifier_model`, `commit_docs`, `parallelization`, `branching_strategy`, `branch_name`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `plans`, `incomplete_plans`, `plan_count`, `incomplete_count`, `state_exists`, `roadmap_exists`, `phase_req_ids`. +Read worktree config: + +```bash +USE_WORKTREES=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" config-get workflow.use_worktrees 2>/dev/null || echo "true") +``` + +When `USE_WORKTREES` is `false`, all executor agents run without `isolation="worktree"` — they execute sequentially on the main working tree instead of in parallel worktrees. + **If `phase_found` is false:** Error — phase directory not found. **If `plan_count` is 0:** Error — no plans found in phase. **If `state_exists` is false but `.planning/` exists:** Offer reconstruct or continue. @@ -223,6 +231,8 @@ Execute each selected wave in sequence. Within a wave: parallel if `PARALLELIZAT For 200k models, this keeps orchestrator context lean (~10-15%). For 1M+ models (Opus 4.6, Sonnet 4.6), richer context can be passed directly. + **Worktree mode** (`USE_WORKTREES` is not `false`): + ``` Task( subagent_type="gsd-executor", @@ -279,6 +289,19 @@ Execute each selected wave in sequence. Within a wave: parallel if `PARALLELIZAT ) ``` + **Sequential mode** (`USE_WORKTREES` is `false`): + + Omit `isolation="worktree"` from the Task call. Replace the `` block with: + + ``` + + You are running as a SEQUENTIAL executor agent on the main working tree. + Use normal git commits (with hooks). Do NOT use --no-verify. + + ``` + + When worktrees are disabled, execute plans **one at a time within each wave** (sequential) regardless of the `PARALLELIZATION` setting — multiple agents writing to the same working tree concurrently would cause conflicts. + 3. **Wait for all agents in wave to complete.** **Completion signal fallback (Copilot and runtimes where Task() may not return):** diff --git a/get-shit-done/workflows/execute-plan.md b/get-shit-done/workflows/execute-plan.md index cbbf71330..920e92ab9 100644 --- a/get-shit-done/workflows/execute-plan.md +++ b/get-shit-done/workflows/execute-plan.md @@ -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, isolation="worktree") 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. +**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 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. diff --git a/get-shit-done/workflows/quick.md b/get-shit-done/workflows/quick.md index 89441f965..bfd46f718 100644 --- a/get-shit-done/workflows/quick.md +++ b/get-shit-done/workflows/quick.md @@ -126,6 +126,10 @@ AGENT_SKILLS_VERIFIER=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" age Parse JSON for: `planner_model`, `executor_model`, `checker_model`, `verifier_model`, `commit_docs`, `branch_name`, `quick_id`, `slug`, `date`, `timestamp`, `quick_dir`, `task_dir`, `roadmap_exists`, `planning_exists`. +```bash +USE_WORKTREES=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" config-get workflow.use_worktrees 2>/dev/null || echo "true") +``` + **If `roadmap_exists` is false:** Error — Quick mode requires an active project with ROADMAP.md. Run `/gsd:new-project` first. Quick tasks can run mid-phase - validation only checks ROADMAP.md exists, not phase status. @@ -559,7 +563,7 @@ ${AGENT_SKILLS_EXECUTOR} ", subagent_type="gsd-executor", model="{executor_model}", - isolation="worktree", + ${USE_WORKTREES !== "false" ? 'isolation="worktree",' : ''} description="Execute: ${DESCRIPTION}" ) ``` diff --git a/tests/config.test.cjs b/tests/config.test.cjs index 31a2da656..74fa46852 100644 --- a/tests/config.test.cjs +++ b/tests/config.test.cjs @@ -232,6 +232,16 @@ describe('config-set command', () => { assert.strictEqual(config.workflow.text_mode, true); }); + test('sets workflow.use_worktrees to disable worktree isolation', () => { + writeConfig(tmpDir, {}); + + const result = runGsdTools('config-set workflow.use_worktrees false', tmpDir); + assert.ok(result.success, `Command failed: ${result.error}`); + + const config = readConfig(tmpDir); + assert.strictEqual(config.workflow.use_worktrees, false); + }); + test('errors when no key path provided', () => { const result = runGsdTools('config-set', tmpDir); assert.strictEqual(result.success, false); diff --git a/tests/execute-phase-wave.test.cjs b/tests/execute-phase-wave.test.cjs index 871e9904c..d00b453db 100644 --- a/tests/execute-phase-wave.test.cjs +++ b/tests/execute-phase-wave.test.cjs @@ -105,4 +105,20 @@ describe('execute-phase docs: user-facing wave flag', () => { 'help.md should include wave-filter usage' ); }); + + test('workflow supports use_worktrees config toggle', () => { + const content = fs.readFileSync(WORKFLOW_PATH, 'utf-8'); + assert.ok( + content.includes('USE_WORKTREES'), + 'workflow should reference USE_WORKTREES variable' + ); + assert.ok( + content.includes('config-get workflow.use_worktrees'), + 'workflow should read use_worktrees from config' + ); + assert.ok( + content.includes('Sequential mode'), + 'workflow should document sequential mode when worktrees disabled' + ); + }); });