The run (2026-10-10, showcase project — every link is a public page)

One human filed issue #2 "Add per-site latency percentiles (p50/p95)" with the label autopilot at 13:19Z. The Work item created trigger started our Planner + Developer flow (session 9286698), which posted a plan citing AUTOPILOT §2.1 §2.2 §3.4, committed 4 files (code + tests) and opened MR !1. The review-handoff CI job started GitLab Duo Code Review (session 9286720): "found nothing to comment on". policy-check approved, citing five rules. The auto-merge gate refused twice, and said why: first it counted all 44 pre-existing High/Critical base-image findings (the policy says new), then the finding key still carried the per-commit image tag. The fix went into the gate's code, not the policy; after a rebase it passed and MR !1 merged at 14:10Z (de42064a). Main pipeline 2933589447 (Ultimate scanners, dry-run deploys) finished deploy-production at 14:16Z and posted the journey card; the Pipeline passed trigger started our Closer flow (pipeline 2933596153), which wrote the narrative at 14:18Z. Lead time issue → production: 57 minutes. Human actions after filing: zero. CI footprint of the main pipeline: 9.0 runner-minutes ≈ 0.77 gCO2e (an estimate; method in docs/SCI.md).

What's different

  • One numbered policy, cited by the agents and enforced by code. AUTOPILOT.md is nine sections of prose plus a YAML block. Every flow ends its notes with autopilot: rules=[…]; scripts/policy.py reads the same YAML in CI, so the policy-check note and the agents point at the same rule numbers. §1.3 is a judging freeze: after 2026-10-27 13:00 UTC a new issue or MR gets one polite note and no change — enforced by the same script. The reviewer agent's newest signed verdict note decides §3.2. It is not a GitLab MR approval: the approve call returns 401 for our token in this project (likely: the token's user is recorded as the MR author, and authors may not approve).
  • Replay it yourself, on the project, without Duo. The latest main pipeline carries manual demo:* jobs that play the three scenes through the API — hands-off merge + release, the security gate (fastapi==0.125.0 → pip-audit red on starlette PYSEC-2026-248/249 → fix → merge), chaos → Incident → rollback — and a deep link files an autopilot issue the Planner answers in about two minutes.
  • Receipts you can check without signing in. Every journey card carries lead time, the human-touch count and the CI footprint, and the pages job publishes a one-page table of all journeys, security-fix MRs and incidents, each number linking to the GitLab note it came from. The monitor schedule went from every 15 minutes to every 2 hours after measuring its cost: ≈149 → 6 runner-minutes a day.

What it does

An autopilot issue goes in. Agents plan and code it; CI verifies (pytest, ruff), scans (SAST, Secret Detection, pip-audit; Dependency and Container Scanning on Ultimate), packages (image + wheel), cuts a release-cli release, promotes staging → production on Render, monitors production on a schedule, opens a GitLab Incident and rolls back to the last release on failure; the Closer agent writes the story on the issue. In the history project the CI layer merged and released MRs !1–!3 (v0.1.0–v0.1.2) and handled Incident #3: chaos switch → monitor red → incident → rollback to v0.1.1.

How we built it

GitLab Duo Agent Platform: 5 custom flows (flow registry v1, ambient), 4 custom agents, 5 triggers, Code Review with custom instructions, AGENTS.md / agent-config.yml, and a read-only MCP server for the Incident Responder. One 12-stage .gitlab-ci.yml plus scripts/ (policy, auto-merge, monitor, incident, rollback, journey card, SCI, receipts page). The application, pulse, is a small FastAPI site-health monitor with tests, a container, a wheel and two environments. All created after 2026-10-05, MIT, 153 unit tests.

What the live drill found

On 2026-10-14 we ran two failure scenarios in the judged project to give the other three flows real work.

Security loop. A human opened MR !2 pinning fastapi==0.125.0. The Reviewer flow (F2) answered HUMAN REQUIRED, citing §2.2 and §3.3. pip-audit failed pipeline 2945456466. The Security Fixer flow (F3) opened fix MR !3 (fastapi==0.143.0), and F2 approved it. A human merged it (§3.2); auto-merge then merged !2. The vulnerable pin never reached main.

Incident loop. The monitor, pointed at an always-503 URL, failed. The incident job opened Incident #3. The Incident Responder flow (F4) posted the RCA 81 seconds later. It named the cause, a misconfigured probe target, and said a rollback would not help.

Three things broke, each fixed the same day (commits in docs/DRILL-2026-10-14.md):

  1. The gate held a correct security fix. For an MR into a feature branch, the §3.3 "new findings" baseline was empty; it now also includes the default branch.
  2. A deterministic label could override the reviewer agent. policy-check labelled the MR approved over F2's HUMAN REQUIRED. The agent's verdict now decides.
  3. The automatic rollback was refused: "Insufficient permissions to set pipeline variables" (our role is Developer). It now runs on a rollback/<tag>/incident-<iid> branch with no variables. On 2026-10-16 it ran live: after release v0.1.3, the monitor failed again, the incident job opened Incident #6 and started the rollback pipeline on rollback/v0.1.2/incident-6, and production was rolled back 2 min 8 s after the monitor failed: zero human touches, RCA by F4, incident skipped by the Planner.

Run 4, hands-off, after the fixes. A human filed issue #4 at 07:29Z. MR !4 merged at 07:39Z and production deployed at 07:47Z: 18 minutes, zero human touches. But GitLab Duo Code Review had left a valid finding on the tests, and the gate merged past it. Unresolved review threads now hold the merge (AUTOPILOT §3.7).

Run 5, the follow-up, not hands-off. Issue #5 asked for that missing test. The Planner flow opened MR !5 (test-only, +30 lines), F2 approved it, and Code Review "found nothing to comment on". Then the pipeline needed a human twice: a container-registry HTTP 500 failed build-image, nothing retried it, and the MR waited 75 minutes (registry-bound jobs now retry such errors); then two of our fixes interacted, the gate's baseline became a scanner-free schedule run and pre-existing findings looked new (it now skips such runs). After a human rebase, !5 merged and reached production 1 h 40 min after filing.

The 10-14 incident had also woken the Planner flow (every new work item fires its trigger); it now skips incidents.

AI > Sessions need a signed-in member. The judged project's deploys are dry runs (no Render key); real deployments are in the history project, whose monitor is paused.

What's next

Canary percentages as policy, publishing the flows and agents as public AI Catalog items, and a trigger path that needs no CI hand-off.

Built With

  • docker
  • fastapi
  • gitlab
  • gitlab-ci
  • gitlab-duo
  • gitlab-duo-agent-platform
  • mcp
  • python
  • release-cli
  • render
  • semgrep
  • sqlite
Share this project:

Updates

Submission history