feat: implement --reviews flag for gsd:plan-phase
Wire the --reviews flag through the full stack so plan-phase can replan incorporating cross-AI review feedback from REVIEWS.md: - core.cjs: add has_reviews detection in searchPhaseInDir - init.cjs: wire has_reviews and reviews_path through all init functions - plan-phase.md command: add --reviews to argument-hint and flags - plan-phase.md workflow: add step 2.5 validation, skip research, skip existing plans prompt, pass reviews_path to planner - gsd-planner.md: add reviews_mode section for consuming review feedback - COMMANDS.md: add --reviews and missing flags to docs Closes the gap where --reviews was referenced in 6 places (review workflow, review command, help workflow, COMMANDS.md, FEATURES.md) but never implemented. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,7 @@ Spawned by:
|
||||
- `/gsd:plan-phase` orchestrator (standard phase planning)
|
||||
- `/gsd:plan-phase --gaps` orchestrator (gap closure from verification failures)
|
||||
- `/gsd:plan-phase` in revision mode (updating plans based on checker feedback)
|
||||
- `/gsd:plan-phase --reviews` orchestrator (replanning with cross-AI review feedback)
|
||||
|
||||
Your job: Produce PLAN.md files that Claude executors can implement without interpretation. Plans are prompts, not documents that become prompts.
|
||||
|
||||
@@ -966,6 +967,50 @@ node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" commit "fix($PHASE): revise
|
||||
|
||||
</revision_mode>
|
||||
|
||||
<reviews_mode>
|
||||
|
||||
## Planning from Cross-AI Review Feedback
|
||||
|
||||
Triggered when orchestrator sets Mode to `reviews`. Replanning from scratch with REVIEWS.md feedback as additional context.
|
||||
|
||||
**Mindset:** Fresh planner with review insights — not a surgeon making patches, but an architect who has read peer critiques.
|
||||
|
||||
### Step 1: Load REVIEWS.md
|
||||
Read the reviews file from `<files_to_read>`. Parse:
|
||||
- Per-reviewer feedback (strengths, concerns, suggestions)
|
||||
- Consensus Summary (agreed concerns = highest priority to address)
|
||||
- Divergent Views (investigate, make a judgment call)
|
||||
|
||||
### Step 2: Categorize Feedback
|
||||
Group review feedback into:
|
||||
- **Must address**: HIGH severity consensus concerns
|
||||
- **Should address**: MEDIUM severity concerns from 2+ reviewers
|
||||
- **Consider**: Individual reviewer suggestions, LOW severity items
|
||||
|
||||
### Step 3: Plan Fresh with Review Context
|
||||
Create new plans following the standard planning process, but with review feedback as additional constraints:
|
||||
- Each HIGH severity consensus concern MUST have a task that addresses it
|
||||
- MEDIUM concerns should be addressed where feasible without over-engineering
|
||||
- Note in task actions: "Addresses review concern: {concern}" for traceability
|
||||
|
||||
### Step 4: Return
|
||||
Use standard PLANNING COMPLETE return format, adding a reviews section:
|
||||
|
||||
```markdown
|
||||
### Review Feedback Addressed
|
||||
|
||||
| Concern | Severity | How Addressed |
|
||||
|---------|----------|---------------|
|
||||
| {concern} | HIGH | Plan {N}, Task {M}: {how} |
|
||||
|
||||
### Review Feedback Deferred
|
||||
| Concern | Reason |
|
||||
|---------|--------|
|
||||
| {concern} | {why — out of scope, disagree, etc.} |
|
||||
```
|
||||
|
||||
</reviews_mode>
|
||||
|
||||
<execution_flow>
|
||||
|
||||
<step name="load_project_state" priority="first">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
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>]"
|
||||
argument-hint: "[phase] [--auto] [--research] [--skip-research] [--gaps] [--skip-verify] [--prd <file>] [--reviews]"
|
||||
agent: gsd-planner
|
||||
allowed-tools:
|
||||
- Read
|
||||
@@ -35,6 +35,7 @@ Phase number: $ARGUMENTS (optional — auto-detects next unplanned phase if omit
|
||||
- `--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`)
|
||||
|
||||
Normalize phase input in step 2 before any directory lookups.
|
||||
</context>
|
||||
|
||||
@@ -86,8 +86,12 @@ Research, plan, and verify a phase.
|
||||
| Flag | Description |
|
||||
|------|-------------|
|
||||
| `--auto` | Skip interactive confirmations |
|
||||
| `--research` | Force re-research even if RESEARCH.md exists |
|
||||
| `--skip-research` | Skip domain research step |
|
||||
| `--gaps` | Gap closure mode (reads VERIFICATION.md, skips research) |
|
||||
| `--skip-verify` | Skip plan checker verification loop |
|
||||
| `--prd <file>` | Use a PRD file instead of discuss-phase for context |
|
||||
| `--reviews` | Replan with cross-AI review feedback from REVIEWS.md |
|
||||
|
||||
**Prerequisites:** `.planning/ROADMAP.md` exists
|
||||
**Produces:** `{phase}-RESEARCH.md`, `{phase}-{N}-PLAN.md`, `{phase}-VALIDATION.md`
|
||||
|
||||
@@ -613,6 +613,7 @@ function searchPhaseInDir(baseDir, relBase, normalized) {
|
||||
const hasResearch = phaseFiles.some(f => f.endsWith('-RESEARCH.md') || f === 'RESEARCH.md');
|
||||
const hasContext = phaseFiles.some(f => f.endsWith('-CONTEXT.md') || f === 'CONTEXT.md');
|
||||
const hasVerification = phaseFiles.some(f => f.endsWith('-VERIFICATION.md') || f === 'VERIFICATION.md');
|
||||
const hasReviews = phaseFiles.some(f => f.endsWith('-REVIEWS.md') || f === 'REVIEWS.md');
|
||||
|
||||
const completedPlanIds = new Set(
|
||||
summaries.map(s => s.replace('-SUMMARY.md', '').replace('SUMMARY.md', ''))
|
||||
@@ -634,6 +635,7 @@ function searchPhaseInDir(baseDir, relBase, normalized) {
|
||||
has_research: hasResearch,
|
||||
has_context: hasContext,
|
||||
has_verification: hasVerification,
|
||||
has_reviews: hasReviews,
|
||||
};
|
||||
} catch {
|
||||
return null;
|
||||
|
||||
@@ -60,6 +60,7 @@ function cmdInitExecutePhase(cwd, phase, raw) {
|
||||
has_research: false,
|
||||
has_context: false,
|
||||
has_verification: false,
|
||||
has_reviews: false,
|
||||
};
|
||||
}
|
||||
const reqMatch = roadmapPhase?.section?.match(/^\*\*Requirements\*\*:[^\S\n]*([^\n]*)$/m);
|
||||
@@ -152,6 +153,7 @@ function cmdInitPlanPhase(cwd, phase, raw) {
|
||||
has_research: false,
|
||||
has_context: false,
|
||||
has_verification: false,
|
||||
has_reviews: false,
|
||||
};
|
||||
}
|
||||
const reqMatch = roadmapPhase?.section?.match(/^\*\*Requirements\*\*:[^\S\n]*([^\n]*)$/m);
|
||||
@@ -184,6 +186,7 @@ function cmdInitPlanPhase(cwd, phase, raw) {
|
||||
// Existing artifacts
|
||||
has_research: phaseInfo?.has_research || false,
|
||||
has_context: phaseInfo?.has_context || false,
|
||||
has_reviews: phaseInfo?.has_reviews || false,
|
||||
has_plans: (phaseInfo?.plans?.length || 0) > 0,
|
||||
plan_count: phaseInfo?.plans?.length || 0,
|
||||
|
||||
@@ -218,6 +221,10 @@ function cmdInitPlanPhase(cwd, phase, raw) {
|
||||
if (uatFile) {
|
||||
result.uat_path = toPosixPath(path.join(phaseInfo.directory, uatFile));
|
||||
}
|
||||
const reviewsFile = files.find(f => f.endsWith('-REVIEWS.md') || f === 'REVIEWS.md');
|
||||
if (reviewsFile) {
|
||||
result.reviews_path = toPosixPath(path.join(phaseInfo.directory, reviewsFile));
|
||||
}
|
||||
} catch { /* intentionally empty */ }
|
||||
}
|
||||
|
||||
@@ -557,6 +564,7 @@ function cmdInitPhaseOp(cwd, phase, raw) {
|
||||
has_context: phaseInfo?.has_context || false,
|
||||
has_plans: (phaseInfo?.plans?.length || 0) > 0,
|
||||
has_verification: phaseInfo?.has_verification || false,
|
||||
has_reviews: phaseInfo?.has_reviews || false,
|
||||
plan_count: phaseInfo?.plans?.length || 0,
|
||||
|
||||
// File existence
|
||||
@@ -589,6 +597,10 @@ function cmdInitPhaseOp(cwd, phase, raw) {
|
||||
if (uatFile) {
|
||||
result.uat_path = toPosixPath(path.join(phaseInfo.directory, uatFile));
|
||||
}
|
||||
const reviewsFile = files.find(f => f.endsWith('-REVIEWS.md') || f === 'REVIEWS.md');
|
||||
if (reviewsFile) {
|
||||
result.reviews_path = toPosixPath(path.join(phaseInfo.directory, reviewsFile));
|
||||
}
|
||||
} catch { /* intentionally empty */ }
|
||||
}
|
||||
|
||||
|
||||
@@ -26,15 +26,15 @@ INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" init plan-phase "$PH
|
||||
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
|
||||
```
|
||||
|
||||
Parse JSON for: `researcher_model`, `planner_model`, `checker_model`, `research_enabled`, `plan_checker_enabled`, `nyquist_validation_enabled`, `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `has_research`, `has_context`, `has_plans`, `plan_count`, `planning_exists`, `roadmap_exists`, `phase_req_ids`.
|
||||
Parse JSON for: `researcher_model`, `planner_model`, `checker_model`, `research_enabled`, `plan_checker_enabled`, `nyquist_validation_enabled`, `commit_docs`, `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`.
|
||||
|
||||
**File paths (for <files_to_read> blocks):** `state_path`, `roadmap_path`, `requirements_path`, `context_path`, `research_path`, `verification_path`, `uat_path`. These are null if files don't exist.
|
||||
**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>`).
|
||||
Extract from $ARGUMENTS: phase number (integer or decimal like `2.1`), flags (`--research`, `--skip-research`, `--gaps`, `--skip-verify`, `--prd <filepath>`, `--reviews`).
|
||||
|
||||
Extract `--prd <filepath>` from $ARGUMENTS. If present, set PRD_FILE to the filepath.
|
||||
|
||||
@@ -47,6 +47,24 @@ 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
|
||||
|
||||
```bash
|
||||
@@ -190,7 +208,7 @@ If "Run discuss-phase first":
|
||||
|
||||
## 5. Handle Research
|
||||
|
||||
**Skip if:** `--gaps` flag or `--skip-research` flag.
|
||||
**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.
|
||||
|
||||
@@ -349,7 +367,9 @@ Use AskUserQuestion:
|
||||
ls "${PHASE_DIR}"/*-PLAN.md 2>/dev/null
|
||||
```
|
||||
|
||||
**If exists:** Offer: 1) Add more plans, 2) View existing, 3) Replan from scratch.
|
||||
**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
|
||||
|
||||
@@ -363,6 +383,7 @@ RESEARCH_PATH=$(printf '%s\n' "$INIT" | jq -r '.research_path // empty')
|
||||
VERIFICATION_PATH=$(printf '%s\n' "$INIT" | jq -r '.verification_path // empty')
|
||||
UAT_PATH=$(printf '%s\n' "$INIT" | jq -r '.uat_path // empty')
|
||||
CONTEXT_PATH=$(printf '%s\n' "$INIT" | jq -r '.context_path // empty')
|
||||
REVIEWS_PATH=$(printf '%s\n' "$INIT" | jq -r '.reviews_path // empty')
|
||||
```
|
||||
|
||||
## 7.5. Verify Nyquist Artifacts
|
||||
@@ -404,7 +425,7 @@ Planner prompt:
|
||||
```markdown
|
||||
<planning_context>
|
||||
**Phase:** {phase_number}
|
||||
**Mode:** {standard | gap_closure}
|
||||
**Mode:** {standard | gap_closure | reviews}
|
||||
|
||||
<files_to_read>
|
||||
- {state_path} (Project State)
|
||||
@@ -414,6 +435,7 @@ Planner prompt:
|
||||
- {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)
|
||||
</files_to_read>
|
||||
|
||||
@@ -733,6 +755,8 @@ Verification: {Passed | Passed with override | Skipped}
|
||||
**Also available:**
|
||||
- cat .planning/phases/{phase-dir}/*-PLAN.md — review plans
|
||||
- /gsd:plan-phase {X} --research — re-research first
|
||||
- /gsd:review {X} --all — peer review plans with external AIs
|
||||
- /gsd:plan-phase {X} --reviews — replan incorporating review feedback
|
||||
|
||||
───────────────────────────────────────────────────────────────
|
||||
</offer_next>
|
||||
|
||||
Reference in New Issue
Block a user