-
-
The problem: writing code takes minutes, everything after it still waits on people
-
How it works: one issue in, eight steps by Duo flows and GitLab pipelines
-
Run #20: "Released in board-v0.11.0", 25 minutes after the issue was filed
-
Run #20: the Duo review flow approves !48, and the bot merges it 29 seconds later
Inspiration
Coding agents can write a fix in minutes. Everything after the code still waits on people: deciding whether an issue deserves a fix, reviewing it, waiting for green CI, cutting a release, deploying it, checking production, telling the person who asked. shipmill is an open-source "software factory" that does that rest. Before this hackathon it ran on GitHub, with its agents as sessions started from a laptop, so the loop stopped whenever the laptop slept. The hackathon's theme, "code generation is solved", is exactly the problem shipmill exists for, and GitLab's Duo Agent Platform let the whole loop live inside the code host.
What it does
A member files an issue. Nobody touches it again:
- A Duo triage flow starts on the "work item created" trigger, checks the claim against
main, and posts a verdict with a plan - A Duo resolve flow writes a regression test that fails first, the fix and a changelog entry, and opens a merge request
- The merge request's pipeline runs the tests, SAST and Secret Detection
- A Duo review flow reruns the tests, reads the diff and every scan finding, and approves or asks for changes, naming the exact commit it reviewed
- The project's bot merges only a green merge request approved at its current head
- shipmill's planner cuts a release candidate by a policy file in the repo, publishes a GitLab Release, and deploys it to Cloud Run staging; a health check proves it, and the same image is promoted to production
- The issue gets a comment: "Released in board-v0.11.0" with the production link
A bad deploy rolls traffic back and opens an incident issue. A single hold issue stops every release. The app it ships is the Board, a small dashboard of the project's own release lines, pipelines, environments and delivery metrics, so every run changes the page that shows the run.
Measured: issue #15 went from filing to "Released in" in 24.5 minutes with no person in between, and #20, the run in the video, in 25 minutes 18 seconds. The first full run took 1 hour 50 minutes; the time came down by replacing every wait with a GitLab event.
How we built it
- Judgment in flows, writes in CI. Three custom Duo flows (triage, resolve, review) are rendered from stack-neutral playbooks and published to the project's AI Catalog. Every deterministic write (labels, merges, tags, releases, deploys, incidents, notices) is a CI job running the
shipmillCLI as the project's bot - The gate. A flow can't start another flow, and flow triggers don't fire for what a flow or a bot did. So a
gatejob in each Release pipeline reads the state and starts the next flow through the Flows API. GitLab starts that pipeline on every event that matters: a project webhook (a triage verdict, a passed merge request pipeline, a review's verdict) received by the Board on Cloud Run and turned into a pipeline with a trigger token; each merge; each healthy deploy. A schedule is only a fallback - Release lanes from the changelog. shipmill's planner decides when an rc and a stable release are due from changelog fragments and a policy in
.gitlab/shipmill.toml - Google Cloud without keys. The Deploy pipeline signs in with GitLab's OIDC token through Workload Identity Federation; the image is built once per rc and promoted unchanged; secrets live in Secret Manager
- One codebase, two code hosts. shipmill's core talks to a
CodeHostport with GitHub and GitLab adapters, so the same planner and policy run on both - The loop builds the loop. Since October 17, the coding agent's own changes go through the same loop: an issue, a branch, the review flow, the bot's merge
Challenges we ran into
- Flows can't chain, and bots can't fire triggers. The deterministic gate in CI, started by events, was the answer
- No pipeline variables. The hackathon group locks them, so every pipeline starts with inputs declared in
.gitlab-ci.yml - The Duo sandbox isn't CI. Its environment overrides git's identity, has no
ps, and a read-only home; three test failures had three different causes - A
trigger:job aimed at its own project is refused (invalid_bridge_trigger), and a flow trigger ignores a pipeline a flow's push created; a project webhook fires for everyone - Twenty-minute waits. The early runs spent most of their time between schedule ticks; each wait was replaced by an event or by the gate waiting in its own job
- A review flow can't approve in GitLab's approval rules, so the merge reads the review's note and the exact commit it names
Accomplishments that we're proud of
- Hands-off for real: eight runs with nobody between the issue and production
- All nine DevSecOps stages, each a GitLab feature a judge can open
- The reviews catch real bugs, including in the agent's own changes: a case-sensitive webhook header check, a missing changelog entry, a CI job GitLab never created. GitLab's Fix CI/CD Pipeline flow picked up a failed pipeline on its own and proposed a fix in four minutes
- The secure stage closed a real SAST finding (an SSRF in the Board) through the loop, with the review proving the tests fail without the fix
What we learned
- The platform's limits shape the design more than the agents do: where a flow can't act, a deterministic job started by an event is simpler and auditable
- Measure the loop, not the agent: the agents always worked for minutes; the hours were waits
- Hold the agent's own changes to the same review as everyone's
What's next for shipmill
- Bring the GitLab adapter back to the open-source shipmill on GitHub, so any GitLab project can run the loop with
shipmill init --ci gitlab - Publish images to GitLab's container registry, and port shipmill's
operate(bake times, promotion between environments) to GitLab deployments - A hosted shipmill for teams that want the loop without running it
Built With
- artifact-registry
- claude
- gitlab
- gitlab-ci
- gitlab-duo-agent-platform
- gitlab-sast
- gitlab-secret-detection
- google-cloud-run
- python
- secret-manager
- workload-identity-federation

Log in or sign up for Devpost to join the conversation.