Inspiration
The hackathon's theme said it best: code generation is solved — what happens next is the challenge. AI can already write code. The boring, stressful part is everything that comes after: a pipeline goes red at 2 a.m., a test breaks, a dependency goes missing, and a human has to drop everything to read logs and patch it.
I asked a simple question: what if the pipeline could fix itself?
That became Self-Healing Pipeline Agent — a project where a broken build doesn't wait for a human. The pipeline notices the failure, works out what went wrong, and either fixes it on its own or hands it to GitLab Duo for a smarter, code-level fix. You push code and walk away; the pipeline works to get itself back to green.
What it does
When CI fails, the project diagnoses the failure and heals it along two honest paths:
| Path | Failure type | Who fixes it |
|---|---|---|
| Deterministic | Lint (messy code), missing dependency | Our own script fixes it and opens a merge request |
| AI-powered | Test regression, build/syntax error | GitLab Duo (Fix CI/CD Pipeline Flow) writes the code-level fix |
The pipeline has four stages — verify → package → release → heal. The heal stage only runs when something fails. It:
- Reads the failed job's logs through the GitLab API.
- Classifies the root cause (lint, dependency, test, or build).
- Simple problems: runs the fix (for example
ruff --fix), commits it, and opens a merge request labeledself-healing. - Hard problems: hands the failure to GitLab Duo, because a logic bug needs real reasoning, not a regex.
The result is a pipeline that behaves less like a tripwire and more like a teammate.
How we built it
The sample app. A tiny Flask calculator API (add, subtract, multiply, divide, plus a /health endpoint). It's deliberately small so there's a real, breakable surface to demo on.
The safety net. A pytest suite that defines "correct." These tests are the gate — breaking them is what triggers the whole healing loop.
The pipeline (.gitlab-ci.yml). Four stages:
verify— lint with ruff and run the testspackage— compile the app to catch syntax errorsrelease— start the app and check/healthheal— runs onlywhen: on_failure
The robot's brain (automation/). Two focused scripts:
diagnose.py— a classifier that turns messy job logs into a clean JSON verdict (category, confidence, evidence).heal.py— the actor. It fixes lint/dependency failures itself and defers test/build failures to GitLab Duo instead of pretending it can fix them.
The GitLab Duo integration.
AGENTS.md— a rule book that steers Duo's Fix CI/CD Pipeline Flow: fix the code, never the tests; never disable a pipeline stage; make the smallest change; escalate when unsure.- Duo's Fix pipeline with Duo flow does the actual code-level repair and proposes it back as a merge request / suggestions.
Tech stack: Python 3.12, Flask, pytest, ruff, GitLab CI/CD, and the GitLab Duo Agent Platform.
Challenges we ran into
This was a journey, and the lessons came the hard way.
The "slim" image had no git. The
healjob crashed withNo such file or directory: 'git'becausepython:3.12-slimships without it. Fix: install git in the job and do a full clone so it can branch and push.We fought our own
.gitignore. The heal job tried to commit a file under.heal/, which we had ignored, sogit addrefused. A self-inflicted bug that taught us to test the whole path, not just the happy path.Pushing from CI used the wrong token. The runner's default remote is read-only. We had to push with the
HEAL_BOT_TOKENvia anoauth2:URL so the bot could actually open merge requests."Pending forever." Pipelines sat in pending with no runner. The lesson: a new account needs verification and available shared runners before anything runs.
The honesty problem (the big one). Our first design pretended a custom YAML "agent" could fix any failure, including logic bugs. It couldn't — there was no LLM behind it. We rebuilt the project to be truthful: scripts handle what scripts can (lint, dependencies), and real code fixes are delegated to GitLab Duo. The project got simpler, smaller, and far more credible.
The subscription wall (
M3006). Duo wouldn't run on a personal account without a subscription. The breakthrough was realizing the project belonged in the hackathon's showcase group, which had Duo enabled — and sure enough, a Duo agent session ran successfully there.
Accomplishments that we're proud of
- A pipeline that genuinely heals itself end-to-end for lint and dependency failures — no human in the loop.
- A clean, honest split between what automation should do and what AI should do.
- A real GitLab Duo agent session running on our project in the hackathon group.
- Documentation anyone can follow — including a version written for a 10-year-old.
What I learned
- Be honest about an agent's limits. The project got dramatically better the moment we stopped faking capabilities and let each tool do what it's actually good at.
- CI debugging is its own skill. Base images, tokens, runners, and ignore files all have sharp edges that only show up in the pipeline, not on your laptop.
- GitLab Duo is the real deal for code-level healing — but it needs the right subscription, runners, and group settings, and those are easy to miss.
- The log always has the answer. Nearly every blocker was solved by reading the failing job's output one more time.
What's next
- Fully hands-off healing using a Duo Custom Flow triggered on pipeline failure, so no human clicks anything.
- More failure categories — flaky tests, timeouts, and formatting drift.
- A real deployment to Google Cloud Run so the
releasestage ships, not just health-checks. - A loop-breaker so the agent never retries the same failed fix twice.
Log in or sign up for Devpost to join the conversation.