Agents ship to production. A blast-radius budget decides how far they can go.
Repository mirror. The autonomous loop runs on GitLab Duo Agent Platform; the verified end-to-end run and nine-stage pipeline live in the GitLab project. This GitHub mirror runs the deterministic verification suite on every push.
Radius is a nine-stage autonomous delivery loop for GitLab Duo Agent Platform. One human creates a work item. From there, agents plan, open a merge request, run the nine-stage pipeline, pass security gates, merge, deploy a canary, measure it against an error/latency/spend budget, and either promote or roll back — with a JSON evidence pack for every decision.
The boundary is not a prompt. It is autonomy.yaml, a
versioned contract enforced by policy/check.py in CI and
read by the agents.
Built for GitLab Transcend — Life After Code, Path A (Start Fresh), Hands-off autonomy. No Google Cloud dependency.
- 90% of developers use AI, but 30% report little or no trust in its output (DORA 2025).
- 46% distrust AI accuracy versus 33% who trust it; only 3% highly trust it (Stack Overflow 2025).
- GitHub's own coding agent cannot mark a PR ready, approve or merge; a human must do it (GitHub Docs).
- GitLab has no time-based triggers and bots cannot start flows; the documented workaround needs a long-lived human PAT (gitlab-org/gitlab#590618, Triggers).
Agents are capable enough to write the code. The missing piece is a way to let them finish the job without asking a human to be the merge button — and without trusting them blindly when production disagrees with CI.
Full evidence and gap analysis: docs/EVIDENCE.md.
human creates ONE work item
│
▼ trigger: work item created
┌───────────────────────┐
│ Triage & Plan │ reads autonomy.yaml, writes the change,
└──────────┬────────────┘ opens branch + merge request, posts the plan
▼ trigger: merge request created
┌───────────────────────┐
│ Release Captain │ policy check → merge via Git credential
└──────────┬────────────┘ → watch pipeline → read canary evidence
▼ pipeline
plan → create → verify → secure → package → release → configure → monitor → govern
│ │
│ ├─ canary against the stable revision
│ ├─ error/latency budget
│ └─ rollback + /health proof
▼
evidence/canary.json
evidence/REPORT.md
Every stage is a real job in .gitlab-ci.yml; the stage table
with one evidence link per stage is docs/STAGES.md.
spec:
service:
environment: production
data_class: internal
budgets:
error_rate_max: 0.02 # 2%
latency_p95_ms_max: 800
spend_usd_per_day_max: 5.00
change_lines_max: 400
blast_radius: canary
canary_traffic_percent: 25
freeze_windows:
- name: month-end-close
starts_at: 2026-10-30T22:00:00Z
ends_at: 2026-11-02T02:00:00Z
escalation:
require_human_for: [freeze_window, budget_breach, data_class_violation]policy/check.py is a deterministic, dependency-light gate:
python policy/check.py --action promote --error-rate 0.60
# exit 2, "error_budget: error_rate=0.600 limit=0.020"The same file is read by the agents, so the soft gate and the hard gate cannot drift apart.
- A human creates one work item from the Radius ship template.
- The triage flow posts a plan that quotes the real budgets and chooses
PROCEEDorESCALATE. - The Triage flow commits the smallest change to a branch and opens the MR.
- The Release Captain checks the contract and merges through the Git credential available to the flow.
- The pipeline builds a wheel, publishes it, runs a canary against the previous published revision, injects a controlled fault, and evaluates the budget.
- The policy denies promotion. The harness stops the candidate, restarts the
previous revision, and proves it with
/health. - The Release Captain reads
evidence/canary.jsonand comments the rollback with the live revision and the policy reason.
Then the presenter runs the healthy canary job manually to show the same loop promoting a good revision. Two outcomes, one contract.
python -m pytest -q # 16 tests
ruff check . # clean
python scripts/canary.py --scenario breach --requests 20
python scripts/canary.py --scenario clean --requests 15
python scripts/stage_report.pyMeasured locally on 26 Oct 2026:
| Run | Result |
|---|---|
| End-to-end breach | Issue #3 → Triage session 10056015 → MR !9 → Release session 10056111 → pipeline 2989901218: 16/30 failed (53.3%), policy denied, rollback verified to baseline-d5274e72 (channel baseline) |
| Earlier breach | 19/30 failed (63.3%), policy denied, rollback verified to baseline-fd56add3 |
| Healthy | 15 requests, policy allowed, candidate promoted |
| Freeze | merge denied with freeze_window reason |
Evidence files are written to evidence/ (JSON + Markdown) and uploaded by the
monitor and govern jobs.
| Criterion | What to look at |
|---|---|
| Technological implementation | real policy engine with tests, real two-process canary, automatic rollback verified by revision, nine CI stages, flow YAML linted in CI |
| Design | one contract file, one decision CLI, stage names that match the lifecycle, evidence pack a human can read in 10 seconds |
| Potential impact | directly addresses the 30–46% trust gap; lets platform teams grant merge/deploy rights with enforceable limits |
| Innovation | the unit of autonomy is a budgeted canary, not a PR; rollback is part of the agent loop, not an incident runbook |
| Presentation | one human action → visible plan → red canary → automatic rollback → evidence, in under 3 minutes |
app/ FastAPI demo service (/health, /quote, /work, /metrics, /admin/chaos)
policy/ deterministic contract engine + tests
scripts/ canary harness, config renderer, stage report, flow linter
.gitlab/duo/flows/ source of truth for the two custom flows
.gitlab/issue_templates/ship.md
autonomy.yaml the contract
docs/ evidence, stage table, runbook
.gitlab-ci.yml nine-stage pipeline
Requires Python 3.12.
python3.12 -m venv .venv && source .venv/bin/activate
pip install -r requirements-dev.txt
pytest -q
python scripts/canary.py --scenario breach --requests 20
python scripts/canary.py --scenario clean --requests 15No external services, no cloud account, no credentials.
The flow YAML in .gitlab/duo/flows/ is the source of truth, but GitLab
requires custom flows to be created in the UI (Maintainer/Owner). Exact steps,
trigger configuration and the two-trigger setup are in
docs/FLOW_REGISTRATION.md, with the full operating
runbook in docs/RUNBOOK.md.
- Production is a canary process on the CI runner, not a multi-node cluster.
- The error budget is measured over 30 requests, not a long SLI window.
- The flows need to be registered once in the UI; see the runbook.
- Radius is a reference implementation for one service, not a deployment platform.
MIT — see LICENSE.