# Hydra

> Use when the user asks for Hydra, a deep multi-perspective code review, architecture or security tradeoffs, blind spots, or iterative re-review. Avoid for simple fixes and lookups.

- Skill: `opencue/hydra` (Agent Skill, multi-file: 78 files)
- Install (CLI): `npx skillmds@latest add opencue/hydra`
- Raw SKILL.md: https://api.skillmd.com/api/skills/opencue/hydra/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: opencue (https://skillmd.com/u/opencue)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/opencue/hydra

---


<!-- v2.0: per ADR docs/adr/0001-execution-substrate.md (Option C, accepted 2026-05-23),
     interactive /hydra runs in THIS harness (Agent tool + codex-companion), so SKILL.md is
     the living product surface. Prompt-level v2.0 wins land here directly (Echo advisor;
     chairman grounding + suspicious-verdict gate). The Python core in hydra/ is scoped to
     the bench (deterministic citation-grounding + reproducible scoring) -- it does NOT
     replace this runtime. Design context: docs/specs/2026-04-17-hydra-2.0-core-design-v2.md. -->

# Hydra

## Example invocation

```text
Run Hydra for a deep security and architecture review of this branch.
```

Four advisors analyze your code from different angles by default (standard mode) --
including Echo, which reviews AI-assisted-development failure modes. Escalate to deep
mode for the full council: six advisors, three cross-examining reviewers, and a
chairman synthesizing the final verdict.

Standard mode runs 4 advisors + chairman on Opus (~$0.35-0.65). Deep mode adds 2 more
advisors (including 2 Codex), 3 reviewers, and cross-model diversity (~$1.50-2.50).

Reference files in `references/` define all prompts and protocols -- read them at the
relevant step.

---

## Modes

| Mode | CLI | Advisors | Reviewers | Chairman | Total | Est. Cost |
|------|-----|----------|-----------|----------|-------|-----------|
| **standard** | *(default)* | 4 (Cassandra + Mies+ + Sentinel + Echo) | 0 | 1 Opus | 5 | ~$0.35-0.65 |
| **deep** | `--mode deep` | 6 (4 Opus + 2 Codex) | 3 (all Opus) | 1 Opus | 10 | ~$1.50-2.50 |

Modifiers (combinable):
- `--no-codex` -- the deep-mode Codex advisors (Mies+, Sentinel) run on Opus instead.
- `--no-review` -- Skip peer review phase. Only meaningful with deep (reduces to 7 agents, ~$1.00).

**Minimum thresholds** -- formula: `ceil(N * 0.6)`, min 2:

| Mode | Min Advisors | Min Reviewers |
|------|-------------|---------------|
| standard | 3 of 4 | -- |
| deep | 4 of 6 | 2 of 3 (if reviewers active) |

**Mode resolution:** Two modes + modifiers:
- No flags -> **standard**
- `--mode deep` -> **deep**
- `--no-codex` -> modifier (Codex advisors run on Opus)
- `--no-review` -> modifier (skip peer review; only meaningful with deep)

Legacy aliases (emit migration hint):
- `--mode lite`, `--mode quick`, `--mode full`, `--mode broad`, `--mode secure`, `--mode focused` -> `[Hydra] Unknown mode. Use 'standard' (default) or '--mode deep'.`

**Focus modes** (combinable with any mode): `--focus security | perf | readability | architecture | reliability`
When a focus flag is active, the primary advisor for that focus gets 2x word budget.
The chairman receives a focus directive weighting that advisor's findings at 1.5x.
Focus mapping: security -> Sentinel, perf -> Volta, readability -> Mies+, architecture -> Navigator, reliability -> Cassandra.
Note: focus flags for Volta or Navigator auto-escalate to deep mode when used with standard (these advisors only exist in deep mode). Mies+ exists in both modes (readability focus) and never auto-escalates.

---

## How a Hydra Session Works

### Step 0: Pre-flight Gate

1. **Concrete code or specific decision?** If too vague, ask ONE clarifying question.
2. **Hydra-worthy?** Simple questions get answered directly: `[Hydra] Not Hydra-worthy -- answering directly.`
3. **Input size check:** If user code exceeds ~500 lines, ask user to highlight the critical section. Max enriched input: ~3000 tokens of source code.
4. **Secrets scan:** Check for credentials using these patterns:
   Cloud keys: `AKIA[A-Z0-9]{16}`, `ASIA[A-Z0-9]{16}`,
   Azure: `DefaultEndpointsProtocol=`, `AccountKey=[A-Za-z0-9+/=]{86,88}`, `SharedAccessSignature=`,
   GCP: `"type"\s*:\s*"service_account"`, `"private_key_id"\s*:\s*"[a-f0-9]{40}"`,
   Git/CI: `ghp_...`, `github_pat_...`, `glpat-...`,
   Slack: `xox[bpsa]-...`, `https://hooks.slack.com/...`,
   Stripe: `sk_live_`, `sk_test_`, `pk_live_`, `rk_live_`, `rk_test_`, `whsec_`,
   AI keys: `sk-ant-`, `sk-proj-`, `AIzaSy`,
   PEM: `-----BEGIN.*PRIVATE.*KEY-----`, `-----BEGIN.*KEY-----`,
   JWT: `eyJhbG...eyJ` (require header.payload, not just header prefix),
   DB strings: `(mongodb|postgres|mysql|redis)://[^:]+:[^@]+@`,
   Datadog: `DD_API_KEY`, `DD_APP_KEY`,
   Twilio: `AC[a-f0-9]{32}`, `SK[a-f0-9]{32}`,
   Other: `AccountKey=`, `SG\.[a-zA-Z0-9_-]{22}\.`, `.env` contents.
   Replace matches with `[REDACTED]`. Use a plain marker without any session-specific
   information -- do not derive the redaction marker from the boundary token or any other
   security-critical value. The marker is identical for all redactions in a session.
   Orchestrator keeps an internal count and mapping (type + location) for the user-facing
   confirmation only -- this mapping is never included in agent prompts.
   If secrets found: show redacted locations and ask user to confirm before proceeding.

   **Scan procedure name: `secrets-scan`** -- referenced by scan points in Steps 3-6.
