Back to Initiative Library
Config & Standards Medium complexity

Switch to T-Shirt Sized GitHub Actions Runners

✦ Sample Prompt
Migrate every `runs-on:` in our GitHub Actions workflows to one of the T-shirt
sized runners: `runner-s`, `runner-m`, `runner-l`, `runner-xl`.

Sizing rules (customize before running):
- Lint, formatting, typecheck, doc builds → `runner-s`
- Unit tests, light integration tests → `runner-m`
- Image builds (`docker buildx`), heavy integration tests, monorepo builds → `runner-l`
- End-to-end test suites, multi-arch image builds → `runner-xl`

For each repository:
1. Find every `runs-on:` in `.github/workflows/*.yml`, including:
   - Top-level `jobs.<id>.runs-on`
   - Matrix entries (`strategy.matrix.runner` and similar)
   - Reusable workflow `runs-on` overrides
2. Map the current label using the rules above and the job name as a hint:
   - `ubuntu-latest` on a lint job → `runner-s`
   - `self-hosted-large` / `self-hosted-builder` on an image job → `runner-l`
   - Anything ambiguous → `runner-m` (the safe default)
3. Leave specialized runners alone: GPU runners (`gpu-*`), Windows
   (`windows-*`), macOS (`macos-*`), and ARM-specific labels unless explicitly
   opted in.
4. Respect `# runner-pin` comments, any `runs-on:` directly preceded by that
   comment is not modified.
5. If a reusable workflow caller sets `runs-on:` via input, leave the input wiring
   and update only the default.

The Problem

Over time `runs-on:` labels in workflows turn into a junk drawer. Some say `ubuntu-latest`, some say `self-hosted-large`, some say `gpu-builder-v2`. There’s no consistent sizing, no cost attribution, and no way to scale a fleet rationally.

Standardizing on T-shirt sizes (`runner-s`, `runner-m`, `runner-l`, `runner-xl`) makes capacity planning sane: each size maps to a known instance type, the platform team can autoscale per size, and finance can attribute spend. But it requires touching every `runs-on:` in every workflow across the org.

What Tidra Does

  1. Scans .github/workflows/*.yml for every runs-on: reference (including matrix builds)
  2. Maps the current label to the appropriate T-shirt size using rules you provide (heuristics: image build → runner-l, lint → runner-s)
  3. Leaves GPU and other specialized runners alone unless explicitly opted in
  4. Updates reusable workflow callers consistently
  5. Opens one PR per repo with the before/after sizing table

Before & After

diff
.github/workflows/ci.yml
@@ -8,7 +8,7 @@
jobs:
lint:
- runs-on: ubuntu-latest
+ runs-on: runner-s
steps: [...]
build:
- runs-on: self-hosted-large
+ runs-on: runner-l
steps: [...]

Customization Tips

  • Sizing rules: Define a mapping (regex on job name or current label → T-shirt size) up front. Tidra applies it consistently.
  • Reusable workflows: If you call reusable workflows, decide whether the caller or callee owns the runs-on: value before rolling out.
  • Opt-out marker: Add a # runner-pin comment in places that must keep a specific label (e.g., GPU jobs). Tidra honors it.

Ready to run this across your repos?

Connect your Git provider and Tidra opens pull requests in every repo that needs them.