feat(config): add workflow.use_worktrees toggle to disable worktree isolation

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) <noreply@anthropic.com>
This commit is contained in:
Tibsfox
2026-03-28 10:11:49 -07:00
parent 1421dc07bc
commit d1ff0437f1
8 changed files with 64 additions and 3 deletions

View File

@@ -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',

View File

@@ -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. |
</config_schema>
<commit_docs_behavior>

View File

@@ -55,6 +55,12 @@ gaps = [
</step>
<step name="report_plan">
**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<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",
isolation="worktree",
${USE_WORKTREES !== "false" ? 'isolation="worktree",' : ''}
description="Debug: {truth_short}"
)
```

View File

@@ -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 `<parallel_execution>` block with:
```
<sequential_execution>
You are running as a SEQUENTIAL executor agent on the main working tree.
Use normal git commits (with hooks). Do NOT use --no-verify.
</sequential_execution>
```
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):**

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, 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.

View File

@@ -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}"
)
```

View File

@@ -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);

View File

@@ -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'
);
});
});