che-ci-fixer
Diagnoses and fixes failing CI runs on GitHub Actions (or a PR). Takes a PR URL or Actions run URL, identifies failing jobs/steps with logs, classifies root cause (build/lint/typecheck/infra/flaky/dep
SKILL.mdskills/che-ci-fixer/SKILL.md
GitHubChe — CI Fixer
SHARED REFERENCES (CANONICAL — DO NOT DUPLICATE body here):
- GitHub CLI gh auth + CI logs pull commands:
_shared_checklists/GITHUB_CLI_COMMON.md- Nx/pnpm install + build + lint + typecheck + test run order + CI common fixes table:
_shared_checklists/NX_PNPM_COMMON.md- Security/PII secret rotation scenario classification:
_shared_checklists/SECURITY_PII_COMMON.md
Given a failing GitHub Actions run (or a PR whose latest checks are failing), this role:
- Identifies WHICH jobs/steps are failing.
- Reads logs.
- Classifies root cause category.
- Implements a minimal fix (per engineering-contracts precedence rules).
- Confirms locally / re-triggers.
Stops and escalates to user if root cause is non-code (infra, secrets, 3rd party outage).
0. Preconditions & environment
- Input from user: OR
- A URL to a PR:
https://github.com/owner/repo/pull/123OR - A URL to a specific Actions run:
https://github.com/owner/repo/actions/runs/456
- A URL to a PR:
- Worktree path (for local fix). If not provided → ASK user which worktree to make fixes in.
gh auth statusOK. If not → guide user login first.
1. STEP 1 — Identify failing jobs / steps
Case A: Input is a PR URL.
# Get all check runs / status checks for PR HEAD commit
gh pr checks <PR_URL>
Record: names, status (fail / pass / pending), conclusion, started_at, run_id for each failed check.
Case B: Input is an Actions run URL.
Extract run_id from URL.
gh run view <RUN_ID> --json jobs,name,status,conclusion,url
Inspect .jobs[] — each has .steps[] with .conclusion.
Final structure: build FAILING_JOBS[]
FAILING_JOBS[] = [
{
job_name: "Build / Platform (lint-build-test)",
run_id: "456789",
failed_steps: [
{ name: "Run corepack pnpm lint", exit_code: 1, log_url: "..." },
{ name: "Run Playwright E2E", exit_code: 2, log_url: "..." }
]
}
]
2. STEP 2 — Extract error logs & classify each failure
For EACH failed step:
gh run view <RUN_ID> --log-failed | grep -A 40 -B 5 "<job name>" > /tmp/job-X.log
Or get per-step log via gh run view <RUN_ID> -i <step-index> --log style if available.
2.1 Root Cause Classification Framework
Classify EACH failure into EXACTLY ONE of these categories (priority order — match first applicable):
| # | Category | Signals in log | Typical fixes |
|---|---|---|---|
| R1 | 🔴 BUILD / TYPECHECK FAILURE | tsc error TS2307, Could not resolve, Module not found, SyntaxError, Java/Kotlin/groovyc/rustc compile error, webpack/rollup/vite build error |
Fix broken imports, types, missing dependencies, TS strict errors. |
| R2 | 🟠 LINT / FORMAT FAILURE | Biome check found, ESLint: 3 errors, Ruff: failed, clippy error, Prettier diff, golangci-lint |
Apply auto-fix CLI first (biome check --apply, eslint --fix). For manual: rename vars, remove unused, fix format. |
| R3 | 🟠 TEST FAILURE (deterministic) | Unit / integration / Vitest / Jest / pytest — specific assertion fails, same error across reruns | Fix the bug / assertion. If our change broke it: minimal fix. TDD style: confirm test failure → implement minimal fix → confirm pass. |
| R4 | 🟡 FLAKY TEST (non-deterministic) | Same test passed in previous run; fails intermittently; errors like timeout, race condition, network call, external sandbox rate limit. NOT reproducible locally first try. | First: rerun failed jobs via gh run rerun <RUN_ID> --failed-only. If still fails → add retry config, add wait/polling, remove external flaky dependency. |
| R5 | 🟡 DEPENDENCY / LOCKFILE / CACHE FAILURE | Lockfile is out of sync, corepack prepare failed, pnpm install integrity, Cache miss cascade, node-gyp native module error on wrong node version, cargo error pulling crate. |
Re-run install with correct engine version. corepack pnpm install + commit lockfile changes. Match Node/pnpm version from .nvrc / package.json. |
| R6 | 🟡 CI SCRIPT / YAML / INFRA BUG | Command not found, No such file, Permission denied, No space left on device, action.yml not found, incorrect if: logic in workflow, wrong secrets variable name. |
Fix the YAML or the setup script. Use gh workflow run to test changes if possible. |
| R7 | 🔴 INFRA / EXTERNAL (DO NOT CODE) | GitHub outage, npm registry 500, Rate limit exceeded, Service role key expired, AWS connection timeout. |
STOP. Report to user. Do not attempt code fixes. Suggest retry later. |
| R8 | 🟠 DB / MIGRATION FAILURE | Migration failed, Table already exists, Constraint violation, Prisma generate failed. |
Check migration order, consolidate branch migrations, fix SQL syntax. |
| R9 | 🟡 TEST MISMATCH (intentional behavior change) | Test fails because behavior changed INTENTIONALLY but test was not updated. Signals: logic is correct, tests just outdated. | Update the tests to match the new behavior/spec. DO NOT revert code. |
3. STEP 3 — Fix Implementation (Local Worktree)
For categories R1, R2, R3, R5, R6, R8, R9:
- Verify locally FIRST. Try to run the same command that failed in CI inside the worktree. Confirm it fails with same error.
- Implement minimal fix following
engineering-contracts. - Run local check again. Confirm PASS.
- If multiple failed jobs: fix one by one or in logical batches.
4. STEP 4 — Push and Verify
- Commit and Push. Use conventional commits:
fix(ci):,fix(lint):,fix(build):. - Trigger re-run. Use
gh run rerun <RUN_ID> --failed-onlyor just push and wait for new run. - Report to user.
- Summary of what failed.
- Root cause classification (R1-R9).
- What was fixed.
- Link to new run or confirm status green.
5. Appendix A — Summary report template
# CI Fix Report — <PR_#N>
## Summary
- Failing run: <url>
- Jobs failed: <count>
- Categories: <R1, R3, ...>
## Job Analysis
### Job: <name>
- Failed step: <step_name>
- Classification: <R-type>
- Root cause: <short explanation>
- Fix: <what was changed>
## Status
- [x] Verified locally
- [x] Fix pushed
- [ ] CI re-run status: <Pending/Passed/Failed>