5. **Iteration detection** (skip if fresh review):
   ```bash
   ls -1t .hydra/reports/hydra-*.md 2>/dev/null | grep -v transcript | head -1
   ```
   If trigger is an iterate-trigger (`hydra iterate`, `re-review`, `check my fixes`, etc.)
   AND a previous report exists: set `HYDRA_ITERATE=true`, extract Top Actions + Verdict
   lead + timestamp from the report. Default to standard mode unless user passes `--mode deep`.
   Print: `[Hydra] Iterating on: {{PREV_REPORT}} ({{AGE}} ago)`
   If no previous report exists: warn user, fall back to fresh review.

   **Report validation:** If a previous report IS found, verify it contains:
   - `**Top Actions:**` block with at least one numbered item (required)
   - Timestamp in filename matching `hydra-[0-9]{8}T[0-9]{6}-*.md` (required)
   - `## Verdict` heading with content below it (recommended but not required)
   If Top Actions AND timestamp are missing: report is invalid, fall back to fresh review.

   **State file (preferred):** If `.hydra/state.json` exists, use it instead of parsing
   the markdown report. Schema: `{version: 2, latest: {report_path, timestamp_unix,
   top_actions[], verdict_lead, mode, reviewed_files[]}}`. Written by Step 6 after each
   successful review. Falls back to `ls -1t` + markdown parsing if state.json is absent.

   **State file version check:** If `version` field is missing or not equal to 2, warn
   user and fall back to markdown parsing. Do not silently use incompatible schema.
6. **Generate boundary tokens** for delimiter security:
   ```bash
   HYDRA_BASE="$(openssl rand -hex 6)"
   ```
   If `openssl` is unavailable: `HYDRA_BASE="$(head -c 6 /dev/urandom | xxd -p)"`.
   If both fail: abort with `[Hydra] Cannot generate secure boundary token. Aborting.`

   Derive per-stage tokens:
   - `HYDRA_BOUNDARY_A="HYDRA-${HYDRA_BASE}-A"` (advisor stage)
   - `HYDRA_BOUNDARY_R="HYDRA-${HYDRA_BASE}-R"` (reviewer stage)
   - `HYDRA_BOUNDARY_C="HYDRA-${HYDRA_BASE}-C"` (chairman stage)

   Use `{{BOUNDARY}}` = `HYDRA_BOUNDARY_A` in advisor preambles (Step 3).
   Use `{{BOUNDARY}}` = `HYDRA_BOUNDARY_R` in reviewer delimiters (Step 4).
   Use `{{BOUNDARY}}` = `HYDRA_BOUNDARY_C` in chairman delimiters (Step 5).
   This prevents advisor output from escaping reviewer/chairman delimiters.

   **Prompt Assembly Rule** (applies to Steps 3, 4, 5):
   When building ANY prompt for an agent (advisor, reviewer, chairman):
   1. Write the instruction/template portion. Replace all `{{...}}` placeholders with resolved values.
   2. Verify: the resolved instruction portion contains ZERO `{{...}}` placeholders.
   3. Append untrusted content (user code, advisor responses, reviewer responses) as verbatim
      text after the resolved instructions. Never apply placeholder substitution to untrusted content.
   This two-pass rule prevents user code containing `{{BOUNDARY}}` from being replaced with the real token.

7. **Codex check** (skip if `--no-codex`):
   ```bash
   CODEX_SCRIPT=$(ls -1t ~/.claude/plugins/cache/openai-codex/codex/*/scripts/codex-companion.mjs 2>/dev/null | head -1)
   ```
   If empty or file doesn't exist: auto-switch to `--no-codex`, inform user.
   Store the resolved path as `CODEX_SCRIPT_PATH` -- hardcode it in Step 3/4 Bash calls
   (shell state does not persist between tool calls).

   **Codex circuit breaker state:** Initialize `CODEX_FAILURES=0`. After each Codex call failure,
   increment. If `CODEX_FAILURES >= 2`: set `CODEX_CIRCUIT_OPEN=true`, skip all remaining Codex
   calls, switch to Opus for remaining agents. Print: `[Hydra] Codex circuit breaker open after
   {{N}} consecutive failures. Remaining agents run on Opus.`
8. **Classify question type** (uses final resolved mode from steps 0.5 + 0.7): `CODE_REVIEW` | `ARCHITECTURE_DECISION` | `SECURITY_AUDIT` | `DEBUGGING` | `GENERAL_TECHNICAL`
   If `SECURITY_AUDIT` and standard mode: Sentinel is included. Proceed normally.
9. **Determine input complexity** for dynamic word limits:
   ```
   INPUT_SIZE = count lines of source code provided
   if INPUT_SIZE < 100:   COMPLEXITY = small   (word limits x 0.60)
   if INPUT_SIZE < 300:   COMPLEXITY = medium  (word limits x 1.00)
   if INPUT_SIZE >= 300:  COMPLEXITY = large   (word limits x 1.20)
   ```
   The `COMPLEXITY` variable determines advisor word limits (see `references/advisors.md`).
   Mies+ carries two lenses (reduction + readability) and scales with complexity like the others.
10. **Cost warning + confirmation:**

