Treating every Mac mini M4 in your fleet as an undifferentiated “fast machine” is how teams accidentally build queues that feel random. In 2026, the operators who win are the ones who publish a capacity envelope: a transparent contract for baseline concurrency, controlled burst borrowing from a shared pool, and reset windows that return borrowed slots before thrashing begins. This article gives two decision matrices, numeric starting points you can paste into runbooks, and eight rollout steps aligned with label-based routing you may already use.
Companion reads: soft vs hard affinity and spread rules, reservations, preemption, and cooldown. When you are ready to add nodes in Hong Kong, Japan, Korea, Singapore, or the United States, start from pricing and keep help open for SSH/VNC onboarding patterns.
Why average CPU on Mac runners misleads capacity planning
Apple Silicon Mac CI hosts often show “comfortable” CPU averages while queues still miss deadlines. The reason is structural: Xcode compiles, UI tests, and signing steps create short spikes that serialize on disk IO, Metal, or the codesign chain. Averages hide head-of-line blocking, especially when multiple repositories share one host without an envelope. The envelope model forces you to reason in concurrent jobs and queue depth, not utilization charts alone.
- Concurrent jobs are the true currency; CPU percentage is only a secondary signal.
- Queue depth tells you whether borrowers are starving baselines; latency percentiles tell you whether resets are too aggressive.
- Reset windows convert “polite agreements” into enforceable policy so shared pools stay fair under incident load.
Three-layer envelope: baseline, burst pool, reset
Think of each business unit (or each mission-critical pipeline) as owning a baseline envelope on a tagged set of Mac mini M4 nodes. The burst pool is shared capacity that any eligible workflow may borrow when labels match, subject to a maximum borrow and a time-based or job-count-based reset. The reset layer is what prevents “temporary burst” from becoming permanent encampment.
| Layer | What it guarantees | Typical control |
|---|---|---|
| Baseline | Minimum concurrent jobs reserved for a squad or release train | Dedicated labels, runner groups, or hard min replicas per queue |
| Burst borrow | Extra concurrency during release weeks or incident hotfix storms | Shared burst-eligible label with a numeric cap per tenant |
| Reset | Borrowed slots expire unless renewed by an approved policy | Cooldown minutes, calendar reset, or “borrow token” budget per day |
Decision matrix: allow burst borrow vs enforce hard cap
Use this matrix when onboarding a new repository to your Mac fleet. If you are uncertain, default to hard cap for anything that touches signing keys or production release artifacts, then relax after observability proves stable queueing.
| Workload pattern | Borrow? | Rationale |
|---|---|---|
| Feature branch CI (lint + unit) | Yes, with reset | Elastic demand; failures are cheap; great fit for shared burst |
| Release train (RC builds) | Limited borrow | Time-bound burst + strict reset aligns with change-advisory windows |
| UI test shards needing GPU stability | Usually no | Hidden contention on WindowServer; prefer labeled shards and hard caps |
| Signed notarized artifacts | Hard cap | Auditability and deterministic ordering outweigh throughput |
Executable parameters you can adopt this week
Numbers are starting points—tune with your own p95 job duration. The goal is to make policy legible to developers (“you always get two lanes; you may request four during release if the pool has room”).
- Baseline per squad: 2 concurrent macOS jobs on M4 hosts with ≥24 GB RAM for mobile teams; 1 concurrent job for smaller services squads.
- Burst ceiling per squad: no more than +3 borrowed jobs above baseline unless temporarily raised in the change ticket.
- Reset window: borrowed slots expire after 45 minutes wall time or after 12 completed burst jobs, whichever comes first.
- Queue depth alert: page when macOS queue depth > 25 jobs for 10 minutes in any region.
- Fairness guard: if a single repository consumes >35% of burst minutes in a day, auto-revoke burst labels until reviewed.
Operations note: burst borrowing without resets is how “five teams share ten Macs” silently becomes “one team owns nine.” Publish the numbers in your internal developer portal; secrecy guarantees resentment, not compliance.
Eight rollout steps for fleet-wide adoption
- Inventory runners by label, region, RAM tier, and Xcode pin; reject unknowns from burst pools.
- Define baselines per squad in a spreadsheet signed by engineering managers—not only infra.
- Implement burst labels separate from baseline labels; document eligibility in README templates.
- Automate reset with a scheduled job or policy engine that removes burst labels when budgets expire.
- Wire metrics for queue depth, wait time p95, borrow minutes per repo; keep dashboards per region.
- Game-day twice a quarter: simulate burst exhaustion and verify baselines still clear.
- Post-incident reviews must cite envelope parameters; update caps when evidence demands.
- Scale hardware when baselines are routinely starved—NodeMac offers dedicated M4 nodes across HK/JP/KR/SG/US for predictable baselines without colo logistics.
FAQ
What is a capacity envelope for Mac CI runners in 2026?
It is a contract per team or pipeline that states baseline concurrent jobs, optional burst borrowing rules, and how borrowed capacity resets. The envelope makes fairness operational instead of cultural.
When should burst borrowing be disabled?
Disable borrowing for exclusive hardware needs, deterministic flaky-test isolation, or regulated builds where queue order must match audit evidence. Prefer hard caps and dedicated runner groups.
How does a reset window reduce fleet thrashing?
Resets force borrowed concurrency to expire unless explicitly renewed, which stops long-term camping on shared pools and gives baselines breathing room after incidents.