Who did what (read this first)

Step Human Duo / agent CI / GitLab
Ask for the change writes the issue (or the monitor does)
Make the change assigns the issue to the flow Duo ShipGate Implement commits and opens the MR
Judge it Duo Code Review comments / approves gates, SAST, secret detection, guard decide red/green
Repair assigns the fixer (Duo flow) or the dispatcher repairs Duo ShipGate Fixer / deterministic fixer commits pipeline reruns
Merge + deploy clicked merge on the Duo MRs merge when green, Pages, monitor

Unattended laps: on a schedule the dispatcher turned issues #7 and #6 into MRs !8 and !9, repaired them to green, merged them itself (merged by the project bot), and the pages deploy and monitor ran green; no human after writing the issue. A bot cannot start a Duo flow, so Duo takes part unattended through its built-in Code Review, and the custom flows run on a human assignment.

Summary

ShipGate turns "after the code" into a pipeline an agent can run safely. A page with 10 errors (no lang, no title, a phone number in the HTML, a dead link, a mixed-content script...) is blocked by the gates; a repair commit fixes what is mechanical; CI goes green; GitLab merges and deploys it; a monitor audits the live site. Nothing is mocked: the public demo page is generated from the real audit output on every pipeline.

The key idea: agents may change content only. The gates, policy, tests, CI and agent rules sit behind a CI job (shipgate:guard) that fails any MR touching them without a human-applied label; the job runs the base commit's code and policy, so an MR cannot grade itself (MR !7 shows it stopping a policy change). Residual limit, stated up front: the job definition lives in .gitlab-ci.yml, which an MR could edit; closing that needs a pipeline execution policy or required approvals on a protected branch.

Evidence (all public, repo: https://gitlab.com/fujiken-lab/life-after-code)

Claim Where to look
Issue -> MR -> red -> repair -> green -> auto-merge issue #2, MR !4: red pipeline 2958237285, green 2958240114, merged 5 min 34 s after the MR opened
Unattended laps, merged by the bot MRs !8 and !9, docs/DUO_EVIDENCE.md section 6a
The brakes work MR !3 (the fixer stopped at a judgement call); MR !2 (a CI bug the loop exposed)
54 unit tests, Python 3.9 and 3.12 in CI job shipgate:unit
21 gate ids, each with a test case python -m shipgate checks, tests/test_audit.py
Duo flows ran ShipGate Implement: issue #3 -> Duo-authored commit d24969d + MR !5 (audit PASS). ShipGate Fixer: red MR !6 -> Duo-authored fix dd50029 -> green
Duo Code Review + Chat @GitLabDuo reviewed !6 (4 comments, blocked the merge, approved after the fix). Duo Chat found real bypasses in our own guard; fixed in b5e7088
Autonomy boundary enforced shipgate:guard job, MR !7, GuardTests
Monitor opens an issue on regression issue #8 (a deliberate, reversible regression)
Deployed https://life-after-code-7e4245.gitlab.io/ and https://life-after-code-7e4245.gitlab.io/demo.html
GitLab stages Plan, Create, Verify, Secure, Package (package:site), Release/Deploy (pages, environment production), Configure, Monitor, Govern: table in the README

Inspiration

Writing the change is the easy part. For small content sites the time goes to review, accessibility and privacy checks, security scans, deploy, and noticing later that something broke. The same post-code mistakes repeat (missing alt text, a phone number left in a page, an oversized page, a broken link). ShipGate turns those checks into gates and lets a loop run them.

What it does

  • Gate (CI, deterministic): accessibility, SEO, broken links, external-host and mixed-content security, personal-data privacy, byte budgets: 21 gate ids.
  • Secure: GitLab SAST and Secret Detection on every MR; pages waits for all of them.
  • Loop: issue labelled shipgate -> dispatcher opens an MR set to merge when green -> red MR gets a repair commit (max 3 cycles) -> then a human.
  • Govern: protected paths, allow-listed issue authors, caps on cycles and open agent MRs.
  • Watch: the monitor audits the live pages with the same gates and opens one deduplicated issue on regression.
  • Measure: every report carries an SCI carbon figure (Sustainable Web Design v4); each MR prints the delta against its base.
  • Agent-facing: the gates are an MCP server (python -m shipgate mcp: audit, explain, list_checks) with a workspace config for Duo.

How we built it

Python standard-library gates (shipgate/, about 1,400 lines), a stdlib dispatcher/fixer/guard, .gitlab-ci.yml, two Duo flows that ran (implement, fixer) plus an unregistered third definition (release-note), an MCP server, AGENTS.md and CODEOWNERS. Everything is MIT.

Challenges

The loop found its own bugs: the first lap failed because a freshness check in build:site fired before the audit could report the real defects (MR !2). An unauthenticated API rate limit (HTTP 429) hit the dispatcher: it now retries with backoff. The monitor's first live run flagged five "broken" links that were just un-downloaded stylesheets; it now fetches referenced assets. A bot assignment does not start a Duo flow (flows need a human identity), so the unattended engine is deterministic and Duo joins through its built-in Code Review. Duo Chat reviewed our own guard and found two complete bypasses (the guard ran from files the MR controls; stdlib shadow files), both fixed.

Accomplishments

Unattended issue-to-live laps merged by the bot, a measured 5 min 34 s lap with one red-to-green repair, an autonomy boundary that CI enforces, and a gate suite useful with no agent at all.

What we learned

Deterministic gates plus an agent that can only change content is a safer autonomy boundary than an agent with free access to the pipeline, and a loop is only as trustworthy as its brakes: every brake here has a test.

What's next

A pipeline execution policy so the CI job definition is not MR-controlled, per-site policy packs, the third (release-note) flow, starting Duo flows from the schedule.

Honest status (read this)

  • Duo Agent Platform ran, on the maintainer's free Ultimate trial (ends 2026-11-16): two custom flows, the built-in Code Review flow and Duo Chat. Evidence and limits: docs/DUO_EVIDENCE.md.
  • The fixer's red MR (!6) was seeded with defects by a human; the implement flow passed the audit on its first try (!5). The Duo flows were started by an assignment from the maintainer and the Duo MRs were merged by the maintainer; MRs !4, !8 and !9 were merged by the dispatcher.
  • The maintainer had to allow the bot to merge on main first. The monitor's issue-opening branch was exercised once on purpose (issue #8). The CI job definition is still MR-controlled (residual risk, documented).
  • Not claimed: Google Cloud bonus (the untested deploy job was removed); AI-inference energy in the carbon figure (no published number); the third flow (release-note) was not run.

Links

Built With

Share this project:

Updates

Submission history