Epic completion review - adversarial dual-model review, external bot self-heal, browser QA, and learning capture. Full thorough review at epic level. Triggers on /flux:epic-review.
From fluxnpx claudepluginhub nairon-ai/flux --plugin fluxThis skill uses the workspace's default tool permissions.
fluxctl-reference.mdworkflow.mdDesigns and optimizes AI agent action spaces, tool definitions, observation formats, error recovery, and context for higher task completion rates.
Enables AI agents to execute x402 payments with per-task budgets, spending controls, and non-custodial wallets via MCP tools. Use when agents pay for APIs, services, or other agents.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
Read workflow.md for detailed phases and anti-patterns.
Thorough review at epic completion. Combines adversarial dual-model review (two different models reach consensus), external bot self-heal (Greptile/CodeRabbit), browser QA, and learning capture. Cross-lab pairs (Anthropic + OpenAI) are strongest, but same-provider pairs work too. Per-task lightweight reviews happen via /flux:impl-review — this is the heavy-weight pass.
Role: Epic Review Coordinator (NOT the reviewer) Backends: RepoPrompt (rp) or Codex CLI (codex)
On entry (after FLUXCTL is resolved), set the session phase:
$FLUXCTL session-phase set epic_review
On completion, reset:
$FLUXCTL session-phase set idle
CRITICAL: fluxctl is BUNDLED — NOT installed globally. which fluxctl will fail (expected). Always use:
PLUGIN_ROOT="${DROID_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}}"
[ ! -d "$PLUGIN_ROOT/scripts" ] && PLUGIN_ROOT=$(ls -td ~/.claude/plugins/cache/nairon-flux/flux/*/ 2>/dev/null | head -1)
FLUXCTL="${PLUGIN_ROOT}/scripts/fluxctl"
Priority (first match wins):
--review=rp|codex|none argumentFLUX_REVIEW_BACKEND env var (rp, codex, none).flux/config.json → review.backendCheck $ARGUMENTS for:
--review=rp or --review rp → use rp--review=codex or --review codex → use codex--review=none or --review none → skip reviewIf found, use that backend and skip all other detection.
BACKEND=$($FLUXCTL review-backend)
if [[ "$BACKEND" == "ASK" ]]; then
echo "Error: No review backend configured."
echo "Run /flux:setup to configure, or pass --review=rp|codex|none"
exit 1
fi
echo "Review backend: $BACKEND (override: --review=rp|codex|none)"
For rp backend:
setup-review - handles window selection + builder atomically--new-chat after first reviewFor codex backend:
$FLUXCTL codex completion-review exclusively--receipt for session continuity on re-reviewsFor all backends:
REVIEW_RECEIPT_PATH set: write receipt after SHIP verdict (RP writes manually after fix loop; codex writes automatically via --receipt)<promise>RETRY</promise> and stopflux-receive-review when sorting valid issues from reviewer or bot feedback.FORBIDDEN:
Arguments: $ARGUMENTS
Format: <epic-id> [--review=rp|codex|none]
fn-1 or fn-22-53k--review - Optional backend overrideSee workflow.md for full details on each phase.
The epic review is a multi-phase pipeline:
.flux/brain/pitfalls/ or structural rule candidatesPLUGIN_ROOT="${DROID_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}}"
[ ! -d "$PLUGIN_ROOT/scripts" ] && PLUGIN_ROOT=$(ls -td ~/.claude/plugins/cache/nairon-flux/flux/*/ 2>/dev/null | head -1)
FLUXCTL="${PLUGIN_ROOT}/scripts/fluxctl"
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
$FLUXCTL architecture status --json
Parse $ARGUMENTS for:
fn-* → EPIC_ID--review=<backend> → backend override# Read adversarial reviewers and bot config
REVIEWER1=$($FLUXCTL config get review.reviewer1 2>/dev/null || echo "")
REVIEWER2=$($FLUXCTL config get review.reviewer2 2>/dev/null || echo "")
REVIEW_BOT=$($FLUXCTL config get review.bot 2>/dev/null || echo "")
SEVERITIES=$($FLUXCTL config get review.severities 2>/dev/null || echo "critical,major")
REVIEWER1: First review model (e.g., claude-sonnet-4-6, gpt-5.4)REVIEWER2: Second review model — must be different from REVIEWER1 (e.g., gpt-5.3-codex, claude-opus-4-6)REVIEW_BOT: greptile, coderabbit, or emptySEVERITIES: comma-separated list of severity levels to auto-fix (e.g., critical,major)Run backend detection from above. Then branch:
RECEIPT_PATH="${REVIEW_RECEIPT_PATH:-/tmp/completion-review-receipt.json}"
$FLUXCTL codex completion-review "$EPIC_ID" --receipt "$RECEIPT_PATH"
# Output includes VERDICT=SHIP|NEEDS_WORK
On NEEDS_WORK: fix code, commit, re-run (receipt enables session continuity).
Missing architecture-diagram updates are in scope here when the epic changed the product's
high-level architecture. .flux/brain/codebase/architecture.md is a canonical artifact, not optional docs.
Stop: You MUST read and execute workflow.md now.
Go to the "RepoPrompt Backend Workflow" section in workflow.md and execute those steps. Do not proceed here until workflow.md phases are complete.
Return here only after workflow.md spec compliance review is complete.
Only runs if BOTH reviewer1 AND reviewer2 are configured.
If only one reviewer or neither is configured, skip to Step 4.
See workflow.md "Adversarial Review Phase" for full details. Summary:
The adversarial approach catches more issues than a single model while reducing false positives through consensus.
Split all issues (from spec review + adversarial review) into two buckets:
Severity ranking: critical > major > minor > style
If SEVERITIES = ["critical", "major"], then critical and major issues are auto-fixed; minor and style are logged only.
CRITICAL: Do NOT ask user for confirmation. Automatically fix ALL issues in the fix-list and re-review. Never use AskUserQuestion in this loop.
If verdict is NEEDS_WORK and fix-list is non-empty, loop internally until SHIP:
fluxctl codex completion-review (receipt enables context)$FLUXCTL rp chat-send --window "$W" --tab "$T" --message-file /tmp/re-review.md (NO --new-chat)<verdict>SHIP</verdict>CRITICAL: For RP, re-reviews must stay in the SAME chat so reviewer has context. Only use --new-chat on the FIRST review.
MAX ITERATIONS: Limit fix+re-review cycles to ${MAX_REVIEW_ITERATIONS:-3} iterations. If still NEEDS_WORK after max rounds, output <promise>RETRY</promise> and stop.
Before declaring SHIP at any phase boundary, apply flux-verify-claims.
Runs automatically when changed files touch security-sensitive areas.
Detect if the epic's changed files include security-sensitive patterns:
CHANGED_FILES="$(git diff main..HEAD --name-only 2>/dev/null || git diff master..HEAD --name-only)"
# Security-sensitive patterns: auth, API routes, middleware, config, secrets, permissions
SECURITY_FILES=$(echo "$CHANGED_FILES" | grep -iE '(auth|login|session|token|middleware|permission|rbac|acl|secret|credential|api[-_]?key|security|crypto|encrypt|password|oauth|jwt|cors|csrf|sanitiz|valid)' || echo "")
If SECURITY_FILES is non-empty: Run the flux-security-review skill in staged mode against the branch diff. This invokes the full STRIDE scan (Spoofing, Tampering, Repudiation, Information Disclosure, DoS, Elevation of Privilege) with exploitability validation.
If SECURITY_FILES is empty: Skip security scan (pure UI or non-security changes).
After scan:
validated-findings.json for confirmed vulnerabilities (confidence >= 0.8)SEVERITIES config)git commit -m "fix: address security scan findings"Security findings are also captured in the Learning Capture phase.
Only runs if review.bot is configured AND a PR exists for the branch.
See workflow.md "External Bot Self-Heal Phase" for full details. Summary:
coderabbit review CLI or poll PR comments for CodeRabbit reviewOnly runs if agent-browser is detected on PATH AND a Browser QA Checklist task exists for this epic.
During scoping (/flux:scope), Flux auto-creates a "Browser QA Checklist" task for epics that involve frontend/web changes. This task contains testable criteria — URLs, expected elements, user flows — that the browser QA phase follows.
See workflow.md "Browser QA Phase" for full details. Summary:
agent-browser is available: command -v agent-browser >/dev/null 2>&1$FLUXCTL tasks --epic "$EPIC_ID" --json | jq '.[] | select(.title | test("Browser QA|browser.qa"; "i"))'agent-browser open <url>agent-browser snapshot -iagent-browser screenshot "/tmp/qa-${EPIC_ID}-${n}.png"agent-browser closeAfter the full review pipeline reaches SHIP, extract learnings from any NEEDS_WORK iterations and persist them to the brain vault.
Pitfalls are organized by area of concern under .flux/brain/pitfalls/<area>/. The agent decides the area intelligently based on the pitfall's domain.
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
PITFALLS_DIR="$REPO_ROOT/.flux/brain/pitfalls"
# Determine area from the pitfall's domain
# Common areas: frontend, backend, security, async, api, database, testing, infra
# Create new area if none of the existing ones fit
AREA="<area>" # e.g., "frontend", "security", "async"
mkdir -p "$PITFALLS_DIR/$AREA"
# Write one file per learning (slug from pattern name)
cat > "$PITFALLS_DIR/$AREA/<pattern-slug>.md" << 'EOF'
# <Pattern Name>
<description>
**Source**: epic-review (<epic-id>)
**Date**: <date>
EOF
Area selection rules:
.flux/brain/pitfalls/ — use one if it fitsfrontend not react-forms)ls .flux/brain/pitfalls/Update .flux/brain/index.md to include new pitfall area entries.
Format: one file per pattern, organized by area (e.g., .flux/brain/pitfalls/frontend/missing-error-states.md).
What to capture:
Only capture generalizable patterns, not one-off fixes. These feed back into the worker via .flux/brain/pitfalls/ which is read during re-anchor — but only the relevant area subdirectories are loaded, keeping context lean. Over time, /flux:meditate promotes recurring pitfalls into proper principles and prunes one-offs.
Only runs if desloppify is installed. This is a scan-only pass — no fix loop, no auto-fix. The purpose is to surface quality regressions introduced during the epic.
if command -v desloppify >/dev/null 2>&1; then
# Get directories touched in this epic
CHANGED_DIRS=$(git diff "${DIFF_BASE}"..HEAD --name-only | xargs -I{} dirname {} | sort -u | grep -v '^\.$')
if [ -n "$CHANGED_DIRS" ]; then
for DIR in $CHANGED_DIRS; do
desloppify scan --path "$DIR" 2>/dev/null
done
fi
fi
"Consider running /flux:desloppify to address quality issues introduced in this epic."See workflow.md "Frustration Signal" for full detection logic (quantitative + qualitative).
Two-part detection system:
Part 1 — Quantitative friction score from pipeline counters:
FRICTION_SCORE = NEEDS_WORK_COUNT + SECURITY_FINDINGS + BROWSER_QA_FAILURES + (SAME_CATEGORY_PITFALLS * 2)
Part 2 — Qualitative friction analysis from three sources:
responsive, css_issues, ui_issues).flux/brain/pitfalls/frontend/ → frontend, ui_issuesCombined into FRICTION_DOMAINS (what's broken) and FRICTION_SIGNALS (what /flux:improve should search for).
If FRICTION_SCORE >= 3, auto-trigger /flux:improve with the detected friction context:
---
**Friction detected** (score: {FRICTION_SCORE}):
Quantitative:
- Review iterations: {NEEDS_WORK_COUNT}
- Security findings: {SECURITY_FINDINGS}
- Browser QA failures: {BROWSER_QA_FAILURES}
- Repeated pitfall categories: {SAME_CATEGORY_PITFALLS} (2x weight)
Diagnosis: {primary friction domain} — {one-sentence summary}
Evidence:
{top 2-3 quotes/issues/pitfalls}
Auto-searching for recommendations to address this...
---
RECS_RAW=$(curl -sL --connect-timeout 10 --max-time 30 "https://raw.githubusercontent.com/Nairon-AI/flux-recommendations/main/recommendations.json")
CURL_EXIT=$?
If CURL_EXIT != 0 or RECS_RAW is empty, tell the user recommendations are unavailable and skip steps 3-4. Do not fail the entire epic review.
Guard against empty friction domains — if FRICTION_DOMAINS is empty but score >= 3 (can happen when score comes purely from quantitative counters), use the quantitative signal types as search terms instead (e.g., NEEDS_WORK → "linting, formatting", SECURITY_FINDINGS → "security scanning", BROWSER_QA_FAILURES → "visual regression testing").
Search the recommendations for entries matching FRICTION_DOMAINS and FRICTION_SIGNALS. Score each recommendation by how many friction signals it addresses. Present the top 3-5 matches with:
Ask the user which (if any) to install now. Do not auto-install — the user picks.
The --user-context flag pre-fills the detected friction domains so /flux:improve's matching engine can skip discovery and go straight to relevant tool recommendations.
ALWAYS run at the very end of command execution:
PLUGIN_ROOT="${DROID_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}}"
[ ! -d "$PLUGIN_ROOT/scripts" ] && PLUGIN_ROOT=$(ls -td ~/.claude/plugins/cache/nairon-flux/flux/*/ 2>/dev/null | head -1)
UPDATE_JSON=$("$PLUGIN_ROOT/scripts/version-check.sh" 2>/dev/null || echo '{"update_available":false}')
UPDATE_AVAILABLE=$(echo "$UPDATE_JSON" | jq -r '.update_available')
LOCAL_VER=$(echo "$UPDATE_JSON" | jq -r '.local_version')
REMOTE_VER=$(echo "$UPDATE_JSON" | jq -r '.remote_version')
If update available, append to output:
---
Flux update available: v${LOCAL_VER} → v${REMOTE_VER}
Update Flux from the same source you installed it from, then restart your agent session.
---