🤖 Auto-generated by weekly-pattern-learner · qodoloop and coderabbitloop share the push→poll→diagnose→fix→repeat loop; CI failures have the same shape but no dedicated skill existed
CI Fix Loop
Drive a GitHub Actions CI run from red to green: fetch failure logs, diagnose, apply a targeted fix, push, and repeat until all required checks pass or a blocker is hit.
Inputs
- PR number (optional): detect from current branch if not given.
- Check names (optional): limit to specific failing checks instead of all.
- Max iterations (default: 5)
Workflow
1. Identify the PR and current CI state
# Detect PR from current branch
gh pr view --json number,headRefName,headRefOid \
-q '{number, branch: .headRefName, sha: .headRefOid}'
# Current check status
gh pr checks --json name,state,conclusion 2>/dev/null \
|| gh run list --branch <branch> --limit 5
Classify each check as: pass, fail, pending, or skipped.
Exit immediately if all required checks already pass: nothing to do.
2. Loop (max 5 iterations)
A. Identify failing checks
gh pr checks --json name,state,conclusion \
--jq '.[] | select(.conclusion == "failure" or .state == "FAILURE")'
For each failing check, record: check name, workflow file, job name.
Stop if the working set is empty: all required checks are green.
B. Check for base-branch regression first
Before touching any code, verify the failure is not already present on main:
gh run list --branch <base-branch> --workflow <workflow-name> --limit 3 \
--json conclusion --jq '.[].conclusion'
If the same check is failing on the base branch, stop and report:
this is not your PR's fault. Do not attempt a fix that masks a base-branch problem.
Wait for a Base branch recovered notice before re-trying.
C. Fetch failure logs
For each failing check:
# Latest run ID for this branch/workflow
gh run list --branch <branch> --workflow <workflow-name> --limit 1 \
--json databaseId --jq '.[0].databaseId'
# Fetch only failing steps (not the full log)
gh run view <run-id> --log-failed
Cap log reading at ~200 lines per job: the error is almost always in the last 50 lines of a failed step.
D. Diagnose
Classify the failure before writing any code:
| Category | Examples | Fix target |
|---|---|---|
| Test failure | FAIL TestFoo, AssertionError, expected X got Y |
Source or test |
| Lint / format | gofmt, eslint, ruff, prettier |
Run auto-formatter |
| Build error | compile error, missing import, type mismatch | Source |
| Dependency | npm ERR!, missing module, lockfile mismatch |
Update lockfile |
| CI config | YAML parse error, bad action ref, missing secret | Workflow YAML |
| Flaky test | same test passes on manual re-run | Re-run first; mark if it keeps failing |
For flaky-looking failures, re-run the check before touching code:
gh run rerun <run-id> --failed
Wait for the rerun result. If it passes on rerun, skip this iteration and go to step F to poll for the new result.
E. Apply a targeted fix
Fix only what the log names as the failure. Do not refactor surrounding code, add unrelated tests, or touch files the failing step never mentioned.
Common one-liners:
# Go format
gofmt -w .
goimports -w .
# Node format / lint
npx prettier --write .
npx eslint --fix .
# Python
ruff check --fix .
black .
# Lockfile
npm install # Node
poetry lock --no-update # Python
go mod tidy # Go
For test failures: read the failing test and the code it exercises. Fix the code or the assertion, but not both in one commit unless the test was clearly wrong and the fix is trivial.
F. Commit and push
Stage only the files touched in step E: never git add -A, which can sweep
in unrelated local changes:
git add <files touched>
git commit -m "fix(ci): <what was broken> (ci-fix-loop iteration N)"
git push
Confirm the push succeeded before polling. A resolved check whose fix never reached the branch is worse than an unresolved one.
G. Wait for CI on the new SHA
Poll every ~15s (timeout ~8min) for all previously-failing checks to complete on the new push:
gh pr checks --json name,state,conclusion,startedAt
Wait until all previously-failing checks show a new result (pass or fail)
on the current SHA. Do not act on a result that still shows the old SHA.
Go back to step A.
3. Report
| Field | Value |
|---|---|
| Iterations | N |
| Checks fixed | names + root cause |
| Checks blocked | names + reason (flaky / needs human / base-branch red) |
| Final status | all green / partial / blocked |
CI fix loop complete.
Iterations: 2
Fixed: lint (gofmt: 3 files), test (TestUserCreate: nil pointer in fixture)
Blocked: none
Status: all required checks green
Chaining
| Before this skill | After this skill |
|---|---|
olko:pr-description-writer |
olko:qodoloop |
Any git push with failing CI |
olko:coderabbitloop |