-
-
Joule Thief: hands-off GitLab Duo agents that hold deferrable work until the grid has clean power to spare.
-
The opportunity: grids waste clean power, most post-code work can wait, and the best hours come when nobody is at work.
-
From issue to signed deployment with no human step. The one new decision in the loop is when to start.
-
@grid on issue #15: held overnight at 370 g/kWh, released Saturday 10:30 into a 0 €/MWh surplus, shipped 15 minutes later.
-
Friday 9 to Saturday 10 October against the Spanish day-ahead price: #3 and #8 released at midday, #15 held overnight.
-
A delivery pipeline on GitLab: energy test, security scans, signed receipt, canary, energy monitor and carbon accounting.
-
Eleven agent-written merge requests, merged by the agents after every gate passed, with no human step.
-
Energy is tested like correctness: the first agent-written MR cut the slowest endpoint's energy per request by 85 %.
-
For a team on its own machines: 20–30 % less carbon per work item and electricity about a third cheaper, no missed deadlines.
-
Why hands-off: office-hours agents save less and miss 10–29 deadlines per run; hands-off agents miss none.
-
All nine DevSecOps stages, each with a job the agents or the pipeline run: plan, create, verify, package, secure and more.
-
Results: replays on real British and Spanish grid data, and the live GitLab project from 9 to 17 October.
Joule Thief makes a software team's automated work cleaner and cheaper by running it at the right time. Hands-off GitLab Duo agents hold deferrable post-code work until the grid has clean power to spare, do the work, and ship it with a signed carbon receipt. Urgent work runs at once.
Measured on the live project, the first agent-written merge request cut the slowest endpoint's energy per request by 85 % before it merged, and a whole delivery pipeline uses about 2 Wh, accounted job by job on a signed receipt. For a team that runs its own machines, replays of real British and Spanish grid data on synthetic backlogs show 20–30 % less carbon per work item and electricity bought about a third cheaper, with no missed deadlines.
Inspiration
I lead AI adoption for the internal audit function of a French banking group. Every agent use case I approve adds compute, and all of it runs the moment someone files the work. Four facts make that a missed opportunity:
- Most post-code work can wait. Dependency upgrades, refactors, test matrices and full scans have deadlines in hours or days, not seconds.
- Grids waste clean power. Spain's day-ahead price was at or below zero for 760 hours between January and September 2025. Britain paid £363 m to curtail 10 TWh of renewables in 2025.
- More companies run their own compute. In Broadcom's Private Cloud Outlook 2026 (1,800 senior IT decision-makers), 56 % of enterprises run or plan production AI inference on private cloud, and public cloud's share of that work fell from 56 % to 41 % in a year. 50 % have moved some workloads back from public cloud, up from 35 % a year earlier. GitLab Duo Self-Hosted has been generally available since February 2025.
- For those companies, timing is money and carbon. They pay for every kilowatt-hour and report its emissions. Moving deferrable work into surplus hours lowers both.
The best hours often come at night or at the weekend, when nobody is there to approve a job. Capturing them takes autonomy. I wanted to measure what that autonomy is worth.
What it does
From issue to signed deployment with no human step. The one new decision in the loop is when to start.
- Surge Intake (custom Duo flow, triggered when an issue is created) sets the issue's priority and kind of work, and decides whether it can wait.
- The dispatcher on Cloud Run, ticked every 30 minutes by Cloud Scheduler, plans the backlog against each issue's deadline using the grid's marginal signal: the emissions of the next kilowatt-hour.
- @grid, the electricity grid with a seat at code review, posts every hold and every release on the issue with the numbers behind it.
- Surge Worker (Duo flow, started through the Flows API) does the work when the window opens. Claude Haiku 4.5 explores; Claude Sonnet 5.5 writes the change and opens the merge request.
- Pipeline gates run tests, four security scanners and an energy check that measures joules per request. The Carbon Reviewer flow joins only when energy gets worse or a hot line of code changes. The merge request merges itself when every gate passes.
- Signed deploy: the main pipeline signs a carbon receipt (in-toto, Sigstore), deploys a Cloud Run canary, and promotes it only if it is not hungrier per request than production. @grid then posts the carbon balance on the issue.
- Retry Guard (Duo flow) reads any failed pipeline, never retries a deterministic failure, and files a new issue for the loop to fix.
Every number in the loop comes from code. The agents triage, implement and explain.
The value for a company that runs its own machines
Hands-off against running every job at once. Carbon is net of everything Joule Thief adds. Price is the mean day-ahead price paid for the backlog's electricity in Spain. Replays of real grid data with a synthetic backlog.
- Spain: 30 % less carbon per work item in spring and 29 % less in summer. The same work bought its electricity at 9.5 instead of 14.5 €/MWh in spring, and 23.3 instead of 34.0 €/MWh in summer.
- Great Britain: 20 % less carbon per work item.
- Every kilowatt-hour moved saves 26–90 g of CO₂, depending on grid and season.
- No missed deadlines in any of the 15 runs (five backlogs, three grids).
- It knows where it pays. Work above roughly 9–30 Wh per item is worth scheduling: heavy CI, security scans, fuzzing, self-hosted inference. Smaller work runs at once.
Why it has to be hands-off
Emissions against running every job at once. Supervised agents may start work only in office hours; hands-off agents may start it at any hour. Supervised missed 10–29 deadlines per run; hands-off missed none.
Many clean hours fall outside the working day: windy nights, sunny weekends. Against office-hours approval, removing the human step is worth 7–10 extra points of carbon reduction, and it met every deadline. The gain is the weekends and the nights: matching it took someone approving work seven days a week from 07:00 to 22:00. Hands-off does that with nobody on the rota.
Proven on a live project
The whole loop runs on the public GitLab project and on Google Cloud. From 9 to 23 October it handled 24 issues and merged 12 agent-written merge requests with no human step, across 466 pipelines.
Friday 9 to Saturday 10 October (UTC), against the Spanish day-ahead price. @grid released #3 and #8 into the midday surplus and held #15 overnight for the next one.
| Issue | Filed | @grid's decision | Result |
|---|---|---|---|
| #3 Dashboard comparison is slow | Fri 08:37 UTC | Released at 09:00 into a surplus | !1 merged 09:08, live 12:02 |
| #8 Refresh pinned dev dependencies | Fri 12:06 | Released at 12:30 | !2 merged 12:36, live 13:01 |
| #15 Health endpoint should name the running revision | Fri 18:43 | Held overnight: 370 g/kWh then, 11 g/kWh expected Saturday 10:30 | Released Sat 10:30 at 0 €/MWh; !6 merged 10:36, live 10:45 |
| #16 configure:eco-mode timeout | Retry Guard, Wed 14 Oct 11:24 | High priority, no cleaner slot before its deadline: run now | !7 merged 12:36, live 12:47 |
| #24 configure:eco-mode GitLab API timeout | Retry Guard, Wed 21 Oct 09:24 | High priority, but the deadline left room: held 30 minutes, 16 → 11 g/kWh | Released 10:00 at −0.1 €/MWh; !13 merged 10:07, live 10:17 |
@grid's notes on issue #15, unedited: the hold, the release, and the carbon balance of the shipped change.
Urgent work never waits. On 14 October a price API timed out and broke a pipeline. Retry Guard diagnosed it and filed #16, and @grid ran the fix at once because no cleaner hour fit the deadline.
The live project proves the loop: @grid decides when the work runs, and the agents follow. Its CI runs on GitLab's hosted runners in us-east1 and its agents on hosted models, so the saving itself comes with a runner and the models in the grid zone @grid reads (What's next).
The submission is frozen in code from the deadline (27 October, 13:00 UTC): Surge Intake, @grid and Retry Guard keep working and the service stays live, but no agent changes main while it is judged.
Energy is tested like correctness. The first agent-written merge request cut the slowest endpoint's energy per request by 85 %, measured before merge.
Why the numbers hold
- Decisions use the marginal signal. What matters is the emissions of the next kilowatt-hour, not the average. Finland averages 39 g/kWh but about 785 g/kWh on the margin.
- Robust to the carbon model. In Spain, a price at or below zero is read as surplus renewable power (11 g/kWh), and a price above 40 €/MWh as fossil power on the margin. Moving that threshold anywhere between 20 and 80 €/MWh still leaves a 22–39 % cut. The price results need no carbon model at all.
- Robust to the backlog. Across five backlogs and three grids, hands-off beat supervised in all 15 runs.
- No hindsight. The replay sees only prices published at decision time and is scored on what the grid actually did.
- Measured where possible. Agent calls and tokens are read from each GitLab Duo session; CPU time is measured per request. Standard coefficients (EcoLogits, Cloud Carbon Footprint) convert them to energy, reported as ranges.
- Standard frameworks. SCI (ISO/IEC 21031:2024) and SCI for AI. Britain's figures use NESO's average intensity, the best free signal available there.
Lean by design
- Code first, LLM last. Plans, @grid's notes, footprints, receipts and carbon balances use no LLM. Measuring itself cut LLM calls per code change from 19 to 5.
- The right model for each step. Triage and exploration run on Claude Haiku 4.5; only implementation runs on Claude Sonnet 5.5.
- Energy regressions are bugs. Joules per request on every merge request, and an energy canary in front of production.
- No receipt, no deploy. Every deployable image carries a signed carbon receipt: its build footprint, the grid data used (with content hashes), the GitLab Duo sessions behind the change, and the month's running total checked against the budget.
- A small footprint of its own. Cloud Run scales to zero in
europe-north1(98 % carbon-free energy). Its heartbeat costs about 1.1 g of CO₂ a day.
How I built it
- GitLab Duo Agent Platform: 4 custom flows (public in the AI Catalog) and 2 custom agents. Triggers on issue creation, failed pipelines, reviewer assignment and mentions. Flows API,
model_tagsrouting, enforced tool options,coding_environment: nonefor API-only flows,agent-config.yml, and an MCP server for Duo Agentic Chat, IDE and CLI. Every flow is validated in CI against GitLab's own flow schema. - GitLab CI/CD: 9 stages, merge request pipelines, JUnit and metrics reports, SAST, secret detection, dependency and container scanning, environments, releases, auto-merge, interruptible pipelines, feature flags, schedules. Heavy security work waits for a clean window and blocks like any test: Bandit, 20,000 fuzz cases on the parsers that read outside data, and an OWASP ZAP scan of the live service. Its first run found six missing security headers; they are set now, and the scan fails if one goes missing.
- Google Cloud: Cloud Run (scale to zero), Artifact Registry with cleanup, Workload Identity Federation (no keys), Secret Manager, Cloud Scheduler, Cloud Storage for shared OpenTofu state, and a Cloud Function that unlinks billing at €5. GitLab Duo ran on Claude models on Vertex AI.
- Code: Python, standard library first; OR-Tools CP-SAT; EcoLogits; Cloud Carbon Footprint coefficients; free data from Energy-Charts, OMIE, NESO and Open-Meteo.
Challenges I ran into
- My own gate cried wolf. The energy canary blocked the first deploy three times, and each block filed an incident the agents picked up. The cause was noise: per-request CPU on Cloud Run varies by about ±30 % for the same code. The gate now compares the canary with a fresh copy of production in interleaved warm runs, and blocks only a consistent regression.
- GitLab's flow validator is stricter than the spec. It rejects
max_cycles, so I vendored GitLab's schema into the tests and kept token use down with narrow toolsets and fixed step lists. - Averages mislead. Scheduling on average intensity moves work into hours that only look clean. Every decision uses the marginal signal.
- Retry Guard filed duplicates. On 14 October the price API stayed down. Retry Guard filed one issue per failed run, three in 16 minutes (#17–#19), and Surge Worker raised the same timeout three times. The fifth failure got the fix that held, a fallback to the annual figure (#20). When the GitLab API timed out a week later, Surge Worker first raised that timeout too (#21), then added retries instead (#24). Retry Guard now checks for an open or recently fixed issue on the same job before it files, whatever the failure.
Accomplishments that I'm proud of
- A full hands-off loop on a real project, from issue to production, every step linked and still running.
- An overnight hold that ended where @grid said it would: 370 g/kWh on Friday evening, 0 €/MWh on Saturday at 10:30.
- A carbon tool that tells a team which work is worth scheduling, and proves it on its own footprint.
What I learned
Autonomy pays a climate dividend when agents may wait and the work runs on the grid they watch. Self-hosted runners and models are where that happens, and they are where more and more compute now runs.
What's next
- The self-hosted deployment: a self-managed runner and GitLab Duo Self-Hosted in the grid zone the dispatcher reads, so the agents' own inference moves with the rest of the work.
- Metered energy on that hardware (RAPL and NVML counters).
- More grids through WattTime's marginal signal, and the
grid-windowCI/CD Catalog component for teams that want the scheduling without the agents.
Sources: OMIE day-ahead prices (Spain); edie, "Renewable energy curtailment reached record high in 2025" (Britain); Broadcom, Private Cloud Outlook 2026, as reported by Redmond Channel Partner, 25 June 2026; GitLab 17.9 release notes (Duo Self-Hosted). Method and results: docs/METHODOLOGY.md, docs/results/.
Built With
- claude
- cosign
- ecologits
- fastapi
- gitlab
- gitlab-ci
- gitlab-duo-agent-platform
- gitlab-duo-flows
- google-artifact-registry
- google-cloud
- google-cloud-functions
- google-cloud-run
- google-cloud-scheduler
- google-secret-manager
- in-toto
- model-context-protocol
- opentofu
- or-tools
- python
- sigstore
- vertex-ai
- workload-identity-federation
