Life-After-Code-Train: Commit. Board. Arrive.

Inspiration

After the code is written, developers still spend a lot of time on manual checks, on making sure every change is covered, and on planning rollbacks in case something goes wrong. GitLab gave us the chance to automate that whole flow, so we built an agent orchestration we call Life-After-Code-Train.

What it does

Life-After-Code-Train takes a GitLab ticket all the way to production. 15 GitLab Duo agents each own one stop on the track (requirements, coding, rollback planning, spec review, security review, release, incident response, audit and more), and fail-closed CI gates check every verdict they give. Each change goes from dev (a temporary canary cluster per MR) to staging to production. Humans step in only where judgment matters: writing the ticket, coding changes that aren't simple, pushing the release tag, and approving one-way steps.

How we built it

  • GitLab Duo Agent Platform flows (.gitlab/duo/flows/*.yaml) for the 15 agents, published to the AI Catalog.
  • GitLab CI for the whole pipeline: readiness check → scope guard → rollback plan → lint, tests, build and scanners → Spec Reviewer → dev canary → Security Reviewer → auto-merge.
  • Fail-closed gates: each agent ends its note with a verdict line (VERDICT: PASS, SECURITY VERDICT, ROLLBACK PLAN: OK) that CI parses. A missing verdict or a FAIL blocks the merge.
  • Relay branches so agents can hand work to each other, with only allow-listed flows allowed.
  • A $5/month Linode Nanode runs staging and production behind a Caddy weighted canary, with a database backup and an automatic rollback.

Challenges we ran into

  • Agents can't start other agents. GitLab only lets humans fire flow triggers, so one agent mentioning another started nothing. We built relay branches: an agent pushes relay/<flow>/<id>, a one-job pipeline starts the next flow through the Flows API, then deletes the branch.
  • A commit message closed our issue too early. "implement #1" counts as a GitLab closing keyword, so the ticket closed before its MR existed.
  • Duplicate pipelines. The Rollback Planner's commit started a second full MR pipeline, so every gate ran twice.
  • Agent sandboxes have no Postgres, so the database tests failed there even though CI passed.
  • The audit trail named the wrong actor: GitLab recorded an agent as the one who merged.

Accomplishments that we're proud of

In our first live run, ticket #1 ("Add GET /version endpoint") went from issue to automatic merge in 36 min 49 s:

  • 9 agent sessions and 2 relay handoffs, with 0 human actions after the ticket was written
  • 100% of changed lines covered and 0 scanner findings
  • The canary was promoted with p95 latency ≈ 23.8 ms and 0% errors
  • Every merge leaves audit evidence: the acceptance criteria traced to code and tests, both review verdicts, and a rollback plan

What we learned

  • Agents are only trustworthy when another check reads their verdict. Fail-closed parsing mattered more than a clever prompt.
  • Platform limits shape the design: since GitLab doesn't let one agent trigger another, the agents hand work off through git.
  • Small details matter in automation. One closing keyword in a commit message was enough to break the issue lifecycle.
  • Keeping humans "at the switches" (tagging releases, approving one-way steps) makes full automation easier to accept.

What's next for Life-After-Code-Train: Commit. Board. Arrive.

  • Skip duplicate agent runs when an earlier verdict already covers the same diff, to cut CI time.
  • Give agents a sandbox test setup (such as a SQLite fixture) so their test results match CI.
  • Fix the merge attribution in the audit trail, and add automatic retries to flows:sync.
  • Have flows:sync open an MR when it updates the agent lock file, so versions never go stale.
  • Run more tickets through it, including security fixes from Security Triage and a full production incident drill.

Built With

  • claude
  • duo-agent
  • gitlab
Share this project:

Updates

Submission history