-
-
One issue in: Duo agents plan, code, review and test; at every gate the Governor sets the level as min(policy, trust, risk, health).
-
Two real runs, one policy rule: docs shipped hands-off, a cart bug took one approval, and login code needs a human at every gate.
-
Real trust history: five approved docs ships raised trust from 50 to 70, so the next docs change went from issue to production hands-off.
-
The real escalation card from MR !8: risk, reasons and the binding constraint, then one comment to approve, reject or allow.
Inspiration
AI agents can now write code in seconds. The hard part starts afterwards: someone still has to decide whether a change is safe to merge, safe to stage and safe to ship. Teams end up at one of two extremes. Either they let agents act freely and hope nothing breaks in production, or they approve every step by hand and lose the speed agents promise.
Neither matches how good teams already work. A new colleague starts supervised and earns freedom one clean change at a time; a typo in the docs never needs the same scrutiny as a change to the login system; and regulated code always needs a human, however good the author is. We wanted agents to be governed the same way: autonomy that is earned, explained and audited.
What it does
PostCode handles everything after the code is written (review, testing, security scanning, merge and release) with GitLab Duo agents, and decides for every change, at every step, how much freedom those agents get.
A change passes through gates: G2 merge, G3 staging, G4 production canary and G5 promote. At each gate the Governor returns one of three levels:
- L3 Hands-off: the agents continue alone.
- L2 Supervised: the agents continue, but a human approves production.
- L1 Assisted: a human approves every gate.
The level is the lowest of four inputs:
$$\text{level} = \min(\text{policy},\ \text{trust},\ \text{risk},\ \text{health})$$
- Policy: policy as code per path. For example,
auth/is SOX-tagged with a production ceiling of L1, so no amount of trust overrides it. - Trust: earned per agent role and per service. +4 for every clean ship, and lost fast on rollbacks, incidents or rejections. L3 needs 70.
- Risk: a 0–100 score from the files touched, the size of the change, coverage of the changed lines, security findings and whether it deploys to production.
- Health: the service's remaining error budget.
When a human is needed, the Governor posts an escalation card on the merge request. The card shows the risk, the reasons and the binding constraint. The approver replies /postcode approve, /postcode reject or /postcode allow (which approves and proposes a narrow, 14-day policy rule as its own merge request). Every decision is an audit record pinned to the exact commit, and merges are SHA-pinned, so an approval only ever applies to the code that was reviewed.
Real runs in the hackathon project
Every run started from an issue written in plain English:
- Earning trust (MR !1 to !5): five docs changes, each approved once at production, raised the docs agents' trust from 50 to 70.
- Hands-off (MR !7): the next docs change scored risk 19/100 with trust above 70. Every gate from merge to promote returned L3: merged, staged and released with no human involved.
- Supervised (MR !8): a real shopping-cart bug (one cart line could exceed 99 items), fixed with new tests. G2 merged it at L2; G4 stopped with an escalation card because the agents had no trust on checkout yet. One comment resumed the pipeline.
How we built it
- GitLab Duo Agent Platform: three custom flows. Ship (triage → builder → reviewer → test agents, from an issue to a merge request), Fix Pipeline (repairs a failed merge request pipeline) and Incident (writes the incident note after a failed or rolled-back deploy). Each flow has its own service account, which can never approve.
- The Governor: a deterministic FastAPI service in Python (no LLM in the decision path). It provides the gate API, the trust ledger, the policy engine with scoped allows, a GitLab webhook for
/postcodecommands, and an MCP server so agents can ask the Governor why it decided something, using their own read-only token. Storage is in memory, a JSON file or Firestore. - The governed pipeline (
.gitlab-ci.yml): plan-check, build, test with coverage, SAST, dependency and secret scanning, then gate jobs that call the Governor through a small CLI (postcode-ci). The same CLI has anscicommand that computes the Green Software Foundation SCI per shipped change from pipeline job lists. - Infrastructure: Terraform for Cloud Run canaries at 5%, 25% and 100% with automatic rollback on p95 latency or error-rate regression, Workload Identity Federation (no service-account keys), Firestore and Secret Manager, with budget and instance caps.
- Quality: over 1,100 tests across the Governor, the CI tools and the sample services, a Docker end-to-end check, ruff lint, and a written decision record for every non-obvious design choice.
Challenges we ran into
Running the full loop on real infrastructure exposed problems that unit tests never would. Each one was fixed with tests, a review and a written decision record:
- No protected branches. The hackathon workspace doesn't allow branch rules, and PostCode relied on them to keep the Governor token away from untrusted branches. We added an explicit
same-projectmode: the merge gate accepts an unprotectedpostcode/*branch only from this project, never from a fork, and the trade-off is disclosed. - Who is the author? Duo lists the human who started a flow as the merge request's author, so the "authors cannot approve their own change" rule blocked the only human. The Governor now asks GitLab's GraphQL API who actually made each commit, and allows the approval only if agent accounts made every one, including the commit the decision was made for.
- Merged-results pipelines ran on a temporary merge commit, so the SHA-pinned merge was rejected. A timed-out merge call left a change stranded; merges now retry after transient failures.
- Silent L2 caps. GitLab's dependency-scanning template overrode the artifact paths that carried the scan report, so every gate saw "no scan results" and capped itself at L2. Test files counted as "uncovered code", and agent-written tests mapped to a service that could never earn trust. Hands-off only became possible after all three were fixed.
- Staying free. No cloud credits were available, so the Governor runs locally behind a tunnel, in a "local mode" designed into the pipeline itself.
Accomplishments that we're proud of
- A real hands-off release earned through real history: five approved docs changes, then one that went from issue to production with nobody touching it.
- The same agents and the same pipeline give three different answers for a docs change, a cart bug and a regulated login change, and explain each one.
- Fail-closed by design: an unreachable Governor, a missing scan report or an unknown author always means "ask a human", never "proceed".
- Honesty built in: every limitation we found is written into the submission and the decision records, not hidden.
What we learned
- Governance has to be deterministic. Agents can be creative; the thing that decides whether they may act must be predictable, explainable and reproducible from its inputs.
- Bind every decision to a commit. Approving "a merge request" is not enough; approving an exact SHA is what makes an audit trail mean something.
- Real platforms disagree with your assumptions, about authorship, merge refs, template overrides and branch permissions. Live end-to-end runs found what 1,100 tests could not.
- Measure the right thing. One mis-measured input (coverage of test files) was enough to block autonomy that had been fairly earned.
What's next for PostCode
- Switch on the cloud path: Cloud Run canaries with automatic rollback, which are built and tested but were not deployed for this submission.
- Pipeline in a protected governance project, so agent branches can never edit the pipeline that governs them, plus approval rights restricted to approvers and the Governor.
- Per-service dependency scanning: GitLab's Python analyzer only scans the first project directory it finds, so today only
auth/gets dependency scanning. - Turn on the read-only dashboard (trust history, decisions and audit trail with GitLab sign-in), and support multiple approvers with separation of duties for SOX paths.
- Learn policy from history: suggest scoped allows when a path keeps getting approved with no issues.
Limits we disclose
The demo runs the Governor locally, so gates decide live but nothing is deployed to real servers. Because of hackathon workspace permissions, protected branches and a separate pipeline project aren't available, which means an agent branch could in principle edit its own pipeline. Every such edit stays visible in the merge request. The full write-up is in docs/submission.md.
Log in or sign up for Devpost to join the conversation.