* feat(review): add per-CLI model selection via config - Add review.models.<cli> dynamic config keys to VALID_CONFIG_KEYS - Update review.md to read model preferences via config-get at runtime - Null/missing values fall back to CLI defaults (backward compatible) - Add key suggestion for common typo (review.model) - Update planning-config reference doc Closes #1849 * fix(review): handle absent and null model config gracefully Address PR #1859 review feedback from @trek-e: 1. Add `|| true` to all four config-get subshell invocations in review.md so that an absent review.models.<cli> key does not produce a non-zero exit from the subshell. cmdConfigGet calls error() (process.exit(1)) when the key path is missing; the 2>/dev/null suppresses the message but the exit code was still discarded silently. The || true makes the fall-through explicit and survives future set -e adoption. 2. Add `&& [ "$VAR" != "null" ]` to all four if guards. cmdConfigSet does not parse the literal 'null' as JSON null — it stores the string 'null' — and cmdConfigGet --raw returns the literal text 'null' for that value. Without the extra guard the workflow would pass `-m "null"` to the CLI, which crashes. The issue spec documents null as the "fall back to CLI default" sentinel, so this restores the contract. 3. Add tests/review-model-config.test.cjs covering all five cases trek-e listed: - isValidConfigKey accepts review.models.gemini (via config-set) - isValidConfigKey accepts review.models.codex (via config-set) - review.model is rejected and suggests review.models.<cli-name> - config-set then config-get round-trip with a model ID - config-set then config-get round-trip with null (returns "null") Tests follow the node:test + node:assert/strict pattern from tests/agent-skills.test.cjs and use runGsdTools from helpers.cjs. Closes #1849
9.1 KiB
This implements adversarial review: different AI models catch different blind spots. A plan that survives review from 2-3 independent AI systems is more robust.
Check which AI CLIs are available on the system:# Check each CLI
command -v gemini >/dev/null 2>&1 && echo "gemini:available" || echo "gemini:missing"
command -v claude >/dev/null 2>&1 && echo "claude:available" || echo "claude:missing"
command -v codex >/dev/null 2>&1 && echo "codex:available" || echo "codex:missing"
command -v coderabbit >/dev/null 2>&1 && echo "coderabbit:available" || echo "coderabbit:missing"
command -v opencode >/dev/null 2>&1 && echo "opencode:available" || echo "opencode:missing"
Parse flags from $ARGUMENTS:
--gemini→ include Gemini--claude→ include Claude--codex→ include Codex--coderabbit→ include CodeRabbit--opencode→ include OpenCode--all→ include all available- No flags → include all available
If no CLIs are available:
No external AI CLIs found. Install at least one:
- gemini: https://github.com/google-gemini/gemini-cli
- codex: https://github.com/openai/codex
- claude: https://github.com/anthropics/claude-code
- opencode: https://opencode.ai (leverages GitHub Copilot subscription models)
Then run /gsd-review again.
Exit.
Determine which CLI to skip based on the current runtime environment:
# Environment-based runtime detection (priority order)
if [ "$ANTIGRAVITY_AGENT" = "1" ]; then
# Antigravity is a separate client — all CLIs are external, skip none
SELF_CLI="none"
elif [ -n "$CLAUDE_CODE_ENTRYPOINT" ]; then
# Running inside Claude Code CLI — skip claude for independence
SELF_CLI="claude"
else
# Other environments (Gemini CLI, Codex CLI, etc.)
# Fall back to AI self-identification to decide which CLI to skip
SELF_CLI="auto"
fi
Rules:
- If
SELF_CLI="none"→ invoke ALL available CLIs (no skip) - If
SELF_CLI="claude"→ skip claude, use gemini/codex - If
SELF_CLI="auto"→ the executing AI identifies itself and skips its own CLI - At least one DIFFERENT CLI must be available for the review to proceed.
INIT=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" init phase-op "${PHASE_ARG}")
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
Read from init: phase_dir, phase_number, padded_phase.
Then read:
.planning/PROJECT.md(first 80 lines — project context)- Phase section from
.planning/ROADMAP.md - All
*-PLAN.mdfiles in the phase directory *-CONTEXT.mdif present (user decisions)*-RESEARCH.mdif present (domain research).planning/REQUIREMENTS.md(requirements this phase addresses)
# Cross-AI Plan Review Request
You are reviewing implementation plans for a software project phase.
Provide structured feedback on plan quality, completeness, and risks.
## Project Context
{first 80 lines of PROJECT.md}
## Phase {N}: {phase name}
### Roadmap Section
{roadmap phase section}
### Requirements Addressed
{requirements for this phase}
### User Decisions (CONTEXT.md)
{context if present}
### Research Findings
{research if present}
### Plans to Review
{all PLAN.md contents}
## Review Instructions
Analyze each plan and provide:
1. **Summary** — One-paragraph assessment
2. **Strengths** — What's well-designed (bullet points)
3. **Concerns** — Potential issues, gaps, risks (bullet points with severity: HIGH/MEDIUM/LOW)
4. **Suggestions** — Specific improvements (bullet points)
5. **Risk Assessment** — Overall risk level (LOW/MEDIUM/HIGH) with justification
Focus on:
- Missing edge cases or error handling
- Dependency ordering issues
- Scope creep or over-engineering
- Security considerations
- Performance implications
- Whether the plans actually achieve the phase goals
Output your review in markdown format.
Write to a temp file: /tmp/gsd-review-prompt-{phase}.md
GEMINI_MODEL=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" config-get review.models.gemini --raw 2>/dev/null || true)
CLAUDE_MODEL=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" config-get review.models.claude --raw 2>/dev/null || true)
CODEX_MODEL=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" config-get review.models.codex --raw 2>/dev/null || true)
OPENCODE_MODEL=$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" config-get review.models.opencode --raw 2>/dev/null || true)
For each selected CLI, invoke in sequence (not parallel — avoid rate limits):
Gemini:
if [ -n "$GEMINI_MODEL" ] && [ "$GEMINI_MODEL" != "null" ]; then
gemini -m "$GEMINI_MODEL" -p "$(cat /tmp/gsd-review-prompt-{phase}.md)" 2>/dev/null > /tmp/gsd-review-gemini-{phase}.md
else
gemini -p "$(cat /tmp/gsd-review-prompt-{phase}.md)" 2>/dev/null > /tmp/gsd-review-gemini-{phase}.md
fi
Claude (separate session):
if [ -n "$CLAUDE_MODEL" ] && [ "$CLAUDE_MODEL" != "null" ]; then
claude --model "$CLAUDE_MODEL" -p "$(cat /tmp/gsd-review-prompt-{phase}.md)" 2>/dev/null > /tmp/gsd-review-claude-{phase}.md
else
claude -p "$(cat /tmp/gsd-review-prompt-{phase}.md)" 2>/dev/null > /tmp/gsd-review-claude-{phase}.md
fi
Codex:
if [ -n "$CODEX_MODEL" ] && [ "$CODEX_MODEL" != "null" ]; then
codex exec --model "$CODEX_MODEL" --skip-git-repo-check "$(cat /tmp/gsd-review-prompt-{phase}.md)" 2>/dev/null > /tmp/gsd-review-codex-{phase}.md
else
codex exec --skip-git-repo-check "$(cat /tmp/gsd-review-prompt-{phase}.md)" 2>/dev/null > /tmp/gsd-review-codex-{phase}.md
fi
CodeRabbit:
Note: CodeRabbit reviews the current git diff/working tree — it does not accept a prompt or model flag. It may take up to 5 minutes. Use timeout: 360000 on the Bash tool call.
coderabbit review --prompt-only 2>/dev/null > /tmp/gsd-review-coderabbit-{phase}.md
OpenCode (via GitHub Copilot):
if [ -n "$OPENCODE_MODEL" ] && [ "$OPENCODE_MODEL" != "null" ]; then
cat /tmp/gsd-review-prompt-{phase}.md | opencode run --model "$OPENCODE_MODEL" - 2>/dev/null > /tmp/gsd-review-opencode-{phase}.md
else
cat /tmp/gsd-review-prompt-{phase}.md | opencode run - 2>/dev/null > /tmp/gsd-review-opencode-{phase}.md
fi
if [ ! -s /tmp/gsd-review-opencode-{phase}.md ]; then
echo "OpenCode review failed or returned empty output." > /tmp/gsd-review-opencode-{phase}.md
fi
If a CLI fails, log the error and continue with remaining CLIs.
Display progress:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GSD ► CROSS-AI REVIEW — Phase {N}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
◆ Reviewing with {CLI}... done ✓
◆ Reviewing with {CLI}... done ✓
---
phase: {N}
reviewers: [gemini, claude, codex, coderabbit, opencode]
reviewed_at: {ISO timestamp}
plans_reviewed: [{list of PLAN.md files}]
---
# Cross-AI Plan Review — Phase {N}
## Gemini Review
{gemini review content}
---
## Claude Review
{claude review content}
---
## Codex Review
{codex review content}
---
## CodeRabbit Review
{coderabbit review content}
---
## OpenCode Review
{opencode review content}
---
## Consensus Summary
{synthesize common concerns across all reviewers}
### Agreed Strengths
{strengths mentioned by 2+ reviewers}
### Agreed Concerns
{concerns raised by 2+ reviewers — highest priority}
### Divergent Views
{where reviewers disagreed — worth investigating}
Commit:
node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" commit "docs: cross-AI review for phase {N}" --files {phase_dir}/{padded_phase}-REVIEWS.md
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GSD ► REVIEW COMPLETE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Phase {N} reviewed by {count} AI systems.
Consensus concerns:
{top 3 shared concerns}
Full review: {padded_phase}-REVIEWS.md
To incorporate feedback into planning:
/gsd-plan-phase {N} --reviews
Clean up temp files.
<success_criteria>
- At least one external CLI invoked successfully
- REVIEWS.md written with structured feedback
- Consensus summary synthesized from multiple reviewers
- Temp files cleaned up
- User knows how to use feedback (/gsd-plan-phase --reviews) </success_criteria>