```
[Hydra] {{MODE_NAME}} mode -- {{AGENT_COUNT}} agents.
{{PROVIDER_NOTE}}.

Advisors: {{ADVISOR_NAMES}}
Reviewers: {{REVIEWER_COUNT}} ({{REVIEWER_NAMES_OR_NONE}})
Chairman: 1 Opus
{{FOCUS_NOTE_IF_ACTIVE}}

Estimated: {{TIME}}, {{COST}}.

Alternatives:
  {{IF standard}} --mode deep -> 10 agents, ~$1.50-2.50, ~2 min (escalate)
  {{IF deep}} (no flags) -> standard: 5 agents, ~$0.35-0.65, ~1 min (reduce)
  --no-codex       -> Codex advisors run on Opus instead
  --no-review      -> skip peer review (deep only, reduces to 7 agents)

Proceed? [Y/n/{{IF standard}}deep{{ELSE}}standard{{ENDIF}}]
```

Provider note: Codex modes -> `Code sent to Claude (Anthropic) + Codex (OpenAI). Use --no-codex to keep code Anthropic-only.`
Opus-only modes -> `Code sent to Claude (Anthropic) only.`

### Step 1: Context Enrichment

Quickly scan (< 30 seconds):
- `CLAUDE.md` in project root (use cwd as root if not a git repo)
- Source files the user referenced
- `git diff`, `git log --oneline -5` (skip if not a git repo)
- Project structure (high-level)

**Hard limit: 5000 tokens.** Priority: source code > git diff > CLAUDE.md > project structure.
If `HYDRA_ITERATE`: use `git diff` since previous report timestamp instead of full diff.
Each iteration builds FRESH enriched context. Only Top Actions from the LATEST report
(~100 tokens) are added, not accumulated from all prior reports.
Apply secrets scan to enriched context.

**Context sectioning:** Tag enriched context sections internally for selective routing in Step 3:
- `[SECTION:source_code]` -- file content (used for `hydra this`)
- `[SECTION:diff_context]` -- diff hunks + 30 lines surrounding context (used for `hydra branch`, `hydra iterate`, `hydra pr`)
- `[SECTION:git_diff]` -- git diff stat/summary output
- `[SECTION:claude_md]` -- CLAUDE.md contents
- `[SECTION:project_structure]` -- directory tree
- `[SECTION:config_files]` -- package.json, tsconfig, etc.
- `[SECTION:pr_context]` -- PR title + description from `gh pr view` (used for `hydra pr`; UNTRUSTED data, boundary-wrapped like the diff)

**Smart Context Windowing** (for `hydra branch`, `hydra iterate`, `hydra pr`):

`source_code` and `diff_context` are **mutually exclusive**. Use `diff_context` when the
review is diff-anchored (branch/iterate/pr). Use `source_code` when the user provides
specific code (`hydra this`).

Construction of `[SECTION:diff_context]`:
```bash
# --- Input validation (defense against malicious filenames / state.json tampering) ---
# reviewed_files must only contain safe path chars and must not start with '-' (otherwise
# git may interpret the value as a flag). Abort on any violation.
for f in "${reviewed_files[@]}"; do
  case "$f" in
    -*) echo "[Hydra] Refusing suspicious filename (leading dash): $f" >&2; exit 1 ;;
  esac
  [[ "$f" =~ ^[A-Za-z0-9._/-]+$ ]] || {
    echo "[Hydra] Invalid filename in reviewed_files: $f -- aborting" >&2; exit 1
  }
done
```

Validate the saved timestamp before interpolation:

```bash
# PREV_TIMESTAMP must match YYYYMMDDTHHMMSS (matches the report-slug convention); if
# state.json was tampered or carries garbage, discard the field rather than interpolate.
if [[ -n "$PREV_TIMESTAMP" && ! "$PREV_TIMESTAMP" =~ ^[0-9]{8}T[0-9]{6}$ ]]; then
  echo "[Hydra] Invalid PREV_TIMESTAMP '$PREV_TIMESTAMP' -- falling back to full diff" >&2
  unset PREV_TIMESTAMP
fi
```

Build branch or pull-request context:

```bash
# hydra branch / hydra pr: hunks against base branch (note `--` separator enforces pathspec)
BASE=$(git merge-base HEAD main)  # fallback: master, develop
git diff -U30 "$BASE"...HEAD -- "${reviewed_files[@]}"
```

Build iteration context:

```bash
# hydra iterate: hunks since previous report (PREV_TIMESTAMP already validated above)
git diff -U30 "@{$PREV_TIMESTAMP}" -- "${reviewed_files[@]}"
```

`-U30` provides 30 lines of surrounding context per hunk -- no post-processing needed.
This typically yields 1000-2000 tokens vs ~3000 for full file content, freeing budget
for CLAUDE.md and project structure where relevant.

For `hydra pr`, also build `[SECTION:pr_context]` from the pull request's title + body
(see the PR Review section) -- untrusted, secrets-scanned, boundary-wrapped data.

**Diff budget strategy** (prevents budget blow-up on large branches):
1. Run `git diff --stat` first -- rank files by lines changed (descending).
2. Include hunks file-by-file until reaching 3000 token budget (reserves 2000 for other sections).
3. If focus flag active (e.g., `--focus security`): prioritize files matching focus signal patterns.
4. Remaining files: include only as `[TRUNCATED: {{N}} more files -- see git diff --stat below]`.
5. Always include the full `git diff --stat` summary so advisors know what they're NOT seeing.

For `hydra this`: no windowing. Use full `[SECTION:source_code]` as before.

**Set `IS_WINDOWED`:** After context construction, set `IS_WINDOWED = true` if `[SECTION:diff_context]`
was used (branch/iterate/pr), `false` otherwise. This variable is consumed by confidence calibration
in Step 5.

