Inspiration

Electricity is not equally dirty all day. On Great Britain's grid over the last twelve months, carbon intensity ranged from 20 to 282 gCO₂/kWh, a 13.8x swing between the cleanest and dirtiest hour of the year.

A huge share of demand does not care when it runs. An EV charging overnight, a dishwasher, a CI queue, a model training job: these have a deadline, not a start time. Today almost all of it runs whenever it was switched on, emitting entirely avoidable CO₂ for no benefit to anyone.

The reason carbon-aware scheduling has not spread is not that nobody thought of it. It is a data problem: only a handful of grids on Earth publish an open, real-time carbon-intensity forecast. Britain does. California, Texas, India and Australia do not. Without a forecast, there is nothing to schedule against.

What it does

GridShift's core insight is that you do not need a carbon API. You need weather. Grid carbon intensity is largely a function of things weather already tells you: how hard the wind is blowing across the turbine fleet, how much sun is hitting the panels, and how cold it is, which drives demand.

So GridShift learns weather to carbon intensity where ground truth exists, then transfers it anywhere on Earth using free global weather forecasts.

You type what you are running in plain language ("charge my EV overnight", "8 hour data centre batch, no rush") and it returns the lowest-emission window that still meets your deadline, for any of 214 grid regions.

How we built it

Three layers, and the boundary between them is the design.

1. A gradient-boosted forecasting model. 400 trees, 31 features, mapping weather and calendar to gCO₂/kWh. Trained on 8,640 hours of real GB grid data paired with reanalysis weather. Deliberately non-autoregressive: it never sees a past carbon-intensity value, because a model that needs yesterday's intensity cannot transfer to a grid that publishes none.

Domain physics is encoded in the features rather than left for the trees to rediscover: a real turbine power curve (cubic ramp from 3.5 m/s cut-in to 12.5 m/s rated, flat to 25 m/s, then zero as turbines feather in a storm), asymmetric heating and cooling degree-days, and a dunkelflaute term for the calm, dark conditions that force gas onto the margin.

2. Claude for intent. Natural language becomes a validated job spec via strict-schema tool use. It infers what a human would: an EV charger is interruptible, a dishwasher cycle is not; a rack GPU job draws about 0.7 kW; "before I wake up" means roughly 07:00.

3. A deterministic optimiser for everything numeric. A sliding-window prefix-sum search for contiguous jobs, and an exact dynamic program for splittable jobs with a minimum block length.

Claude never computes a number the user sees. It does not multiply a wattage by a carbon intensity, pick a window, or estimate a saving. Every figure comes from a pure function that is unit-tested against hand-computed expectations.

The dashboard runs the actual trained trees client-side in your browser. There is no backend.

Results

Chronological train (70%) / validation (15%) / test (15%) split. Parameters fit on train, scheduling policy chosen on validation, every number below from the test set, touched once.

29.3% lower MAE than an hour-of-day climatology baseline (30.81 vs 43.58). That baseline is the honest bar, because anyone can tell you the grid is cleaner at 3am.

CO₂ reductions measured against what the grid really did:

Workload Deadline slack CO₂ cut
Data-centre batch 48h −40.5%
ML training run 24h −31.0%
Dishwasher 12h −27.8%
EV charge 14h −22.6%
CI batch 8h −6.3%

Savings scale with slack. A job with two days of room finds a genuinely clean window; a 2-hour job inside the workday mostly cannot, and GridShift reports 6% rather than 40%.

Challenges we ran into

We found a bug that made the product actively harmful. The first honest evaluation gave EV charging a savings capture rate of −0.44. Negative. Following our advice emitted more CO₂ than plugging in immediately.

The cause was statistical rather than a coding error. It is the optimiser's curse. A contiguous job averages the forecast over a window, so errors partly cancel. A splittable job takes an argmin over individual hours, and argmin over noisy estimates preferentially selects the hours the model most under-predicts. Selection amplifies exactly the errors you would least like to trust.

We hypothesised the fix was pessimism, selecting on a predicted upper quantile, and swept quantile regression at 0.5 through 0.9 against smoothing windows. Our hypothesis was wrong. Pessimism barely helped. What worked was low-pass filtering the forecast before selection, so a single noisy hour cannot win the argmin alone. Chosen on validation, then measured once on test: −0.88 to +0.03, with no regression anywhere else.

We report that fixed EV number as 0.03, not a tuned-until-pretty figure. It is the weakest case in the product and it is visible in the README.

What we learned

RMSE was the wrong objective. A scheduler does not need to know that 3am will be 91 gCO₂/kWh; it needs to know 3am is cleaner than 6pm. A forecast biased by a constant 40 gCO₂/kWh scores terribly on MAE and schedules perfectly. So we evaluate on savings capture rate: of the CO₂ a perfect-foresight oracle could have saved, what fraction did we capture?

We also learned that a green build proves very little about a web page. Four real defects reached the live site past passing tests, a clean linter and a successful build, and were only caught by rendering the page in a real browser and looking at it.

What's next

Validating the transfer. The model is trained on GB and applied elsewhere with an affine rescale to each grid's published annual average. The weather-driven shape should transfer since the physics is universal, but the absolute level is a calibration rather than a measurement, and we have no ground truth to check it against. Every such forecast is labelled transferred in the UI. We would also like to move from average to marginal carbon intensity, which is arguably the correct signal for a shifting decision.

Built With

Share this project:

Updates

Submission history