ci-triage
Shared logic for classifying a failed CI workflow run and recording the
outcome. Used by humans (or Claude in an interactive session) when
triaging a red
workflow or a red check on an open PR — the latter
via the consumer repo's
skill (e.g.
,
,
).
This skill owns the taxonomy, the de-dup rules for the
issue, and
the issue template. Workflow-specific reproduction steps live in the
consumer repo's
skill (for build-tool-specific
detail) and in
(for e2e).
Taxonomy
Every failure lands in exactly one bucket. Be explicit — "unclear" is not a
bucket,
is.
| Bucket | Signal | Default action |
|---|
| Reproduces deterministically on at HEAD | File/update , @-mention suspect author |
| Same workflow passed on the previous main commit without code change | Comment on the existing issue if one is open; otherwise skip |
| Postgres service didn't come up, rustup 403, pnpm registry down | File/update labelled ; do not @-mention authors |
| Logs truncated, auth failed, classification genuinely ambiguous | Open a issue with raw log excerpt, label |
Do
not invent a fifth bucket. If the signal you see fits nothing above,
it's
.
Suspect commit identification
The GitHub
payload includes
. That's the commit that
triggered this run — on a
event, it is the merge commit.
- Fetch the commit via .
- If the commit message matches , the suspect PR is
; its author is the suspect author.
- Otherwise (direct push to main, squash-merge), use the commit author
directly.
Never blame more than one commit per failure. If the previous main commit's
CI was also red, link that issue rather than opening a new one.
The rolling issue
One open issue at a time. If main is broken for three days,
that's one issue accumulating comments — not twelve.
Before filing:
- with
labels: main-red, state: open
.
- If one exists, append a comment:
Run #<run-id> also failed. Workflow
, bucket
,
suspect <sha-short> (#<pr-or-none>, @<author>). <one-line-cause>.
- Only open a new issue if none is open. Title:
main is red: <workflow> (<bucket>)
. Labels: , plus
or if applicable.
When main goes green again (the next successful run on the same workflow),
close the issue with a comment naming the green run id. This close step
is manual.
Issue body template
markdown
**Workflow**: <workflow-name>
**Run**: <run-url>
**First failed step**: <step-name>
**Bucket**: <regression|flake|infra|needs-human>
**Suspect**: <sha-short> — <commit-subject> (PR #<n>, @<author>)
### Failure excerpt
<last 30 lines of the failing step, or the ripgrep-extracted error block>
### Reproduction
<one of:>
- Deterministic: `<exact command from the workflow yaml>`
- Flake: passed on <prev-sha-short>; rerun button: <run-url>/attempts/2
- Infra: <service name> — <symptom>
- Needs human: <why the logs are ambiguous>
### Next action
<one line — "revert #N and reland", "rerun", "fix <specific thing>", "human eyes">
Keep the excerpt tight. Dumping the full log helps nobody.
Reproducing locally
A human invoking this skill via the consumer repo's
skill should reproduce before filing, using the
commands in that skill's CI-triage section.
For a
failure caught from outside a PR, check out
at the
suspect SHA and run the same commands locally before filing.
For
failures specifically, delegate classification to
's triage mode — it handles
regression-vs-flake for browser-driven tests (the ambiguous case).
Log access
cannot read authenticated GitHub Actions logs (403). The
GitHub MCP gives you:
mcp__github__pull_request_read
with — step
names, status, timings (no log body).
- The workflow run's via +
traversal — same metadata.
Log bodies are not reliably accessible from the GitHub MCP. When the log
body is unavailable, classify from step names + exit codes + the workflow
yaml, and bias toward
rather than guessing.
Flake-detection heuristic
A failure is
only if
both hold:
- The same workflow on the previous main commit passed (check via
mcp__github__list_commits
+ check runs on the prior sha).
- The failing step's logs do not contain a symbol name, file path, or
assertion message that appears in the suspect commit's diff.
One of those alone is not enough. A deterministic regression can pass on the
prior commit; a real flake can mention a touched file by coincidence.
Constraints
- Never open a PR from this skill. Triage is read-only on the codebase.
- Never @-mention for or buckets — alert fatigue kills the
signal.
- Never close a issue without a green run id to cite.
- Scope: any GitHub-Actions–driven repo. The taxonomy and rolling
pattern are repo-agnostic; the consumer repo's CLAUDE.md
can override triggers and label conventions.
Relationship to other surfaces
| Surface | Role |
|---|
| (consumer-repo skill, e.g. ) | Interactive caller; humans use this when triaging a red PR check. |
| Delegated to for workflow classification. |