**Scope metrics** (computed when `IS_WINDOWED = true`, used by report-template + in-conversation summary):
- `DIFF_LINES`: count non-header lines in the assembled diff_context
- `EST_TOTAL_LINES`: sum of `wc -l` for all reviewed files
- `SCOPE_PCT`: integer 0-100. Compute as `min(100, int(round(DIFF_LINES / max(EST_TOTAL_LINES, 1) * 100)))`. The upper clamp handles deleted-only branches where `DIFF_LINES` may exceed `EST_TOTAL_LINES`; the `int()` cast guarantees an integer (never a float like `46.0`) for downstream schema consumers.

### Step 2: Frame the Question

```
QUESTION: [core decision or review request]
CONTEXT: [key context from user + enriched files]
QUESTION TYPE: [classification]
STAKES: [why this decision matters]
```

If `HYDRA_ITERATE`, append to the framed question:

```
ITERATION CONTEXT:
Previous review: {{PREV_REPORT}} ({{AGE}} ago)
Previous Top Actions:
{{TOP_ACTIONS_FROM_PREV_REPORT}}
Changes since: {{GIT_DIFF_STAT_SUMMARY}}
TASK: Re-review -- verify fixes and assess remaining/new issues.
```

### Step 3: Spawn Advisors (parallel)

Read `references/advisors.md`. It defines a Common Preamble (shared by all advisors)
and each advisor's unique prompt. Interpolate `{{FRAMED_QUESTION}}`,
`{{ENRICHED_CONTEXT}}`, and `{{BOUNDARY}}` (use `HYDRA_BOUNDARY_A` from Step 0) into the Common
Preamble, then append each advisor's unique section.

**Selective context routing:** Each advisor receives only the context sections relevant to their scope.
`source_code` and `diff_context` are mutually exclusive (see Step 1). When `diff_context` is
active (branch/iterate/pr), advisors that had `source_code` receive `diff_context` instead.

| Advisor | source_code / diff_context | git_diff | claude_md | project_structure | config_files |
|---------|:--------------------------:|:--------:|:---------:|:-----------------:|:------------:|
| Cassandra | Y | Y | | | |
| Mies+ | Y | Y | Y | Y | Y |
| Navigator | Y | Y | | Y | |
| Volta | Y | Y | | | Y |
| Sentinel | Y | Y | | | |
| Echo | Y | Y | Y | Y | |

When `diff_context` is active, all advisors receive diff hunks + 30-line context instead of
full file content. The `-U30` window provides sufficient surrounding code for failure-chain
analysis (Cassandra), boundary tracing (Navigator), and readability assessment (Mies+).

**Echo also receives `[SECTION:pr_context]`** when present (`hydra pr` mode), which activates its
plan-vs-diff drift and scope-creep checks (4-5). The PR description is untrusted data, boundary-wrapped
like all review content.

**Which advisors** -- see Modes table above. In standard mode: Cassandra, Mies+, Sentinel, Echo (4 advisors).
In deep mode: all 6 advisors. With `--no-codex`, Mies+ and Sentinel run as Opus agents
(same prompts, spawn via Agent tool instead of Codex). All perspectives are preserved;
only cross-model diversity is lost.

**Opus Advisors:** Spawn via Agent tool with `model: "opus"`.

**Codex Advisors** (deep mode only -- skip if `--no-codex` or `CODEX_CIRCUIT_OPEN`).

**Standard mode dispatch:**
```
Batch 1 (dispatch all simultaneously):
  - Agent tool: Cassandra (Opus)
  - Agent tool: Mies+ (Opus)
  - Agent tool: Sentinel (Opus)
  - Agent tool: Echo (Opus)
```
Standard mode is Opus-only: all 4 advisors run as Opus Agent calls in parallel. Codex advisors are deep-mode only (see the Codex section above).

**Deep mode dispatch:**
**IMPORTANT: Codex tasks run SEQUENTIALLY** (codex-companion allows only one active task
per workspace). Launch the first Codex task in the SAME batch as the 4 Opus Agent calls:

```
Batch 1 (dispatch all simultaneously):
  - Agent tool: Cassandra (Opus)
  - Agent tool: Navigator (Opus)
  - Agent tool: Volta (Opus)
  - Agent tool: Echo (Opus)
  - Bash tool: Codex Mies+ (see below)

After Mies+ Bash returns:
  If Mies+ TIMED OUT (exit 124):
    - Spawn Sentinel as Opus via Agent tool (skip sequential Codex slot).
      Increment CODEX_FAILURES. Use same Sentinel prompt, route through Agent tool
      with `model: "opus"`. Set {{SENTINEL_MODEL}} = "Opus".
  Else:
    - Bash tool: Codex Sentinel (see below)
```

**Codex invocation per advisor** (each is a separate Bash tool call):

First, create temp dir (separate Bash call):
```bash
HYDRA_TMP=$(mktemp -d "${TMPDIR:-/tmp}/hydra-XXXXXX") && chmod 700 "$HYDRA_TMP" && echo "$HYDRA_TMP"
```

Write prompt files via Write tool to `$HYDRA_TMP/prompt-mies_plus.md` and `$HYDRA_TMP/prompt-sentinel.md`.

Then for each Codex advisor (one Bash call per advisor, set Bash tool timeout to 90000ms):

```bash
HYDRA_TMP="{{HYDRA_TMP_PATH}}"
CODEX="{{CODEX_SCRIPT_PATH}}"
```

Select the available timeout command:

```bash
# Timeout: gtimeout (brew coreutils) > timeout (linux) > perl fallback
if command -v gtimeout >/dev/null 2>&1; then
  TIMEOUT_CMD="gtimeout 60"
elif command -v timeout >/dev/null 2>&1; then
  TIMEOUT_CMD="timeout 60"
else
  TIMEOUT_CMD="perl -e 'alarm(60); exec @ARGV' --"
fi
```

Run the advisor:

```bash
$TIMEOUT_CMD node "$CODEX" task \
  --prompt-file "$HYDRA_TMP/prompt-{{ADVISOR_NAME}}.md" \
  --effort {{EFFORT_LEVEL}} \
  > "$HYDRA_TMP/output-{{ADVISOR_NAME}}.txt" 2>"$HYDRA_TMP/stderr-{{ADVISOR_NAME}}.txt"
EXIT_CODE=$?
```

