ci-debug
/ci-debug
Diagnozuje jeden nieudany przebieg CI lub sprawdzenie PR według 11 wzorców i proponuje poprawkę, bez jej samodzielnego wprowadzania.
- Autor
- yonatangross ↗
- Repozytorium
- orchestkit ↗
- Licencja
- MIT
- Ostatnia zmiana repozytorium
- 13.11.2026
Ocena i bezpieczeństwo
- Pliki w paczce
- 1
- Skrypty
- 0
- Komentarze HTML
- 0
- Adresy URL w SKILL.md
- 3
Brak sygnałów. Repozytorium zmienione 13.11.2026, bez odwołań do wycofanych modeli i API.
MIT, otwarta: można używać i zmieniać, z zachowaniem informacji o autorze.
Co robi i kiedy
Diagnozuje jeden nieudany przebieg CI lub sprawdzenie PR według 11 wzorców i proponuje poprawkę, bez jej samodzielnego wprowadzania.
Argumenty
/ci-debug <PR-number | run-URL | job-URL>
Oryginalny opis (EN)
Diagnoses one failing CI run or PR check against an 11-pattern playbook and proposes the exact fix, never applying it unasked. Use when a GitHub Actions job failed. Not for sweeping all red PRs (use ci-sentinel) or app test failures.
Jak działa
- Input
- Execution
- Headless invocation (permission mode)
- CRITICAL guardrails
- When to invoke
- When NOT to invoke
- Adding patterns
- Related Skills
Podgląd SKILL.md
---
name: ci-debug
license: MIT
compatibility: "Claude Code 2.1.277+ — uses `gh` CLI for GitHub Actions log inspection. Works in interactive sessions and headless `claude -p` invocations."
description: "Diagnoses one failing CI run or PR check against an 11-pattern playbook and proposes the exact fix, never applying it unasked. Use when a GitHub Actions job failed. Not for sweeping all red PRs (use ci-sentinel) or app test failures."
argument-hint: "<PR-number | run-URL | job-URL>"
context: fork
# user-typed commands stay interactive; CC >= 2.1.218 backgrounds forks by default (#3093)
background: false
disable-model-invocation: false
user-invocable: true
allowed-tools: "Bash Read Grep Glob"
skills: [github-operations, memory]
model: sonnet
metadata:
category: workflow-automation
origin: "/insights audit 2026-05-11 — recurring CI-debug pattern across 12 sessions in 3 weeks"
version: "0.2.0"
author: "OrchestKit"
complexity: "medium"
tags: "ci, github-actions, debugging, classification, propose-dont-apply"
triggers:
keywords: ["ci failure", "build red", "actions failed", "workflow failed", "PR check failed", "CI broken"]
examples:
- "PR #1842 build is red, what happened?"
- "/ci-debug 822"
- "/ci-debug https://github.com/owner/repo/actions/runs/12345"
anti-triggers: ["what's failing across the org", "test broke in my code"]
paths:
- ".github/workflows/**/*.yml"
---
# /ci-debug — classify a failing CI run
Direct response to the recurring CI-debug pattern surfaced by `/insights`: ~12 sessions in 3 weeks doing the same classification dance. This skill encodes the 11 patterns so the dance becomes a lookup.
## Input
User invokes with one of:
- **PR number**: `/ci-debug 822` (default repo from context; ask if ambiguous)
- **Run URL**: `/ci-debug https://github.com/owner/repo/actions/runs/12345`
- **Job URL**: `/ci-debug https://github.com/owner/repo/actions/runs/X/job/Y`
## Execution
### 1. Resolve the failing job
```bash
# From PR number:
gh pr checks <n> --repo <owner>/<repo> --json bucket,link,name \
--jq '.[] | select(.bucket=="fail") | "\(.name)|\(.link)"'
# From run URL:
gh api repos/<owner>/<repo>/actions/runs/<run-id>/jobs \
--jq '.jobs[] | select(.conclusion=="failure")
| {id, name, runner_name, started_at, completed_at,
steps: [.steps[] | select(.conclusion=="failure") | {name, number}]}'
```
If multiple jobs failed, pick the one with the **shortest duration** — root cause is usually the first failure; later jobs cascade.
**No job in the `fail` bucket but a check won't settle?** If `gh pr checks` shows zero `fail`-bucket entries yet a status sits in `pending` that never resolves (and `gh pr view --json mergeStateStatus` returns `UNSTABLE` while `mergeable=MERGEABLE`), this is a *stuck external status*, not a failure — jump straight to **Pattern #11**. There is no failing log to fetch; classify on the commit-status metadata (`gh api repos/<o>/<r>/commits/<sha>/status`).
### 2. Fetch the failing log
```bash
gh api repos/<owner>/<repo>/actions/jobs/<job_id>/logs 2>&1 \
| grep -iE '(error|fail|ERR_|CONFLICT|Process completed with exit code)' \
| head -30
```
Capture the **FIRST distinct error message** (later lines often echo).
### 3. Classify against the playbook
Walk the patterns in order. **First match wins.**
| # | Pattern | Signature in logs | Memory ref | Proposed fix |
|---|---------|-------------------|------------|--------------|
| 1 | **Billing block** | runner_name empty + steps[] empty + ~3s duration + annotation: "recent account payments have failed or your spending limit needs to be increased" | `billing-surface-hosted-vs-self-hosted.md` | Org admin → Settings → Billing & plans → raise limit / update card. No code change. |
| 2 | **Root-lockfile drift** | `ERR_PNPM_OUTDATED_LOCKFILE` mentioning `<ROOT>/typescript/<pkg>/package.json` | `pnpm-lock-root-vs-workspace-duality.md` | `pnpm install --lockfile-only && git add pnpm-lock.yaml && git commit && git push`. |
| 3 | **uv.lock drift** | `error: The lockfile at uv.lock needs to be updated` | `changeset-release-uv-lock-drift.md` | `cd python && uv lock` then commit. |
| 4 | **ci-shared.yml missing permissions** | startup_failure pattern (empty runner_name + steps[]=[] + ~3s) BUT billing is resolved | `ci-shared-permissions-block-required.md` | Add `permissions: { contents: read, packages: read }` to the caller workflow. |
| 5 | **YAML python embed** | YAML parse error pointing at a multi-line block scalar with `python -c` | `yaml-python-embed.md` | Rewrite `python -c` as a separate shell script invocation; never inline multi-line python in YAML. |
| 6 | **actionlint shellcheck false-positive** | audit/actionlint job failing with SC2086/SC2046 on workflow YAMLs you didn't touch | `audit-actionlint-triggers-on-workflow-edit.md` | Not required check; safe to merge past if the warnings predate your change. Optional: add shellcheck disable comments. |
| 7 | **macOS BSD date %3N** | `%3N` printed literally in CI output / arithmetic fails | `macos-bsd-date-no-percent-3N.md` | Replace `date +%s%3N` with `node -e 'console.log(Date.now())'` or `python3 -c 'import time; print(int(time.time()*1000))'`. |
| 8 | **Runner pnpm Rosetta arch drift** | pnpm install fails with "wrong-arch native bin" / dlopen error on a self-hosted runner | `runner-pnpm-rosetta-arch-drift.md` | Restart the affected runner pool; root cause is node x64↔arm64 flips storing wrong-arch native bins in shared cache. |
| 9 | **Shallow clone false divergence** | `git status` reports diverged but PR was actually merged | `shallow-clone-false-divergence.md` | `git fetch origin <branch> --unshallow` then `gh pr view --merge-commit` to verify. |
| 10 | **Publish run cancelled** | Publish-tag workflow run shows `conclusion=cancelled`; artifact never lands | `publish-runs-cancelled-need-redrive.md` | Re-fire via `gh workflow run publish-python.yml -f tag=<tag>` (adjust for your publish workflow). |
| 11 | **Vercel status orphaned (path-skip)** | No job in the `fail` bucket, but `Vercel` appears as a *commit status* (not a check-run) stuck `state=pending` with `created_at == updated_at` and no terminal update; all GitHub Actions checks green; `mergeStateStatus=UNSTABLE` + `mergeable=MERGEABLE` on an unprotected base branch | `vercel-pending-orphaned-on-path-skip.md` | Not a failure — cosmetic. Vercel posted a `pending` status then **skipped** the build (project-root path filter, e.g. a docs-only change that never touches `apps/web`), orphaning the status. Safe to merge: `gh pr merge <n> --repo <owner>/<repo> --squash`. Permanent fix: the Vercel project's **Ignored Build Step** must exit `0` AND report success for skipped paths so the status flips instead of dangling. |
The memory references point at user-curated memory files (`~/.claude/projects/<project>/memory/*.md`). If your memory doesn't have them yet, the signature column is enough to classify — the memory citation is a nice-to-have, not required.
### 4. Report
For a **matched** pattern:
```markdown
## CI Debug: <repo> · <pr-or-run-ref>
**Failing job:** `<job name>` (<duration>s) on runner `<runner_name>`
**Failing step:** <step name> (#<step number>)
**Error excerpt:**
\`\`\`
<first 3 lines of grep'd error>
\`\`\`
**Classification:** Pattern #<n> — <pattern name>
**Reference:** memory `<memory-file.md>`
**Proposed fix:**
<exact commands, one per line>
**Will I apply this?** No — awaiting your approval. Reply "go" to ship.
```
For an **UNMATCHED** failure:
```markdown
## CI Debug: <repo> · <pr-or-run-ref> · NOVEL
**Failing step:** <step name>
**Unique log lines:**
\`\`\`
<top 10 distinct error lines>
\`\`\`
This doesn't match any of the 11 playbook patterns. Surfacing the raw
evidence for your read. Once you identify the root cause, consider
adding it to the playbook (in this SKILL.md) so the next run catches
it automatically.
```
## Headless invocation (permission mode)
`/ci-debug` REQUIRES Bash tool access — `gh pr checks`, `gh run view`, and `gh api .../jobs/.../logs` are how it fetches evidence. In a headless `claude -p` run that loads this skill:
- Use `--permission-mode acceptEdits` — the headless "use tools without prompting" mode. The skill is read-only by design, so this grants nothing risky.
- **NEVER `dontAsk`** — it silently REFUSES permission-requiring tools (including Bash), so every analysis returns empty output with no error (#1862 Bug C).
- `claude -p` reports auth/permission failures as JSON on **stdout**, not stderr — capture and log both streams on failure (see `shared/rules/cc-bare-auth-gotcha.md` for the auth side).
## CRITICAL guardrails
- **NEVER auto-apply a fix.** This skill proposes; the user approves. Wasted cycles from misclassification are exactly the failure mode we're hardening against.
- **NEVER skip the fetch-log step.** Without the actual error text, classification is guessing. If logs are gone (>90 days old, run deleted), say so and stop.
- **Cite the exact memory entry** (filename + section heading where relevant) so the user can verify the analogy.
- **Each classification must have falsifying evidence** — the signature must match. Don't pattern-match on hope.
## When to invoke
- A specific CI run / job / PR check has failed and the user wants the diagnosis.
- The user pastes a run URL or "PR #N is failing — why?".
## When NOT to invoke
- For every open PR with red checks at once, use `ci-sentinel`, a workflow that classifies them with a copy of this playbook.
- For application-level test failures (the playbook is **CI-infra-specific**, not e.g. pytest failures).
- Before reading the actual log — don't speculate.
## Adding patterns
When a novel CI failure surfaces (the UNMATCHED report fires), add a row to the table above:
1. **Signature**: the unique-enough log line / metadata combination. Must be falsifiable.
2. **Memory ref**: name the memory file you wrote with the full incident write-up.
3. **Proposed fix**: the EXACT command line. No prose, no "you might want to". The skill produces commands the user runs; ambiguity defeats the purpose.
Commit the SKILL.md change as `docs(ci-debug): add pattern #N (<short-name>)`. Add the pattern to the prompt in `.github/workflows/ci-sentinel.yml` in the same change: that workflow runs with no tools, cannot load this skill, and keeps its own list.
## Related Skills
- **Related:** `ci-sentinel` (a manually dispatched workflow that applies a copy of this playbook to open red PRs).
- **Anti-pattern** — manually re-running `gh pr checks` and eyeballing the logs across N repos. That's exactly the toil this skill kills.
- **Upstream** — `/status` for org-wide sweeps that surface WHICH PRs are red; this skill answers WHY.
Wersje
| Repozytorium | Wynik | Licencja |
|---|---|---|
| Ta strona · yonatangross/orchestkit | 100 | MIT |
| yonatangross/orchestkit | 100 | MIT |
Migawka bazy z 13.11.2026 · wersja paczki 3d29ff93caa7 (skrót SHA-256 całej paczki)
Pobrania w ostatnich 30 dniach: 0 · ranking
Zgłoś problem z tym skillem: szkodliwa treść, błędny opis albo prośba autora o usunięcie.
Podobne skille
- 90ci
Diagnozuje czerwone CI w GitHub Actions lub GitLab CI, czyta logi nieudanych zadań i proponuje poprawkę, a przy niestabilnych błędach uruchamia ponownie. - 90fix-ci
Diagnozuje i naprawia nieudany check GitHub Actions w PR, odtwarzając lokalnie polecenie, które wywołuje błąd. - 100fix-failing-actions
Diagnozuje i naprawia nieudane workflowy GitHub Actions w repozytorium drift: błędy CI, kontroli higieny bezpieczeństwa i workflowu wydań. - 100ci-debug-loop
Obserwuje przebieg GitHub Actions, diagnozuje awarie z logów, stosuje poprawki i ponownie pushuje, aż CI zazielenieje lub trzeba eskalować. - 100ci-fix
Naprawia nieudany pipeline CI u źródła problemu, weryfikuje poprawkę lokalnie i zatwierdza zmiany na podstawie linku do runa, joba, PR lub commita. - 100fix-ci
Diagnozuje i naprawia nieudany przebieg CI: pobiera logi (gh run view --log-failed), odtwarza błąd lokalnie, usuwa przyczynę źródłową i weryfikuje zielony wynik przed pushem i po nim.