---
name: pr-council-review
version: "2.1"
description: Multi-dimensional LLM council review of an open PR (default) or a local feature branch (§ 8 branch mode, invoked via `/gflow:branch-review`). Five baseline dimensions (correctness, quality, security, tests, memory-hygiene) plus adaptive dimensions per surface (transports / data / CLI / docs / auth / BDD / scripts / release-gate). Each agent invokes specialized skills (security-review, code-review, verify) for its dimension. Reads files via `git show <sha>:<path>` to avoid stale-working-tree false positives. Cross-tool portable.
---

# `pr-council-review` — PR Council Review skill

Council-driven PR review. Dispatches **5 baseline + N adaptive** parallel reviewers, each scoped to one dimension, each invoking the relevant Claude Code specialized skill (e.g. `security-review`, `code-review`, `verify`), then synthesizes a single consensus verdict.

This skill is the canonical body. The Claude Code slash command at `.claude/commands/gflow/pr-council-review.md` is a thin wrapper that invokes this skill. Non-Claude tools (Gemini CLI / Codex / Cursor / Aider) can consume this SKILL.md directly via their own skill loaders.

**Three modes:**
1. **No argument** → list open PRs ranked by review priority; user picks. (See § 1.)
2. **`PR#` argument** → run the full council on that PR. (See § 2 onward.)
3. **Branch mode** → run the full council on the current local feature branch (no PR yet). Invoked via the `/gflow:branch-review` wrapper. See § 8 for the PR→branch translation table and pre-flight.

Treat **YELLOW as soft block** (per memory `[[llm-council-data-layer-fixes]]`).

---

## 0 · Pre-flight

**All five checks are mandatory. Any failure halts before Phase 1/2.**

1. **`gh` authenticated** — run `gh auth status`. Non-zero exit → stop with: *"`gh` is not authenticated. Run `gh auth login` and re-invoke."*
2. **Inside the repo** — assert `AGENTS.md` AND `CLAUDE.md` exist in the working directory.
3. **Resolve the argument:**
   - **Empty** → jump to **Phase 1 (Prioritize)**.
   - **PR number** → validate with `gh pr view <N> --json number`. If error → stop with the error verbatim.
