---
description: "Diagnoses failing CI/CD pipelines from build logs. Classifies failures, performs root cause analysis, applies targeted fixes. Inspired by Codex gh-fix-ci."
alwaysApply: true
---

# CI Fix Agent

> **Purpose:** Diagnose and fix failing CI/CD pipelines. Reads build logs, identifies root causes, and applies targeted fixes.

---

## Invocation

```
/fix-ci [--run-id <id>]
```

Without a run ID, fetches the latest failed run for the current branch.

---

## Diagnosis Process

### Step 1: Fetch CI Logs

```bash
gh run list --branch $(git branch --show-current) --status failure --limit 1
gh run view <run_id> --log-failed
```

### Step 2: Classify the Failure

| Pattern | Category | Priority |
|---------|----------|----------|
| `npm ERR! peer dep` | Dependency conflict | High |
| `ENOSPC` / `out of memory` | Resource limit | Medium |
| `FAIL src/tests/` | Test failure | High |
| `error TS` / `type error` | Type error | High |
| `ESLint:` / `Lint error` | Lint violation | Low |
| `ETIMEOUT` / `connect ECONNREFUSED` | Network/service | Medium |
| `permission denied` | Permissions | Medium |
| `Module not found` | Missing dependency | High |
| `exit code 137` | OOM killed | High |

### Step 3: Root Cause Analysis

For each failure category:

**Test failures:**
1. Read the failing test file
2. Read the source file it tests
3. Check recent changes to both: `git log --oneline -5 <file>`
4. Identify if the test or the source is wrong

**Type errors:**
1. Read the error location
2. Check if types changed upstream
3. Verify import paths are correct

**Dependency issues:**
1. Check `package-lock.json` for conflicts
2. Compare with the last passing CI run
3. Try `npm ci` vs `npm install`

### Step 4: Apply Fix

- Edit the minimum files needed
- Run the same CI step locally to verify
- Commit with: `fix(ci): <description of what was wrong>`

---

## Common Fixes

| Issue | Fix |
|-------|-----|
| Snapshot mismatch | `npx vitest run --update` if change is intentional |
| Missing env var | Add to CI config secrets, not to code |
| Lock file conflict | `npm ci` (clean install from lock) |
| Flaky test (timing) | Add `vi.useFakeTimers()` or increase timeout |
| OOM on build | Split the build step or increase runner memory |

---

## Rules

- Never skip or delete failing tests — fix the root cause
- Never add `--no-verify` or `continue-on-error` to hide failures
- If a test is genuinely flaky, fix the flakiness don't skip it
- Always verify the fix locally before pushing

## Playground

<!DOCTYPE html><html><head><meta charset='utf-8'><style>*{box-sizing:border-box;margin:0;padding:0}body{background:#0d1117;color:#e6edf3;font-family:monospace;font-size:12px;height:100vh;display:flex;flex-direction:column;overflow:hidden}.header{background:#161b22;border-bottom:1px solid #30363d;padding:8px 14px;font-size:11px;color:#8b949e;display:flex;justify-content:space-between;align-items:center;flex-shrink:0}.title{color:#58a6ff;font-weight:bold;font-size:13px}.panels{display:flex;flex:1;overflow:hidden}.panel{flex:1;overflow:auto;padding:12px;border-right:1px solid #30363d}.panel:last-child{border-right:none}.label{font-size:10px;color:#8b949e;text-transform:uppercase;letter-spacing:.08em;margin-bottom:6px}pre{white-space:pre-wrap;word-break:break-word;line-height:1.5}</style></head><body><div class='header'><span class='title'>CI Fix Agent</span><span>Example · SkillSlap</span></div><div class='panels'><div class='panel'><div class='label'>Input: Failing CI step</div><pre><span style='color:#8b949e'>Step: Build (npm run build)</span>
<span style='color:#8b949e'>Exit: 1</span>

<span style='color:#8b949e'>Error:</span>
<span style='color:#8b949e'>./app/dashboard/page.tsx</span>
<span style='color:#8b949e'>Type error: Property 'slug' does</span>
<span style='color:#8b949e'>not exist on type 'Skill'.</span>

<span style='color:#8b949e'>  45 |   return skill.slug</span></pre></div><div class='panel'><div class='label'>Output: Fix steps</div><pre><span style='color:#f85149'>Root cause</span>
<span style='color:#8b949e'>`slug` was removed from the Skill</span>
<span style='color:#8b949e'>type in a recent schema update but</span>
<span style='color:#8b949e'>dashboard/page.tsx still references it.</span>

<span style='color:#58a6ff'>Fix</span>
<span style='color:#3fb950'>1. Check lib/types/skill.ts for the</span>
<span style='color:#3fb950'>   new field name (likely `handle`</span>
<span style='color:#3fb950'>   or read from SKILLS_COLUMNS).</span>
<span style='color:#3fb950'>2. Replace `skill.slug` with correct</span>
<span style='color:#3fb950'>   field name.</span>
<span style='color:#3fb950'>3. Search: grep -r "skill\.slug" app/</span>

<span style='color:#58a6ff'>Verify</span>
<span style='color:#3fb950'>npm run build -- --no-lint</span>
<span style='color:#3fb950'>→ must exit 0 before pushing</span></pre></div></div></body></html>