workflow-health-triage
Skill0 starsChanged 3 months agoMITView on GitHub
Triages a failing GitHub Actions workflow run on `develop` or `main` per `spec/project/workflow-health/`. Classifies the failure into one of `defect` / `flake` / `infra` / `stale pin` / `secret drift` / `other`, dispatches the most specialised Claude agent that matches the classification, records the classification plus the dispatched agent's name in the eventual fix PR's Risk / rollout notes, and verifies the standard `fix/`-PR flow. Invoke when the user asks to \"triage this red workflow\", \"classify this CI failure\", or equivalent German-language requests. Don't use to silence checks via `continue-on-error` shortcuts or by removing required-checks entries (forbidden by spec); don't use to bypass branch protection (`enforce_admins` on develop has no exception path); don't use to merge a fix PR (use `pull-request-merge`). Supports resume on re-invocation per `spec/claude/resumable-work/`.
- Reads credentials
In this repository36 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- audience-identifySkill
- backlog-delivery-orchestrateSkill
- backstage-catalog-generateSkill
- blog-authorSkill
- blog-author-triggerSkill
- cicd-pipeline-designSkill
- continuous-improvement-triageSkill
- cookiecutter-template-manageSkill
- docs-audience-tracks-applySkill
- docs-dry-refactorSkill
- github-issue-templates-applySkill
- issue-backlog-partitionSkill
- issue-batch-orchestrateSkill
- issue-orchestrateSkill
- lektorat-applySkill
- lektorat-auto-reviseSkill
- mermaid-diagrams-applySkill
- mkdocs-structure-applySkill
- permission-allowlist-maintainSkill
- portfolio-auditSkill
- portfolio-inflight-triageSkill
- project-structure-applySkill
- pull-request-createSkill
- pull-request-mergeSkill
- pull-request-runner-sweepSkill
- readme-structure-applySkill
- release-notes-curateSkill
- release-publish-triggerSkill
- requirements-elicitSkill
- spec-drift-auditSkill
- specSkill
- tech-stack-captureSkill
- vocab-drift-auditSkill
- working-copy-startSkill
- yaml-json-schemaSkill
The file
We split this skill into the rules it gives an agent
8 rules. About 0 are common, 1 is distinctive, and 7 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
7
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 82
Hard: never call gh run rerun <id> more than once before a recorded classification exists.
- Very specific: line 102
If the user wants the skill to open the fix PR itself, dispatch pull-request-create with these two lines pre-populated in the Risk / …
- Very specific: line 106
After the fix PR opens, the skill stops.
- Very specific: line 120
Read examples/01-defect-classification-dispatch.md when triaging a failure that classifies as defect and dispatches to a specialised agent.
- Very specific: line 121
Read examples/02-stale-pin-portfolio-gap.md when the failure root-causes to a stale pin in the portfolio plumbing.
- Very specific: line 122
Read examples/03-flake-no-fix-record-only.md when the failure classifies as flake and the skill records the classification without opening …
- Distinctive: line 136
Always: prefer a plugin-distributed specialised agent over the generalist when one matches.
- Very specific: line 137
When spec/project/workflow-health/ disagrees with this skill, the spec wins.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Workflow Health Triage
Implements spec/project/workflow-health/ §Triage before remediation and §Specialised-agent dispatch for remediation. The skill is the generalist that classifies a failure and dispatches the hands-on fix to the most specialised available Claude agent; it never performs the fix itself when a matching specialised agent exists.
Why this is a skill, not an agent
- Externally-visible mutations gate on user confirmation. Classification ambiguity, agent-dispatch confirmation, and the fix-PR title / body are mid-flow user dialogues; an agent's fire-and-forget shape would miss them.
- Orchestrator pattern (per
skill-vs-agent). The work itself is classify, dispatch, verify; the dispatched specialised agent does the editing. The orchestrator stays in the main thread and chains other skills (pull-request-createfor the fix PR, optionallypull-request-mergeafter CI is green). - Per-classification user gating. At least three of the six classes (
defect,flake,secret drift) need a human "yes that's the right call" before the dispatcher commits to a remediation lane. - Counter-dimension considered: a narrow agent could handle the classification step in isolation and gain context-window protection, but every downstream lane (PR creation, agent dispatch, verification) is interactive—keeping the whole flow in one skill is simpler than splitting at the classification boundary.
User-language policy
Detect the user's language and respond in it. All git, gh, and Agent(subagent_type=…) invocations stay English so the audit trail (PR titles, classification labels, agent names) is grep-able portfolio-wide.
Preconditions
Before any classification:
- Confirm the working directory is a git repository and
gh auth statusreports authenticated. - Confirm
spec/project/workflow-health/<canonical_language>.mdis reachable — in the current project or, when absent there, at${CLAUDE_PLUGIN_ROOT}/spec/project/workflow-health/<canonical_language>.md(the copy shipped inside the installednolte-sharedplugin). If neither is reachable, stop and report—without it the classifications are ad-hoc; this skill is the spec's implementer, not its replacement. - The user supplies the failing workflow run (a
gh run view <id>URL, a workflow file name likerelease-publish.yml, or "the red one on develop"). If nothing is supplied, rungh run list --status failure --branch develop --limit 5and ask which run to triage.
Operations
1. Inspect the failing run
Run in parallel:
gh run view <id> --json name,headBranch,headSha,event,status,conclusion,workflowName,url,jobsgh api repos/<owner>/<repo>/actions/runs/<id>/jobs --jq '.jobs[] | {name, conclusion, html_url}'gh run view <id> --log-failed(capture the failing-step output for classification)git log --oneline -1 <headSha>(resolve the commit under the run)
Tooling (optional GitHub MCP): the GitHub reads above are Actions / workflow-run
reads. When a connected GitHub MCP server exposes an actions read toolset, prefer it
and verify the exact tool names against the pinned server version, per
spec/claude/mcp-tool-preference/; the reference hosted endpoint exposes no actions
toolset, so these reads stay on gh (a documented OQ-D coverage gap). gh stays
authoritative and the fallback is never removed.
Confirm the run is on develop or main (the spec's scope) and is conclusion: failure. If it's still in_progress, stop and ask the user to wait for completion before triage. If it's cancelled, classify as other with a one-line note and stop—unless the lane's recent runs (gh run list --workflow <file> --limit 20) are majority-cancelled: then the lane delivers no verdict at all, and the subject is the lane, not the run. Route it to spec/project/workflow-health/ §"Cancellation rates" and its two-cause fork: measure the median wait (started_at − created_at, jobs with no needs: only) beside the runtime per ${CLAUDE_PLUGIN_ROOT}/skills/cicd-pipeline-design/references/slot-capacity-measurement.md; wait that dominates runtime is a capacity finding for cicd-pipeline-design, runtime above the trigger cadence is the cadence remedy, runtime far below it is churn. Stop after naming which of the three applies; the remediation isn't a fix/ PR from this skill.
2. Classify before any re-run
Walk the table top-down and stop at the first match. The rows are ordered by specificity rather than by the spec's class order, so a narrow signal is tested before the broader rows that would also capture it; every row still resolves to one of the spec's six classes:
| Signal in the failed-step output | Classification |
Push rejected with refusing to allow a GitHub App to create or update workflow ... without 'workflows' permission | infra — evaluate this row first. Both the defect row (the rejection names a workflow file the diff modified) and the secret drift row (it is a 403) would otherwise capture it, and neither is right: it is a deterministic platform constraint, not a repository defect and not an expired credential |
| Failing step references a file the head commit's diff modified | defect |
Re-run of the same headSha would produce green (no infra signal, no code change in the failing step's surface) | flake |
| HTTP 5xx, rate-limit, registry-unreachable, GitHub status incident | infra |
uses: pin in the workflow points to a nolte/gh-plumbing (or other reusable) tag, and a newer tag exists with the relevant fix | stale pin |
Token, deploy key, or OIDC trust expired or rotated; failure references 401, 403, expired, unauthorized | secret drift |
| None of the above | other (with a short note explaining why) |
Confirm the chosen class with the user before proceeding—at minimum for defect, flake, and secret drift, where misclassification has the highest cost. Apply the classification by writing it to a scratch note that becomes the seed of the fix PR's Risk / rollout notes.
Hard: never call gh run rerun <id> more than once before a recorded classification exists; repeated blind re-runs are drift per spec/project/workflow-health/ §Triage before remediation.
3. Dispatch the most specialised available agent
The set of available agents changes over time; never freeze a snapshot of "which agents exist" inside this skill body. Resolve the dispatch target dynamically each invocation:
- Resolve the candidate set.
Globagents/*.md(plus.claude/agents/*.md(project-distributed; additionally~/.claude/agents/*.mdfor user-level agents) for the project-distributed half), thenReadthedescription:line of every candidate. Build a (name,description) table; the table is the runtime inventory. - Match classification to candidate. Walk the candidates and pick the one whose
descriptionmost closely matches the (classification, failing-artefact-area) pair: adefectin a markdown spec/skill/agent file maps to whichever agent's description names "spec-conformant authoring" or the equivalent; adefectin a workflow YAML maps to whichever agent's description names "workflow YAML" or "GitHub Actions"; a documentationdefectmaps to whichever agent names an audience-targeted documentation responsibility; and so on. The match is on the description's stated responsibility, not on the agent's name. - Recognise the no-fix classifications.
flakeandsecret driftproduce no agent dispatch by design — the work is documenting the flake in the project's flake registry (FLAKES.mdor theflake-labelled issue set, whichever the repository uses) forflake, or rotating the credential outside Claude forsecret drift. The skill produces only the fix PR that re-references the rotated credential. - No match is a portfolio gap. When the candidate walk produces no plausible match and the failure class has occurred three or more times historically (use
gh run list --status failure --branch develop --limit 50plus a quick grep to estimate), surface this as a portfolio gap perspec/project/workflow-health/§Specialised-agent dispatch — the user is asked whether to author a new agent (viaclaude-plugin-developer) before the fix PR opens. When a match exists, dispatch withAgent(subagent_type="<plugin>:<agent>")and pass the classification, the run URL, the failing-step excerpt, and the fix-PR-title hint. The classification is a hypothesis about the cause, so the dispatch brief MUST authorise refutation perspec/claude/dispatch-brief/: tell the agent it may refute the classification, and treat a returned refutation (contradicting evidence plus what it did instead) as a first-class result — re-classify rather than force the fix — not a failed dispatch. Wait for the agent's report.
The dynamic-lookup design means a new specialised agent that lands in agents/ becomes dispatchable immediately, without a coordinated edit to this skill — and a renamed or removed agent stops being a target the next time the skill runs, with no stale snapshot to mislead the dispatch.
4. Verify the fix PR carries the audit trail
Whether the editing was done by a specialised agent or the generalist, the resulting fix PR MUST carry both pieces of evidence in its Risk / rollout notes section per the pull-request-workflow spec:
- Triage classification verbatim (one of the six labels above, with a one-line note for
other) - Dispatched agent name (the literal
subagent_typeargument), or the literal phrase "no matching specialised agent—generalist remediation"
If the user wants the skill to open the fix PR itself, dispatch pull-request-create with these two lines pre-populated in the Risk / rollout notes; the user still confirms the title and body before push, per the pull-request-create spec's externally-visible-action gate.
5. Verify the standard PR gate
After the fix PR opens, the skill stops. The actual merge belongs to pull-request-merge, which re-validates the gate. The skill MUST NOT:
- merge the fix PR itself (out of scope;
pull-request-mergeowns that) - pass
--adminanywhere (enforce_admins: trueondevelophas no exception) - waive a still-failing required check on the fix PR (the spec forbids
continue-on-errormasking and required-check removal)
Report back the run ID, the classification, the dispatched agent name (or "generalist"), the fix-PR URL, and a one-line "next action: invoke pull-request-merge after CI is green".
Old patterns
Earlier revisions of this skill enumerated specific agent names inline (for example workflow-yaml-fixer, claude-plugin-developer, audience-doc-author) as the dispatch table. That snapshot rotted whenever a new agent landed or an existing one renamed; the runtime-Glob design in Operation 3 replaces it. The historical mapping is preserved here only so a reader who recognises the prior wording can spot the transition: defect in workflow YAML used to fall back to generalist (no matching agent), defect in spec / skill / agent files used to dispatch claude-plugin-developer, defect in documentation used to dispatch audience-doc-author. Use the runtime lookup in Operation 3 instead of this snapshot.
Examples
- Read
examples/01-defect-classification-dispatch.mdwhen triaging a failure that classifies asdefectand dispatches to a specialised agent. - Read
examples/02-stale-pin-portfolio-gap.mdwhen the failure root-causes to a stale pin in the portfolio plumbing. - Read
examples/03-flake-no-fix-record-only.mdwhen the failure classifies asflakeand the skill records the classification without opening a fix PR.
Resumability
Per spec/claude/resumable-work/, this skill is resumable: true. State is persisted to .resume/workflow-health-triage/<run-id>.yml after every successful user-approval gate and after each named phase boundary. On re-invocation, scan that directory for files with status: in_progress whose inputs: snapshot matches the current invocation; if one matches, prompt the operator with Resume run <run_id> from phase <phase> (last checkpoint <last_checkpoint_at>)? [resume / start-new / discard]. The state-file envelope (schema_version, run_id, inputs, phase, decisions[], status, ...) and the fail-closed semantics on schema or YAML errors are load-bearing in the spec; don't duplicate those rules here.
Hard rules
- Never re-run a failed required workflow run more than once before a recorded triage classification exists; the spec calls repeated blind re-runs drift.
- Never classify a failure as
flakewithout reproducible evidence (re-run of the sameheadShareturned green and no infra signal explains the first failure). - Never mask a failure: don't propose
continue-on-error: trueon a required job, don't propose removing a check from the required-checks set in.github/settings.ymlwithout a tracking Issue, don't propose repointing anolte/gh-plumbingpin from a tag to a branch. - Never bypass branch protection on the fix PR;
enforce_admins: trueondevelophas no exception path. - Never dispatch a specialised agent with a classification the spec doesn't list. The closed set is
defect / flake / infra / stale pin / secret drift / other. - Never open a fix PR whose Risk / rollout notes don't carry the classification and the dispatched agent name (or the explicit "no matching specialised agent" note).
- Always prefer a plugin-distributed specialised agent over the generalist when one matches; the spec's §Specialised-agent dispatch makes this a SHOULD that this skill upgrades to a hard contract for the dispatch step.
- When
spec/project/workflow-health/disagrees with this skill, the spec wins. Propose updating this skill rather than silently diverging.
Gotchas
Per spec/claude/skill-management/ §Gotchas—concrete corrections to non-obvious environment facts the executing agent would otherwise get wrong.
GITHUB_TOKEN-cascade failures aren'tdefect. Arelease-drafter.ymlthat doesn't fire after anautomerge.yamlsquash-merge, or arelease-cd-refresh-master.ymlthat doesn't fire afterrelease-publish.yml, is the documentedinfraclass perspec/project/workflow-health/§Known platform constraints—and the remediation is upstream innolte/gh-plumbing, not in the consumer repo. Don't open a fix PR against the consumer's workflow YAML; document theinfraclassification and reference thenolte/gh-plumbingtracking Issue.- A workflow-file push rejection reads like
secret driftand isn't.refusing to allow a GitHub App to create or update workflow ... without 'workflows' permissionis a 403-flavoured rejection, so thesecret driftrow matches it on the surface. It's the second constraint inspec/project/workflow-health/§Known platform constraints:GITHUB_TOKENis a GitHub App identity and can never write under.github/workflows/, and thepermissions:block has noworkflowsscope to grant. Rotating a credential fixes nothing. Classifyinfraand route to the App-token remediation, whose installation needsworkflows: writeon top ofcontents: write. It surfaces intermittently, only when the pushed diff happens to touch a workflow file, so a green history doesn't rule it out. pascalgn/automerge-actionexits 0 onmergeResult: 'merge_failed'. Aautomerge.yamlrun with conclusionsuccesswhose log carriesmergeResult: 'merge_failed'orFailed to merge PR:is astale pinfailure (the reusable'sMERGE_METHODdefault doesn't match the repo's allowed strategy in some pre-fix versions). Triage theautomerge.yamluses:tag, not the workflow YAML itself.- Renovate-generated bump PRs for
nolte/gh-plumbingaren't automerged in this portfolio. Astale pinremediation that proposes to enable Renovate automerge fornolte/gh-plumbingviolatesworkflow-health§Upstream drift and the AC against it. The remediation is a human-acknowledged Renovate PR, not an automerge rule. flakewithout reproducible evidence isdefect. A "let's just re-run and hope" reflex is exactly what the spec forbids. If the sameheadShadoesn't re-run cleanly green and no infra signal explains the first failure, the class isdefectand the work is a fix, not a tracking entry.
Multi-model testing
Examples and operations in this skill are verified on Claude Sonnet as the default model; spot-checked on Haiku for cost-sensitive runs; Opus is appropriate for high-stakes audits that require deeper reasoning. The skill body has no model-specific assumptions beyond standard tool-call semantics.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

