Where the CI bill goes, what Blacksmith measured on a real run, and three options for making the $9k GitHub credit last longer. For Fede and Gera.
2026-09-09 · Decided: Option A (Fede, 2026-09-09), PR #7437 closed; cuts pending approval · Trello qw8iq00P · PR #7437 held, not merged
Blacksmith does not lower the bill, it moves it from credit to cash. Its 4-vCPU machines cost the same per minute as GitHub's standard runners, both round every job up to a whole minute, and about 4,400 billed jobs a day are the problem, not the hardware. Recommendation: stay on the credit, close the PR, and cut job count.
At the 2026-09-08 standup Fede said GitHub Actions is costing thousands a month. Aldo (ex-colleague, at Zillow) said he went from about $300 to $80 a month on Blacksmith and that it is faster. Fede ran Blacksmith's migration wizard on 2026-09-09; it opened PR #7437 swapping the runner label in all 66 workflow files. The goal Fede stated in session: about $9,000 of GitHub credit remains, it expires in twelve months, the run rate is over $3,000 a month, and the aim is to make the credit last longer, not to hit twelve months. Cash spend on a vendor is only worth it if speed matters somewhere.
Prior work on the same bill: a self-hosted runner on the Mac mini was tried and reverted on 2026-07-31 (Fede: no self-hosted runners). The August 9 to 11 sessions targeted a 50% cut and shipped push debouncing, incremental re-review and guard consolidation; the target was not reached. On 2026-08-18 the full test suite moved to GitHub's 8-core ARM pool (PR #5856), measured then at 7 min to 2.3 min wall and $0.35 to $0.22 per run. Blacksmith itself had never been evaluated before today.
Source. Every job GitHub ran between 2026-09-08 23:28 UTC and 2026-09-09 17:04 UTC, pulled from the Actions jobs API: 2,982 workflow runs, 10,752 jobs, of which 4,395 actually executed (the rest were skipped by an if: and are not billed). Priced at GitHub's published private-repo list rates per runner label, each job rounded up to a whole minute as GitHub bills, then scaled to 30 days. These are modeled figures, not the invoice; the org billing endpoint needs an admin scope this session's login lacks.
| Item | Per month (modeled) | Share | What it is |
|---|---|---|---|
| Full unit-test suite, 12 shards on the 8-core ARM pool | $647 | 23% | About 57 full-suite runs a day. 54% of the shards are triggered by review verdicts on hub-module PRs, 27% by pushes to main, 17% by PR pushes that escalated to full mode. |
| Type check, build, lint on every PR push | $430 | 15% | Three jobs per push, roughly 120 to 180 of each a day. |
| Affected unit tests on PR pushes | $257 | 9% | One shard per push, median 56 s. |
| AI code review runner, parked while the model reviews | $167 | 6% | Median 5.1 min, p90 8.6 min per review, on a billed machine that does nothing but wait. |
| Guard pins | $113 | 4% | Post-merge only since 2026-08-20; still 229 jobs a day. |
| Everything else, about 60 small jobs | $1,225 | 43% | Gates, drift checks, preview mint and remove, harnesses, evals, deploys. Most finish in under 30 s and bill one minute each. |
| Total | $2,839 | 100% | Matches Fede's "over $3k" once storage and the review bot's own spend are added. |
Source. The PR's own checks ran on Blacksmith machines because a workflow edit takes effect inside its pull request. First run at 2026-09-09 17:44 UTC, a rerun of five workflows about an hour later after the first run had warmed what it could. GitHub-side numbers are the median of the same job over the sample above, and step timings come from one representative GitHub PR run (34379781500) against the Blacksmith rerun (34384721571).
| Step or job | GitHub | Blacksmith | Read |
|---|---|---|---|
| Type check, the CPU-bound step alone | 79 s | 35 s | 2.3x faster Twice the cores show up where the work is pure compute. |
| Lint, the CPU-bound step alone | 5 s | 7 s | Same. |
| Hermetic harness jobs (AppFolio loop, turnover intake, app intake, portfolio), whole job | 116 to 174 s | 68 to 79 s | 40 to 58% faster One run each on Blacksmith; consistent direction. |
| Semgrep scan, whole job | 77 s | 47 s | 39% faster |
| Installing dependencies | 29 s cache restore | 90 s full npm install | 3x slower, every job Main seeds the node_modules cache on GitHub's cache backend. Blacksmith redirects the cache action to its own backend, so nothing seeded on GitHub is visible there. This persists until the seed job itself runs on Blacksmith, which means a full move, not a partial one. |
| Git checkout | 5 to 25 s | 13 to 288 s | Unstable One checkout took nearly five minutes; most took 13 to 26 s. |
| Lint, whole job, first run | 49 s | 629 s | Cold lint cache plus cold dependencies. Warm rerun: 141 s, still 3x slower because of the install. |
| Affected unit tests, whole job | 109 s | 74 s, then 533 s on rerun | Inconclusive The rerun selected a different set of tests and hit the slow checkout. |
| Small gate jobs (nested gate, quality gate, preview mint) | 14 to 17 s | 55 to 105 s | Slower These jobs are almost all install time. On GitHub the install is a 29 s restore; on Blacksmith it is a full install. |
Every check that matters passed on Blacksmith: build, lint, type check, all unit test shards, the leasing regression gate, the escape gate, the preview deploys, the harnesses. The one red check, the renewal conversation scoping eval, fails identically on main today (dispatched on main at 17:56 UTC to confirm) and is a prompt problem unrelated to runners. It is not a required check.
Source. blacksmith.sh/pricing and docs.blacksmith.sh runner overview, fetched 2026-09-09; GitHub rates from the 2026-08-18 billing pull recorded in the CI workflow file and the August sessions.
| Machine | GitHub | Blacksmith | Note |
|---|---|---|---|
| Standard x64 (GitHub 2-core vs Blacksmith 4-vCPU, the wizard's mapping) | $0.008/min | $0.008/min | Same price, twice the cores. Blacksmith bills per vCPU: $0.004 per 2-vCPU minute. |
| Standard ARM (GitHub 4-core ARM vs Blacksmith 4-vCPU ARM) | $0.005/min | $0.005/min | Same. ARM is 0.625x the x64 rate on both sides. |
| 8-core ARM (the test-suite pool) | $0.014/min | $0.010/min | 29% cheaper per minute. This is the only line where Blacksmith's rate is lower. |
| Free tier | Team plan minutes, not applicable to larger runners | 3,000 2-vCPU x64 minutes a month | About $12 of value at our volume. |
| Rounding | Up to the minute | Up to the minute | The $800 a month of round-up moves with the jobs. |
Aldo's $300 to $80 result is consistent with a small team whose jobs are compute-bound and whose GitHub bill was mostly larger-runner minutes. Our bill is thousands of one-minute jobs, where the rate is identical.
| Option | GitHub credit burn | Cash | Speed | Verdict |
|---|---|---|---|---|
| A. Stay on GitHub, close the PR, cut job count | $2,840 today, falling with each cut below | $0 | Unchanged | Recommended Every dollar stays on the credit; the cuts are the only thing that actually extends runway. |
| B. Full move to Blacksmith (the PR as written) | $0 | about $2,600 modeled at the same job mix and durations | Compute steps about 2x faster; installs and checkouts slower or unstable; net wall-clock unproven | No Trades credit for cash with no bill reduction. Also moves the cache backend, so every job re-seeds until main has run there. |
| C. Partial: only the 8-core test shards (narrow the PR to that one label) | minus $647 | about $460 modeled at today's shard durations | Shards likely faster once the cache is seeded on Blacksmith; unmeasured, since full mode did not run on the PR | Only if speed matters Cash for credit again, and the node_modules seed would have to run on Blacksmith too or every shard pays the 90 s install. |
Ranked by modeled monthly saving from the same sample. Arithmetic: jobs in the 17.6 h sample x 1.364 for a day x 30 x billed minutes x rate. All are estimates until shipped and re-measured.
| Cut | Per month | Shape |
|---|---|---|
| Fold the auto-merge arm-or-disarm job into a step of an already-running job | $99 | 412 one-minute jobs a day that do 8 s of work. Mechanical. |
| Fold the two unit-test reporter jobs into the last shard's step | $112 | 465 one-minute jobs a day, 3 to 9 s of work each. Mechanical. |
| Gate or retire the Quality Gate POC's three jobs | $97 | 402 one-minute jobs a day. Needs an owner's call on whether the POC is still an experiment. |
| Fold preview-domain mint and remove into steps | $62 | 259 one-minute jobs a day. |
| Stop parking a runner for the AI review | up to $167 | Re-architecture: the review runs inline on a billed machine for 5 to 9 min. The August 9 session already proposed an async executor on Lambda as "Decision 3", not committed. |
| Full suite on review verdicts | up to $350 | 54% of full-suite shards come from review verdicts on hub PRs, by design since PR #5518 so hub changes get full coverage before merge. Cutting this is a coverage decision, not a cleanup. |
| Remaining sub-30-second jobs | $125 to $165 realistic | About 1,270 more tiny jobs a day across 40 workflows; maybe a third can fold or path-filter. Low confidence. |
The mechanical cuts alone are about $370 a month, 13% of the bill, and take the credit from roughly three months of runway toward three and a half. Getting to a real stretch needs the two design decisions above (review parking, full suite on verdicts), which together are another $500 or so and would push runway toward five months.
runner.arch to the keys. Two free skips added for Agent Smith's nightly branches in the preview-domain workflow.if: cannot make; the two unit-test reporter jobs are kept separate by an incident rule from 2026-08-02. The $370 estimate for this line is withdrawn.| What | Before the cuts | After the cuts | Change |
|---|---|---|---|
| Cost of one PR's CI run (median) | $0.070 | $0.055 | -21% fewer jobs run per push (18 → 15, median), from moving the full suite off the PR path |
| Cost of one merge to main (median) | $0.498 | $0.519 | +4%, flat the ARM savings got eaten by more of that work landing on the pricier 8-core runner (32% → 41% of merge minutes) |
| Jobs running per PR push (median) | 18 | 15 | -17% |
| Share of all CI minutes on the old x64 machines | 36% | 12% | real, clean win this is the ARM move working as intended, and it doesn't depend on how many runs happened that day |
| Time from a PR push to CI finishing (median, real runs only) | 21s | 24s | flat |
| Time from a PR push to CI finishing (slow 10%) | 419s | 549s | up — the PR lane's remaining work (affected tests + the merged lint/type/build job) is now a bigger share of what's left |
| Main went red after a merge | 8 of 28 pushes | 58 of 104 pushes | looks much worse raw, but see below |
On that last row — the red-main count needs unpacking, not just quoting. Grouping the 58 red pushes into distinct incidents (not counting the same broken thing twice while it's being fixed forward) gives 14 separate episodes, not 58. Together they left main red for about 9.2 hours total across the 15.3-hour window (the longest single stretch was 1.9 hours, right after the cut shipped) — that's the time production promotes were held.
PropFlow Docs