Key Takeaway
CI Doctor is a gh-aw agentic workflow that runs when a CI workflow fails, reads the failed job's logs and the triggering commit, and files one structured issue with a likely cause instead of editing code. It runs read-only, writes only through declared safe outputs, and folds repeat failures into the existing issue.
The most expensive minute in a red pipeline is the first one: someone opens the run, scrolls past 3,000 lines of log, and works out which error was the cause and which were fallout. I wanted to know whether an agent could do that minute for me without being trusted to touch the code.
GitHub's CI Doctor, one of the featured workflows in gh-aw (GitHub Agentic Workflows), is built for exactly that. I read its documentation, its actual workflow source and the security pages behind it. I did not run it in production for this post, so every claim below traces to a page I read, and where a page is silent I say so.
Diagnose, do not repair: the design choice that matters
CI Doctor's output is an issue, not a patch. The gh-aw home page describes it as a workflow that runs when CI fails, reads the failed job's logs along with the commit and pull request that triggered the failure, and opens one issue with the likely cause and next steps. If the same failure repeats, it updates the existing issue rather than creating a new one.
That is a deliberately small blast radius. An agent that can only file an issue can be wrong, but it cannot push a bad commit, and a wrong diagnosis costs a human a minute to dismiss. The workflow's own prompt reinforces this: it asks for high, medium or low confidence on every diagnosis and says not to present a guess as fact.
The whole workflow file, read line by line
The workflow lives in githubnext/agentics as a Markdown file with YAML frontmatter and a natural-language body. The frontmatter below is what I read in that file on 17 October 2026; I have trimmed the description field and the prompt, which is a long investigation protocol.
---
on:
workflow_run:
workflows: ["CI"]
types: [completed]
branches: [main]
# workflow_run also fires for green and cancelled runs. Filter here so
# the agent job is never even scheduled for them.
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
permissions: # the agent job is read-only
actions: read
contents: read
issues: read
pull-requests: read
safe-outputs: # the only writes, applied by a separate job
create-issue:
title-prefix: "[CI failure] "
add-comment:
timeout-minutes: 10
---Three lines carry the design. The if condition on the workflow conclusion stops the agent from running for successful or cancelled runs. The permissions block gives the agent job read access only, including actions: read, which is what lets it fetch job logs. And safe-outputs names the only two writes that exist: an issue with a title prefix, and a comment.
The prompt body is worth reading in full, because it is the actual product. It tells the agent to start from the earliest failed job and the first meaningful error rather than later errors that may be consequences, to classify the failure as code or test, dependency or toolchain, workflow configuration, runner or network, flaky, or external service, and to search existing issues for the workflow name, job name and distinctive error text before filing anything.
Installing it, and why you commit two files
The CI Doctor documentation gives a two-command install through the gh extension, then a customise loop: edit the trigger, run gh aw compile, and commit both the Markdown and its generated lock file to the default branch. The compile step is where gh-aw's first defence lives, since the architecture page says it enforces schema validation, expression allowlisting and action pinning, and can run actionlint, zizmor and poutine over the output.
# Install the extension, then add the workflow with the wizard
gh extension install github/gh-aw
gh aw add-wizard githubnext/agentics/ci-doctor
# After editing the Markdown (trigger names, branches, prompt), recompile.
# The extra flags run actionlint, zizmor and poutine over the generated YAML.
gh aw compile --actionlint --zizmor --poutine
# Commit BOTH files to the default branch. The Markdown alone changes nothing:
# Actions runs the compiled .lock.yml.
git add .github/workflows/
git commit -m "ci: add CI Doctor failure triage"The caveat in the docs is easy to miss: editing the Markdown without recompiling and committing the lock file does not update the running workflow. Treat the .md file like source and the .lock.yml like a build artefact that must travel with it, and add a CI check that fails when they drift.
The trigger trap: what the default does not watch
By default CI Doctor monitors failures from the workflow named CI on the main branch, and the docs say to edit on.workflow_run.workflows and on.workflow_run.branches for your repository. The names must match your workflow names exactly, so a repository whose pipeline is called Build, or whose deploys live in a second workflow, gets silence rather than an error.
# Wrong: the default watches only a workflow named "CI" on main.
# A failing "Deploy" workflow or a release branch is never diagnosed.
on:
workflow_run:
workflows: ["CI"]
branches: [main]
# Right: name every workflow you want diagnosed, and the branches that matter.
on:
workflow_run:
workflows: ["CI", "Deploy", "Nightly integration"]
types: [completed]
branches: [main, "release/*"]
safe-outputs:
staged: true # week one: preview the issues in the step summary, write nothing
create-issue:
title-prefix: "[CI failure] "
labels: [ci-failure, agentic]
max: 1 # one new issue per run
expires: 14 # integer = days; stale diagnoses close themselves
close-older-issues: true # supersede earlier issues from this workflowThe second block is my tuned variant, assembled from options on the safe-outputs reference page, not a file I ran. The staged setting is the one I would turn on first: the reference says staged mode skips every write and shows a labelled preview in the Actions step summary, which lets you judge the diagnoses before an issue ever appears.
Safe outputs: how one failure becomes one issue
The create-issue output has options that decide whether this tool is a help or a nuisance. These are the ones I would look at first, with defaults only where the page states them.
| Option | What the reference says | Why it matters for CI |
|---|---|---|
| title-prefix | Prefix for issue titles; CI Doctor ships with [CI failure] | Lets you filter and search every diagnosis in one query |
| labels | Labels attached to the issue | Route diagnoses to a board or an on-call view |
| max | Maximum issues per run; default 1 | Caps the damage if the agent loops on a noisy failure |
| expires | Auto-close after a period; integers are days, or false to disable | A diagnosis of a fixed failure should not linger |
| close-older-issues | Closes up to 10 earlier open issues from the same workflow as not planned; default false | Stops a stack of stale issues for one flaky job |
| deduplicate-by-title | true matches titles exactly; an integer from 0 to 100 sets an edit distance | Catches near-identical titles the prompt-level dedup missed |
| group-by-day | Same-day runs comment on one open issue instead of creating new ones; default false | One thread per bad day, not one per failed push |
CI Doctor already dedupes at the prompt level, since its instructions say to add a comment to an open issue with the same root cause instead of creating another. These options are the second net, enforced by the safe-output handler rather than by the model's judgement. The same page says an issue body must be between 20 and 65,000 characters, so a near-empty diagnosis is rejected outright.
Six layers of defence, mapped to a failing build
The gh-aw home page frames the risk as the lethal trifecta: private data, untrusted content and outbound access held by one agent at once. A CI Doctor run has all three ingredients, since logs are untrusted text, the repository is private data, and the agent can talk to a model. The six layers on that page are how it breaks the trifecta apart.
| Layer | What the docs say it does | What it means for CI Doctor |
|---|---|---|
| Compile-time validation | Schema checks, expression allowlisting and pinned actions before a workflow can run | A typo in the trigger or a loose expression fails at gh aw compile, not at 2 a.m. |
| Sandboxed agent | Read-only by default; the firewall routes HTTP and HTTPS through a Squid proxy with a domain allowlist | The agent can read logs but cannot post them to an arbitrary host |
| Credential isolation | An API proxy holds tokens so the agent never sees them | A log that tricks the agent into printing its environment finds no model key |
| Integrity filtering | Untrusted GitHub content is removed before the engine sees it, by trust level | Matters for the issue and PR text CI Doctor reads around a failure |
| Threat detection | A separate job scans proposed outputs for prompt injection, secret leaks and malicious patches | A diagnosis that quotes a leaked token can be blocked before it becomes a public issue |
| Safe outputs | Only declared writes are applied, by a separate job with its own permissions | The job that writes the issue holds issues: write; the agent that read the logs does not |
The architecture page spells out the split: the agent job runs with minimal read-only permissions and its writes are buffered as artifacts, a detection job with no write permissions downloads and judges them, and only then do safe-output jobs run with scoped permissions such as issues: write for create_issue. If detection finds a threat, the workflow fails and nothing is written.
Do not read the six layers as a licence to point CI Doctor at logs you have not looked at. The docs say the API proxy should not be treated as a separate caller-authentication boundary for code already running inside the agent container, and that the MCP gateway agent identifier should be treated as leaked by design. The defences narrow what a compromised agent can do; they do not make a compromise impossible.
Where it can fail: noise, cost, blind spots and the silent skip
The first failure mode is the one I would expect to hit first: no output. The default trigger watches one workflow on one branch, the if condition drops everything that is not a failure, and the prompt tells the agent not to open an issue for a cancelled run, a duplicate or a failure with no actionable new information. Every one of those is correct behaviour, and every one looks identical to a broken install, so the first week needs staged mode and a deliberate red build.
The second is the detection layer's own behaviour. The threat detection page lists a 10-minute default timeout for the detection job, a note that large patches may need longer, and a warning that AI-based analysis can flag legitimate content. It also lists continue-on-error as defaulting to true, with warnings and failures producing a caution notice instead of blocking. I did not run a workflow to see how that interacts with a blocked output, so read your compiled lock file before relying on detection as a hard gate.
The third is scope and cost. The home page names max-ai-credits (default 1,000 per run), max-turns and max-daily-ai-credits (default 5,000 per 24 hours), so a red main branch with a failing push every few minutes is bounded rather than open-ended. Separately, the v0.88.4 release notes for the week of 7 September 2026 are about hardening the firewall, a Pi Anthropic routing fix and DIFC policy generation for GitHub App workflows, and they do not mention CI Doctor at all, so do not read that release as a CI Doctor change. Finally, the integrity page says nothing about how workflow_run data is handled, and on public repositories with no min-integrity set it applies approved by default, so check what your repository's visibility changes.
What to do on Monday
Run this as a one-week experiment on a single repository, with writes switched off, and judge it on diagnoses rather than on feature lists.
- List your real workflow names and recent failures with the gh commands below, so the trigger matches exactly and you have a test set.
- Install with gh aw add-wizard, edit on.workflow_run.workflows and branches, set safe-outputs staged to true, then compile and commit both files.
- Cause one deliberate failure on a branch the trigger covers, and read the preview in the Actions step summary.
- Compare the diagnosis with what a human would have concluded from the same log, and note the confidence level it chose.
- Turn staged off only when diagnoses are right more often than they are noise, then add labels, max, expires and close-older-issues.
# 1. List the workflow names your repository actually has. These are the
# strings workflow_run.workflows must match, character for character.
gh workflow list --all --json name,state --jq '.[] | [.name, .state] | @tsv'
# 2. Find your most recent real failures: the test set for the first week.
gh run list --status failure --limit 20 --json databaseId,workflowName,headBranch,displayTitle --jq '.[] | [.databaseId, .workflowName, .headBranch, .displayTitle] | @tsv'
# 3. Read the log the agent will read, starting from the earliest failed job.
gh run view <run-id> --log-failed | head -80If the diagnoses are good, the next question is not how to let the agent fix things. It is whether the confidence field and the classification categories are consistent enough to route issues to different owners automatically.
Make your pipeline fail fast with a clear first error as a team habit too. CI Doctor starts from the earliest failed job and the first meaningful error, so a pipeline that stops early gives the agent, and your humans, the best chance of a correct reading.
A failure-triage agent earns trust by being boring: read-only on the way in, one declared write on the way out, and a diagnosis you can dismiss in a minute. Start in staged mode, make the trigger match your real workflow names, and judge it on whether the first paragraph of each issue saves a human the log scroll.
Sources
- gh-aw: GitHub Agentic Workflows home page (CI Doctor, safe outputs, six layers)
- gh-aw blog: weekly update for v0.88.4, 7 September 2026
- githubnext/agentics: the CI Doctor workflow documentation
- githubnext/agentics: workflows/ci-doctor.md, the workflow source
- gh-aw reference: safe outputs and create-issue options
- gh-aw reference: threat detection
- gh-aw: security architecture (compile-time checks, AWF, permissions model)
- gh-aw reference: integrity filtering