Report the outcome:

```bash
if [ $EXIT_CODE -eq 124 ]; then
  echo "HYDRA_STATUS=TIMEOUT"
elif [ $EXIT_CODE -ne 0 ]; then
  echo "HYDRA_STATUS=ERROR_$EXIT_CODE"
  echo "STDERR:"
  cat "$HYDRA_TMP/stderr-{{ADVISOR_NAME}}.txt"
else
  echo "HYDRA_STATUS=OK"
  cat "$HYDRA_TMP/output-{{ADVISOR_NAME}}.txt"
fi
```

**Effort strategy:**
| Role | Model | Effort | Rationale |
|------|-------|--------|-----------|
| Mies+ | GPT-5.4 | `high` | Two lenses (reduction + first-reader walkthrough) need sustained reasoning |
| Sentinel | GPT-5.4 | `high` | Security = thorough analysis of attack surfaces |

**Auth error detection:** After each Codex call, check stderr for auth errors:
```bash
if grep -qi "401\|403\|not authenticated\|unauthorized\|login\|ENOENT" "$HYDRA_TMP/stderr-{{NAME}}.txt" 2>/dev/null; then
  echo "HYDRA_AUTH_FAIL=true"
fi
```
If auth error detected: increment `CODEX_FAILURES`, skip next Codex call immediately.
If timeout (exit 124): increment `CODEX_FAILURES` but still attempt next Codex call (transient).
If other error: increment `CODEX_FAILURES`, attempt next Codex call.

All advisors dispatched in parallel (Opus) and sequentially (Codex, but overlapping with Opus).
Print: `[Hydra] Advisors spawned ({{N}}). Waiting...`
As each completes: `[Hydra] {{Name}} done ({{M}}/{{N}}) {{TIME}}s {{MODEL_TAG}}`

After each advisor completes, validate the response (structured output first, prose fallback):

**Structured output extraction:** Search for the LAST occurrence of
`---HYDRA-STRUCTURED [{{BOUNDARY_A}}]---` / `---END-HYDRA-STRUCTURED [{{BOUNDARY_A}}]---`
in the response (use `rfind` / last-match, prevents user-code injection from matching).
Extract the JSON between delimiters.

**Validation states (canonical enum -- exactly one per advisor response):**
- **VALID_STRUCTURED:** JSON epilog present, parses as valid JSON, contains `position`
  (APPROVE|CONCERN|REJECT) and `findings` (array). Prose portion also has POSITION line.
  Extract structured data for downstream use (confidence computation, chairman compression).
- **VALID_PROSE:** No JSON epilog, but contains a `POSITION: APPROVE|CONCERN|REJECT` line
  AND either (1) at least one advisor-specific finding field, or (2) an explicit
  "no findings"/"no issues" statement. Tag output with `[PROSE-ONLY: structured output missing]`.
  Fall back to regex extraction for downstream processing.
- **DEGRADED:** Has POSITION line but missing structural fields OR malformed JSON inside
  well-formed delimiters. Forward with warning `[DEGRADED: {{reason}}]`.
- **INVALID:** Missing POSITION line entirely, or response under 100 characters. Tag as
  `[INVALID -- missing POSITION]`. Do NOT forward to reviewers or chairman.
- **TIMEOUT:** Empty or no response within timeout.

**Response counting** (for Codex cascade check, minimum-advisors gate, and confidence formula):
- Counts as "responded": VALID_STRUCTURED, VALID_PROSE, DEGRADED
- Counts as "failed": INVALID, TIMEOUT

Print structured output status: `[Hydra] {{Name}}: {{valid_structured|valid_prose|degraded|invalid|timeout}}`

**Scan:** Run secrets-scan (Step 0.4) on each advisor output. Silent redact.

**Codex cascade check:** After all advisors complete:
- If both Codex advisors failed/invalid: auto-switch to Opus-only for reviewer phase.
  Print: `[Hydra] Both Codex advisors failed. Reviewers run Opus-only.`
- If only one failed: proceed normally, count toward minimum.
- Auth/script-not-found errors trigger immediate circuit breaker regardless of count.

**Post-cascade model resolution:** Set model labels based on ACTUAL execution:
- If Mies+ ran on Opus (cascade or --no-codex): `{{MIES_PLUS_MODEL}}` = "Opus"
- If Sentinel ran on Opus: `{{SENTINEL_MODEL}}` = "Opus"
- If BOTH ran on Opus: remove cross-model rules from chairman prompt.

### Step 4: Peer Review (parallel)

**Skip entirely** if mode has no review phase (standard, or deep --no-review).

Read `references/review-protocol.md` for the full protocol.

1. Collect all advisor responses. Label and wrap per `references/review-protocol.md`.
   Use `HYDRA_BOUNDARY_R` (reviewer-stage token) for response delimiters.
2. Spawn 3 Opus reviewers in parallel via Agent tool with `model: "opus"`.

Print: `[Hydra] Peer review started (3 reviewers)...`
As each reviewer completes: `[Hydra] Reviewer {{N}} done ({{M}}/3)`
**Timeout: 120 seconds per reviewer.**

**Scan:** Run secrets-scan on each reviewer output. Silent redact.

### Step 5: Verdict Synthesis (dual-path)

Read `references/chairman-protocol.md` for verdict formats and the focused chairman prompt.

**Orchestrator pre-computation (PANEL SUMMARY):**
Before choosing a verdict path, compute from advisor/reviewer outputs:

