fix(orchestrators): inline file contents in Task prompts

The @ file reference syntax does not expand across Task() boundaries.
Subagents receive literal @path strings instead of file contents.

Changed orchestrator→subagent handoffs to explicitly read files and
inline content before spawning:

- plan-phase → gsd-planner: STATE, ROADMAP, REQUIREMENTS, CONTEXT, RESEARCH
- plan-phase → gsd-plan-checker: PLAN files, REQUIREMENTS
- plan-phase → gsd-planner (revision): PLAN files
- execute-phase → gsd-executor: PLAN, STATE, config

Fixes #182

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Lex Christopherson
2026-01-19 23:11:09 -06:00
parent fb397df9b2
commit ce4fc96ff7
3 changed files with 75 additions and 33 deletions

View File

@@ -230,12 +230,22 @@ After user runs /gsd:plan-phase {Z} --gaps:
<wave_execution>
**Parallel spawning:**
Spawn all plans in a wave with a single message containing multiple Task calls:
Before spawning, read file contents. The `@` syntax does not work across Task() boundaries.
```bash
# Read each plan and STATE.md
PLAN_01_CONTENT=$(cat "{plan_01_path}")
PLAN_02_CONTENT=$(cat "{plan_02_path}")
PLAN_03_CONTENT=$(cat "{plan_03_path}")
STATE_CONTENT=$(cat .planning/STATE.md)
```
Spawn all plans in a wave with a single message containing multiple Task calls, with inlined content:
```
Task(prompt="Execute plan at {plan_01_path}\n\nPlan: @{plan_01_path}\nProject state: @.planning/STATE.md", subagent_type="gsd-executor")
Task(prompt="Execute plan at {plan_02_path}\n\nPlan: @{plan_02_path}\nProject state: @.planning/STATE.md", subagent_type="gsd-executor")
Task(prompt="Execute plan at {plan_03_path}\n\nPlan: @{plan_03_path}\nProject state: @.planning/STATE.md", subagent_type="gsd-executor")
Task(prompt="Execute plan at {plan_01_path}\n\nPlan:\n{plan_01_content}\n\nProject state:\n{state_content}", subagent_type="gsd-executor")
Task(prompt="Execute plan at {plan_02_path}\n\nPlan:\n{plan_02_content}\n\nProject state:\n{state_content}", subagent_type="gsd-executor")
Task(prompt="Execute plan at {plan_03_path}\n\nPlan:\n{plan_03_content}\n\nProject state:\n{state_content}", subagent_type="gsd-executor")
```
All three run in parallel. Task tool blocks until all complete.

View File

