StudioDecision record

The ten pound rule

In October our GitHub Actions use ran to nearly five times the minutes our plan includes, and a spending cap we kept raising turned two dozen alerts red. On 5 November we set one rule for every metered vendor: free tier or £10 a month.

£10 set large on a black background beside five vendor rows, Bright Data, DataForSEO, Cloudflare, GitHub Actions and Sentry, each with a hard stop at £10, above the words: A month, per vendor, enforced in code
14,214hosted Linux minutes on GitHub Actions in October
$85.82gross October Actions bill, before the compute our plan includes
~25red CI alerts on 22 October caused by the spending stop
$13the monthly cap for each metered vendor, fixed at £10

On 22 October about 25 “CI red on main” alerts arrived across our repos, and not one of them was broken code. GitHub had stopped starting our hosted jobs. October’s Actions spend had reached the $25 budget we had set, the budget had a hard stop, and every workflow that needed a GitHub-hosted runner simply did not run.

The alerts were doing their job. The money was the problem, and the way we had been handling it.

A budget that only went up

We raised the cap to $40 the same day and re-ran the 18 failed runs. The next day the forecast said $43.50 by the end of the month, which would have hit the new stop around 29 October, so we raised it to $60. Two days later the forecast was $55.75 of $60 with six days left, and it went to $80.

The GitHub Actions budget, October to November

Each raise made sense on the day. The $20 is what the live cap read on 5 November before the change; we have no record of when it came down from $80.

$25To 22 Oct$4022 Oct$6023 Oct$8025 Oct$205 Nov, before$135 Nov, after

Source: Estate decision log and task log, 22 October to 5 November 2026

Every one of those raises was reasonable in isolation. Hosted jobs included deploys of client sites, and blocking those to save a few dollars felt like the wrong trade. That is exactly how a budget turns into a number that follows spending instead of limiting it.

October closed at 14,214 hosted Linux minutes: $85.82 gross. GitHub’s Team plan includes $18 a month of compute, about 3,000 Linux minutes. We used nearly five times that. The busiest single repo, one client platform, used 6,220 minutes on its own.

GitHub was not the only vendor without a ceiling. Our search-data provider had no monthly limit either. Nobody had done anything wrong. There was just no rule.

One rule for every vendor

On 5 November Mark set one. Our vendor budgets standard says that each of Bright Data, DataForSEO, Cloudflare, GitHub Actions and Sentry stays inside its free tier or under £10 a month. The £10 is a ceiling, not a target. In practice it is $13, at a fixed £1 to $1.30, and we will review that rate by February.

Keep raising the budgetWhat October did

Three raises in four days, each defensible. The forecast kept up with every one, and the cap stopped meaning anything.

A cap per vendor, tuned to its valueRejected

The ask was one rule for everyone. A number per vendor is a number to argue about every month.

A kill switch inside the agent toolsNot built yet

A spend ledger plus a check before bulk work is enough for two low-volume vendors. We will revisit if one of them breaches the cap.

Free tier or £10 a month, for all fiveChosen

One number, checked every morning. At the cap the vendor is off for the month, and nobody, person or agent, raises it without a director saying yes.

A rule nobody checks is a wish, so each vendor got a way to enforce it. GitHub’s org budget went to $13 with the hard stop left on. Cloudflare has no hard spending cap at all, so it got budget alerts at $4, $6.50 and $8 of usage on top of the $5 base plan, plus a daily check that raises an alert if any paid subscription other than that plan appears. The prepaid wallet stays on manual top-ups with auto-recharge off. Sentry stays on its free plan with a pay-as-you-go budget of $0. A script runs the checks at 07:30 every day and posts to our budget alerts channel and the alerts inbox.

Most of our day-to-day work runs through AI coding agents, so the rule says what they may do as well. Before more than about 100 calls to a paid data API, an agent checks the month’s spend and stops if the job would pass 80% of the cap. At the cap it says so, files a task and carries on without that vendor. It may never top up, upgrade, switch on auto-recharge or raise a budget on its own. That takes a director’s explicit yes in chat and a decision log entry that says how to undo it. And no second account to reset a free tier, because that is the cap being dodged, not kept.

A fair challenge is that £10 a vendor looks like a hobby budget for a company that sells hosting and software. It applies to metered usage, the kind where a loop or a busy month can spend money without anyone deciding to, and it is a default, not a belief that cheap is good. Flat plans we have chosen are outside it. Raising a cap takes a director’s yes and a log entry that says how to undo it, and the rate itself is due for review by February. At our size, one number everyone can remember beat a spreadsheet of exceptions.

Cutting minutes instead

The rule had an obvious consequence. On the first five days of November, hosted Linux was running at 274 minutes a day, a forecast of $31.31 net for the month. To fit under $13 the month needed to average 172 or fewer. Left alone, the hard stop would block hosted jobs around the middle of November.

We could have raised the cap. Instead we moved work. Our own Mac runners carry no per-minute charge, and the same day we moved four of the busiest client platform’s jobs onto them. Those jobs had stayed on hosted Linux for documented reasons: tests assumed GNU sed, and 37 Postgres tests had failed on macOS. When we tried again, the sed tests passed with the BSD tools, the 37 failures did not reproduce, and one real fault turned up (Postgres dying without a locale set), which we fixed. The proof was a full run on a Mac: 4,312 engine tests passed against 4,310 on hosted, and 4,544 Postgres tests with no failures against 4,543. We also cut a nightly hosted parity run on another repo to weekly. The projection, and it is only a projection, is about 140 hosted minutes a day.

Moving work to our own runners only helps if the work is lean, because there are only a few of them and every minute a gate holds one is a minute another pull request waits. Ed had already shown how much slack there was. Profiling our booking engine’s gate on 28 October found one stage eating two thirds of it.

Where one 1,169 second gate went

Our booking engine's full gate, profiled on 28 October 2026.

Behaviour tests792 sSurface checks182 sTap checks122 sEverything else, each under 40 s73 s

Source: CI speed rules, 28 October 2026

Half the browser suite’s time went on Playwright’s 500 millisecond networkidle floor and on fixed sleeps, while the Mac sat at about 0.4 of its 12 cores. The fix was to replace the idle floor with a short quiet window, swap sleeps for conditions, and give the jobs that mostly wait a second process. The two behaviour shards went from 398 and 487 seconds to between 149 and 168. A second round took the gate from four jobs and 824 runner-seconds to three jobs and 347.

That is the part we like. The cap forced a choice between paying more and wasting less, and wasting less turned out to have plenty of room in it.

Update, 7 November 2026

The day after, the measured numbers came in and they were less tidy than the projection. November to date was 1,608 hosted minutes, and 5 November alone was 432, partly our own proof runs. The rest of the month now needed about 148 a day, and 6 November was on pace for about 175. So two more sets of jobs moved to the Mac runners, including a render check that compares no pixels and so had no reason to be on Linux: 961 renders, no failures, in 36 minutes on hosted, 33 on one Mac and 35 on the other. The estimate is now about 100 hosted minutes a day. It has not been measured yet.

We also had to correct ourselves. Our second Mac has no Google Cloud command line, so 13 contract tests skip there. “No gate weakened” had only been true on one of the two Macs, until a hosted job for those tests was added on pushes to main. And GitHub’s own dependency update jobs turned out to count against the minutes too, about 160 a week. The cap stays at $13. The forecast method straight-lines the whole month, so the slow first five days keep it above $13 until around 22 November even if the cuts work.