PR-Ready Checklist (/pr-ready)¶
In plain terms
The final quality gate: run this before you call a task "done" to make sure everything is verified and ready to submit.
What this skill does
Runs the full pre-submission quality gate — lint, type-check, tests, optional SonarCloud scan, E2E, and manual checks — before code is committed or a pull request is opened. Use when the user says they're done, wants to submit, finish, prepare a PR, or get code ready to commit.
[!IMPORTANT] Run this before telling the user "I'm done" with any non-trivial task.
[!NOTE] This is a single skill that adapts to the project. It works for both Python/FastAPI and Node/Express backends, and for projects with or without SonarCloud. Step 0 detects which apply; every later step says exactly what to do per stack. Run only the branches that match the detected setup, and mark anything not applicable as
⊘ skipped/N/A.
Trigger Conditions¶
- Keywords: "I'm done", "Submit this", "Prepare for PR", "Finished", "Ready to commit"
Step 0 — Detect this project's setup (REQUIRED, DO FIRST)¶
Detect how the project is configured and reuse these facts throughout the run:
- Backend stack
- Python / FastAPI — if
backend/pyproject.tomlorbackend/requirements.txtexists. Type-check withpython -m mypy app/, test withpytest, run withuvicorn. - Node / Express — if
backend/package.jsonexists. Type-check and test with the project's npm scripts, run withnpm run dev. - Repo layout — split (
frontend/+backend/directories) or single-root. Run eachnpmcommand from the correct directory (examples below assume a split layout; drop thecd frontendif the frontend lives at the repo root). - Backend health URL — from the project's config/
.env. Common: FastAPI onhttp://localhost:8000/api/system/health; Express onhttp://localhost:5001/health. - SonarCloud — enabled only if
SONAR_ENABLED=true(mirrors the GitHub Actions repo variable). Check once:echo "SONAR_ENABLED=${SONAR_ENABLED:-false}". If enabled, read the project key fromsonar-project.properties(sonar.projectKey=…). If it is unset/false, skip all SonarCloud phases (Phase 3 and Phase 6) and mark their report rows⊘ skipped (SONAR_ENABLED!=true). - Architecture linter — if
scripts/check-architecture.jsexists, include it as a Phase 1 check. - Localization — if the frontend uses a translation helper (e.g.
t('Category','Key')/useLanguage()), include the localization check in Phase 4. - OpenAPI types — if the frontend consumes generated types from
@/types/api(typical for FastAPI backends that publishopenapi.json), include the OpenAPI sync + API-types checks.
State the detected setup in one line before continuing (stack, layout, Sonar on/off).
Step 0a — Backend Reachability Check (REQUIRED)¶
Many later checks (E2E, smoke tests) need the backend running.
- Probe the detected health URL:
curl -s -o /dev/null -w "%{http_code}" <HEALTH_URL> || echo "unreachable" - If reachable (200): continue to Step 0b.
- If not reachable: start the backend for the detected stack:
- Python/FastAPI:
cd backend && uvicorn main:app --reload --port 8000 & - Node/Express:
cd backend && npm run dev &then poll up to 15s:for i in {1..15}; do sleep 1; curl -s <HEALTH_URL> && break; done - If still unreachable after 15s, STOP and ask the user to start the backend, then re-run.
Step 0b — Branch Sync Check (REQUIRED)¶
git fetch origin maingit log HEAD..origin/main --oneline— does remotemainhave commits not present locally?- If yes: show them, run
git merge origin/main. If it conflicts, STOP and list the conflicting files for the user to resolve. If clean, continue. - If no new commits, continue.
Step 1 — Progress Tracking (REQUIRED)¶
Create a TodoWrite task list so progress is visible. Include only the steps that apply to the detected setup (omit SonarCloud rows if disabled, the architecture-linter row if no linter, localization if no translation system, OpenAPI/API-types if not an OpenAPI backend):
0a. Backend reachability 0b. Branch sync
1. Frontend lint 2. Frontend type-check
3. Backend type-check 4. Architecture lint (if present)
5. OpenAPI sync (if OpenAPI) 6. Frontend tests
7. Backend tests 8. Latency tests (Node, if present)
9. SonarCloud scan + gate + issues + duplication (if SONAR_ENABLED)
10. E2E tests 11. Console cleanup
12. Auth guards 13. No `any` types
14. Causal order 15. API types (if OpenAPI)
16. Localization (if present) 17. No window.alert()
18. Test sync + alignment 19. Architecture review
20. Temp cleanup 21. Release notes
22. Commit & push 23. Post-push Sonar verify (if SONAR_ENABLED)
24. Summary
Mark each in_progress when started and completed when it passes.
Phase 1 — Static Analysis (run in PARALLEL)¶
Send a single message with the applicable checks running simultaneously:
- Frontend Lint:
cd frontend && npm run lint - Frontend Type-Check:
cd frontend && npm run check(ornpm run type-check— use the project's script) - Backend Type-Check:
- Python/FastAPI:
cd backend && python -m mypy app/(skip silently as N/A if mypy isn't configured) - Node/Express:
cd backend && npm run type-check - Architecture Lint (only if
scripts/check-architecture.jsexists):node scripts/check-architecture.js - OpenAPI Sync Check (only for OpenAPI backends): inspect
git diff --name-only main...HEADfor changes underbackend/app/; if any route/schema changed, flag that/openapi-syncmust run before continuing.
Wait for all to finish; apply auto-fixes (below) before Phase 2.
Step 1a — Lint Auto-Fix (max 2 iterations)¶
Group lint errors by file domain and launch one subagent per group in parallel. Each agent:
read the file first, fix using Edit only (no bash). Suggested groups — Python/FastAPI:
backend/app/api/**, backend/app/services|models/**, frontend/src/components/**,
frontend/src/{hooks,services,context,pages}/**; Node/Express: backend/src/routes/**,
backend/src/{services,middleware}/**, frontend hooks|context|services/**,
components|src/**. Re-run lint after. If errors remain after iteration 2, STOP and report.
Step 1b — Type Auto-Fix (max 2 iterations)¶
Same grouping/agent approach for type errors. Fix only type errors — no unrelated refactors. Re-run the type-check. If errors remain after iteration 2, STOP and report.
Phase 2 — Tests (run in PARALLEL)¶
- Frontend Tests:
cd frontend && npm run test -- --run(generates lcov coverage for Sonar) - Backend Tests:
- Python/FastAPI:
cd backend && pytest --cov=app --cov-report=xml --tb=short -q(generatescoverage.xml) - Node/Express:
cd backend && npm run test:smoke - Latency Tests (Node/Express, only if a latency script exists):
cd backend && npm run test:latency— flag any endpoint over 500 ms average.
All must pass before continuing. Do not proceed to a Sonar scan if any suite fails.
Phase 3 — SonarCloud (only if SONAR_ENABLED=true; otherwise skip to Phase 3b)¶
Coverage reports from Phase 2 are reused — do not re-run tests.
Run Sonar Scan¶
echo "🔍 Starting SonarCloud scan — this takes 2–4 minutes..."
JAVA_HOME=/opt/homebrew/opt/java SONAR_TOKEN=${SONAR_TOKEN:-$SONARQUBE_TOKEN} sonar-scanner \
-Dsonar.host.url=https://sonarcloud.io 2>&1 | \
grep --line-buffered -E "INFO|WARN|ERROR|Sensor|Analysis|Upload|Quality Gate|ANALYSIS SUCCESSFUL"
echo "✅ Scan uploaded — polling SonarCloud for results..."
After upload, poll mcp__sonarqube__get_project_quality_gate_status (use the projectKey from
sonar-project.properties) every 10s, max 12 attempts, until analysisDate changes. Use
run_in_background: true on any wait commands.
BLOCKER — scan fails with 401/403 or "Project not found": the
SONAR_TOKEN/SONARQUBE_TOKENis missing/expired/under-permissioned. STOP — do not commit or push. Tell the user to generate a new Project Analysis Token at https://sonarcloud.io/account/security for the project, updateSONARQUBE_TOKENin~/.bash_profile,sourceit, and re-run.
Quality Gate / Issues / Duplication¶
mcp__sonarqube__get_project_quality_gate_status— anystatus:"ERROR"→ fix (auto-fix below).mcp__sonarqube__search_sonar_issues_in_projectswithissueStatuses:["OPEN"]— split into frontend/backend.mcp__sonarqube__search_duplicated_files— if new duplication density > 3%, extract shared code.
Sonar Auto-Fix (max 2 iterations)¶
Group open issues by file domain, one subagent per group in parallel (read first, Edit only).
Common rule fixes: S1128 remove unused imports · S6582 optional chaining · S1854 dead assignments ·
S2486 handle caught exceptions · S3358 simplify ternaries · S125 remove commented-out code ·
S7785 fix async/await misuse · S6606 use ??. Python issues: replace bare except: with
except Exception:, add return type hints, extract magic numbers, PEP 8 naming. After fixes:
re-run the type-checks, re-run the scan, re-check gate + issues. If issues remain after iteration 2,
STOP and report with file + line.
Phase 3b — E2E Tests¶
Requires the backend running (verified in Step 0a).
cd frontend && npx playwright test --reporter=line 2>&1
Check exit code and the summary line (e.g. 21 passed, 3 failed). For each failure: read the
trace, identify the cause (selector, missing data-testid, timing, backend state), apply a fix if
clear, re-run the failing spec. Max 2 iterations, then STOP and report which tests failed, the
error, your diagnosis, and the fix needed. Add results to the final summary.
Phase 4 — Manual Checks (run in PARALLEL)¶
- Console Cleanup: in files from
git diff --name-only main...HEAD, remove strayconsole.log/debug/warn,debugger, and debugprint(— keep intentional structured logging. - Auth Guards:
- Python/FastAPI: each new/modified route handler has
require_auth+require_permissiondependencies (or a documented exception). - Node/Express: each new/modified route in
backend/src/routes/applies auth middleware. - Frontend: new API calls handle 401s (global interceptor or explicit handling).
- No
anyTypes: replace explicitanyin new/modified TS with a proper type orunknown+ narrowing. - Causal Order (CRITICAL): no fire-and-forget that must finish before the response —
Python: no stray
asyncio.create_task(); Node/Frontend: no floating Promises (missingawait). - API Types Check (OpenAPI backends only): frontend API response shapes import from
@/types/api(generated), not hand-written local interfaces. - Localization (only if the project uses a translation system): no hardcoded user-facing
strings — use
t('Category','Key'). - No
window.alert(): replacewindow.alert()/confirm()/alert()with Toasts/Modals.
Record pass/fail for each.
Test Sync & Alignment (REQUIRED)¶
Run /test-sync to create/update tests for changed files, then verify (passing tests with stale
assertions are worse than none). Confirm each changed source file has an up-to-date test:
- Python/FastAPI:
backend/app/api/[x].py→backend/tests/test_[x].py;frontend/src/components/[X].tsx→frontend/src/tests/components/[X].test.tsx. - Node/Express:
backend/src/routes/[x].ts→backend/tests/integration/routes/[x].test.ts;backend/src/services/[x].ts→backend/tests/unit/services/[x].test.ts.
Check: test file exists, was updated, covers new behavior, and removed behavior's tests are deleted.
Architecture Review¶
Run /architecture-review as a final structural check.
Phase 5 — Finalization (Pre-Push)¶
- Temp Cleanup: run
/cleanup-temp. - Release Notes: from
git diff --name-only main...HEAD, skip if every changed file is undertests//coverage/; otherwise run/release-notes(do NOT bump versions manually). - Branch Guard (REQUIRED): never commit to
main. Ifgit branch --show-currentismain, create a namespaced branch first:Otherwise reuse the current branch.DEV=$(git config user.name | tr ' /' '-' | tr '[:upper:]' '[:lower:]') git switch -c "pr-ready/${DEV}/<short-slug>" - Commit & Push: commit everything and push the current (non-
main) branch — this triggers CI.
Phase 6 — Post-Push Verification (only if SONAR_ENABLED=true)¶
The remote CI scan is the definitive source of truth.
- Wait for remote scan: poll
gh run list --branch $(git branch --show-current) --limit 1 --json status,conclusionevery 15s (max 20 attempts),run_in_background: true. (Orgh run watchin background.) - Re-check quality gate + open issues + duplication (projectKey from
sonar-project.properties). - Repair loop (max 2): fix → verify type-checks → commit & push → poll CI → re-check. If still failing after 2 iterations, STOP and report.
Final Summary Report¶
Present a markdown table of every applicable check (Check | Status ✅/❌/⊘ | Notes), with rows for
the steps you actually ran. Mark Sonar/localization/OpenAPI rows ⊘ skipped when not applicable.
Verdict: READY / NOT READY — if NOT READY, list every blocker with file path + line reference.
[!IMPORTANT] The Final Report is the LAST output of this skill. Do NOT call TodoWrite afterward — the report is the deliverable.