What it does

CarbonWindow is a scheduler for compute that has a deadline but no fixed start time — batch jobs, model training runs, backups, CI pipelines. You give it a job length and a deadline; it returns the half hour to start, chosen for the lowest grid carbon intensity that still meets the deadline, and it reports what that choice would have saved.

$ python -m carbonwindow.cli plan --duration 1h --deadline 2026-10-21T09:00Z
start 2026-10-21T02:30Z  mean 71.5 gCO2/kWh
vs. starting now (113.0 gCO2/kWh): -36.7 %

Why the grid, and why half hours

The GB grid is not equally dirty all day. Over the 90-day window we measured, the daily mean carbon intensity ranged from 48.6 to 209.8 gCO2/kWh — a 4.3x spread between the cleanest and dirtiest day — and there are further swings inside each day. Shifting a flexible job by a few hours is free carbon.

How it works

  1. Data. 90.19 days of National Grid ESO Carbon Intensity data for the GB national average: 4,329 consecutive half hours, 2026-07-21 23:30Z → 2026-10-20 04:00Z, 100 % coverage, 0 gaps interpolated. Mean 115.72, median 110, max 247 gCO2/kWh. The snapshot is committed in the repo (data/ci_90d.json), so every number below is reproducible offline.
  2. Two information sets. Oracle: decisions made with hindsight (the ceiling). Forecast: decisions made with the day-ahead forecast that was actually published for that slot (what a real deployment would know). Forecast quality in the window: MAE 12.56, median absolute error 8.0, p95 39, max 165 gCO2/kWh.
  3. Exact optimisation, not a greedy peek. Choosing the minimum-mean window of a fixed length over a horizon is a sliding-window problem: prefix sums plus a monotonic deque find it in O(n) with no legal window missed. The test suite checks the optimiser against brute force on random series.

Measured results (medians over every legal start time)

job deadline forecast-driven perfect foresight
30 min 6 h 3.36 % 12.61 %
1 h 12 h (reference) 18.91 % 25.93 %
1 h 24 h 34.51 % 39.76 %
2 h 24 h 35.29 % 38.06 %

At a 1.0 kW load a 1 h job is 1.00 kWh, so the reference condition saves about 19 gCO2 per job at the median.

The bad news, printed next to the good

A median is not a guarantee, and the forecast is sometimes wrong. In the reference condition 13.8 % of arrivals ended up worse than starting immediately, and the worst single arrival was -108 % — the forecast promised a clean half hour and the grid delivered a dirty one. The number of arrivals that lose carbon falls as the deadline lengthens (10.2 % at 24 h) and rises when the window is short (23.7 % at 30 min / 6 h). The report prints this tail rather than hiding it, because a scheduler that silently makes things worse is not a climate tool.

What was hard

  • Separating forecast from hindsight. It is easy to compute an impressive number with hindsight and call it a saving. We replay both information sets and label them.
  • A single 0 gCO2/kWh reading (2026-08-06 11:00Z) makes the "best day" of the naive ranking an artefact. We kept it in the headline numbers and added a sensitivity block that excludes it: the median for that day drops from 56.8 % to 25.2 %.
  • Windows must be legal by construction: a window that runs past the deadline is not a saving, it is a missed deadline.

Try it out

Built with

Python (standard library only), HTML + hand-written SVG for the report, JSON for the data snapshot, ffmpeg + Pillow for the demo video, pytest for the test suite.

Built With

Share this project:

Updates

Submission history