@@ -205,21 +205,23 @@ ls "${PHASE_DIR}"/*-PLAN.md 2>/dev/null
**If exists:** Offer: 1) Continue planning (add more plans), 2) View existing, 3) Replan from scratch. Wait for response.
## 7. Gather Context Paths
## 7. Read Context Files
Identify context files for the planner agent:
Read and store context file contents for the planner agent. The `@` syntax does not work across Task() boundaries - content must be inlined.
```bash
# Required
STATE=.planning/STATE.md
ROADMAP=.planning/ROADMAP.md
REQUIREMENTS=.planning/REQUIREMENTS.md
# Read required files
STATE_CONTENT=$(cat .planning/STATE.md)
ROADMAP_CONTENT=$(cat .planning/ROADMAP.md)
# Optional (created by earlier steps or commands)
CONTEXT="${PHASE_DIR}/${PHASE}-CONTEXT.md"
RESEARCH="${PHASE_DIR}/${PHASE}-RESEARCH.md"
VERIFICATION="${PHASE_DIR}/${PHASE}-VERIFICATION.md"
UAT="${PHASE_DIR}/${PHASE}-UAT.md"
# Read optional files (empty string if missing)
REQUIREMENTS_CONTENT=$(cat .planning/REQUIREMENTS.md 2>/dev/null)
CONTEXT_CONTENT=$(cat "${PHASE_DIR}"/*-CONTEXT.md 2>/dev/null)
RESEARCH_CONTENT=$(cat "${PHASE_DIR}"/*-RESEARCH.md 2>/dev/null)
# Gap closure files (only if --gaps mode)
VERIFICATION_CONTENT=$(cat "${PHASE_DIR}"/*-VERIFICATION.md 2>/dev/null)
UAT_CONTENT=$(cat "${PHASE_DIR}"/*-UAT.md 2>/dev/null)
```
## 8. Spawn gsd-planner Agent
@@ -233,7 +235,7 @@ Display stage banner:
◆ Spawning planner...
```
Fill prompt and spawn:
Fill prompt with inlined content and spawn:
```markdown
<planning_context>
@@ -242,23 +244,23 @@ Fill prompt and spawn:
**Mode:** {standard | gap_closure}
**Project State:**
@.planning/STATE.md
{state_content}
**Roadmap:**
@.planning/ROADMAP.md
{roadmap_content}
**Requirements (if exists):**
@.planning/REQUIREMENTS.md
{requirements_content}
**Phase Context (if exists):**
@.planning/phases/{phase_dir}/{phase}-CONTEXT.md
{context_content}
**Research (if exists):**
@.planning/phases/{phase_dir}/{phase}-RESEARCH.md
{research_content}
**Gap Closure (if --gaps mode):**
@.planning/phases/{phase_dir}/{phase}-VERIFICATION.md
@.planning/phases/{phase_dir}/{phase}-UAT.md
{verification_content}
{uat_content}
</planning_context>
@@ -320,7 +322,17 @@ Display:
◆ Spawning plan checker...
```
Fill checker prompt and spawn:
Read plans and requirements for the checker:
```bash
# Read all plans in phase directory
PLANS_CONTENT=$(cat "${PHASE_DIR}"/*-PLAN.md 2>/dev/null)
# Read requirements (reuse from step 7 if available)
REQUIREMENTS_CONTENT=$(cat .planning/REQUIREMENTS.md 2>/dev/null)
```
Fill checker prompt with inlined content and spawn:
```markdown
<verification_context>
@@ -329,10 +341,10 @@ Fill checker prompt and spawn:
**Phase Goal:** {goal from ROADMAP}
**Plans to verify:**
@.planning/phases/{phase_dir}/*-PLAN.md
{plans_content}
**Requirements (if exists):**
@.planning/REQUIREMENTS.md
{requirements_content}
</verification_context>
@@ -371,6 +383,12 @@ Track: `iteration_count` (starts at 1 after initial plan + check)
Display: `Sending back to planner for revision... (iteration {N}/3)`
Read current plans for revision context:
```bash
PLANS_CONTENT=$(cat "${PHASE_DIR}"/*-PLAN.md 2>/dev/null)
```
Spawn gsd-planner with revision prompt:
```markdown
@@ -380,7 +398,7 @@ Spawn gsd-planner with revision prompt:
**Mode:** revision
**Existing plans:**
@.planning/phases/{phase_dir}/*-PLAN.md
{plans_content}
**Checker issues:**
{structured_issues_from_checker}
@@ -388,7 +406,7 @@ Spawn gsd-planner with revision prompt:
</revision_context>
<instructions>
Read existing PLAN.md files. Make targeted updates to address checker issues.
Make targeted updates to address checker issues.
Do NOT replan from scratch unless issues are fundamental.
Return what changed.
</instructions>

View File

@@ -170,9 +170,18 @@ Execute each wave in sequence. Autonomous plans within a wave run in parallel.
- Bad: "Executing terrain generation plan"
- Good: "Procedural terrain generator using Perlin noise — creates height maps, biome zones, and collision meshes. Required before vehicle physics can interact with ground."
2. **Spawn all autonomous agents in wave simultaneously:**
2. **Read files and spawn all autonomous agents in wave simultaneously:**
Use Task tool with multiple parallel calls. Each agent gets prompt from subagent-task-prompt template:
Before spawning, read file contents. The `@` syntax does not work across Task() boundaries - content must be inlined.
```bash
# Read each plan in the wave
PLAN_CONTENT=$(cat "{plan_path}")
STATE_CONTENT=$(cat .planning/STATE.md)
CONFIG_CONTENT=$(cat .planning/config.json 2>/dev/null)
```
Use Task tool with multiple parallel calls. Each agent gets prompt with inlined content:
```
<objective>
@@ -189,9 +198,14 @@ Execute each wave in sequence. Autonomous plans within a wave run in parallel.
</execution_context>
<context>
Plan: @{plan_path}
Project state: @.planning/STATE.md
Config: @.planning/config.json (if exists)
Plan:
{plan_content}
Project state:
{state_content}
Config (if exists):
{config_content}
</context>
<success_criteria>