---
name: gemini-verify
description: Cross-model second-opinion verification via Gemini CLI (tiered timeouts, mandatory Claude Sonnet fallback on failure/timeout)
argument-hint: "[target path or git range] [--complexity simple|standard|complex]"
allowed-tools:
  - Bash
  - Read
  - Task
---

# /gmd:gemini-verify

Request a Gemini second opinion on a specific artifact (plan, phase diff, agent/skill definition, or VERIFICATION.md report). Dispatches a Gemini subprocess with a tier-appropriate timeout and falls back to a fresh-context Claude Sonnet subagent if Gemini is unavailable, disabled, times out, or exits non-zero.

**When to use:**
- Audit wave of a phase (validate that existing agents/skills meet their requirements from an external perspective)
- After phase completion for cross-model verification
- Before committing a high-stakes change (auth, payments, security)
- As a second opinion when Claude's verification is uncertain

**When NOT to use:**
- Tight inner loops (dispatch overhead + timeout budget matters)
- Pre-merge checks where latency blocks the user (use `/gmd:verify-phase` instead)

## Relationship to /gmd:codex-verify

`/gmd:codex-verify` is the Codex counterpart. Gemini is primary (CONTEXT.md lock — Gemini has faster observed latency than Codex in prior GMD work). Codex is opt-in separately via `/gmd:external-agents`. Both commands share the same tier vocabulary and fallback contract.

## Timeout Tiers

Tier vocabulary matches Phase 4.1's COMPLEXITY_MODEL (references/model-profiles.md §Complexity Tiers) — one vocabulary across subsystems.

| Tier | Budget | Use For |
|------|--------|---------|
| simple | 60s | Single-file review, skill audit, small commit diff |
| standard | 180s | Phase-level verification, multi-file diff (3-15 files) |
| complex | 300s | Milestone integration, full codebase review, large migration |

Literal tier defaults in shell: `"60"`, `"180"`, `"300"` — audit-visible (60/180/300).

Tier values are read from `.planning/config.json` `workflow.cross_model_timeouts` (defaults shown above) so they can be tuned without editing the command file.

## Tier Invocation Reference

Parameterized form actually used (see `dispatch_gemini_primary` step). Literal per-tier forms shown here for audit visibility — if `/gmd:gemini-verify` is invoked with each tier, the resolved shell command is one of:

```bash
# simple tier
timeout 60 gemini --prompt "$AUDIT_PROMPT" --approval-mode plan -o text \
  || { echo "no second opinion available from Gemini"; Task subagent_type=gmd-verifier; }

# standard tier
timeout 180 gemini --prompt "$AUDIT_PROMPT" --approval-mode plan -o text \
  || { echo "no second opinion available from Gemini"; Task subagent_type=gmd-verifier; }

# complex tier
timeout 300 gemini --prompt "$AUDIT_PROMPT" --approval-mode plan -o text \
  || { echo "no second opinion available from Gemini"; Task subagent_type=gmd-verifier; }
```

Each literal `timeout N gemini` above has a matching `|| { ... Task subagent_type=gmd-verifier ... }` fallback branch on the same logical line — Pitfall 5 closed: every timeout has a fallback, audit-countable 1:1.

## Usage

```
/gmd:gemini-verify [target] [--complexity simple|standard|complex]
```

Arguments:
- `target` (required): path to file, phase directory, or git range to review
- `--complexity` (optional): tier, defaults to `standard`

## Steps

<step name="load_config">

```bash
# Read tier budgets from config
CONFIG_PATH=".planning/config.json"
SIMPLE_TO=$(node -e "console.log((JSON.parse(require('fs').readFileSync('$CONFIG_PATH','utf8')).workflow?.cross_model_timeouts?.simple)||60)" 2>/dev/null || echo 60)
STANDARD_TO=$(node -e "console.log((JSON.parse(require('fs').readFileSync('$CONFIG_PATH','utf8')).workflow?.cross_model_timeouts?.standard)||180)" 2>/dev/null || echo 180)
COMPLEX_TO=$(node -e "console.log((JSON.parse(require('fs').readFileSync('$CONFIG_PATH','utf8')).workflow?.cross_model_timeouts?.complex)||300)" 2>/dev/null || echo 300)

# Resolve tier from --complexity flag or env (defaults to standard)
AUDIT_COMPLEXITY="${COMPLEXITY:-standard}"
case "$AUDIT_COMPLEXITY" in
  simple)   TIMEOUT=$SIMPLE_TO ;;
  standard) TIMEOUT=$STANDARD_TO ;;
  complex)  TIMEOUT=$COMPLEX_TO ;;
  *)        TIMEOUT=$STANDARD_TO ; AUDIT_COMPLEXITY=standard ;;
esac
```

</step>

<step name="build_audit_prompt">