4. **Draft check** (PR# mode only) — if `gh pr view <N> --json isDraft` returns `true`, surface a banner citing memory `[[draft-pr-merge-trap]]`: *"PR #N is DRAFT. Reviewing is fine, but do NOT merge a draft (the merge API can close it + delete the head ref). Run `gh pr ready N` first if you intend to merge. Continue review? (yes/no)"*. Ask the user before dispatching.
5. **Capture PR head ref + SHA (pin the review)** — `head_branch=$(gh pr view <N> --json headRefName --jq '.headRefName')` and `head_sha=$(gh pr view <N> --json headRefOid --jq '.headRefOid')`. **Pin both to a `REVIEWED_SHA` variable** and pass to every dispatched agent so the council's verdict is anchored to one commit. The local working tree is NOT on the PR head; all file reads must go through `git show $REVIEWED_SHA:<path>` (or `git show origin/$head_branch:<path>` if you fetched first). If the author pushes new commits during the review, the council still reports against `REVIEWED_SHA`; the synthesizer notes any divergence in Phase 5 step 5.

---

## 1 · Prioritize (no-argument mode)

```bash
gh pr list --state open --json number,title,author,isDraft,headRefName,updatedAt,additions,deletions,labels,reviewDecision,statusCheckRollup
```

**Empty-list short-circuit:** if the result is `[]`, print *"No open PRs to review."* and exit.

Rank with these heuristics (highest priority first):

| Signal | Weight | Why |
|---|---|---|
| `isDraft == false` AND CI all-green | +3 | Ready to merge once approved — highest ROI |
| Touched path includes `src/gflow_cli/api/transports/` | +2 | UI-automation is the highest-risk surface (memory `[[pr-must-verify-on-affected-surface]]`) |
| Touched path includes `src/gflow_cli/auth/` or `recaptcha` | +2 | Auth changes need security-deep-dive |
| Touched path includes `src/gflow_cli/api/client.py` or `src/gflow_cli/api/_sapisidhash.py` | +2 | Auth-token plumbing (Bearer / access-token / SAPISID) — lives outside `auth/` but is security-material; backtest found 3 historical fixes here |
| Touched path includes `src/gflow_cli/data/` | +2 | Migration safety + #86 hygiene history |
| Older than 7 days (stale risk) | +1 | Conflict risk grows with age |
| `additions + deletions <= 300` | +1 | Small PRs ship faster |
| Label contains `release-blocker`, `security`, `hotfix` | +5 | Anything labelled urgent jumps the queue |
| `isDraft == true` AND CI red | −2 | Author still iterating; review wastes their time |

Present a numbered table, then **stop and ask** the user to pick a PR number. Do NOT auto-start on Rank 1 — *recommend*, do not *pre-select*.

---

## 2 · Gather context (PR# mode)

Pull in parallel via `ctx_batch_execute`:
- `PR_META` → `gh pr view <N> --json title,body,author,baseRefName,headRefName,headRefOid,state,isDraft,additions,deletions,changedFiles,labels,files,statusCheckRollup`
- `PR_DIFF` → `gh pr diff <N>`
- `PR_CHECKS` → `gh pr checks <N>`
- `TOUCHED_PATHS` → `gh pr view <N> --json files --jq '.files[].path' | sort -u`
- `RECENT_COMMITS` → `gh pr view <N> --json commits --jq '.commits[-5:] | .[] | "\(.oid[:7]) \(.messageHeadline)"'`

**Reference files** (read via `git show origin/$head_branch:<path>` — NOT local `Read`, because the working tree is on `develop`):
- `CLAUDE.md`, `AGENTS.md`, `docs/INDEX.md`

**Memory traversal:** for each `TOUCHED_PATH`, look up relevant slugs:
- `transports/` → `[[pr-must-verify-on-affected-surface]]`, `[[flow-locale-leak-icon-ligatures]]`, `[[playwright-click-no-downstream-event-signature]]`, `[[rest-transports-drop-ui-fields]]`, `[[image-video-mode-switch-symmetry]]`, `[[video-generation-spec]]`, `[[image-generation-401-next]]`
- `data/` → `[[data-layer-overview]]`, `[[data-layer-test-pollution-trap]]`, `[[data-layer-v0.9.0-bugs]]`, `[[exit-code-16-data-store]]`, `[[on-started-callback-recorder-safety]]`
- `auth/` → `[[real-browser-auth-mandatory]]`, `[[release-signing]]`
- `cli` → `[[release-back-merge-gap-recovery]]`, `[[wheel-build-sanity-gate]]`
- `tests/` (any) → `[[bdd-stubs-mirror-runtime-signatures]]`, `[[background-e2e-pytest-pattern]]`, `[[full-test-suite-ooms]]`, `[[stale-test-discovery]]`, `[[structlog-cache-logger-off-for-tests]]`
- `tests/features/` (BDD) → also `[[bdd-stubs-mirror-runtime-signatures]]`
- `scripts/` → `[[wheel-build-sanity-gate]]`, `[[release-back-merge-gap-recovery]]`
- `.planning/`, `docs/superpowers/` → `[[release-spec-plan-memory-consolidation]]`
- `docs/`, `*.md` → `[[readme-hybrid-router-pattern]]`, `[[llm-council-doc-review-v0.9.0]]`, `[[agents-md-vs-llms-txt]]`, `[[pypi-readme-staleness-fix]]`
- `pyproject.toml`, `.github/` → `[[release-spec-plan-memory-consolidation]]`, `[[pr-hygiene-revert-and-multi-commit]]`, `[[draft-pr-merge-trap]]`, `[[pypi-rejected-filename-reusable]]`

---

## 3 · Detect adaptive dimensions

| Dimension | Always? | Activates when… |
|---|---|---|
| **D1 — Correctness & completeness** | ✅ baseline | always |
| **D2 — Code quality & best practices** | ✅ baseline | always |
| **D3 — Security** | ✅ baseline | always |
| **D4 — Tests & coverage** | ✅ baseline | always |
| **D5 — Memory hygiene & consolidation** | ✅ baseline (NEW v2) | always |
| **D6 — UI / live-verification** | adaptive | any path under `src/gflow_cli/api/transports/` or `tests/e2e/` |
| **D7 — Data-migration safety** | adaptive | any path under `src/gflow_cli/data/` or `*.sql` |
| **D8 — CLI UX & help-text consistency** | adaptive | any path matching `src/gflow_cli/cli*.py` or `src/gflow_cli/commands/` |
| **D9 — Docs cross-reference & drift** | adaptive | ≥2 of: `README.md`, `docs/**`, `CHANGELOG.md`, `AGENTS.md`, `CLAUDE.md`, `PLAN.md` |
| **D10 — Auth / reCAPTCHA / Chrome-profile** | adaptive | any path under `src/gflow_cli/auth/` or label `security` |
| **D11 — Release-gate compliance** | adaptive | `pyproject.toml`, `src/gflow_cli/__init__.py`, `.github/workflows/`, `release/*` branch |
| **D12 — BDD step-stub signatures** | adaptive | any path under `tests/features/` |
| **D13 — Dev / release scripts** | adaptive | any path under `scripts/` |

**Baseline floor is non-negotiable.** D1–D5 ALWAYS run. **Docs-only PRs** (100% paths under `*.md`, `docs/**`, `CHANGELOG.md`, `README.md`, `LICENSE`, `AUTHORS`) → D4 reframes from "test code coverage" to "docs-verification"; D5 still runs unchanged.

---

## 4 · Dispatch the council

Use the `superpowers:dispatching-parallel-agents` skill. Send **all** agents in one message — they must run concurrently.

### Per-dimension specialized-skill mapping (NEW v2)

Each agent is a `general-purpose` agent (only subagent type that supports arbitrary parallel dispatch), but the prompt instructs it to invoke the relevant Claude Code skill **inside** the agent for specialized capability. Mapping:

| Dim | Agent invokes skill (via Skill tool) | Rationale |
|---|---|---|
| D1 Correctness | `review` (single-agent PR review built-in) | Provides PR-review framing for free |
| D2 Code quality | `code-review` | Reuse-and-quality lens |
| D3 Security | **`security-review`** | Built-in security-review skill — the most important specialization |
| D4 Tests | `superpowers:test-driven-development` (informed) | TDD principles + verification mindset |
| D5 Memory hygiene | (none — direct memory inspection) | Inspect memory files via `git show` + filesystem |
| D6 UI/live-verify | `verify` (if live-verify approved) | Runs the app to confirm behavior |
| D7 Data-migration | (none — direct code inspection) | |
| D8 CLI UX | (none — direct help-text inspection) | |
| D9 Docs drift | (none — direct doc-cross-ref) | |
| D10 Auth | `security-review` (subset of D3 with auth-specific lens) | |
| D11 Release-gate | (none — direct config inspection) | |
| D12 BDD | (none — direct stub-signature inspection) | |
| D13 Scripts | (none — direct script inspection) | |

### Per-agent prompt skeleton (mandatory v2 changes in bold)

```
You are one of <N> parallel reviewers on a council reviewing PR #<N> of `gflow-cli` at C:\development\github\gflow-cli.

Your dimension is **<DIMENSION NAME>**. Other agents handle <other dimensions> — do NOT duplicate their work.

**PR head branch:** `<head_branch>` (head SHA: `<head_sha>`).
**Base branch:** `<base_branch>`.

**🚨 CRITICAL — file reading + verification rules (v2 stale-tree-reads fix + v2.1 verify-before-claim):**

The orchestrator's working tree is on `<base_branch>` (typically `develop`), NOT the PR head. If you `Read` a file in `C:\development\github\gflow-cli\`, you get the PRE-PR copy and will produce FALSE POSITIVES like "file X doesn't exist" or "claim Y not applied" when in fact X and Y are present on the PR head.

**Mandatory rules:**

1. **For file inspection** — ALWAYS use `ctx_execute(language="shell", code="git show <REVIEWED_SHA>:<path>")` (or `git show origin/<head_branch>:<path>`). For the diff itself, `gh pr diff <N>`. For metadata, `gh pr view <N> --json ...`. NEVER use `Read` on a repo file unless you have verified `git branch --show-current` returns `<head_branch>`.

2. **Verify-before-claim — applies to BEHAVIOR claims, not just file existence (v2.1 NEW):** any "feature/setting/marker/env-var is NOT present" or "is missing" or "is wrong" claim MUST be backed by an explicit `git show <REVIEWED_SHA>:<path> | grep <expected>` (or equivalent) that you ran. Quote the exact command + its output in your report. Do NOT rely on memory or summary; the v2 council had a real false-negative where D5 claimed "PR doesn't add addopts filter" because the agent assumed-not-verified — the addopts WAS added but the agent never ran `git show <SHA>:pyproject.toml`. Treat your own claims like a code reviewer: would this assertion survive a hostile re-review? If yes, ship it; if uncertain, re-verify.

3. **SHA pinning verification (v2.1 NEW):** before reporting findings, run `git rev-parse $REVIEWED_SHA` (or `git ls-remote origin <head_branch>`) and confirm your reads were against `<REVIEWED_SHA>`. If the author has pushed new commits during your dispatch, your findings still apply to `<REVIEWED_SHA>` — the synthesizer will note any divergence at Phase 5 step 5.

**Specialized skill (if listed for your dimension):** before deep analysis, invoke the Skill tool for `<skill_name>` to load specialized review guidance. Apply that skill's checklists in addition to the dimension-specific questions below.

Assess specifically:
1. <dimension-specific question 1, with code citation hooks>
2. <…>

**Mandatory memory you MUST consult and cite if relevant:** <fixed slug list from the Dimension → Slugs table>.

Output a structured report under 500 words:
- Verdict: GREEN / YELLOW / RED
- Must-fix (numbered, file:line refs)
- Nice-to-have (numbered)
- Confirmed-<good/safe/correct> (1-line bullets)

If you have nothing to flag, say so explicitly and state GREEN with a one-line justification — do NOT manufacture findings.

If you are NOT sure a finding is real because it depends on file content, VERIFY via `git show origin/<head_branch>:<path>` before reporting it. Stale-tree false positives are a documented v1 council bug.
```

### Dimension → mandatory memory slugs table

| Dim | Mandatory memory slugs |
|---|---|
| D1 | `[[pr-must-verify-on-affected-surface]]` |
| D2 | (none mandatory; consult surrounding code style) |
| D3 | `[[real-browser-auth-mandatory]]`, `[[release-signing]]` |
| D4 | `[[pr-must-verify-on-affected-surface]]`, `[[full-test-suite-ooms]]`, `[[stale-test-discovery]]`, `[[structlog-cache-logger-off-for-tests]]` |
| D5 | `[[release-spec-plan-memory-consolidation]]`, `[[pr-council-review-stale-tree-reads]]` (this very bug, as the council should self-improve) |
| D6 | `[[flow-locale-leak-icon-ligatures]]`, `[[playwright-click-no-downstream-event-signature]]`, `[[rest-transports-drop-ui-fields]]`, `[[image-video-mode-switch-symmetry]]`, `[[verification-ledger-5-layer]]` |
| D7 | `[[on-started-callback-recorder-safety]]`, `[[data-layer-test-pollution-trap]]`, `[[exit-code-16-data-store]]`, `[[data-layer-v0.9.0-bugs]]` |
| D8 | (none mandatory) |
| D9 | `[[readme-hybrid-router-pattern]]`, `[[agents-md-vs-llms-txt]]`, `[[pypi-readme-staleness-fix]]`, `[[llm-council-doc-review-v0.9.0]]` |
| D10 | `[[real-browser-auth-mandatory]]` |
| D11 | `[[release-back-merge-gap-recovery]]`, `[[wheel-build-sanity-gate]]`, `[[pypi-rejected-filename-reusable]]`, `[[draft-pr-merge-trap]]` |
| D12 | `[[bdd-stubs-mirror-runtime-signatures]]` |
| D13 | `[[wheel-build-sanity-gate]]` |

### Per-dimension specifics

- **D1 Correctness & completeness:** root cause vs symptom? Edge cases? CHANGELOG matches diff? PR-body compliance (test-plan checkboxes + `Closes #N` acceptance criteria met)?
- **D2 Code quality:** style consistency? Comments WHY-not-WHAT (per CLAUDE.md)? SRP intact? Type annotations on every new signature?
- **D3 Security:** injection vectors? Env-var trust boundary? Shell interpolation? Path traversal? Secret-shaped literals? `--no-verify` / signature-bypass?
- **D4 Tests:**
  - **Mandatory affected-surface check:** identify the runtime surface (T2V / I2V / data / CLI / auth / etc.). If the suite doesn't exercise that exact surface → **automatically YELLOW**. Cite the test file:line proving coverage, or state explicitly no such test exists.
  - Test pyramid placement? Behavior vs shape? Coverage delta meaningful vs dead?
- **D5 Memory hygiene & consolidation (NEW v2, refined v2.1):**
  - Inspect `~/.claude/projects/C--development-github-gflow-cli/memory/` (file-based memory — primary source).
  - **Concrete MCP memory-server probe (v2.1):** in the current session, look at the tool list for any tool whose name matches `mcp__*memory*`, `mcp__*mempalace*`, `mcp__*mem0*`, `mcp__*context-mode*` (for indexed KB), or any tool the user explicitly mentioned. If found, invoke its "list" / "search" / "stats" tool to enumerate stored items. If no such tool is loaded in-session, state explicitly "no MCP memory server loaded; D5 scope = file-based memory only".
  - For each memory entry potentially relevant to the PR's surface: does the PR's content CONTRADICT or SUPERSEDE it? If so, the PR must include a memory edit/delete in the same change. Flag missing edits.
  - Does the PR introduce a new durable pattern / failure mode / decision that should be captured as a NEW memory entry? Flag missing additions.
  - Is `MEMORY.md` index still in sync (entries listed correspond to existing files)? Flag drift.
  - Per `[[release-spec-plan-memory-consolidation]]`: any spec/plan in `docs/superpowers/` or `.planning/` that's now post-ship should be deleted on merge, with durable bits extracted to memory. **When D5 fires RED on consolidation, D9 (Docs drift) defers to D5 — do not double-list the same plan-file finding in both dimensions.**
  - **Verify-before-claim discipline applies here too (v2.1):** any "this memory entry is missing X" or "this PR doesn't update memory Y" claim must cite the exact memory file you read (`git show` or filesystem `cat`) and the line range. The v2 run had a real false-claim here.
- **D6 UI/live-verify:** selector matches real DOM on non-EN? Runtime evidence beyond static-string invariants? Live-verify evidence (file count + magic bytes + Pillow dims + structlog events: `new_project_clicked`/`submit_clicked`/`frame_attached`/`image_mode_entered`/`count_setter_completed`/`reference_attached`) in PR body? Absent → YELLOW per `[[pr-must-verify-on-affected-surface]]`.
- **D7 Data-migration:** on_started callback safety (every callsite wrapped in `try/except DataStoreError` — bare callback in paid-generation path = RED). Schema compat. Migration idempotent. `DataStoreError` vs `DataMigrationError` vs `DataIntegrityError` semantics.
- **D8 CLI UX:** help text matches? Flag names `--kebab-case`? `--help` golden-snapshot tests updated? Docstring examples runnable?
- **D9 Docs drift:** cross-references mutually consistent? Code examples run? Version strings consistent?
- **D10 Auth:** Chrome-strategy profile required (memory `[[real-browser-auth-mandatory]]`)? Profile-dir SecurityError boundary intact? No new secret-shaped strings?
- **D11 Release-gate:** version match `pyproject.toml` ↔ `src/gflow_cli/__init__.py` (RED if drift). `[Unreleased]` emptied + new version added. Wheel build clean. Back-merge gap addressed.
- **D12 BDD:** new `_run_*` kwarg → mirror in `tests/features/_fake_*` stubs (silent TypeError trap).
- **D13 Scripts:** Windows-clean (memory `[[windows-dev-quirks]]`); release scripts include wheel-build sanity gate.

---

## 5 · Synthesize the verdict

1. **Tally verdicts** per dimension.
2. **Handle missing agents:** any dimension that failed → mark `UNKNOWN`, downgrade consensus by one step (GREEN→YELLOW, YELLOW→YELLOW, RED→RED). Never wait indefinitely.
3. **Consensus rule:**
   - Any RED → **RED** (block merge).
   - Any YELLOW → **YELLOW** (soft block per `[[llm-council-data-layer-fixes]]`).
   - All GREEN → **GREEN** (mergeable).
4. **Deduplicate must-fix AND confirmed-good** — same finding from two dimensions = list once + credit both.
5. **False-positive filter + SHA divergence check (NEW v2, refined v2.1):**
   - **Spot-check 2-3 file-state claims** via `git show <REVIEWED_SHA>:<path>` (NOT `git show origin/<head>:<path>` — the remote may have moved since dispatch). If any agent claim contradicts `<REVIEWED_SHA>`, mark it FALSE POSITIVE in the report — do not silently drop, so accuracy is auditable.
   - **Also spot-check 1-2 BEHAVIOR/content claims** (v2.1) — e.g. "marker X isn't registered", "addopts doesn't have Y". Same `git show` verification. The v2 council had a real false-claim here from D5 (assumed-not-verified).
   - **SHA divergence note:** check `gh pr view <N> --json headRefOid --jq '.headRefOid'`. If the current head differs from `<REVIEWED_SHA>`, note this prominently in the report: *"Author pushed N new commits during the review. This verdict reports against `<REVIEWED_SHA>`; the new commits may have resolved findings (re-run the council to confirm)."* Do NOT try to re-review the new commits silently.
6. **Live-verify gate** (D6 fired + PR body has unchecked live-verify boxes): explicit `AskUserQuestion` with three options — *Run now (~1 Flow credit per locale)*, *Block merge — add to PR body as required reviewer action*, *Skip and accept risk*. Cite `[[verification-ledger-5-layer]]`. Do NOT spend credits without affirmative click.
7. **Memory-action gate** (D5 fired with must-fix items): explicit `AskUserQuestion` offering to APPLY the memory edits/additions/deletions in the same PR or as a follow-up.
8. **YELLOW escape valve:** the Phase 6 `AskUserQuestion` MUST include a *"Dismiss YELLOW with justification (logged)"* option. Dismissal requires a one-line reason appended to the PR body or comment, so the override is auditable.

---

## 6 · Report

```
# PR #<N> — Council Review Verdict

## Consensus: <emoji> <GREEN | YELLOW | RED>

| Dimension | Verdict | Headline |
|---|---|---|
| <D1> | … | <one-line summary> |
| <D2> | … | … |

## Must-fix (<N>)
1. **<short title>** — `<file>:<line>`. <description>. <which dimension flagged>.
2. …

## Nice-to-have (<N>)
1. …

## False positives (filtered out — agents misread stale tree)
- D<n> claim about <…>: verified absent on PR HEAD via `git show origin/<head>:<path>` — dropping.

## Confirmed-good (high-confidence positives)
- …

## Memory actions (D5)
- ADD: <slug> capturing <pattern>
- UPDATE: <slug> — claim X is now stale because <…>
- DELETE: <slug> — superseded by <…>

## How to proceed
<AskUserQuestion>
```

Always end with an `AskUserQuestion`.

---

## 7 · Provenance & extensions

> **Provenance:** v1 protocol validated on PR #93 (locale selectors, 2026-05-26). v2 evolved 2026-05-27 after running on PR #95 surfaced two real defects: (a) sub-agents read stale working-tree files producing 5+ false positives (memory `[[pr-council-review-stale-tree-reads]]`), (b) baseline missed memory-hygiene as a dimension. Both fixed in v2.

- Council baseline = 5 dimensions (D1–D5). Adaptive ceiling = D6–D13. Going beyond ~13 adds noise faster than signal — split into two reviews instead.
- Sub-agents are `general-purpose` agents that invoke specialized skills (`security-review`, `code-review`, `verify`, `review`) inside their prompt for dimension-specific capability.
- The command is **stateless** and **read-only** — concurrent invocations on different PRs don't share data. No `gh pr merge`, no `git push`, no `gh pr close`.
- **Idempotence:** same PR SHA → comparable verdicts on different days. Drift usually means memory grew new precedents or the mandatory-slug table needs an update.
- **Sibling commands.** `/review` is the single-agent Claude-Code built-in (one-pass, cheap) — use for spot-checks or draft iteration. `/gflow:pr-council-review` is the council version for pre-merge audits and high-risk surfaces.
- **Cross-tool portability.** This SKILL.md is the canonical body. The Claude Code slash command at `.claude/commands/gflow/pr-council-review.md` is a thin wrapper. Other tools (Gemini CLI / Codex / Cursor / Aider) consume this file directly via their own skill-loading mechanism. See `[[pr-council-review-portability-backlog]]` for the cross-tool playbook.

---

## 8 · Branch Mode (for `/gflow:branch-review`)

Same council, but run against a local feature branch instead of an open PR — pre-PR review. The slash command `/gflow:branch-review` invokes this skill in branch mode.

### Sections replaced in branch mode

- **§ 1 (Prioritize, no-argument mode)** — skipped; branch mode operates on the current branch, no PR list to rank.
- **§ 2 (Gather context, PR# mode)** — replaced by the translation table below + the branch-mode pre-flight.
- **§ 0 (Pre-flight)** — steps 1, 3, 4 replaced (see "Pre-flight" subsection below); step 2 (`AGENTS.md` + `CLAUDE.md`) is kept.

All other sections (§ 3 Detect adaptive dimensions, § 4 Dispatch, § 5 Synthesize, § 6 Report, § 7 Provenance) apply unchanged.

### Argument shape

`--base <ref>` — base reference to diff against. Default: `develop`.

### Translation table — PR mode → branch mode

| Step | PR mode | Branch mode |
|---|---|---|
| Reviewed SHA | `gh pr view <N> --json headRefOid --jq '.headRefOid'` | `git rev-parse HEAD` |
| Head branch name | `gh pr view <N> --json headRefName --jq '.headRefName'` | `git branch --show-current` |
| Diff | `gh pr diff <N>` | `git diff <base>..HEAD` |
| Changed files | `gh pr view <N> --json files --jq '.files[].path'` | `git diff --name-only <base>..HEAD` |
| Recent commits | `gh pr view <N> --json commits …` | `git log --oneline <base>..HEAD` |
| PR metadata (title, body, labels, CI checks) | `gh pr view <N> --json …` | N/A — skip; use `git log <base>..HEAD` for narrative |
| Output channel | terminal | terminal + optional `.planning/branch-review-<branch>-<ts>.md` (gitignored). **Never** posts to a PR. |

### Pre-flight (replaces § 0 steps 1, 3, 4)

Steps that stay: § 0 step 2 (`AGENTS.md` AND `CLAUDE.md` exist). Step 5 (REVIEWED_SHA capture) is replaced as below.

1. `git rev-parse --is-inside-work-tree` returns true. Otherwise: *"Not in a git repo."*
2. `current_branch = git branch --show-current`. Must be non-empty AND not `main` AND not `develop`. If empty (detached HEAD) or matches a protected branch, refuse with: *"Branch-review is for feature branches. For a PR, run `/gflow:pr-council-review <N>`. For ad-hoc audit, check out a feature branch first."*
3. `git diff --quiet <base>..HEAD` — exit code MUST be non-zero (there must be a diff). If exit code is zero (no diff), exit with: *"No commits ahead of `<base>` — nothing to review."*
4. `REVIEWED_SHA = git rev-parse HEAD` — pin up front and pass to every dispatched agent.
5. PR-draft check (§ 0 step 4) is skipped — there is no PR yet.

### Sub-agent file reads

Same rule as PR mode (§ 4 mandatory rule 1): read via `git show $REVIEWED_SHA:<path>`. Even though the working tree is ON the reviewed branch, pinning to `REVIEWED_SHA` keeps the verdict stable if the branch moves mid-review.

### `release/*` branch downgrade

If `current_branch` matches `release/*`, D11 (Release-gate compliance) will RED-flag the in-progress CHANGELOG / version bump as expected for a release-in-progress. The synthesizer auto-downgrades D11 **RED → YELLOW** when `git tag --list "v*" --contains HEAD` returns empty (release tag not yet cut). Surface the downgrade in the verdict so users don't chase a false negative. Per memory `[[release-back-merge-gap-recovery]]` + `[[wheel-build-sanity-gate]]`, this downgrade does NOT suppress findings about missing back-merge or skipped wheel-sanity.

### SHA drift at synthesis

At Phase 5 (Synthesize), compare `git rev-parse HEAD` to `REVIEWED_SHA`. If diverged (user committed mid-review, ran `git stash pop`, rebased, etc.), prepend the report with: *"Local HEAD moved during review (was `<X>`, now `<Y>`). Findings apply to `<X>`."* Do NOT silently re-review the new commits.

### Output

- Terminal report identical in shape to PR mode § 6.
- Optional save to `.planning/branch-review-<branch>-<ts>.md` (path is gitignored per the repo's `.gitignore` for `.planning/`).
- No `gh pr comment`, no `gh pr review`, no `gh pr merge`. Branch mode is local-only and read-only.

### What does NOT change

Dimension detection (§ 3), memory traversal (§ 2 — same Dimension → Slugs table), agent dispatch (§ 4), synthesis rules (§ 5), and report shape (§ 6). Same baseline D1–D5 + adaptive D6–D13. Same per-dimension specialized-skill mapping. Same false-positive filter and YELLOW soft-block treatment.

### Why a mode, not a sibling skill

Single source of truth. ~90% of the council protocol is shared between PR mode and branch mode; only the input channel (PR vs `git diff`) and the output channel (terminal vs terminal + `.planning/`) differ. A sibling skill would drift over time.
