-
-
EcoGate: every merge request gets a Carbon Receipt and an AI release review. A human approves every step.
-
After the fix, Release Guardian re-reviews and says READY TO SHIP. Only a human merges.
-
Carbon Receipt on MR !4: 1 of 5 test files, 0.16 g CO2e, 42% less than main. Then a human assigns Release Guardian to review.
-
MR !4 merged by a human after the agent's review: tests and security scans passed, then the main pipeline passed.
Inspiration
Pipelines run thousands of times a day. Most teams re-run every test on every change and build container images they never ship. Nobody sees what that costs the planet, because carbon is invisible at the one moment it could be reduced: inside the merge request.
I hold a certificate in sustainable finance. In finance, what gets measured and disclosed gets managed, and emissions reporting changed how companies invest. I wanted the same thing for software delivery: a receipt on every merge request, in a recognised standard, sitting next to the security results, at the moment a human decides to ship.
At the same time, tests and scanners pass while real bugs still slip through, and reviewers rarely have time to read every diff. So EcoGate puts both questions in one place: is this change safe to ship, and what did it cost to check?
What it does
Every merge request passes through EcoGate before it ships.
- Carbon-aware pipeline. EcoGate reads the diff and runs only the tests that change can affect (on our demo MR, 1 of 5 test files). Config or dependency changes still run the full suite. SAST and secret detection always run. The container image is built only on
main, never on merge requests. - Carbon Receipt. A comment on the MR with the energy, grid intensity, embodied emissions and the SCI per pipeline (Green Software Foundation, ISO/IEC 21031:2024), compared with the last
mainpipeline. It also shows what the same work would emit in the greenest Google Cloud region. The receipt updates in place on every push. - Release Guardian (a custom GitLab Duo Agent Platform flow). A human assigns it as reviewer or mentions it. It reads the MR, the diffs, the Carbon Receipt and the security findings, posts inline comments with one-click suggested fixes, and gives a verdict: ✅ READY TO SHIP, ⚠️ NEEDS CHANGES or ⛔ BLOCKED, with a checklist of what is left for the human. It never merges, approves or deploys.
- After merge: the deploy region is picked from Google Cloud's carbon data, the Cloud Run deploy is manual (human approval), and a health check opens an incident issue if the service fails.
What happened in the demo (MR !4, unedited run)
- A new
/api/compareendpoint was pushed. Lint, tests and both security scanners passed. - The pipeline ran 1 of 5 test files: 0.16 g CO₂e, 41% less than the last
mainpipeline. - Release Guardian found two bugs the tests missed: an unknown region raised a
KeyError(HTTP 500), and a region with zero grid intensity would raise aZeroDivisionError. It posted a one-click fix that returns HTTP 400 for both, and said NEEDS CHANGES. - I applied the fix with one click. The pipeline re-ran and the receipt updated.
- I mentioned the agent again. It checked the fix commit, said READY TO SHIP, and suggested a unit test for the 400 path as an optional follow-up.
- I merged.
The agent only called the tools it needed. It skipped the pipeline-error and finding-detail tools because the pipeline passed and there were no findings.
How I built it
- Release Guardian is a custom flow (YAML v1, ambient environment) with one
AgentComponent. It uses the GitLab toolsget_merge_request,list_merge_request_diffs,list_all_merge_request_notes,list_security_findings,get_security_finding_details,get_pipeline_errors,get_repository_file,create_merge_request_diff_noteandcreate_merge_request_note. It is triggered by Assign reviewer and Mention. The prompt limits it to at most three inline suggestions and one structured report, and forbids merging, approving or deploying. - The carbon engine (
carbon_ci/, Python) gets job durations from the GitLab API and calculates energy with the Cloud Carbon Footprint method. It takes grid intensity from Google Cloud's published per-region data and adds embodied emissions, then writes the SCI. - Test selection maps changed files to the test files they can affect, with a safe fallback to the full suite for anything global (CI config, dependencies,
conftest.py, data files). - The pipeline covers verify, secure, package, configure, deploy, monitor and report stages, with GitLab SAST and Secret Detection enabled on MR pipelines (
AST_ENABLE_MR_PIPELINES). - A Flask dashboard shows recent pipeline receipts, a what-if estimator and Google Cloud regions ranked by grid intensity. It is containerised for Cloud Run.
- 39 pytest tests. MIT licensed.
DevSecOps lifecycle coverage
| Stage | How EcoGate touches it |
|---|---|
| Create | Release Guardian reviews the diff and posts one-click code suggestions |
| Verify | Carbon-aware test selection; JUnit report on every MR |
| Secure | GitLab SAST + secret detection on MR pipelines; the agent explains findings |
| Package | Container image built only on main and tags |
| Configure | Deploy region chosen from Google Cloud's carbon data |
| Release | Ship verdict from the agent; manual, human-approved Cloud Run deploy |
| Monitor | Post-deploy health check; opens an incident issue on failure |
| Govern | Carbon Receipt + agent report kept on every MR as an audit trail |
Challenges I ran into
- Security scanners skipped MR pipelines by default. My first receipts looked much better than reality because SAST and secret detection weren't running on merge requests. I enabled them on MR pipelines and re-measured. Honest numbers mattered more than big ones.
- Test selection had an accumulation bug: one changed file could pull in tests that belonged to another. I fixed it and added tests for it.
- Keeping the agent in its lane. It took several prompt iterations to get one structured report, at most three suggestions, and a clear rule that it never takes a shipping action itself.
Accomplishments I'm proud of
- The agent caught a real second bug (division by zero) that I had not planted.
- Every number on the receipt can be traced to a published method and dataset, and every coefficient can be overridden with a CI variable.
- The whole loop (pipeline → receipt → agent review → one-click fix → re-review → merge) runs inside GitLab, with a human approving every step.
What I learned
- An agent is most useful when it explains and proposes, and a person decides.
- Carbon data is only actionable if it appears where the decision is made, not in a quarterly report.
- Building with the Duo Agent Platform: flows, triggers, tools and service accounts.
What's next
- Use real runner telemetry (Eco CI energy measurements) instead of estimated power.
- Time-shifting: defer non-urgent pipelines to hours with cleaner grid power.
- A carbon budget per project, with the agent flagging MRs that exceed it.
- Learn the test map from coverage data instead of file naming rules.
Built With
- docker
- flask
- gitlab
- gitlab-ci
- gitlab-duo
- google-cloud
- google-cloud-run
- green-software
- pytest
- python
Log in or sign up for Devpost to join the conversation.