feat(budget): warn before the org runs out of Actions minutes - #128
Merged
Conversation
This estate ran out mid-working-session with no warning at all. Every private
repo went dark -- runs created, no runner allocated, failing within seconds
with zero steps executed -- and the first sign of it was workflows failing for
reasons that looked like broken code.
Nothing watched the spend. This does: it reads the org's Actions consumption
for the current month, compares it against the plan's included minutes, and
warns while there is still room to act.
Three things it has to get right, each of which would otherwise produce a
watchdog that reads plausibly and reports nonsense:
- The classic /orgs/{org}/settings/billing/actions endpoint returns 410 Gone.
The replacement needs no admin:org scope, only an ordinary token.
- The response covers public and private repos together, and public usage is
fully discounted rather than absent. Counting it overstates consumption
several times over, so repo visibility is resolved and public excluded.
- Included minutes are consumed at a per-runner multiplier, not one minute
per minute: a macOS minute costs ten, Windows two. Raw minutes would
under-report a macOS-heavy month by an order of magnitude. Unrecognised
minute SKUs warn rather than being assumed 1x, because silently
under-counting is exactly the failure that lets a cap arrive unannounced.
'Actions storage' is excluded outright; it is billed in GigabyteHours.
Critical fails the run so it is visibly red even if nobody reads issues;
warning stays green because it is information, not an incident. The alert
issue is sticky -- updated in place rather than reopened every run -- for the
same reason the hygiene sweep's comment is.
Verified against live billing data, including that the alarm fires rather than
only that it stays quiet:
- allowance 10000 -> 32%, notice only, exit 0
- allowance 4200 -> 75%, ::warning::, exit 0
- allowance 3000 -> 105%, ::error::, exit 1
That 105% is real: private repos have used 3,159 of 3,000 included minutes for
August 2026, so the org is currently past its allowance.
Refs #126
This was referenced Aug 29, 2026
Merged
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The org ran out of Actions minutes mid-working-session with no warning at all. Every private repo went dark — runs created, no runner allocated, failing within seconds with zero steps executed — and the first sign of it was workflows failing for reasons that looked like broken code. Nothing watched the spend.
What it found immediately
Run against live billing data:
The org is already past its allowance for August — which is why a monetary budget was needed. Note this is higher than the ~2,975 I reported on the 27th: that figure came from a top-N repo list and missed three private repos.
Three things that would otherwise make it report nonsense
/orgs/{org}/settings/billing/actionsreturns410. The replacement needs noadmin:orgscope, only an ordinary token — confirmed.Actions storageis excluded outright; it is billed in GigabyteHours, not minutes.Verified that the alarm fires, not just that it stays quiet
::warning::::error::Critical fails the run so it is visibly red even if nobody reads issues. Warning stays green — it is information, not an incident. The alert issue is sticky, updated in place rather than reopened each run, same as the hygiene sweep's comment.
One thing a human still needs to confirm
My weighted sum is 3,159. That is the billing API summed correctly as far as I can verify — storage excluded, public excluded, multipliers applied — but whether GitHub's own included-minutes accounting agrees to the minute is worth checking against the billing UI once. If it disagrees materially, the multiplier mapping is the first thing to suspect. Noted on #126.
Caveat on cadence
Its caller will be a scheduled workflow, and GitHub throttles schedules hard in this org — measured at 4–7 runs per repo per day regardless of declared frequency (JorisJonkers-dev/.github#42). For a budget check that is fine: a handful of checks a day is ample, unlike issue boarding. But it cannot promise to warn within minutes of a threshold being crossed, and should not be described as if it could.
Refs #126