Inspiration
A red pipeline pulls someone out of their work: open the log, find the one line that matters, make a small fix, push, wait again. Most failures are routine: a lint error, an off-by-one, a bad version pin, a broken Dockerfile. "Life After Code" pointed us at that loop. We wanted an agent that handles it on the merge request where it happens, while a human still makes the final call.
What it does
Pipeline Doctor is a custom GitLab Duo Agent Platform flow, started by the native Pipeline events > Failed trigger (or on demand with a Mention). Five agents run in a chain:
- Diagnose: reads the failing jobs, their logs, and the files the errors point to.
- Classify: picks one category:
lint,test,dependency,build,deploy,flakyorunfixable. - Fix / Retry / Report:
- Fix edits the code, runs
ruffandpytestlocally (up to 3 attempts), and pushes a[doctor]commit to the same MR. - Retry reruns CI for flaky failures.
- Report explains what a human must do.
- Fix edits the code, runs
- Report: posts one structured note with the category, root cause, action taken, verification result, and a session link.
On main it never pushes. It opens a hotfix MR, or an incident issue when the cause is outside the repo (IAM, secrets, quota). It never merges: a human does. That is the Supervised gate.
Benchmark: 11 seeded failures, no human edits.
- 10/10 classified correctly
- 9/9 fixable failures fixed on the same MR
- 1/1 unfixable failure handed to a human
- Median 1.1 min to the fix commit and 6.0 min to green
How we built it
- Flow:
.gitlab/duo/flows/pipeline-doctor.yml, fiveAgentComponents with a router. Each step gets a minimal toolset: only fix and retry can run commands, and only report can comment. - Rules:
AGENTS.mdholds the taxonomy, commit conventions, protected files and verification commands. - CI/CD:
- lint, test, SAST, secret detection and dependency scanning
- Cloud Build into Artifact Registry
- Cloud Run in low-carbon
europe-north1: no-traffic deploy,/healthsmoke test, then promote or roll back automatically - MR preview environments
- a GitLab Release for every green
main
- Auth: keyless, using GitLab OIDC and Workload Identity Federation.
- Carbon: every pipeline publishes an SCI estimate:
$$\text{SCI} = \frac{E \cdot I}{R}, \qquad E = \text{runner minutes} \times P_{\text{runner}}$$
where $I$ is the region's grid intensity and $R$ is one pipeline. For example: $0.0647\ \text{kWh} \times 30\ \text{gCO}_2\text{e/kWh} \approx 1.94\ \text{gCO}_2\text{e}$ per pipeline.
- Built with Claude Code subagents working in parallel git worktrees.
Challenges
- Strict flow schema. Every
input_schemafield is required, and several documented fields were rejected. We ended up with a minimal definition. - Mentions from CI don't trigger flows, so we switched to the native pipeline-failure trigger.
- The Doctor couldn't start on the bug it had to fix. Its setup installed the branch's broken pins. It now falls back to a known-good toolchain.
- Previews leaked into production.
gcloud run deployinherits revision settings, so a preview's secret reachedmain. We added a separate preview service and--clear-secrets. The Doctor correctly refused to patch code for this and handed it to a human. - Stale revision tags blocked every deploy. Each deploy now clears them first.
- No project tokens, so no auto-merge. That pushed us to a cleaner Supervised model.
What we learned
- Narrow scope builds trust. Small toolsets, a fixed classification step and one note per run keep the agent predictable and easy to review.
- Verify before push is what turns a suggestion into a fix you can merge.
- Saying "this is unfixable, here is what a human must do" is a feature, not a failure.
- Supervised doesn't mean slow. The human approves one verified commit instead of debugging.
Built With
- fastapi
- gitlab
- gitlab-duo
- google-cloud
- python
Log in or sign up for Devpost to join the conversation.