1. **Position tally:** Count APPROVE/CONCERN/REJECT. Set `{{AGREE_COUNT}}` = most common count.
2. **Cross-model matches:** Opus finding + Codex finding matched by the unified finding-dedup key (same file + overlapping line range + same issue class; see deduplication rule below). Set `{{CROSS_MODEL_COUNT}}`. Opus-only: 0.
3. **Verified count:** Count all `[VERIFIED]` labels. Set `{{VERIFIED_COUNT}}`.
4. **Signal line:** CODE_REVIEW→"quality assessment", ARCHITECTURE_DECISION→"confidence level",
   SECURITY_AUDIT→"risk level", DEBUGGING/GENERAL_TECHNICAL→"root-cause confidence".
5. **Coverage gaps:** Findings missing file path refs → collect as finding ID + advisor name.
6. **Reviewer label summary** (skip if no reviewers): Count [CORROBORATED], [CONTRADICTED],
   [CRITICAL MISS], [SHARED BLIND SPOT]. For [CONTRADICTED] include conflicting IDs.
7. **Severity scan:** Collect SERIOUS/CATASTROPHIC findings. Set `HAS_SERIOUS_PLUS`.
8. **Evidence chains:** Extract CHAIN lines from each finding for dedup and verify.

**Consensus Map construction (orchestrator-owned):**
Build from advisor POSITION lines:
- For each advisor: Position + key finding (first finding title, max 60 chars)
- Override: APPROVE + SERIOUS findings → CONCERN with note
- Timeout → "N/A" / "[TIMEOUT]"

**Confidence calibration** (numeric 0-100% with backward-compatible labels):

Compute `CONFIDENCE_SCORE` from pre-computed values (use structured output JSON when available,
fall back to regex extraction from prose):

```
EXPECTED_ADVISORS = 4 (standard) or 6 (deep)  // always expected, not responding
TOTAL_FINDINGS    = sum of all findings across responding advisors
IS_WINDOWED       = true if diff_context was used (branch/iterate/pr)

// --- Base components ---
agreement      = (AGREE_COUNT / EXPECTED_ADVISORS) * 40

// Evidence: zero findings with unanimous approval = full marks (absence of findings IS evidence)
IF TOTAL_FINDINGS == 0 AND AGREE_COUNT == EXPECTED_ADVISORS:
  evidence     = 30
ELSE:
  evidence     = (VERIFIED_COUNT / max(TOTAL_FINDINGS, 1)) * 30

cross_model    = min(CROSS_MODEL_COUNT * 15, 30)
corroboration  = min(CORROBORATED_COUNT * 5, 15)    // 0 if no reviewers
deductions     = (CONTRADICTED_COUNT * -10) + (BLIND_SPOT_COUNT * -5)

// --- Scope correction for windowed reviews ---
// Windowed reviews see partial code -- cap evidence to prevent inflation on finding-based scoring.
// EXCEPTION: zero-finding unanimous case — "absence of findings IS evidence" already
// communicates scope via the scope indicator line below; the cap does not re-apply.
IF IS_WINDOWED AND TOTAL_FINDINGS > 0:
  evidence     = min(evidence, 15)   // half-max: windowed reviews can't fully verify findings

raw_score      = agreement + evidence + cross_model + corroboration + deductions
CONFIDENCE_SCORE = clamp(raw_score, 5, 100)
```

**Finding deduplication** (unified key, applied before computing VERIFIED_COUNT AND for cross-model
matching): Findings from different advisors count as 1 finding when ALL of the following hold:
- same `file` path
- overlapping `line_range` (any line shared between the two ranges, not exact equality -- so
  `auth.ts:47-62` and `auth.ts:48-55` are the same finding)
- same `issue_class` (the semantic category -- e.g. "race condition", "null deref", "SQL
  injection" -- derived from the finding title or from the advisor's scope signature; NOT
  severity, which may legitimately differ across advisors describing the same phenomenon)

Use structured output JSON fields (`file`, `lines`, `title`) when available, fall back to prose
extraction. Severity is NOT part of the key; this avoids treating the same issue reported at
SERIOUS by Cassandra and MODERATE by Navigator as two distinct findings.

**Mode-aware label thresholds** (standard lacks reviewers + cross-model, so thresholds are lower):
- Standard: HIGH >= 60, MEDIUM >= 30, LOW < 30
- Deep: HIGH >= 75, MEDIUM >= 40, LOW < 40

**Zero-finding unanimous override:** If ALL of these hold:
- `AGREE_COUNT == EXPECTED_ADVISORS` (unanimous)
- `TOTAL_FINDINGS == 0`
- every responding advisor is in state VALID_STRUCTURED or VALID_PROSE (no DEGRADED responses
  promoted to HIGH -- a malformed panel has not earned high confidence even when it approves)

then set `CONFIDENCE_LABEL = HIGH` regardless of mode threshold, and append an override note
line after the scope indicator: `Basis: unanimous approval, zero findings (structured).`

Rationale: unanimous approval with zero findings from structurally-valid responses is a
categorical signal (absence of findings = evidence) that is independent of the numeric scale.
This prevents deep-mode and windowed zero-finding reviews from being mislabeled MEDIUM when the
review is actually maximally clean for its scope. The DEGRADED exclusion prevents a malformed-
output panel from earning HIGH without structural validation.
Display format unchanged: `Confidence: {{SCORE}}% ({{LABEL}})`.

**Degraded panel override:** If fewer than minimum advisors responded, cap score at 25 and
force label to LOW with note: `(degraded: {{N}}/{{EXPECTED}} responded, score capped at 25)`.
The cap is set below both modes' LOW thresholds (Standard < 30, Deep < 40) so the forced LOW
label is consistent with the displayed number in either mode.

**Scope indicator** (always show when `diff_context` is active):
Print after confidence line: `SCOPE {{DIFF_LINES}}/{{EST_TOTAL_LINES}} lines ({{SCOPE_PCT}}%) -- diff-anchored review`
If 0 findings + windowed: append warning: `Note: 0 findings on limited scope does NOT validate unreviewed code.`

