name: gsd-plan-phase description: "Create detailed phase plan (PLAN.md) with verification loop" argument-hint: "[phase] [--auto] [--research] [--skip-research] [--gaps] [--skip-verify] [--prd <file>] [--reviews] [--text]" agent: gsd-planner allowed-tools:
- Read
- Write
- Bash
- Glob
- Grep
- Task
- AskUserQuestion
- WebFetch
- mcp__context7__*
<objective> Create executable phase prompts (PLAN.md files) for a roadmap phase with integrated research and verification.
Default flow: Research (if needed) → Plan → Verify → Done
Orchestrator role: Parse arguments, validate phase, research domain (unless skipped), spawn gsd-planner, verify with gsd-plan-checker, iterate until pass or max iterations, present results. </objective>
<!-- Workflow content (was: plan-phase.md) --> <purpose> Create executable phase prompts (PLAN.md files) for a roadmap phase with integrated research and verification. Default flow: Research (if needed) -> Plan -> Verify -> Done. Orchestrates gsd-phase-researcher, gsd-planner, and gsd-plan-checker agents with a revision loop (max 3 iterations). </purpose><required_reading> Read the skill content below before starting.
@${CLAUDE_PLUGIN_ROOT}/references/ui-brand.md </required_reading>
<available_agent_types> Valid GSD subagent types (use exact names — do not fall back to 'general-purpose'):
- gsd-phase-researcher — Researches technical approaches for a phase
- gsd-planner — Creates detailed plans from phase scope
- gsd-plan-checker — Reviews plan quality before execution </available_agent_types>
1. Initialize
Load all context in one call (paths only to minimize orchestrator context):
INIT=$(node "$GSD_TOOLS" init plan-phase "$PHASE")
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
AGENT_SKILLS_RESEARCHER=$(node "$GSD_TOOLS" agent-skills gsd-researcher 2>/dev/null)
AGENT_SKILLS_PLANNER=$(node "$GSD_TOOLS" agent-skills gsd-planner 2>/dev/null)
AGENT_SKILLS_CHECKER=$(node "$GSD_TOOLS" agent-skills gsd-checker 2>/dev/null)
CONTEXT_WINDOW=$(node "$GSD_TOOLS" config-get context_window 2>/dev/null || echo "200000")
When CONTEXT_WINDOW >= 500000, the planner prompt includes prior phase CONTEXT.md files so cross-phase decisions are consistent (e.g., "use library X for all data fetching" from Phase 2 is visible to Phase 5's planner).
Parse JSON for: researcher_model, planner_model, checker_model, research_enabled, plan_checker_enabled, nyquist_validation_enabled, commit_docs, text_mode, phase_found, phase_dir, phase_number, phase_name, phase_slug, padded_phase, has_research, has_context, has_reviews, has_plans, plan_count, planning_exists, roadmap_exists, phase_req_ids, response_language.
If response_language is set: Include response_language: {value} in all spawned subagent prompts so any user-facing output stays in the configured language.
File paths (for <files_to_read> blocks): state_path, roadmap_path, requirements_path, context_path, research_path, verification_path, uat_path, reviews_path. These are null if files don't exist.
If planning_exists is false: Error — run /gsd-new-project first.
2. Parse and Normalize Arguments
Extract from $ARGUMENTS: phase number (integer or decimal like 2.1), flags (--research, --skip-research, --gaps, --skip-verify, --prd <filepath>, --reviews, --text).
Set TEXT_MODE=true if --text is present in $ARGUMENTS OR text_mode from init JSON is true. When TEXT_MODE is active, replace every AskUserQuestion call with a plain-text numbered list and ask the user to type their choice number. This is required for Claude Code remote sessions (/rc mode) where TUI menus don't work through the Claude App.
Extract --prd <filepath> from $ARGUMENTS. If present, set PRD_FILE to the filepath.
If no phase number: Detect next unplanned phase from roadmap.
If phase_found is false: Validate phase exists in ROADMAP.md. If valid, create the directory using phase_slug and padded_phase from init:
mkdir -p ".planning/phases/${padded_phase}-${phase_slug}"
Existing artifacts from init: has_research, has_plans, plan_count.
2.5. Validate --reviews Prerequisite
Skip if: No --reviews flag.
If --reviews AND --gaps: Error — cannot combine --reviews with --gaps. These are conflicting modes.
If --reviews AND has_reviews is false (no REVIEWS.md in phase dir):
Error:
No REVIEWS.md found for Phase {N}. Run reviews first:
/gsd-review --phase {N}
Then re-run /gsd-plan-phase {N} --reviews
Exit workflow.
3. Validate Phase
PHASE_INFO=$(node "$GSD_TOOLS" roadmap get-phase "${PHASE}")
If found is false: Error with available phases. If found is true: Extract phase_number, phase_name, goal from JSON.
3.5. Handle PRD Express Path
Skip if: No --prd flag in arguments.
If --prd <filepath> provided:
- Read the PRD file:
PRD_CONTENT=$(cat "$PRD_FILE" 2>/dev/null)
if [ -z "$PRD_CONTENT" ]; then
echo "Error: PRD file not found: $PRD_FILE"
exit 1
fi
- Display banner:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GSD ► PRD EXPRESS PATH
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Using PRD: {PRD_FILE}
Generating CONTEXT.md from requirements...
-
Parse the PRD content and generate CONTEXT.md. The orchestrator should:
- Extract all requirements, user stories, acceptance criteria, and constraints from the PRD
- Map each to a locked decision (everything in the PRD is treated as a locked decision)
- Identify any areas the PRD doesn't cover and mark as "Claude's Discretion"
- Extract canonical refs from ROADMAP.md for this phase, plus any specs/ADRs referenced in the PRD — expand to full file paths (MANDATORY)
- Create CONTEXT.md in the phase directory
-
Write CONTEXT.md:
# Phase [X]: [Name] - Context
**Gathered:** [date]
**Status:** Ready for planning
**Source:** PRD Express Path ({PRD_FILE})
<domain>
## Phase Boundary
[Extracted from PRD — what this phase delivers]
</domain>
<decisions>
## Implementation Decisions
{For each requirement/story/criterion in the PRD:}
### [Category derived from content]
- [Requirement as locked decision]
### Claude's Discretion
[Areas not covered by PRD — implementation details, technical choices]
</decisions>
<canonical_refs>
## Canonical References
**Downstream agents MUST read these before planning or implementing.**
[MANDATORY. Extract from ROADMAP.md and any docs referenced in the PRD.
Use full relative paths. Group by topic area.]
### [Topic area]
- `path/to/spec-or-adr.md` — [What it decides/defines]
[If no external specs: "No external specs — requirements fully captured in decisions above"]
</canonical_refs>
<specifics>
## Specific Ideas
[Any specific references, examples, or concrete requirements from PRD]
</specifics>
<deferred>
## Deferred Ideas
[Items in PRD explicitly marked as future/v2/out-of-scope]
[If none: "None — PRD covers phase scope"]
</deferred>
---
*Phase: XX-name*
*Context gathered: [date] via PRD Express Path*
- Commit:
node "$GSD_TOOLS" commit "docs(${padded_phase}): generate context from PRD" --files "${phase_dir}/${padded_phase}-CONTEXT.md"
- Set
context_contentto the generated CONTEXT.md content and continue to step 5 (Handle Research).
Effect: This completely bypasses step 4 (Load CONTEXT.md) since we just created it. The rest of the workflow (research, planning, verification) proceeds normally with the PRD-derived context.
4. Load CONTEXT.md
Skip if: PRD express path was used (CONTEXT.md already created in step 3.5).
Check context_path from init JSON.
If context_path is not null, display: Using phase context from: ${context_path}
If context_path is null (no CONTEXT.md exists):
Read discuss mode for context gate label:
DISCUSS_MODE=$(node "$GSD_TOOLS" config-get workflow.discuss_mode 2>/dev/null || echo "discuss")
If TEXT_MODE is true, present as a plain-text numbered list:
No CONTEXT.md found for Phase {X}. Plans will use research and requirements only — your design preferences won't be included.
1. Continue without context — Plan using research + requirements only
[If DISCUSS_MODE is "assumptions":]
2. Gather context (assumptions mode) — Analyze codebase and surface assumptions before planning
[If DISCUSS_MODE is "discuss" or unset:]
2. Run discuss-phase first — Capture design decisions before planning
Enter number:
Otherwise use AskUserQuestion:
- header: "No context"
- question: "No CONTEXT.md found for Phase {X}. Plans will use research and requirements only — your design preferences won't be included. Continue or capture context first?"
- options:
- "Continue without context" — Plan using research + requirements only
If
DISCUSS_MODEis"assumptions": - "Gather context (assumptions mode)" — Analyze codebase and surface assumptions before planning
If
DISCUSS_MODEis"discuss"(or unset): - "Run discuss-phase first" — Capture design decisions before planning
- "Continue without context" — Plan using research + requirements only
If
If "Continue without context": Proceed to step 5. If "Run discuss-phase first": IMPORTANT: Do NOT invoke discuss-phase as a nested Skill/Task call — AskUserQuestion does not work correctly in nested subcontexts (#1009). Instead, display the command and exit so the user runs it as a top-level command:
Run this command first, then re-run /gsd-plan-phase {X} ${GSD_WS}:
/gsd-discuss-phase {X} ${GSD_WS}
Exit the plan-phase workflow. Do not continue.
5. Handle Research
Skip if: --gaps flag or --skip-research flag or --reviews flag.
If has_research is true (from init) AND no --research flag: Use existing, skip to step 6.
If RESEARCH.md missing OR --research flag:
If no explicit flag (--research or --skip-research) and not --auto:
Ask the user whether to research, with a contextual recommendation based on the phase:
If TEXT_MODE is true, present as a plain-text numbered list:
Research before planning Phase {X}: {phase_name}?
1. Research first (Recommended) — Investigate domain, patterns, and dependencies before planning. Best for new features, unfamiliar integrations, or architectural changes.
2. Skip research — Plan directly from context and requirements. Best for bug fixes, simple refactors, or well-understood tasks.
Enter number:
Otherwise use AskUserQuestion:
AskUserQuestion([
{
question: "Research before planning Phase {X}: {phase_name}?",
header: "Research",
multiSelect: false,
options: [
{ label: "Research first (Recommended)", description: "Investigate domain, patterns, and dependencies before planning. Best for new features, unfamiliar integrations, or architectural changes." },
{ label: "Skip research", description: "Plan directly from context and requirements. Best for bug fixes, simple refactors, or well-understood tasks." }
]
}
])
If user selects "Skip research": skip to step 6.
If --auto and research_enabled is false: Skip research silently (preserves automated behavior).
Display banner:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GSD ► RESEARCHING PHASE {X}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
◆ Spawning researcher...
Spawn gsd-phase-researcher
PHASE_DESC=$(node "$GSD_TOOLS" roadmap get-phase "${PHASE}" --pick section)
Research prompt:
<objective>
Research how to implement Phase {phase_number}: {phase_name}
Answer: "What do I need to know to PLAN this phase well?"
</objective>
<files_to_read>
- {context_path} (USER DECISIONS from /gsd-discuss-phase)
- {requirements_path} (Project requirements)
- {state_path} (Project decisions and history)
</files_to_read>
${AGENT_SKILLS_RESEARCHER}
<additional_context>
**Phase description:** {phase_description}
**Phase requirement IDs (MUST address):** {phase_req_ids}
**Project instructions:** Read ./CLAUDE.md if exists — follow project-specific guidelines
**Project skills:** Check .claude/skills/ or .agents/skills/ directory (if either exists) — read SKILL.md files, research should account for project skill patterns
</additional_context>
<output>
Write to: {phase_dir}/{phase_num}-RESEARCH.md
</output>
Task(
prompt=research_prompt,
subagent_type="gsd-phase-researcher",
model="{researcher_model}",
description="Research Phase {phase}"
)
Handle Researcher Return
## RESEARCH COMPLETE: Display confirmation, continue to step 6## RESEARCH BLOCKED: Display blocker, offer: 1) Provide context, 2) Skip research, 3) Abort
5.5. Create Validation Strategy
Skip if nyquist_validation_enabled is false OR research_enabled is false.
If research_enabled is false and nyquist_validation_enabled is true: warn "Nyquist validation enabled but research disabled — VALIDATION.md cannot be created without RESEARCH.md. Plans will lack validation requirements (Dimension 8)." Continue to step 6.
But Nyquist is not applicable for this run when all of the following are true:
research_enabledis falsehas_researchis false- no
--researchflag was provided
In that case: skip validation-strategy creation entirely. Do not expect RESEARCH.md or VALIDATION.md for this run, and continue to Step 6.
grep -l "## Validation Architecture" "${PHASE_DIR}"/*-RESEARCH.md 2>/dev/null || true
If found:
- Read template:
${CLAUDE_PLUGIN_ROOT}/templates/VALIDATION.md - Write to
${PHASE_DIR}/${PADDED_PHASE}-VALIDATION.md(use Write tool) - Fill frontmatter:
{N}→ phase number,{phase-slug}→ slug,{date}→ current date - Verify:
test -f "${PHASE_DIR}/${PADDED_PHASE}-VALIDATION.md" && echo "VALIDATION_CREATED=true" || echo "VALIDATION_CREATED=false"
- If
VALIDATION_CREATED=false: STOP — do not proceed to Step 6 - If
commit_docs:commit "docs(phase-${PHASE}): add validation strategy"
If not found: Warn and continue — plans may fail Dimension 8.
5.55. Security Threat Model Gate
Skip if
workflow.security_enforcementis explicitlyfalse. Absent = enabled.
SECURITY_CFG=$(node "$GSD_TOOLS" config-get workflow.security_enforcement --raw 2>/dev/null || echo "true")
SECURITY_ASVS=$(node "$GSD_TOOLS" config-get workflow.security_asvs_level --raw 2>/dev/null || echo "1")
SECURITY_BLOCK=$(node "$GSD_TOOLS" config-get workflow.security_block_on --raw 2>/dev/null || echo "high")
If SECURITY_CFG is false: Skip to step 5.6.
If SECURITY_CFG is true: Display banner:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GSD ► SECURITY THREAT MODEL REQUIRED (ASVS L{SECURITY_ASVS})
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Each PLAN.md must include a <threat_model> block.
Block on: {SECURITY_BLOCK} severity threats.
Opt out: set security_enforcement: false in .planning/config.json
Continue to step 5.6. Security config is passed to the planner in step 8.
5.6. UI Design Contract Gate
Skip if
workflow.ui_phaseis explicitlyfalseANDworkflow.ui_safety_gateis explicitlyfalsein.planning/config.json. If keys are absent, treat as enabled.
UI_PHASE_CFG=$(node "$GSD_TOOLS" config-get workflow.ui_phase 2>/dev/null || echo "true")
UI_GATE_CFG=$(node "$GSD_TOOLS" config-get workflow.ui_safety_gate 2>/dev/null || echo "true")
If both are false: Skip to step 6.
Check if phase has frontend indicators:
PHASE_SECTION=$(node "$GSD_TOOLS" roadmap get-phase "${PHASE}" 2>/dev/null)
echo "$PHASE_SECTION" | grep -iE "UI|interface|frontend|component|layout|page|screen|view|form|dashboard|widget" > /dev/null 2>&1
HAS_UI=$?
If HAS_UI is 0 (frontend indicators found):
Check for existing UI-SPEC:
UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1)
If UI-SPEC.md found: Set UI_SPEC_PATH=$UI_SPEC_FILE. Display: Using UI design contract: ${UI_SPEC_PATH}
If UI-SPEC.md missing AND UI_GATE_CFG is true:
Read auto-chain state:
AUTO_CHAIN=$(node "$GSD_TOOLS" config-get workflow._auto_chain_active 2>/dev/null || echo "false")
If AUTO_CHAIN is true (running inside a --chain or --auto pipeline):
Auto-generate UI-SPEC without prompting:
Skill(skill="gsd-ui-phase", args="${PHASE} --auto ${GSD_WS}")
After gsd-ui-phase returns, re-read:
UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1)
UI_SPEC_PATH="${UI_SPEC_FILE}"
Continue to step 6.
If AUTO_CHAIN is false (manual invocation):
If TEXT_MODE is true, present as a plain-text numbered list:
Phase {N} has frontend indicators but no UI-SPEC.md. Generate a design contract before planning?
1. Generate UI-SPEC first — Run /gsd-ui-phase {N} then re-run /gsd-plan-phase {N}
2. Continue without UI-SPEC
3. Not a frontend phase
Enter number:
Otherwise use AskUserQuestion:
- header: "UI Design Contract"
- question: "Phase {N} has frontend indicators but no UI-SPEC.md. Generate a design contract before planning?"
- options:
- "Generate UI-SPEC first" → Display: "Run
/gsd-ui-phase {N} ${GSD_WS}then re-run/gsd-plan-phase {N} ${GSD_WS}". Exit workflow. - "Continue without UI-SPEC" → Continue to step 6.
- "Not a frontend phase" → Continue to step 6.
- "Generate UI-SPEC first" → Display: "Run
If HAS_UI is 1 (no frontend indicators): Skip silently to step 5.7.
5.7. Schema Push Detection Gate
Detects schema-relevant files in the phase scope and injects a mandatory
[BLOCKING]schema push task into the plan. Prevents false-positive verification where build/types pass because TypeScript types come from config, not the live database.
Check if any files in the phase scope match schema patterns:
PHASE_SECTION=$(node "$GSD_TOOLS" roadmap get-phase "${PHASE}" --pick section 2>/dev/null)
Scan PHASE_SECTION, CONTEXT.md (if loaded), and RESEARCH.md (if exists) for file paths matching these ORM patterns:
| ORM | File Patterns |
|---|---|
| Payload CMS | src/collections/**/*.ts, src/globals/**/*.ts |
| Prisma | prisma/schema.prisma, prisma/schema/*.prisma |
| Drizzle | drizzle/schema.ts, src/db/schema.ts, drizzle/*.ts |
| Supabase | supabase/migrations/*.sql |
| TypeORM | src/entities/**/*.ts, src/migrations/**/*.ts |
Also check if any existing PLAN.md files for this phase already reference these file patterns in files_modified.
If schema-relevant files detected:
Set SCHEMA_PUSH_REQUIRED=true and SCHEMA_ORM={detected_orm}.
Determine the push command for the detected ORM:
| ORM | Push Command | Non-TTY Workaround |
|---|---|---|
| Payload CMS | npx payload migrate | CI=true PAYLOAD_MIGRATING=true npx payload migrate |
| Prisma | npx prisma db push | npx prisma db push --accept-data-loss (if destructive) |
| Drizzle | npx drizzle-kit push | npx drizzle-kit push |
| Supabase | supabase db push | Set SUPABASE_ACCESS_TOKEN env var |
| TypeORM | npx typeorm migration:run | npx typeorm migration:run -d src/data-source.ts |
Inject the following into the planner prompt (step 8) as an additional constraint:
<schema_push_requirement>
**[BLOCKING] Schema Push Required**
This phase modifies schema-relevant files ({detected_files}). The planner MUST include
a `[BLOCKING]` task that runs the database schema push command AFTER all schema file
modifications are complete but BEFORE verification.
- ORM detected: {SCHEMA_ORM}
- Push command: {push_command}
- Non-TTY workaround: {env_hint}
- If push requires interactive prompts that cannot be suppressed, flag the task for
manual intervention with `autonomous: false`
This task is mandatory — the phase CANNOT pass verification without it. Build and
type checks will pass without the push (types come from config, not the live database),
creating a false-positive verification state.
</schema_push_requirement>
Display: Schema files detected ({SCHEMA_ORM}) — [BLOCKING] push task will be injected into plans
If no schema-relevant files detected: Skip silently to step 6.
6. Check Existing Plans
ls "${PHASE_DIR}"/*-PLAN.md 2>/dev/null || true
If exists AND --reviews flag: Skip prompt — go straight to replanning (the purpose of --reviews is to replan with review feedback).
If exists AND no --reviews flag: Offer: 1) Add more plans, 2) View existing, 3) Replan from scratch.
7. Use Context Paths from INIT
Extract from INIT JSON:
_gsd_field() { node -e "const o=JSON.parse(process.argv[1]); const v=o[process.argv[2]]; process.stdout.write(v==null?'':String(v))" "$1" "$2"; }
STATE_PATH=$(_gsd_field "$INIT" state_path)
ROADMAP_PATH=$(_gsd_field "$INIT" roadmap_path)
REQUIREMENTS_PATH=$(_gsd_field "$INIT" requirements_path)
RESEARCH_PATH=$(_gsd_field "$INIT" research_path)
VERIFICATION_PATH=$(_gsd_field "$INIT" verification_path)
UAT_PATH=$(_gsd_field "$INIT" uat_path)
CONTEXT_PATH=$(_gsd_field "$INIT" context_path)
REVIEWS_PATH=$(_gsd_field "$INIT" reviews_path)
7.5. Verify Nyquist Artifacts
Skip if nyquist_validation_enabled is false OR research_enabled is false.
Also skip if all of the following are true:
research_enabledis falsehas_researchis false- no
--researchflag was provided
In that no-research path, Nyquist artifacts are not required for this run.
VALIDATION_EXISTS=$(ls "${PHASE_DIR}"/*-VALIDATION.md 2>/dev/null | head -1)
If missing and Nyquist is still enabled/applicable — ask user:
- Re-run:
/gsd-plan-phase {PHASE} --research ${GSD_WS} - Disable Nyquist with the exact command:
node "$GSD_TOOLS" config-set workflow.nyquist_validation false - Continue anyway (plans fail Dimension 8)
Proceed to Step 8 only if user selects 2 or 3.
8. Spawn gsd-planner Agent
Display banner:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GSD ► PLANNING PHASE {X}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
◆ Spawning planner...
Planner prompt:
<planning_context>
**Phase:** {phase_number}
**Mode:** {standard | gap_closure | reviews}
<files_to_read>
- {state_path} (Project State)
- {roadmap_path} (Roadmap)
- {requirements_path} (Requirements)
- {context_path} (USER DECISIONS from /gsd-discuss-phase)
- {research_path} (Technical Research)
- {verification_path} (Verification Gaps - if --gaps)
- {uat_path} (UAT Gaps - if --gaps)
- {reviews_path} (Cross-AI Review Feedback - if --reviews)
- {UI_SPEC_PATH} (UI Design Contract — visual/interaction specs, if exists)
${CONTEXT_WINDOW >= 500000 ? `
**Cross-phase context (1M model enrichment):**
- Prior phase CONTEXT.md files (locked decisions from earlier phases — maintain consistency)
- Prior phase SUMMARY.md files (what was actually built — reuse patterns, avoid duplication)
` : ''}
</files_to_read>
${AGENT_SKILLS_PLANNER}
**Phase requirement IDs (every ID MUST appear in a plan's `requirements` field):** {phase_req_ids}
**Project instructions:** Read ./CLAUDE.md if exists — follow project-specific guidelines
**Project skills:** Check .claude/skills/ or .agents/skills/ directory (if either exists) — read SKILL.md files, plans should account for project skill rules
</planning_context>
<downstream_consumer>
Output consumed by /gsd-execute-phase. Plans need:
- Frontmatter (wave, depends_on, files_modified, autonomous)
- Tasks in XML format with read_first and acceptance_criteria fields (MANDATORY on every task)
- Verification criteria
- must_haves for goal-backward verification
</downstream_consumer>
<deep_work_rules>
## Anti-Shallow Execution Rules (MANDATORY)
Every task MUST include these fields — they are NOT optional:
1. **`<read_first>`** — Files the executor MUST read before touching anything. Always include:
- The file being modified (so executor sees current state, not assumptions)
- Any "source of truth" file referenced in CONTEXT.md (reference implementations, existing patterns, config files, schemas)
- Any file whose patterns, signatures, types, or conventions must be replicated or respected
2. **`<acceptance_criteria>`** — Verifiable conditions that prove the task was done correctly. Rules:
- Every criterion must be checkable with grep, file read, test command, or CLI output
- NEVER use subjective language ("looks correct", "properly configured", "consistent with")
- ALWAYS include exact strings, patterns, values, or command outputs that must be present
- Examples:
- Code: `auth.py contains def verify_token(` / `test_auth.py exits 0`
- Config: `.env.example contains DATABASE_URL=` / `Dockerfile contains HEALTHCHECK`
- Docs: `README.md contains '## Installation'` / `API.md lists all endpoints`
- Infra: `deploy.yml has rollback step` / `docker-compose.yml has healthcheck for db`
3. **`<action>`** — Must include CONCRETE values, not references. Rules:
- NEVER say "align X with Y", "match X to Y", "update to be consistent" without specifying the exact target state
- ALWAYS include the actual values: config keys, function signatures, SQL statements, class names, import paths, env vars, etc.
- If CONTEXT.md has a comparison table or expected values, copy them into the action verbatim
- The executor should be able to complete the task from the action text alone, without needing to read CONTEXT.md or reference files (read_first is for verification, not discovery)
**Why this matters:** Executor agents work from the plan text. Vague instructions like "update the config to match production" produce shallow one-line changes. Concrete instructions like "add DATABASE_URL=postgresql://... , set POOL_SIZE=20, add REDIS_URL=redis://..." produce complete work. The cost of verbose plans is far less than the cost of re-doing shallow execution.
</deep_work_rules>
<quality_gate>
- [ ] PLAN.md files created in phase directory
- [ ] Each plan has valid frontmatter
- [ ] Tasks are specific and actionable
- [ ] Every task has `<read_first>` with at least the file being modified
- [ ] Every task has `<acceptance_criteria>` with grep-verifiable conditions
- [ ] Every `<action>` contains concrete values (no "align X with Y" without specifying what)
- [ ] Dependencies correctly identified
- [ ] Waves assigned for parallel execution
- [ ] must_haves derived from phase goal
</quality_gate>
Task(
prompt=filled_prompt,
subagent_type="gsd-planner",
model="{planner_model}",
description="Plan Phase {phase}"
)
9. Handle Planner Return
## PLANNING COMPLETE: Display plan count. If--skip-verifyorplan_checker_enabledis false (from init): skip to step 13. Otherwise: step 10.## PHASE SPLIT RECOMMENDED: The planner determined the phase is too complex to implement all user decisions without simplifying them. Handle in step 9b.## CHECKPOINT REACHED: Present to user, get response, spawn continuation (step 12)## PLANNING INCONCLUSIVE: Show attempts, offer: Add context / Retry / Manual
9b. Handle Phase Split Recommendation
When the planner returns ## PHASE SPLIT RECOMMENDED, it means the phase has too many decisions to implement at full fidelity within the plan budget. The planner proposes groupings.
Extract from planner return:
- Proposed sub-phases (e.g., "17a: processing core (D-01 to D-19)", "17b: billing + config UX (D-20 to D-27)")
- Which D-XX decisions go in each sub-phase
- Why the split is necessary (decision count, complexity estimate)
Present to user:
## Phase {X} is too complex for full-fidelity implementation
The planner found {N} decisions that cannot all be implemented without
simplifying some. Instead of reducing your decisions, we recommend splitting:
**Option 1: Split into sub-phases**
- Phase {X}a: {name} — {D-XX to D-YY} ({N} decisions)
- Phase {X}b: {name} — {D-XX to D-YY} ({M} decisions)
**Option 2: Proceed anyway** (planner will attempt all, quality may degrade)
**Option 3: Prioritize** — you choose which decisions to implement now,
rest become a follow-up phase
Use AskUserQuestion with these 3 options.
If "Split": Use /gsd-insert-phase to create the sub-phases, then replan each.
If "Proceed": Return to planner with instruction to attempt all decisions at full fidelity, accepting more plans/tasks.
If "Prioritize": Use AskUserQuestion (multiSelect) to let user pick which D-XX are "now" vs "later". Create CONTEXT.md for each sub-phase with the selected decisions.
10. Spawn gsd-plan-checker Agent
Display banner:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GSD ► VERIFYING PLANS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
◆ Spawning plan checker...
Checker prompt:
<verification_context>
**Phase:** {phase_number}
**Phase Goal:** {goal from ROADMAP}
<files_to_read>
- {PHASE_DIR}/*-PLAN.md (Plans to verify)
- {roadmap_path} (Roadmap)
- {requirements_path} (Requirements)
- {context_path} (USER DECISIONS from /gsd-discuss-phase)
- {research_path} (Technical Research — includes Validation Architecture)
</files_to_read>
${AGENT_SKILLS_CHECKER}
**Phase requirement IDs (MUST ALL be covered):** {phase_req_ids}
**Project instructions:** Read ./CLAUDE.md if exists — verify plans honor project guidelines
**Project skills:** Check .claude/skills/ or .agents/skills/ directory (if either exists) — verify plans account for project skill rules
</verification_context>
<expected_output>
- ## VERIFICATION PASSED — all checks pass
- ## ISSUES FOUND — structured issue list
</expected_output>
Task(
prompt=checker_prompt,
subagent_type="gsd-plan-checker",
model="{checker_model}",
description="Verify Phase {phase} plans"
)
11. Handle Checker Return
## VERIFICATION PASSED: Display confirmation, proceed to step 13.## ISSUES FOUND: Display issues, check iteration count, proceed to step 12.
12. Revision Loop (Max 3 Iterations)
Track iteration_count (starts at 1 after initial plan + check).
If iteration_count < 3:
Display: Sending back to planner for revision... (iteration {N}/3)
Revision prompt:
<revision_context>
**Phase:** {phase_number}
**Mode:** revision
<files_to_read>
- {PHASE_DIR}/*-PLAN.md (Existing plans)
- {context_path} (USER DECISIONS from /gsd-discuss-phase)
</files_to_read>
${AGENT_SKILLS_PLANNER}
**Checker issues:** {structured_issues_from_checker}
</revision_context>
<instructions>
Make targeted updates to address checker issues.
Do NOT replan from scratch unless issues are fundamental.
Return what changed.
</instructions>
Task(
prompt=revision_prompt,
subagent_type="gsd-planner",
model="{planner_model}",
description="Revise Phase {phase} plans"
)
After planner returns -> spawn checker again (step 10), increment iteration_count.
If iteration_count >= 3:
Display: Max iterations reached. {N} issues remain: + issue list
Offer: 1) Force proceed, 2) Provide guidance and retry, 3) Abandon
13. Requirements Coverage Gate
After plans pass the checker (or checker is skipped), verify that all phase requirements are covered by at least one plan.
Skip if: phase_req_ids is null or TBD (no requirements mapped to this phase).
Step 1: Extract requirement IDs claimed by plans
# Collect all requirement IDs from plan frontmatter
PLAN_REQS=$(grep -h "requirements_addressed\|requirements:" ${PHASE_DIR}/*-PLAN.md 2>/dev/null | tr -d '[]' | tr ',' '\n' | sed 's/^[[:space:]]*//' | sort -u)
Step 2: Compare against phase requirements from ROADMAP
For each REQ-ID in phase_req_ids:
- If REQ-ID appears in
PLAN_REQS→ covered ✓ - If REQ-ID does NOT appear in any plan → uncovered ✗
Step 3: Check CONTEXT.md features against plan objectives
Read CONTEXT.md <decisions> section. Extract feature/capability names. Check each against plan <objective> blocks. Features not mentioned in any plan objective → potentially dropped.
Step 4: Report
If all requirements covered and no dropped features:
✓ Requirements coverage: {N}/{N} REQ-IDs covered by plans
→ Proceed to step 14.
If gaps found:
## ⚠ Requirements Coverage Gap
{M} of {N} phase requirements are not assigned to any plan:
| REQ-ID | Description | Plans |
|--------|-------------|-------|
| {id} | {from REQUIREMENTS.md} | None |
{K} CONTEXT.md features not found in plan objectives:
- {feature_name} — described in CONTEXT.md but no plan covers it
Options:
1. Re-plan to include missing requirements (recommended)
2. Move uncovered requirements to next phase
3. Proceed anyway — accept coverage gaps
If TEXT_MODE is true, present as a plain-text numbered list (options already shown in the block above). Otherwise use AskUserQuestion to present the options.
13b. Record Planning Completion in STATE.md
After plans pass all gates, record that planning is complete so STATE.md reflects the new phase status:
node "$GSD_TOOLS" state planned-phase --phase "${PHASE_NUMBER}" --name "${PHASE_NAME}" --plans "${PLAN_COUNT}"
This updates STATUS to "Ready to execute", sets the correct plan count, and timestamps Last Activity.
14. Present Final Status
Route to <offer_next> OR auto_advance depending on flags/config.
15. Auto-Advance Check
Check for auto-advance trigger:
- Parse
--autoand--chainflags from $ARGUMENTS - Sync chain flag with intent — if user invoked manually (no
--autoand no--chain), clear the ephemeral chain flag from any previous interrupted--autochain. This does NOT touchworkflow.auto_advance(the user's persistent settings preference):if [[ ! "$ARGUMENTS" =~ --auto ]] && [[ ! "$ARGUMENTS" =~ --chain ]]; then node "$GSD_TOOLS" config-set workflow._auto_chain_active false 2>/dev/null fi - Read both the chain flag and user preference:
AUTO_CHAIN=$(node "$GSD_TOOLS" config-get workflow._auto_chain_active 2>/dev/null || echo "false") AUTO_CFG=$(node "$GSD_TOOLS" config-get workflow.auto_advance 2>/dev/null || echo "false")
If --auto or --chain flag present AND AUTO_CHAIN is not true: Persist chain flag to config (handles direct invocation without prior discuss-phase):
if ([[ "$ARGUMENTS" =~ --auto ]] || [[ "$ARGUMENTS" =~ --chain ]]) && [[ "$AUTO_CHAIN" != "true" ]]; then
node "$GSD_TOOLS" config-set workflow._auto_chain_active true
fi
If --auto or --chain flag present OR AUTO_CHAIN is true OR AUTO_CFG is true:
Display banner:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GSD ► AUTO-ADVANCING TO EXECUTE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Plans ready. Launching execute-phase...
Launch execute-phase using the Skill tool to avoid nested Task sessions (which cause runtime freezes due to deep agent nesting):
Skill(skill="gsd-execute-phase", args="${PHASE} --auto --no-transition ${GSD_WS}")
The --no-transition flag tells execute-phase to return status after verification instead of chaining further. This keeps the auto-advance chain flat — each phase runs at the same nesting level rather than spawning deeper Task agents.
Handle execute-phase return:
- PHASE COMPLETE → Display final summary:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ GSD ► PHASE ${PHASE} COMPLETE ✓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Auto-advance pipeline finished. Next: /gsd-discuss-phase ${NEXT_PHASE} --auto ${GSD_WS} - GAPS FOUND / VERIFICATION FAILED → Display result, stop chain:
Auto-advance stopped: Execution needs review. Review the output above and continue manually: /gsd-execute-phase ${PHASE} ${GSD_WS}
If neither --auto nor config enabled:
Route to <offer_next> (existing behavior).
<offer_next> Output this markdown directly (not as a code block):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ GSD ► PHASE {X} PLANNED ✓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Phase {X}: {Name} — {N} plan(s) in {M} wave(s)
| Wave | Plans | What it builds |
|---|---|---|
| 1 | 01, 02 | [objectives] |
| 2 | 03 | [objective] |
Research: {Completed | Used existing | Skipped} Verification: {Passed | Passed with override | Skipped}
───────────────────────────────────────────────────────────────
▶ Next Up
Execute Phase {X} — run all {N} plans
/clear then:
/gsd-execute-phase {X} ${GSD_WS}
───────────────────────────────────────────────────────────────
Also available:
- cat .planning/phases/{phase-dir}/*-PLAN.md — review plans
- /gsd-plan-phase {X} --research — re-research first
- /gsd-review --phase {X} --all — peer review plans with external AIs
- /gsd-plan-phase {X} --reviews — replan incorporating review feedback
─────────────────────────────────────────────────────────────── </offer_next>
<windows_troubleshooting> Windows users: If plan-phase freezes during agent spawning (common on Windows due to stdio deadlocks with MCP servers — see Claude Code issue anthropics/claude-code#28126):
- Force-kill: Close the terminal (Ctrl+C may not work)
- Clean up orphaned processes:
# Kill orphaned node processes from stale MCP servers Get-Process node -ErrorAction SilentlyContinue | Where-Object {$_.StartTime -lt (Get-Date).AddHours(-1)} | Stop-Process -Force - Clean up stale task directories:
# Remove stale subagent task dirs (Claude Code never cleans these on crash) Remove-Item -Recurse -Force "$env:USERPROFILE\.claude\tasks\*" -ErrorAction SilentlyContinue - Reduce MCP server count: Temporarily disable non-essential MCP servers in settings.json
- Retry: Restart Claude Code and run
/gsd-plan-phaseagain
If freezes persist, try --skip-research to reduce the agent chain from 3 to 2 agents:
/gsd-plan-phase N --skip-research
</windows_troubleshooting>
<success_criteria>
- .planning/ directory validated
- Phase validated against roadmap
- Phase directory created if needed
- CONTEXT.md loaded early (step 4) and passed to ALL agents
- Research completed (unless --skip-research or --gaps or exists)
- gsd-phase-researcher spawned with CONTEXT.md
- Existing plans checked
- gsd-planner spawned with CONTEXT.md + RESEARCH.md
- Plans created (PLANNING COMPLETE or CHECKPOINT handled)
- gsd-plan-checker spawned with CONTEXT.md
- Verification passed OR user override OR max iterations with user decision
- User sees status between agent spawns
- User knows next steps </success_criteria>
<runtime_note>
Copilot (VS Code): Use vscode_askquestions wherever this workflow calls AskUserQuestion. They are equivalent — vscode_askquestions is the VS Code Copilot implementation of the same interactive question API. Do not skip questioning steps because AskUserQuestion appears unavailable; use vscode_askquestions instead.
</runtime_note>
Flags:
--research— Force re-research even if RESEARCH.md exists--skip-research— Skip research, go straight to planning--gaps— Gap closure mode (reads VERIFICATION.md, skips research)--skip-verify— Skip verification loop--prd <file>— Use a PRD/acceptance criteria file instead of discuss-phase. Parses requirements into CONTEXT.md automatically. Skips discuss-phase entirely.--reviews— Replan incorporating cross-AI review feedback from REVIEWS.md (produced by/gsd-review)--text— Use plain-text numbered lists instead of TUI menus (required for/rcremote sessions)
Normalize phase input in step 2 before any directory lookups. </context>
<process> Execute the plan-phase workflow steps embedded above end-to-end. Preserve all workflow gates (validation, research, planning, verification loop, routing). </process>