Diagnose a failing CI workflow run (lint, markdown lint, build, or unit tests) — identify which job failed, the cause, and a concrete fix
Scanned 9/20/2026
Install to Claude Code
npx -y skills add adamayoung/TMDb --skill diagnose-ci-failure --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Diagnose Ci Failure?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/adamayoung-diagnose-ci-failure)More formats (shields.io, HTML) on the badges page.
---
name: diagnose-ci-failure
description: Diagnose a failing CI workflow run (lint, markdown lint, build, or unit tests) — identify which job failed, the cause, and a concrete fix
---
# Diagnose a CI workflow failure
## Overview
The **CI** workflow (`.github/workflows/ci.yml`) gates every PR and the merge to
`main`. Unlike the live-API integration suite, a CI failure is **almost always
caused by the change under review** — a lint violation, a compile warning/error,
a broken unit test, or a Linux-portability gap. Start from the diff, not from
"maybe it's flaky".
CI fans out into six real jobs (plus a `changes` paths-filter job and a `ci`
gate job that only aggregates results): `Lint`, `Lint Markdown`,
`Build and Test` (macOS), `Build (<platform>)` (an iOS/tvOS/watchOS/visionOS
simulator-build matrix), `Build and Test (Linux)`, and `Test (<timezone>)` (a
time-zone matrix re-running the unit suites). The diagnosis differs per job, so
this skill is a **router**: identify the failing job, then follow the matching
reference file for that job's causes, fixes, and local-reproduction command.
> **Wrong suite?** If the **Integration** workflow (the live-API suite from
> `integration.yml`) failed — not a CI job — use `/diagnose-integration-failure`
> instead. It leads with the opposite assumption: a scheduled/live-API failure
> is usually backend or data drift, not your change.
## Agent Behaviour Contract
1. **Identify the failing job first** — `Lint`, `Lint Markdown`, `Build and Test`
(macOS), `Build (<platform>)`, `Build and Test (Linux)`, or
`Test (<timezone>)`. Don't guess the cause before you know the job.
2. **Assume the change caused it.** CI gates the PR; read the diff and tie the
failure to a changed file. Don't open with "transient" or "flaky".
3. **Treat warnings as errors.** Build steps use `-warnings-as-errors` / `--Werror`
— a deprecation or unused-binding warning is a real failure.
4. **Reproduce locally before declaring a fix** using the matching tool (`/lint`,
`/build-for-testing`, `/test`, `make lint-markdown`, `make build-linux`).
5. **Output the three sections** (Summary / Cause / Fix) defined below — concise,
tied to `file:line`.
## Locate the failing run
Use the first that applies:
- A path or run id the caller handed you.
- The current branch's run via the **GitHub MCP** (owner/repo from the `origin`
remote): `mcp__github__actions_list` method `list_workflow_runs`
(`resource_id: ci.yml`, `workflow_runs_filter: { branch: <branch> }`), then
`mcp__github__get_job_logs` (`run_id: <id>`, `failed_only: true`,
`return_content: true`). (`mcp__github__pull_request_read` method
`get_check_runs` also shows which job is red.) **Headless / no MCP:**
`gh run list --workflow CI --branch "$(git branch --show-current)" --limit 1`,
then `gh run view <id> --log-failed`.
- CI pipes build/test output through **xcsift** in `github-actions` format, so
the failing lines are GitHub `::error::` annotations carrying `file:line` —
read those first.
## Quick decision tree
Once you know which job failed:
- **Lint** (`swiftlint --strict` / `swiftformat --lint` / one of the six
`Scripts/*.py` gate steps)?
└─ `references/lint.md` — style/format violations, the Python gates, and the
version-drift gotcha
- **Lint Markdown** (`markdownlint`)?
└─ `references/markdown.md` — README / DocC / `.claude/` / `knowledge/` rules
- **Build and Test** — the **build** step failed?
└─ `references/build.md` — compile errors and `--Werror` warnings
- **Build and Test** — the **test** step failed?
└─ `references/unit-tests.md` — failing `Suite/test`, fixture/model mismatch
- **Build (iOS / tvOS / watchOS / visionOS)** — a simulator matrix build failed?
└─ `references/build.md` — platform-specific API availability; it is
`xcodebuild`, not SwiftPM, so `make build` green does not clear it
- **Build and Test (Linux)** — fails on Linux but passes on macOS?
└─ `references/linux.md` — Apple-only API gating, Foundation differences
- **Test (America/Los_Angeles or Pacific/Auckland)** — the TZ matrix failed?
└─ `references/unit-tests.md` — a date/calendar assertion depending on the
runner's zone; reproduce with `TZ=<zone> make test`
## Triage-first playbook
Symptom → next move:
- **`error: … is unavailable` / `cannot find … in scope`, Linux job only** → `references/linux.md`
- **`warning: … treated as error`** → `references/build.md`
- **`error:` from `swiftc` on macOS build** → `references/build.md`
- **A `Suite/test` recorded a failure / `#expect` failed** → `references/unit-tests.md`
- **Test fails to decode a fixture (`keyNotFound`, `valueNotFound`)** → `references/unit-tests.md`
- **SwiftLint rule violation (`error: … (rule_id)`)** → `references/lint.md`
- **`superfluous_disable_command` on unchanged code** → `references/lint.md` (suspect version drift)
- **SwiftFormat would reformat a file (`--lint` non-zero)** → `references/lint.md`
- **markdownlint `MD0xx` violation** → `references/markdown.md`
## Output format
Produce exactly these three sections (keep it under ~150 words; if the caller
asked for a file, write the markdown there and nothing else, otherwise reply
directly):
**Summary:** which job and step failed, and the specific error (rule /
`file:line` / failing `Suite/test`).
**Cause:** the root cause, tied to a changed file where possible.
**Fix:** the concrete next step from the relevant reference file.
## Reference files
| File | Failing job | Covers |
|------|-------------|--------|
| `references/_index.md` | — | Navigation index by symptom |
| `references/lint.md` | Lint | SwiftLint `--strict`, SwiftFormat `--lint`, the six `Scripts/*.py` gates, pinned versions, drift |
| `references/markdown.md` | Lint Markdown | markdownlint on README, `CLAUDE.md`, DocC, `.claude/`, `knowledge/`, `.github/*.md` |
| `references/build.md` | Build and Test (build step); Build (\<platform\>) | compile errors, `--Werror` warnings, release build, simulator-matrix availability |
| `references/unit-tests.md` | Build and Test (test step); Test (\<timezone\>) | Swift Testing failures, JSON fixture/model mismatch, TZ-matrix date dependencies |
| `references/linux.md` | Build and Test (Linux) | Apple-only API gating, Foundation portability |
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!