ci-fix-loop · git:20260824.c71bceb · 2026-08-24 · sha256 819f2500b111211a
ci-fix-loop git:20260824.c71bcebA
Immutable. This exact content never changes and is served at /api/v1/blob/819f2500b111211a.
---
name: ci-fix-loop
description: >
Diagnose GitHub Actions CI failures in a loop: fetch the failing check logs, identify
the root cause, apply a targeted fix, push, and wait for the next run — repeating until
all checks are green or a real blocker needs a human. Use when CI is red after a push,
when the user says "fix CI", "make tests pass", "diagnose CI failures", or "drive this
to green". Direct analog of qodoloop / coderabbitloop for automated test and lint failures.
license: MIT
allowed-tools: Bash, Read, Write, Edit
compatibility: Codex, Claude Code, Cursor, GitHub Copilot, Windsurf, Kiro, and other Agent Skills compatible tools. Requires git and gh (GitHub CLI) authenticated, with a GitHub Actions workflow configured.
metadata:
targets: [_source-only]
author: Oleg Koval
tags:
- github-actions
- ci
- testing
- automation
- loop
- fix
source: weekly-pattern-learner
source_reason: "qodoloop and coderabbitloop share the push→poll→diagnose→fix→repeat loop; CI failures have the same shape but no dedicated skill existed"
source_date: "2026-07-28"
---
<!-- Generated by scripts/build-adapters.sh. Do not edit directly. -->
> 🤖 *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
```bash
# 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
```bash
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`:
```bash
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:
```bash
# 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:
```bash
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:
```bash
# 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:
```bash
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:
```bash
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` |