Inspiration
Coding agents write code fast now. The rest of the lifecycle (verify, secure, release, watch the deploy, prove who approved what) is still manual, or fully automated with no human gate. engel guardian borrows one rule from a personal assistant project of mine: observe, propose, verify, report, and apply only after approval. The human comes first, a Guardian policy check second, and the worker agents third. (Pattern only. None of that project's code, servers, models or data is in this repo.)
What it does
A GitLab Duo custom flow starts when the owner adds engel guardian as a reviewer on a merge request:
- Observer reads the merge request, lists the files it touches and sorts the change by type.
- Verifier reads the CI results (tests and lint) and sums them up as pass or fail for Guardian and the owner.
- Guardian checks the change against guardian/policy.yaml (protected paths, owner approval label, token-like strings) and says no, with reasons, when policy breaks. The same policy runs as the guardian-policy CI job. Example: MR !1, job #17035261468, VERDICT: BLOCK for a protected path and something that looks like a GitLab token.
- Owner gate: the flow stops at approve, modify or reject. On MR !1 the owner approved, and the Reporter posted its note. Approving only posts a note; the flow has no merge, tag or deploy tools. This gate is separate from the production lock.
- Reporter posts one short note on the merge request after the owner approves. The pipeline does the shipping: package a versioned tarball, record the feature flag, deploy to staging with a smoke check, write a health report, and write an audit report. Production has its own lock, separate from the Duo flow's owner gate: the deploy-production CI job stays on manual and only the owner can run it.
Lifecycle stages covered
Really run on the public Showcase repo: Verify, Secure, Package, Configure, Release (v0.1.0), Deploy (staging; production waits on the owner), Monitor and Govern. Full main runs: pipeline #2951928453 (earlier), pipeline #2964084866 and pipeline #2968319605 (newest). On #2964084866, tests, lint, scans, package, configure, staging deploy, health check and audit report all passed, and deploy-production stayed on manual and was not run. The newest, #2968319605, is green, and deploy-production is still manual and has not been run. Plan and Create run through the Duo flow (flow 1018301). Its first run, on MR !1, went Observer, Verifier, Guardian (BLOCK) and paused at the owner gate (Duo session 9612922). On Oct 19 the owner pressed Approve, and the Reporter posted its note on MR !1: https://gitlab.com/gitlab-ai-hackathon/transcend-october-2026/43110153/showcase/-/merge_requests/1#note_4047061567. Approving only posts a note, so nothing merged or deployed. deploy-production is a separate manual job and still hasn't run. The same block shows in the guardian-policy job log #17035261468 (VERDICT: BLOCK).
How we built it
GitLab Duo Agent Platform (one custom flow: observer, verifier, guardian, owner gate, reporter), GitLab CI/CD, semgrep-sast, secret_detection, a custom guardian-policy job reading guardian/policy.yaml, and small stdlib Python scripts for packaging, smoke checks, the configure report and the audit report. The feature flag is a CI/CD variable (FEATURE_GREET_EXCLAIM, off by default). The sample web service lives in the same repo.
Challenges
- GitLab Protected environments weren't available on this hackathon project, so the production lock lives in CI: a rule that only creates deploy-production for the owner's login, plus a guard in before_script.
- Guardian blocked our own work. MR !2 edited .gitlab-ci.yml, a protected path, so it sat blocked until the owner added the approval label. Its secret check also flagged our README because a docs example had a fake token string in it, so we rewrote the example in plain words instead of weakening the check.
- GitLab wouldn't load the Duo flow until its schema was fixed: the first try used fields the current flow schema no longer accepts (require_tool_approval, pre_approved_tools, on_tool_approval_request), and dropping them fixed it (commit 008afc7f, MR !3). After that it loaded and was turned on as the flow "engel guardian", triggered by assigning a reviewer.
- Duo's own workload job logs aren't public, so judges can't open them. The public evidence lives on MR !1, the guardian-policy job log and the main pipelines instead.
- The owner's own GitLab group is on the Free tier, which doesn't include Duo Agent Platform, so everything was built in the hackathon workspace project.
Accomplishments
- First main run with package, staging deploy and health check all green: pipeline #2947372611 (Oct 14).
- Tagged release engel guardian v0.1.0 (pipeline #2947477071).
- Every delivery stage, including Configure and Govern, on one main run: pipeline #2951928453 (Oct 16).
- A second main run with every step passing: pipeline #2964084866, with deploy-production left on manual and not run.
- README live on main through MR !4. Guardian passed it; it needed no owner label because only README.md changed. The README's public evidence for the owner gate came in later through MR !5 (merge c5422359).
- First Duo flow run: Guardian blocked MR !1 inside the flow, the flow paused at the owner gate, the owner approved, and the Reporter posted its note on MR !1 (session 9612922).
What we learned
- Duo Agent Platform flows can really stop and wait for a person. The first live run on MR !1 (session 9612922) went Observer, Verifier, Guardian (BLOCK), a pause at the owner gate, the owner's Approve, and the Reporter's note. That pause is the "apply only after approval" rule in practice.
- A safety check that blocks its own team's README is doing its job. The fix belongs in the content, not in a looser rule.
- Keeping production as a manual CI job adds a second hard lock that doesn't depend on the agents.
What's next
- Keep production manual-only, and run it only after an explicit owner OK.
- Reuse the same flow on new merge requests, so every change goes through Observer, Verifier, Guardian, the owner gate and Reporter.
Links
- Repo (public, MIT)
- Pipeline history
- Guardian block example: MR !1
- guardian-policy job log #17035261468 (VERDICT: BLOCK)
- Earlier full main run: pipeline #2951928453
- Newest main run (deploy-production on manual, not run): pipeline #2968319605
- Second full main run: pipeline #2964084866
- README on main: MR !4
Built With
- gitlab
- gitlab-ci
- gitlab-duo
- python
- semgrep
- yaml
Log in or sign up for Devpost to join the conversation.