**Display format:** `Confidence: {{SCORE}}% ({{LABEL}})`, e.g., `Confidence: 78% (HIGH)`.

Inject into PANEL SUMMARY as `CONFIDENCE: {{SCORE}}% ({{LABEL}})` for chairman consumption.
The chairman uses this value as-is and does not recompute.

**Path decision tree:**
```
HAS_REJECT       = any POSITION == REJECT
HAS_MIXED        = positions contain both APPROVE and CONCERN
HAS_CONTRADICTED = [CONTRADICTED] count > 0
HAS_SERIOUS_PLUS = any finding severity >= SERIOUS
IS_ARCHITECTURE  = QUESTION_TYPE == ARCHITECTURE_DECISION

IF ANY true -> FOCUSED CHAIRMAN PATH (LLM)
IF ALL false -> DETERMINISTIC PATH (no LLM call)
```
Print: `[Hydra] Verdict path: {{deterministic|focused chairman}} ({{reason}}).`

**--- DETERMINISTIC PATH ---**
No chairman agent spawned. Orchestrator assembles verdict from pre-computed data:
1. Verdict position from unanimous tally (APPROVE or CONCERN).
2. Confidence line: emit `**Confidence:** {{CONFIDENCE_SCORE}}% ({{CONFIDENCE_LABEL}})` immediately
   after the position, using the pre-computed PANEL SUMMARY values, matching the chairman-path
   verdict template so deterministic and chairman outputs are indistinguishable to downstream consumers.
3. Findings ordered by Reviewer 2's Effort-Risk Ranking (if available) or severity desc.
4. Summary block: Top Actions from ranking, Key Tensions = "None", Insight = omit.
5. Decision rationale: "Unanimous {{POSITION}}, {{N}} advisors, no disputes."
6. If `HYDRA_ITERATE`: DELTA BLOCK assembled mechanically (match findings vs previous top_actions).

**--- FOCUSED CHAIRMAN PATH ---**
Spawn 1 Opus agent with focused chairman prompt from `references/chairman-protocol.md`.
Use `HYDRA_BOUNDARY_C` for delimiters. Adapt per MODE ADAPTATION rules.

**Chairman input optimization:** Send `[SECTION:diff_context]` when available (branch/iterate/pr),
otherwise `[SECTION:source_code]` (never CLAUDE.md/config). For disputed findings ([CONTRADICTED]),
include the full source section for the affected file to enable chairman self-verification.
**Advisor output compression:** When structured output (JSON epilog) is available, extract
the JSON epilog + first finding's prose for context (~400 tokens each). Fall back to
POSITION + findings + evidence chains + labels (~600 tokens each) if no JSON epilog.

Pre-computed injections before RULES:
- `CONFIDENCE: {{SCORE}}% ({{LABEL}})` (from confidence calibration above)
- `CROSS-MODEL MATCHES: {{list or "None"}}`
- `EFFORT-RISK RANKING: {{from Reviewer 2}}`
- `DISPUTES: {{[CONTRADICTED] findings with both positions}}`
- `SERIOUS+ FINDINGS: {{list with attribution}}`
- `COVERAGE GAPS: {{findings missing file refs}}`
- `SCOPE: is_windowed={{IS_WINDOWED}} ({{SCOPE_PCT_OR_NULL}}% of changed lines)` -- windowed reviews see only the diff window; the chairman applies the GROUNDING windowed exception

Chairman focuses on: dispute resolution, synthesis of SERIOUS+ findings, Verify block.
Orchestrator handles: Consensus Map, confidence counts, signal line, formatting.

If `HYDRA_ITERATE`: append to the chairman prompt before RULES:

```
ITERATION MODE -- This is a follow-up review. Previous Top Actions:
{{TOP_ACTIONS_FROM_PREV_REPORT}}
After the verdict, produce a DELTA BLOCK (outside word limit, max 200 words):
**Fixed:** [previous actions now resolved, with evidence]
**Remaining:** [previous actions still present -- why?]
**Regression:** [things that WERE working and now aren't -- highest priority]
**New:** [findings not in previous review]
**Drift:** [if changes go beyond original scope -- flag it]
**Complexity Signal:** [if fix is more complex than issue warranted -- flag it]
**Progress:** [X of Y previous actions addressed]
```

**Scan:** Run secrets-scan on chairman output. Silent redact.

**Chairman retry:** The chairman is the single most critical agent -- its failure loses the
entire synthesis. If the chairman call fails with a retryable error (timeout, 429, 500/502/503):
1. Apply backoff with jitter (same strategy as advisor retries).
2. Retry once: `[Hydra] Chairman failed ({{ERROR_TYPE}}), retrying in {{DELAY}}s (1/1)...`
3. If retry also fails: fall back to degraded path (generate report without verdict,
   include Consensus Map + raw advisor outputs).
Max 1 retry. Non-retryable errors (401/403, 400, content policy) skip straight to degraded path.

### Step 6: Generate Report

Read `references/report-template.md` for the template. Generate inline (no extra agent).

**Final scan:** Run secrets-scan on assembled report before disk write. If findings: redact and append note. If --transcript: scan transcript file too.

**Save to:** `.hydra/reports/hydra-YYYYMMDDTHHMMSS-{slug}.md`
Slug: generate from the first 3-4 words of the title by string manipulation in your
response (do NOT pipe user-derived text into Bash -- shell injection risk):
- Lowercase, replace non-alphanumeric with `-`, collapse consecutive `-`, max 40 chars.
- Example: "Auth Middleware Refactor" -> `auth-middleware-refactor`
If slug is empty after sanitization, use `review`.

