diff --git a/get-shit-done/workflows/autonomous.md b/get-shit-done/workflows/autonomous.md
index b6e1f6448..4d7dc1985 100644
--- a/get-shit-done/workflows/autonomous.md
+++ b/get-shit-done/workflows/autonomous.md
@@ -211,6 +211,9 @@ Proceed to 3b.
**If SKIP_DISCUSS is `false` (or unset):** Execute the smart_discuss step for this phase.
+**IMPORTANT — Discuss must be single-pass in autonomous mode.**
+The discuss step in `--auto` mode MUST NOT loop. If CONTEXT.md already exists after discuss completes, do NOT re-invoke discuss for the same phase. The `has_context` check below is authoritative — once true, discuss is done for this phase regardless of perceived "gaps" in the context file.
+
After smart_discuss completes, verify context was written:
```bash
diff --git a/get-shit-done/workflows/discuss-phase.md b/get-shit-done/workflows/discuss-phase.md
index 1d268b1ba..cb005ec65 100644
--- a/get-shit-done/workflows/discuss-phase.md
+++ b/get-shit-done/workflows/discuss-phase.md
@@ -640,6 +640,16 @@ Each answer (or answer set, in batch mode) should reveal the next question or ne
```
After all areas are auto-resolved, skip the "Explore more gray areas" prompt and proceed directly to write_context.
+**CRITICAL — Auto-mode pass cap:**
+In `--auto` mode, the discuss step MUST complete in a **single pass**. After writing CONTEXT.md once, you are DONE — proceed immediately to write_context and then auto_advance. Do NOT re-read your own CONTEXT.md to find "gaps", "undefined types", or "missing decisions" and run additional passes. This creates a self-feeding loop where each pass generates references that the next pass treats as gaps, consuming unbounded time and resources.
+
+Check the pass cap from config:
+```bash
+MAX_PASSES=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" config-get workflow.max_discuss_passes 2>/dev/null || echo "3")
+```
+
+If you have already written and committed CONTEXT.md, the discuss step is complete. Move on.
+
**Interactive mode (no `--auto`):**
**For each area:**
diff --git a/sdk/prompts/workflows/discuss-phase.md b/sdk/prompts/workflows/discuss-phase.md
index 4db4cc5c6..8c6abe155 100644
--- a/sdk/prompts/workflows/discuss-phase.md
+++ b/sdk/prompts/workflows/discuss-phase.md
@@ -64,6 +64,19 @@ Analyze the phase to identify gray areas:
5. **Log each decision** with rationale
+
+**CRITICAL — Single-pass guard:**
+This step MUST complete in ONE pass. After writing CONTEXT.md, you are DONE. Do NOT re-read your own CONTEXT.md to identify "gaps", "undefined types", or "missing references" and run additional passes. Each decision naturally references other types and interfaces — this is expected, not a gap. The planner and executor will handle implementation details.
+
+Self-referential gap-finding creates an infinite loop where:
+1. Pass N creates decisions referencing types/interfaces
+2. Pass N+1 "discovers" those references as "gaps"
+3. Pass N+1 creates new decisions that reference more types
+4. Repeat forever
+
+Write your decisions once, comprehensively, then stop.
+
+
Create CONTEXT.md capturing decisions made:
diff --git a/sdk/src/config.ts b/sdk/src/config.ts
index 381e2120d..0ab7b7ff2 100644
--- a/sdk/src/config.ts
+++ b/sdk/src/config.ts
@@ -31,6 +31,8 @@ export interface WorkflowConfig {
research_before_questions: boolean;
discuss_mode: string;
skip_discuss: boolean;
+ /** Maximum self-discuss passes in auto/headless mode before forcing proceed. Default: 3. */
+ max_discuss_passes: number;
}
export interface HooksConfig {
@@ -82,6 +84,7 @@ export const CONFIG_DEFAULTS: GSDConfig = {
research_before_questions: false,
discuss_mode: 'discuss',
skip_discuss: false,
+ max_discuss_passes: 3,
},
hooks: {
context_warnings: true,
diff --git a/sdk/src/phase-runner.ts b/sdk/src/phase-runner.ts
index 37dc9051b..a343c38a0 100644
--- a/sdk/src/phase-runner.ts
+++ b/sdk/src/phase-runner.ts
@@ -410,8 +410,9 @@ export class PhaseRunner {
const contextFiles = await this.contextEngine.resolveContextFiles(PhaseType.Discuss);
let prompt = await this.promptFactory.buildPrompt(PhaseType.Discuss, null, contextFiles);
- // Supplement with self-discuss instructions
- prompt += '\n\n## Self-Discuss Mode\n\nYou are the AI discussing decisions with yourself. No human is present. Identify 3-5 gray areas in the project scope, reason through each one, make opinionated choices, and write CONTEXT.md with your decisions.';
+ // Supplement with self-discuss instructions with pass cap
+ const maxPasses = this.config.workflow.max_discuss_passes ?? 3;
+ prompt += `\n\n## Self-Discuss Mode\n\nYou are the AI discussing decisions with yourself. No human is present. Identify 3-5 gray areas in the project scope, reason through each one, make opinionated choices, and write CONTEXT.md with your decisions.\n\n**CRITICAL: Single-pass only.** You MUST complete all decisions in ONE pass and write CONTEXT.md once. Do NOT re-read your own CONTEXT.md to find "gaps" and do additional passes. The maximum allowed passes is ${maxPasses} — if you have already written CONTEXT.md, you are DONE. Proceed to the next workflow step. Self-referential gap-finding loops waste resources without adding value.`;
planResult = await runPhaseStepSession(
prompt,