From 4addcea4cfa177526f9090858b6506593870cb06 Mon Sep 17 00:00:00 2001 From: Chris Esposito Date: Fri, 20 Mar 2026 16:08:17 -0400 Subject: [PATCH 1/3] 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) --- agents/gsd-planner.md | 45 +++++++++++++++++++++++++++ commands/gsd/plan-phase.md | 3 +- docs/COMMANDS.md | 4 +++ get-shit-done/bin/lib/core.cjs | 2 ++ get-shit-done/bin/lib/init.cjs | 12 +++++++ get-shit-done/workflows/plan-phase.md | 36 +++++++++++++++++---- 6 files changed, 95 insertions(+), 7 deletions(-) diff --git a/agents/gsd-planner.md b/agents/gsd-planner.md index ae38de9dd..9c01b4bd7 100644 --- a/agents/gsd-planner.md +++ b/agents/gsd-planner.md @@ -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 + + +## 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 ``. 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.} | +``` + + + diff --git a/commands/gsd/plan-phase.md b/commands/gsd/plan-phase.md index bb377a897..1f26ebbb7 100644 --- a/commands/gsd/plan-phase.md +++ b/commands/gsd/plan-phase.md @@ -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 ]" +argument-hint: "[phase] [--auto] [--research] [--skip-research] [--gaps] [--skip-verify] [--prd ] [--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 ` — 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. diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index a9756c29a..8c7a5e80a 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -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 ` | 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` diff --git a/get-shit-done/bin/lib/core.cjs b/get-shit-done/bin/lib/core.cjs index e92f74916..a068d9ac6 100644 --- a/get-shit-done/bin/lib/core.cjs +++ b/get-shit-done/bin/lib/core.cjs @@ -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; diff --git a/get-shit-done/bin/lib/init.cjs b/get-shit-done/bin/lib/init.cjs index d87302b51..0ce6e0fe5 100644 --- a/get-shit-done/bin/lib/init.cjs +++ b/get-shit-done/bin/lib/init.cjs @@ -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 */ } } diff --git a/get-shit-done/workflows/plan-phase.md b/get-shit-done/workflows/plan-phase.md index 26697dc3e..50fdffdac 100644 --- a/get-shit-done/workflows/plan-phase.md +++ b/get-shit-done/workflows/plan-phase.md @@ -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 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 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 `). +Extract from $ARGUMENTS: phase number (integer or decimal like `2.1`), flags (`--research`, `--skip-research`, `--gaps`, `--skip-verify`, `--prd `, `--reviews`). Extract `--prd ` 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 **Phase:** {phase_number} -**Mode:** {standard | gap_closure} +**Mode:** {standard | gap_closure | reviews} - {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) @@ -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 ─────────────────────────────────────────────────────────────── From 31660d0f17f52846334c09fcbc83e6fd883fec67 Mon Sep 17 00:00:00 2001 From: chrisesposito92 <150860110+chrisesposito92@users.noreply.github.com> Date: Fri, 20 Mar 2026 20:41:06 -0400 Subject: [PATCH 2/3] Update get-shit-done/workflows/plan-phase.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- get-shit-done/workflows/plan-phase.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/get-shit-done/workflows/plan-phase.md b/get-shit-done/workflows/plan-phase.md index 50fdffdac..a8de7b37b 100644 --- a/get-shit-done/workflows/plan-phase.md +++ b/get-shit-done/workflows/plan-phase.md @@ -755,7 +755,7 @@ 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:review --phase {X} --all — peer review plans with external AIs - /gsd:plan-phase {X} --reviews — replan incorporating review feedback ─────────────────────────────────────────────────────────────── From 71aedb28d51f9a29af9acf6c909b811ab87f7f8f Mon Sep 17 00:00:00 2001 From: Chris Esposito Date: Fri, 20 Mar 2026 20:44:24 -0400 Subject: [PATCH 3/3] test: add init tests for has_reviews and reviews_path - Test that has_reviews=true and reviews_path is set when REVIEWS.md exists - Test that reviews_path is undefined and has_reviews=false when missing Co-Authored-By: Claude Opus 4.6 (1M context) --- tests/init.test.cjs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/init.test.cjs b/tests/init.test.cjs index e7655d0e0..929f18473 100644 --- a/tests/init.test.cjs +++ b/tests/init.test.cjs @@ -86,6 +86,19 @@ describe('init commands', () => { assert.strictEqual(output.uat_path, '.planning/phases/03-api/03-UAT.md'); }); + test('init plan-phase detects has_reviews and reviews_path when REVIEWS.md exists', () => { + const phaseDir = path.join(tmpDir, '.planning', 'phases', '03-api'); + fs.mkdirSync(phaseDir, { recursive: true }); + fs.writeFileSync(path.join(phaseDir, '03-REVIEWS.md'), '# Cross-AI Reviews'); + + const result = runGsdTools('init plan-phase 03', tmpDir); + assert.ok(result.success, `Command failed: ${result.error}`); + + const output = JSON.parse(result.output); + assert.strictEqual(output.has_reviews, true); + assert.strictEqual(output.reviews_path, '.planning/phases/03-api/03-REVIEWS.md'); + }); + test('init plan-phase omits optional paths if files missing', () => { const phaseDir = path.join(tmpDir, '.planning', 'phases', '03-api'); fs.mkdirSync(phaseDir, { recursive: true }); @@ -96,6 +109,8 @@ describe('init commands', () => { const output = JSON.parse(result.output); assert.strictEqual(output.context_path, undefined); assert.strictEqual(output.research_path, undefined); + assert.strictEqual(output.reviews_path, undefined); + assert.strictEqual(output.has_reviews, false); }); // ── phase_req_ids extraction (fix for #684) ──────────────────────────────