**Directory setup (first run):**
```bash
mkdir -p .hydra/reports && chmod 700 .hydra && chmod 700 .hydra/reports
echo '*' > .hydra/.gitignore && chmod 600 .hydra/.gitignore
```

**File permissions:** All files in `.hydra/` should be owner-only:
```bash
chmod 600 .hydra/reports/hydra-*.md
chmod 600 .hydra/state.json
```

   **Write state file:** After saving the report, write `.hydra/state.json`:
   ```json
   {
     "version": 2,
     "latest": {
       "report_path": ".hydra/reports/hydra-{TIMESTAMP}-{SLUG}.md",
       "timestamp_unix": {UNIX_EPOCH},
       "top_actions": [
         {"id": "A1", "severity": "CRITICAL", "file": "path", "lines": "47-62", "effort": "S", "summary": "action text"}
       ],
       "verdict_lead": "first 2-3 sentences of verdict",
       "mode": "{PRESET_NAME}",
       "is_windowed": true|false,
       "scope_pct": 0-100 | null,
       "reviewed_files": ["path/to/file1", ...]
     }
   }
   ```
   Extract `top_actions` from chairman's SUMMARY BLOCK (including effort tags and file refs).
   Extract `reviewed_files` from file paths mentioned in advisor responses.
   If state.json write fails: warn, continue (the report is the primary artifact).

   **Reviewer Highlights:** Extract labeled findings from reviewers:
   - Collect all [CORROBORATED] labels -> **High-Confidence Findings**
   - Collect all [CONTRADICTED] labels -> **Disputes** (chairman must resolve)
   - Collect all [UNCORROBORATED] labels -> **Needs Verification** (single-advisor findings)
   - Collect [CRITICAL MISS] labels -> **Missed by Advisors**
   - Collect [SHARED BLIND SPOT] labels -> **Shared Assumptions**
   - Collect "gap" from each reviewer's Section B -> **Blind Spots**
   If no reviewers ran, omit the Reviewer Highlights and Blind Spots sections entirely.

   **Write audit log:** Append one JSONL line to `.hydra/audit.log`:
   ```json
   {"timestamp":"{{ISO_TIMESTAMP}}","session_id":"HYDRA-{{BASE}}","mode":"{{MODE}}","is_windowed":{{IS_WINDOWED}},"scope_pct":{{SCOPE_PCT_OR_NULL}},"question_type":"{{TYPE}}","reviewed_files":[...],"advisors":[{"name":"Cassandra","model":"opus","status":"responded","position":"CONCERN"}],"reviewers":[{"number":1,"model":"opus","status":"responded"}],"chairman":{"model":"opus","status":"responded"},"verdict_position":"CONCERN","degradations":[],"report_path":"{{PATH}}","duration_seconds":{{N}},"iteration":false}
   ```
   **Template substitution rules** (apply to the audit.log JSON line, the state.json schema, and the report frontmatter):
   - `{{IS_WINDOWED}}` -> bareword `true` or `false` (unquoted JSON/YAML boolean, never the string `"true"`).
   - `{{SCOPE_PCT_OR_NULL}}` -> integer literal (e.g. `46`) when `IS_WINDOWED=true`, or the bareword `null` when `IS_WINDOWED=false`. Never emit the string `"null"`.

   Create `.hydra/audit.log` with `chmod 600` on first run. Append-only.

   **Report integrity:** Compute checksum on the assembled report body BEFORE prepending
   the integrity line (otherwise prepending changes the file and invalidates the hash):
   ```bash
   CHECKSUM=$(shasum -a 256 "$REPORT_PATH" | cut -d' ' -f1)
   # Prepend integrity line (checksum covers everything BELOW this line)
   { echo "<!-- hydra-integrity: sha256:${CHECKSUM} session:HYDRA-${HYDRA_BASE} scope:body -->"; cat "$REPORT_PATH"; } > "${REPORT_PATH}.tmp" && mv "${REPORT_PATH}.tmp" "$REPORT_PATH"
   ```
   If `shasum` is unavailable: `openssl dgst -sha256 "$REPORT_PATH" | awk '{print $NF}'`.
   If both fail: skip integrity line (non-critical for local gitignored reports).

Omit sections for advisors/reviewers that didn't participate in this mode (don't list
them as timeout). For actual timeouts: mark as `[TIMEOUT -- no response]`.
Omit `## Peer Reviews` if no reviewers ran. Omit `### Cross-Model Signals` if Opus-only.
If fewer than expected responded, add degradation note at top of Verdict section.

If `--transcript`: save raw agent outputs to separate file (see report-template.md).

### Step 7: Present Results

**Progressive disclosure (3 tiers):**

**Tier 1 (always shown, ~10 lines):**
```
## Hydra: {{TITLE}}

VERDICT    {{ONE sentence from chairman/deterministic verdict}}
ACTIONS    {{N}} findings: {{CRITICAL_N}} critical, {{SERIOUS_N}} serious, {{MODERATE_N}} moderate
  1. [{{SEVERITY}}] {{file:line}} -- {{what}}. Est: {{effort}}.
  2. [{{SEVERITY}}] {{file:line}} -- {{what}}. Est: {{effort}}.
  3. [{{SEVERITY}}] {{file:line}} -- {{what}}. Est: {{effort}}.

Full report: {{path}} | "hydra details" for tensions + insight | "hydra explain #N" for deep dive
```

If `HYDRA_ITERATE`, show the DELTA BLOCK instead (see report-template.md iteration format).

**Tier 2** (`hydra details`): Adds CONFIDENCE, TENSION, INSIGHT, cross-model signals, verify block.
**Tier 3** (`hydra explain #N`): Full finding detail with evidence chains from all advisors.

**Post-review actions:**
```
--- Next Steps ---
  verify         -> run verification for Top Action #1
  fix #N         -> implement Top Action N (with preview)
  hydra explain #N -> deep dive into finding

…(truncated)
