"Diagnose CI failures or cancellations on a PR, take corrective action (re-trigger, fix, or escalate), and report status."
Install
npx skillscat add blamechris/chroxy/claude-skills-fix-ci Install via the SkillsCat registry.
/fix-ci
Diagnose CI failures or cancellations on a PR, take corrective action (re-trigger, fix, or escalate), and report status.
Arguments
$ARGUMENTS- PR number (optional, defaults to current branch's PR)
Instructions
0. Gather CI State
PR_NUM=${1:-$(gh pr view --json number -q .number)}
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
BRANCH=$(gh pr view ${PR_NUM} --json headRefName -q .headRefName)
HEAD_SHA=$(gh pr view ${PR_NUM} --json headRefOid -q .headRefOid)
echo "PR: #${PR_NUM} | Branch: ${BRANCH} | HEAD: ${HEAD_SHA}"
# Get the latest CI run(s) for this branch
# Chroxy uses Copilot review + CodeQL ruleset
gh run list --branch ${BRANCH} --workflow "Copilot review" --limit 5 --json databaseId,status,conclusion,headSha,event,createdAt1. Get Job-Level Status
For the most recent run matching HEAD_SHA:
RUN_ID=<id from step 0>
gh run view ${RUN_ID} --json jobs --jq '.jobs[] | {name, status, conclusion}'Count jobs by status: passed, failed, cancelled, skipped, in_progress.
2. Classify Overall State
Apply these rules in order (first match wins):
| Classification | Condition | Action |
|---|---|---|
| ALL_PASS | Latest run's SHA matches HEAD AND all required jobs passed | Report green, exit |
| IN_PROGRESS | Any job still running or queued | Poll until complete (see Step 2a) |
| STALE | Latest run's SHA does NOT match HEAD | Check for newer run, or retrigger |
| CANCELLED | One or more jobs cancelled, none failed | Check for replacement run (see Step 2b) |
| FAILED | One or more jobs failed | Per-job diagnosis (Step 3) |
2a. IN_PROGRESS โ Poll for Completion
# Chroxy CI typically completes within 5 minutes
MAX_WAIT=300 # seconds
INTERVAL=30
ELAPSED=0
while [ $ELAPSED -lt $MAX_WAIT ]; do
STATUS=$(gh run view ${RUN_ID} --json status -q .status)
[ "$STATUS" = "completed" ] && break
sleep $INTERVAL
ELAPSED=$((ELAPSED + INTERVAL))
echo "Waiting for CI... ${ELAPSED}s / ${MAX_WAIT}s"
done
# Re-classify after completion2b. CANCELLED โ Check for Replacement Run
Cancellation often happens due to concurrency groups (a newer push cancels the older run). Check if a newer run exists for the same SHA:
# Check all runs for this SHA
gh run list --branch ${BRANCH} --workflow "Copilot review" --limit 5 --json databaseId,status,conclusion,headSha,event \
| jq --arg sha "$HEAD_SHA" '[.[] | select(.headSha == $sha)]'Decision logic:
- If a newer completed successful run exists for the same SHA โ ALL_PASS, report green
- If a newer run exists but only ran partial jobs (e.g., different event trigger) โ the full suite never ran, needs RETRIGGER
- If no newer run exists โ needs RETRIGGER
Common cause: CI concurrency groups with cancel-in-progress: true. When fix commits are pushed, the new pull_request event cancels the in-progress run. If the new event is a different type (e.g., pull_request_review which only triggers notification jobs), the full CI suite never re-runs.
3. Per-Job Diagnosis (for FAILED or CANCELLED jobs)
For each non-passing job, fetch logs and diagnose:
# For failed jobs โ get the failure logs
gh run view ${RUN_ID} --log-failed 2>&1 | tail -100
# For cancelled jobs โ limited logs available, check annotations
gh api repos/${REPO}/actions/runs/${RUN_ID}/jobs --jq '.jobs[] | select(.conclusion != "success" and .conclusion != "skipped") | {name, conclusion, steps: [.steps[] | select(.conclusion != "success" and .conclusion != "skipped") | {name, conclusion}]}'Pattern match against known failures:
Chroxy-specific patterns:
npm testfailures in server tests โ check for missing test fixtures or mock setup issuesnpx tsc --noEmitfailures in app โ TypeScript strict mode violations (check foranytypes, platform-specific issues)npm run build -w @chroxy/dashboardfailures โ Vite build errors, missing CSS, or theme issuesnpx jestfailures in dashboard tests โ component rendering or mock issues- WebSocket protocol test failures โ check WS message format or auth flow issues
Generic patterns (apply to all repos):
rate limit/API rate limit exceededโ RETRIGGER (transient)timeout/timed out/deadline exceededโ RETRIGGER (transient, unless recurring)connection refused/network/ECONNRESETโ RETRIGGER (transient)permission denied/403/Resource not accessibleโ ESCALATE (permissions issue)out of disk space/no space left on deviceโ ESCALATE (infrastructure)cancelled(no failure, just cancelled) โ RETRIGGER
Classify each job into exactly ONE outcome:
| Outcome | When | Action |
|---|---|---|
| RETRIGGER | Cancelled by concurrency, transient error (network, timeout, rate limit) | gh run rerun |
| FIX | Known code issue with clear automated fix | Commit fix, push (triggers new CI) |
| ESCALATE | Unknown failure, permissions, infrastructure, or needs human judgment | Report diagnosis + log excerpt |
4. Take Action
RETRIGGER
# Preferred: re-run only failed/cancelled jobs (fast, targeted)
gh run rerun ${RUN_ID} --failed
# Fallback: close and reopen PR to trigger full CI suite
gh pr close ${PR_NUM}
gh pr reopen ${PR_NUM}One retrigger attempt only. If the re-run also fails, escalate instead of retrying.
FIX
# 1. Check out the PR branch
git checkout ${BRANCH}
# 2. Make the fix (specific to the failure pattern matched)
# 3. Commit with descriptive message
git add <files>
git commit -m "fix(ci): Description of fix"
# 4. Push (triggers new CI automatically)
git pushESCALATE
Do NOT take automated action. Report the diagnosis to the user:
## CI Escalation: PR #${PR_NUM}
**Job:** [job name]
**Status:** [failed/cancelled]
**Diagnosis:** [what the logs indicate]
**Log excerpt:**[relevant log lines โ keep under 30 lines]
**Suggested next steps:**
- [specific recommendation based on diagnosis]5. Wait for CI (if action taken)
After RETRIGGER or FIX, wait for the new run to complete:
# Chroxy CI typically completes within 5 minutes
MAX_WAIT=300
INTERVAL=30
ELAPSED=0
# Get the new run ID
sleep 10 # brief delay for run to appear
NEW_RUN_ID=$(gh run list --branch ${BRANCH} --workflow "Copilot review" --limit 1 --json databaseId -q '.[0].databaseId')
while [ $ELAPSED -lt $MAX_WAIT ]; do
STATUS=$(gh run view ${NEW_RUN_ID} --json status -q .status)
[ "$STATUS" = "completed" ] && break
sleep $INTERVAL
ELAPSED=$((ELAPSED + INTERVAL))
echo "Waiting for CI... ${ELAPSED}s / ${MAX_WAIT}s"
done
# Check final result
CONCLUSION=$(gh run view ${NEW_RUN_ID} --json conclusion -q .conclusion)
echo "CI result: ${CONCLUSION}"If the new run also fails, re-classify and escalate. Do NOT retrigger a second time.
6. Summary Report
## CI Status: PR #${PR_NUM}
| Job | Status | Action Taken |
|-----|--------|--------------|
| Job 1 | pass | โ |
| Job 2 | pass (after retrigger) | Retriggered: cancelled by concurrency |
| Job 3 | pass | โ |
**Result:** All jobs passing / N jobs need attention
**SHA:** ${HEAD_SHA}
**Run:** [link to run]For the user-facing output, use a one-line summary table:
| PR | CI Status | Jobs | Action Taken |
|----|-----------|------|--------------|
| #XX | PASS (after retrigger) | 6/6 passed | Retriggered: Run Tests cancelled by concurrency |Decision Tree
Start
โ
โโ Get latest CI run for HEAD SHA
โ
โโ Any run for this SHA?
โ โโ NO โ retrigger (stale)
โ โโ YES โ
โ
โโ Run status?
โ โโ in_progress โ poll until complete, re-classify
โ โโ completed โ
โ โโ other โ investigate
โ
โโ All required jobs passed?
โ โโ YES โ report green, exit
โ โโ NO โ
โ
โโ For each non-passing job:
โ โโ cancelled (no failure)?
โ โ โโ Replacement run exists with full suite? โ use that run
โ โ โโ No replacement โ RETRIGGER
โ โโ failed โ fetch logs, pattern match
โ โ โโ Known fixable pattern โ FIX
โ โ โโ Transient error โ RETRIGGER
โ โ โโ Unknown/infrastructure โ ESCALATE
โ โโ skipped โ check if required (skip if not)
โ
โโ Execute actions (retrigger / fix / escalate)
โ
โโ If action taken โ wait for new CI run
โ โโ Passes โ report green
โ โโ Fails again โ ESCALATE (no second retrigger)
โ
โโ Report summaryCritical Rules
- Diagnose before acting โ Never blindly retrigger. Always check logs and classify the failure first.
- One retrigger attempt โ If the re-run also fails, escalate. Infinite retry loops waste time.
- SHA awareness โ Always verify the CI run matches HEAD. Stale runs on old SHAs are meaningless.
- Log excerpts in escalations โ Never escalate with just "CI failed." Include relevant log lines so the user can act without re-investigating.
- Minimal fix scope โ FIX actions should be surgical. Don't refactor code; just fix the CI failure.
- Composable โ Works standalone (
/fix-ci 42) or from/full-review(Phase 2.5). - Idempotent โ Safe to re-run. If CI is already green, reports success and exits.
- No attribution โ Follow project attribution policy in all commits.