Skip to content

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.toml or backend/requirements.txt exists. Type-check with python -m mypy app/, test with pytest, run with uvicorn.
  • Node / Express — if backend/package.json exists. Type-check and test with the project's npm scripts, run with npm run dev.
  • Repo layout — split (frontend/ + backend/ directories) or single-root. Run each npm command from the correct directory (examples below assume a split layout; drop the cd frontend if the frontend lives at the repo root).
  • Backend health URL — from the project's config/.env. Common: FastAPI on http://localhost:8000/api/system/health; Express on http://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 from sonar-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.js exists, 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 publish openapi.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.

  1. Probe the detected health URL: curl -s -o /dev/null -w "%{http_code}" <HEALTH_URL> || echo "unreachable"
  2. If reachable (200): continue to Step 0b.
  3. If not reachable: start the backend for the detected stack:
  4. Python/FastAPI: cd backend && uvicorn main:app --reload --port 8000 &
  5. 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
  6. If still unreachable after 15s, STOP and ask the user to start the backend, then re-run.

Step 0b — Branch Sync Check (REQUIRED)

  1. git fetch origin main
  2. git log HEAD..origin/main --oneline — does remote main have commits not present locally?
  3. 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.
  4. 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 (or npm 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.js exists): node scripts/check-architecture.js
  • OpenAPI Sync Check (only for OpenAPI backends): inspect git diff --name-only main...HEAD for changes under backend/app/; if any route/schema changed, flag that /openapi-sync must 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 (generates coverage.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_TOKEN is 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, update SONARQUBE_TOKEN in ~/.bash_profile, source it, and re-run.

Quality Gate / Issues / Duplication

  • mcp__sonarqube__get_project_quality_gate_status — any status:"ERROR" → fix (auto-fix below).
  • mcp__sonarqube__search_sonar_issues_in_projects with issueStatuses:["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 stray console.log/debug/warn, debugger, and debug print( — keep intentional structured logging.
  • Auth Guards:
  • Python/FastAPI: each new/modified route handler has require_auth + require_permission dependencies (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 any Types: replace explicit any in new/modified TS with a proper type or unknown + 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 (missing await).
  • 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(): replace window.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].pybackend/tests/test_[x].py; frontend/src/components/[X].tsxfrontend/src/tests/components/[X].test.tsx.
  • Node/Express: backend/src/routes/[x].tsbackend/tests/integration/routes/[x].test.ts; backend/src/services/[x].tsbackend/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 under tests//coverage/; otherwise run /release-notes (do NOT bump versions manually).
  • Branch Guard (REQUIRED): never commit to main. If git branch --show-current is main, create a namespaced branch first:
    DEV=$(git config user.name | tr ' /' '-' | tr '[:upper:]' '[:lower:]')
    git switch -c "pr-ready/${DEV}/<short-slug>"
    
    Otherwise reuse the current branch.
  • 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,conclusion every 15s (max 20 attempts), run_in_background: true. (Or gh run watch in 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.