skills/review/SKILL.md
AI code review via Codex subagent — writes quality-gate-status.json, resolves beads gate on pass. Use when the user wants code reviewed, needs a quality check before PR, or mentions "review", "code review", or "codex review". Also triggers before creating pull requests.
npx skillsauth add tunneleven/C4Flow c4flow:reviewInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Phase: 5: Review & QA Agent type: Main agent (interactive with user) Status: Implemented
BEADS → CODE (per-task: spec review + quality review) → TEST → REVIEW (you) → VERIFY → PR
What CODE already checked (per task):
What REVIEW checks (full branch):
This is the authoritative full-branch review. The per-task reviews in CODE are quick checks to catch issues early; this review is comprehensive.
This skill orchestrates a Codex subagent review, manages the beads gate lifecycle, writes quality-gate-status.json, and handles tool unavailability gracefully.
Pattern: Report and stop — no auto-fix loop. Findings are reported; user fixes manually and re-runs.
Blocking threshold: CRITICAL + HIGH findings block gate resolution. MEDIUM/LOW are informational.
Review scope: codex review --base main (diff of current branch vs main).
You are the c4flow:review agent. Execute the following steps in order.
Run these checks before any other action:
command -v bd
command -v codex
If bd is missing:
Warn the user:
WARNING: beads CLI (bd) is not installed.
Gate management and task lifecycle enforcement are unavailable.
Install from: https://github.com/steveyegge/beads
MANUAL REVIEW CHECKLIST (bd fallback):
[ ] Run: codex review --base main
[ ] Verify: 0 CRITICAL findings
[ ] Verify: 0 HIGH findings
[ ] Check MEDIUM/LOW findings for informational value
[ ] Manually confirm review is complete before proceeding to PR
No quality-gate-status.json will be written (gate ID requires bd).
Exit gracefully — do not proceed to further steps.
If codex is missing but bd IS available:
Warn the user:
WARNING: Codex CLI (codex) is not installed.
Automated AI review is unavailable.
Install from: https://github.com/openai/codex
Create a manual review gate:
GATE_ID=$(bd create "Manual review required (codex not available)" \
--labels "c4flow-quality-gate,gate,manual" \
--description "Codex CLI not available. Complete manual code review against main branch, then resolve this gate manually." \
--json | jq -r '.id')
echo "Manual gate created: $GATE_ID"
echo "Resolve with: bd gate resolve $GATE_ID --reason 'Manual review complete: <your findings summary>'"
Print manual review instructions to the user, then exit gracefully.
If both bd and codex are available: Proceed to Step 2.
Read quality-gate-status.json if it exists at the project root.
# Check for existing status file
if [ -f quality-gate-status.json ]; then
EXPIRES_AT=$(jq -r '.expires_at // empty' quality-gate-status.json 2>/dev/null)
NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
fi
Branch based on what you find:
expires_at is in the future (i.e., EXPIRES_AT > NOW):
use-existing: skip to Step 5, using the data already in the file.re-run: proceed to Step 3.EXPIRES_AT <= NOW or expires_at is null):
Before creating a new gate, check quality-gate-status.json for an existing gate_id (prevents duplicate gate creation across invocations — Pitfall 3).
# Read existing gate_id if file exists
EXISTING_GATE_ID=""
if [ -f quality-gate-status.json ]; then
EXISTING_GATE_ID=$(jq -r '.gate_id // empty' quality-gate-status.json 2>/dev/null)
fi
If EXISTING_GATE_ID is non-empty: Verify the gate still exists:
# Verify gate still active in beads
FOUND=$(bd gate list --json 2>/dev/null | jq -r --arg id "$EXISTING_GATE_ID" '.[] | select(.id == $id) | .id' 2>/dev/null)
if [ -n "$FOUND" ]; then
GATE_ID="$EXISTING_GATE_ID"
echo "Reusing existing gate: $GATE_ID"
fi
If gate not found (empty result): fall through to create a new gate.
If no existing gate ID or gate not found: Create a new gate:
GATE_ID=$(bd create "Quality gate: c4flow review+verify" \
--labels "c4flow-quality-gate" \
--description "Automated gate: resolves when Codex review AND bd preflight pass" \
--json | jq -r '.id')
echo "Gate created: $GATE_ID"
If gate creation fails (empty GATE_ID): Try label-based fallback lookup:
GATE_ID=$(bd gate list --json 2>/dev/null | \
jq -r '.[] | select(.labels[]? | contains("c4flow-quality-gate")) | .id' 2>/dev/null | \
head -1)
If still empty after fallback: warn the user that gate tracking is unavailable for this run, but proceed with review (the file will have gate_id: null).
Store GATE_ID — it will be written to quality-gate-status.json in Step 4.
Dispatch the code-reviewer subagent (.claude/agents/code-reviewer.md). The subagent runs Codex with a 120-second timeout and returns structured JSON.
Subagent dispatch prompt:
Review the current branch diff against main. Use `codex review --base main` (with a 120-second timeout). Return ONLY a JSON object with no surrounding prose. The JSON must have these exact fields: pass, critical_count, high_count, medium_count, low_count, findings (array of objects with severity, file, line, message), and summary. Set pass=true ONLY if critical_count==0 AND high_count==0.
After receiving subagent output, parse and validate:
# Extract JSON from output (handles prose wrapping — Pitfall 1)
REVIEW_JSON=$(echo "$SUBAGENT_OUTPUT" | grep -o '{.*}' | jq . 2>/dev/null)
# Validate required fields
VALID=$(echo "$REVIEW_JSON" | jq 'has("pass") and has("critical_count") and has("findings")' 2>/dev/null)
If parse fails or VALID is not true:
codex_review.pass = falsecodex_review summary: "Failed to parse subagent output — gate remains blocked"[]Write results to quality-gate-status.json using atomic write pattern (Pitfall 2):
bd_preflight results if present:if [ -f quality-gate-status.json ]; then
BD_PREFLIGHT=$(jq '.checks.bd_preflight // {"pass": null, "ran_at": null, "issues": []}' quality-gate-status.json 2>/dev/null)
else
BD_PREFLIGHT='{"pass": null, "ran_at": null, "issues": []}'
fi
GENERATED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
EXPIRY_MINUTES=${C4FLOW_GATE_EXPIRY_MINUTES:-60}
# Add expiry minutes to current time
EXPIRES_AT=$(date -u -d "+${EXPIRY_MINUTES} minutes" +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null \
|| date -u -v+${EXPIRY_MINUTES}M +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null)
overall_pass = true ONLY if BOTH codex_review.pass == true AND bd_preflight.pass == true. If bd_preflight.pass is null, overall_pass MUST be false:CODEX_PASS=$(echo "$REVIEW_JSON" | jq '.pass')
BD_PASS=$(echo "$BD_PREFLIGHT" | jq '.pass')
if [ "$CODEX_PASS" = "true" ] && [ "$BD_PASS" = "true" ]; then
OVERALL_PASS=true
else
OVERALL_PASS=false
fi
jq -n \
--arg schema_version "1" \
--arg generated_at "$GENERATED_AT" \
--arg expires_at "$EXPIRES_AT" \
--arg gate_id "${GATE_ID:-null}" \
--argjson overall_pass $OVERALL_PASS \
--argjson codex_review "$REVIEW_JSON_WITH_RAN_AT" \
--argjson bd_preflight "$BD_PREFLIGHT" \
'{
schema_version: $schema_version,
generated_at: $generated_at,
expires_at: $expires_at,
gate_id: (if $gate_id == "null" then null else $gate_id end),
overall_pass: $overall_pass,
checks: {
codex_review: ($codex_review + {ran_at: $generated_at}),
bd_preflight: $bd_preflight
}
}' > quality-gate-status.json.tmp && mv quality-gate-status.json.tmp quality-gate-status.json
echo "quality-gate-status.json written (expires: $EXPIRES_AT)"
Log a validation entry every time the file is written (required per research warning):
[GATE-STATUS WRITE] generated_at=$GENERATED_AT gate_id=$GATE_ID codex_pass=$CODEX_PASS overall_pass=$OVERALL_PASS
Read the current quality-gate-status.json to determine the outcome.
If codex_review.pass == false:
Report findings to the user in a readable grouped format:
CODE REVIEW FAILED
==================
Gate: $GATE_ID
Reviewed at: $GENERATED_AT
CRITICAL findings ($CRITICAL_COUNT):
- <file>:<line> — <message>
HIGH findings ($HIGH_COUNT):
- <file>:<line> — <message>
MEDIUM findings ($MEDIUM_COUNT) [informational]:
- <file>:<line> — <message>
LOW findings ($LOW_COUNT) [informational]:
- <file>:<line> — <message>
Action required: Fix all CRITICAL and HIGH issues, then re-run /c4flow:review.
Gate $GATE_ID remains open until all checks pass.
Gate remains open — do NOT call bd gate resolve.
If codex_review.pass == true:
Check whether bd_preflight.pass is also true (from the file):
If bd_preflight.pass == true (BOTH pass — gate can be resolved):
Resolve gate with audit trail:
TIMESTAMP=$(jq -r '.checks.codex_review.ran_at' quality-gate-status.json)
MEDIUM_COUNT=$(jq -r '.checks.codex_review.medium_count' quality-gate-status.json)
LOW_COUNT=$(jq -r '.checks.codex_review.low_count' quality-gate-status.json)
bd gate resolve "$GATE_ID" \
--reason "Codex review: 0 critical, 0 high (M:${MEDIUM_COUNT}, L:${LOW_COUNT}). bd preflight: passed. Reviewed at: ${TIMESTAMP}"
Update overall_pass: true in quality-gate-status.json (atomic write as in Step 4).
If bd_preflight.pass is null or false (codex passed, preflight not yet run or failed):
Inform the user:
Codex review PASSED (0 critical, 0 high).
bd preflight has not run yet (or did not pass).
Next step: Run /c4flow:verify to complete the preflight check.
Gate $GATE_ID will auto-resolve when BOTH checks pass.
Gate remains open until both checks pass.
Print a summary box at the end of every run:
╔══════════════════════════════════════════════════════╗
║ C4FLOW REVIEW SUMMARY ║
╠══════════════════════════════════════════════════════╣
║ Overall status : PASS / FAIL ║
║ Gate ID : bd-xxxx ║
║ Expires at : 2026-03-16T11:30:00Z ║
╠══════════════════════════════════════════════════════╣
║ Codex review : PASS/FAIL (C:0 H:0 M:2 L:1) ║
║ bd preflight : PASS/FAIL/NOT RUN ║
╚══════════════════════════════════════════════════════╝
On review pass:
Review passed. Quality gate status written to quality-gate-status.json.
Run /c4flow:verify to complete the preflight check and close the gate.
On review fail:
Review FAILED. $CRITICAL_COUNT critical, $HIGH_COUNT high findings must be resolved.
Fix the issues listed above, then re-run /c4flow:review.
| Variable | Default | Description |
|----------|---------|-------------|
| C4FLOW_GATE_EXPIRY_MINUTES | 60 | Minutes until gate status expires and requires re-run |
| File | Description |
|------|-------------|
| quality-gate-status.json | Ephemeral gate status file (git-ignored, written each run) |
| .claude/agents/code-reviewer.md | Subagent definition dispatched for Codex review |
| quality-gate-status.schema.json | JSON Schema draft-07 validating the status file structure |
.tmp then mv to prevent partial-write corruption (Pitfall 2).gate_id from file before creating a new gate (Pitfall 3).grep -o '{.*}' to handle prose wrapping (Pitfall 1).overall_pass is false whenever any check has pass: null.timeout 120 — synchronous only, never backgrounded (Pitfall 6).After REVIEW passes (0 CRITICAL, 0 HIGH):
quality-gate-status.json has codex_review.pass = truebd_preflight.pass is still null (not yet run)overall_pass is false (both checks needed)Next step: c4flow:verify runs bd preflight, merges results, and resolves the gate when both pass.
REVIEW writes codex_review → VERIFY writes bd_preflight → both pass? → gate resolved → PR
development
Quality gate aggregation — runs bd preflight, combines with Codex review results, declares Ready for PR status. Use when the user wants to check if code is ready for PR, verify quality gates, or run preflight checks. Also triggers when mentioning "verify", "preflight", "quality gate", or "ready for PR".
development
Run unit and integration tests with coverage checking. Auto-detect framework, classify failures, enforce coverage threshold before advancing to review. Use when the user wants to run tests, check coverage, or validate implementation quality. Triggers on "run tests", "check coverage", "test suite", or when the code phase completes.
development
Test-driven development — RED-GREEN-REFACTOR cycles for all C4Flow implementation work. Merged into c4flow:code as a sub-agent phase with a mandatory RED gate pause. Use c4flow:code to run the full task loop.
testing
Sync local project with remote sources — pulls DoltHub beads and GitHub repo to local. Handles the "no common ancestor" Dolt error that occurs when bd init creates a fresh local DB that conflicts with an existing DoltHub history. Use when local beads are out of sync, after a fresh init on a project that already has DoltHub data, or to pull the latest GitHub changes.