Inspiration

Every merge request starts a pipeline: installs, a test matrix, an image build, scans. All of it runs on cloud machines that draw power from a real grid, and none of that shows up in the merge request. Teams treat a slow pipeline as a nuisance. Nobody treats its carbon as something to fix, because nobody sees it. We wanted the carbon of a pipeline to behave like a failing test: visible in the merge request, with a clear owner and a clear fix.

What it does

GreenGate gives every pipeline a carbon budget.

  • A CI/CD component (greengate:measure) computes each pipeline's Software Carbon Intensity (ISO/IEC 21031:2024) from real job durations, runner sizes and the CPU each job ran on. GitLab's hosted runners mix Intel and AMD CPUs inside one pipeline, so the budget is checked on reference hardware: a cheaper CPU draw can't pass a pipeline or count as a saving.
  • A merge request pipeline over its budget fails, like a broken test. That failure fires a GitLab Duo trigger (Pipeline events: Failed). A three-agent custom flow takes over: the auditor reads the carbon report artifact, the optimizer edits the CI config, checks it with the CI linter and opens one merge request without touching any security job, and the reporter posts a carbon receipt and a line in a carbon ledger issue.
  • A person reviews and merges. The next pipeline on main publishes the receipt as a GitLab release and updates a Pages dashboard.
  • A second flow plans ahead: create an issue asking for a carbon budget and it proposes budgets per pipeline type in a merge request and opens a task per hotspot.
  • Any other failure gets one model call and a SKIP. The first came after a broken unit test of ours, and on 19 Oct a security scan that got stuck started a second one.
  • Every main pipeline whose tests and code scans pass also ships the demo service to Google Cloud Run in Montreal. We picked that region on purpose: in Google's 2025 data its grid is the cleanest of all Google Cloud regions, 11.36 gCO2e/kWh, while us-east1, where our CI runs, sits at 579.44. The service scales to zero when nobody calls it. Live at https://bookshelf-418348230685.northamerica-northeast1.run.app

It all ran live on GitLab.com. Merge request !1 failed at 0.54 g CO2e against a 0.35 g budget. Three minutes later GreenGate opened !2 with nine changes. Its pipeline measured 0.25 g. The feature, measured again after the merge, passed at 0.26 g.

Does the saving hold up?

We wrote the benchmark plan into the repo before the first run (docs/benchmark.md), then ran 34 pipelines, old and new config, one at a time in alternating order, with no exclusions.

  • Code change, 10 runs per arm: median 0.4753 g to 0.2385 g per pipeline, -49.8% (95% bootstrap interval -50.8% to -46.7%).
  • About four fifths of that is lighter testing on merge requests: one Python version instead of four, with all four still on main. Counting only identical work, the cut is -17.5% (-19.8% to -12.9%).
  • Per merged change, at equal function, the fix saves 0.378 g.

The demo CI was written wasteful on purpose, so a lean CI has less to cut. The benchmark also caught a mistake by our own agent: its path rules counted the service README as code, so docs-only commits still ran the tests. We recorded it as a deviation and the next flow version forbids such paths.

The agent's own footprint

GitLab records every model call of a flow, so we priced each one. One full run comes to 6.4 to 143 g CO2e, 13.7 g at our central estimate (model calls estimated from open models on H100 nodes, since no provider publishes per-call figures for Claude). At equal function it pays that back after about 37 merged changes, 379 at the high end, and SKIP runs stretch that (the repo has the numbers). The planner turned out to be our most expensive run (159 g central) because it read whole reports into its context. We report it apart and wrote down the fix: let CI compute the summary and give the agent one small file.

How we built it

Python (stdlib only at runtime) for the calculator, compare and policy tools, about 850 tests. A reusable GitLab CI/CD component installs GreenGate from a pinned source archive. Coefficients come from Cloud Carbon Footprint, Google's 2025 grid data and the SCI spec, all cited in docs/methodology.md. The flows are GitLab Duo Agent Platform custom flows with schema-validated YAML. Releases, the Package and Container Registries, SAST, secret detection, dependency and container scanning, Code Quality and metrics reports are all wired in.

The deploy job signs in to Google Cloud with its own GitLab OIDC token through Workload Identity Federation, so we never created a service account key. Google only accepts that token from our main branch. A spend cap of 50 CZK a month pauses the service if it ever gets that far. GreenGate measures the deploy job like any other job: it added 0.09 g to the first main pipeline that ran it, and that pipeline came in at 0.75 g, over its 0.69 g budget. On main that only warns, so we left it visible. The service's own energy on Cloud Run isn't measured, and we don't count the region as a saving.

Built by Karen Yezzhev with Claude Code (Anthropic) as the AI coding agent.

Challenges we ran into

Hosted runners changed CPU from job to job, so the same pipeline looked a third cheaper or half again dearer depending on the draw. We moved every budget and every comparison onto reference hardware. Pricing the agent honestly was harder still. There are no official energy figures for Claude, so we publish a low, central and high estimate and the method behind each.

What we learned

A carbon number only changes behaviour when it sits where decisions happen: in the merge request, with a failing check and a ready fix. And an agent that cuts emissions has to pay for its own, so the payback belongs in the same report as the saving.

What's next

A CI job that summarises the reports for the planner, budgets that tighten as the median drops, carbon aware scheduling for heavy jobs, and the component in the CI/CD Catalog so any GitLab project can add GreenGate in three lines of YAML.

Built With

  • claude
  • cloud-carbon-footprint
  • docker
  • fastapi
  • gitlab-ci
  • gitlab-duo-agent-platform
  • gitlab-pages
  • google-cloud-run
  • python
  • sci
Share this project:

Updates

Submission history