```bash
# Base audit prompt — reviewer persona + severity ladder
AUDIT_PROMPT="You are an independent cross-model reviewer. Review the target artifact for: (1) bugs or logic errors, (2) security vulnerabilities (injection, auth bypass, secrets), (3) missing error handling, (4) incomplete or stub implementations, (5) code quality issues. Rate each finding CRITICAL / HIGH / MEDIUM / LOW. End with an overall PASS or FAIL verdict. Target: $ARGUMENTS"
```

</step>

<step name="check_gemini_enabled">

```bash
EXT_AGENTS_CFG=$(cat .claude/external-agents.json 2>/dev/null || echo '{}')
GEMINI_ENABLED=$(echo "$EXT_AGENTS_CFG" | node -e "
  try {
    const cfg = JSON.parse(require('fs').readFileSync(0,'utf8'));
    console.log(cfg.gemini?.enabled === true || cfg.enabled === true ? 'true' : 'false');
  } catch { console.log('false'); }
")
```

</step>

<step name="dispatch_gemini_primary">

```bash
GEMINI_OUT=$(mktemp /tmp/gemini-audit-XXXXXX.txt)
GEMINI_STATUS=1

# Gemini CLI v0.34.0 flag shape (verified at execution time via `gemini --help`):
#   -p / --prompt           : non-interactive headless mode
#   --approval-mode plan    : read-only mode (no edits applied)
#   -o text                 : plain text output (no JSON wrapping)
# No direct --output-last-message equivalent exists; capture stdout directly.
# Run from a temp CWD to approximate ephemeral sandbox behavior.

if [ "$GEMINI_ENABLED" = "true" ] && command -v gemini >/dev/null 2>&1; then
  GEMINI_CWD=$(mktemp -d)
  ( cd "$GEMINI_CWD" && timeout "${TIMEOUT}s" gemini --prompt "$AUDIT_PROMPT" --approval-mode plan -o text ) > "$GEMINI_OUT" 2>&1
  GEMINI_STATUS=$?
  rm -rf "$GEMINI_CWD"
fi
```

</step>

<step name="fallback_on_failure" priority="mandatory">

```bash
# Mandatory fallback — no silent proceed (Pitfall 5)
# Every `timeout N gemini ...` above has a corresponding fallback branch here.
if [ $GEMINI_STATUS -ne 0 ]; then
  rm -f "$GEMINI_OUT"

  # Fresh-context Claude Sonnet subagent via gmd-verifier
  # (gmd-verifier already has stage-2 code-quality review from plan 05-03)
  FALLBACK_MODEL=$(node bin/gmd-tools.cjs resolve-model gmd-verifier --complexity "$AUDIT_COMPLEXITY" --raw)

  echo "[fallback] Gemini status=$GEMINI_STATUS — no second opinion available from Gemini; dispatching Claude Sonnet via gmd-verifier (complexity=$AUDIT_COMPLEXITY, model=$FALLBACK_MODEL)"

  # Task(
  #   subagent_type="gmd-verifier",
  #   model="$FALLBACK_MODEL",
  #   prompt="<second_opinion_audit complexity='$AUDIT_COMPLEXITY'>\n${AUDIT_PROMPT}\n</second_opinion_audit>",
  #   description="Claude fallback second-opinion audit (Gemini unavailable or failed)"
  # )
else
  echo "## Gemini Verification Report"
  cat "$GEMINI_OUT"
  rm -f "$GEMINI_OUT"
fi
```

**Critical:** If this `if` block is removed or bypassed, the entire cross-model verification becomes decorative (Gemini timeout → silent proceed = no second opinion). The audit script `tests/phase-05/audit-cross-model-tiered-timeouts.sh` greps for this fallback block and fails the build if it is absent.

</step>

<step name="present_findings">

- Print Gemini's output verbatim under a `## Gemini Verification Report` heading (already done on success path above).
- Tally findings by severity.
- **If FAIL or any CRITICAL/HIGH findings:**
  - List each issue with its file reference.
  - Ask the user: "Gemini found [N] issue(s). Fix before continuing? [y/n]"
  - If yes → diagnose each issue and prepare a targeted fix plan.
- **If PASS (no CRITICAL/HIGH):**
  - Confirm: "Gemini review: PASSED. Proceeding."
- **If fallback fired:**
  - Present the Claude Sonnet gmd-verifier report under `## Claude Fallback Verification Report`.

</step>

## Failure Modes

| Condition | Handling |
|-----------|----------|
| gemini not on PATH | Fallback to Claude Sonnet |
| .claude/external-agents.json gemini disabled | Fallback to Claude Sonnet |
| gemini exits non-zero within timeout | Fallback to Claude Sonnet |
| gemini times out | Fallback to Claude Sonnet |
| gemini succeeds | Print stdout, no fallback |

**There is no silent-proceed path.** Either Gemini returns a verdict, or Claude does. Never both, never neither.
