Skip to content

optimise-ci

optimise-ci

optimisewriteshands-on

Use this when: CI is slow or expensive and needs trimming

Problem it solves — CI gets slow and expensive by accretion. This trims the pipeline — caching, parallelism, skipping what a diff doesn't need — without weakening the gate.

Optimise CI (pipeline speed & cost)

Wall-clock feedback time is the cost here — CI runs on a self-hosted runner, so it isn't metered Actions-minutes; the cost is the developer waiting for green. The two biggest levers are almost always cache more and don't run what didn't change. Find those first.

The lenses — this is the skill

Read .github/workflows/* and the ci:check chain in composer.json/package.json, then look for:

  • Caching — Composer + npm dependency caches keyed on the lockfiles; cached build/Vite artifacts. A cold composer install / npm ci every run is the usual top win.
  • Don't-run-the-unaffected — the mutation job is the heavy one; composer ci:check already skips it for FE/docs-only diffs (per CLAUDE.md) — verify the workflow honours that and doesn't run the full gate on a docs PR.
  • Parallelism — split independent jobs (lint / types / analyse / tests) to run concurrently instead of one long serial chain; matrix only where it pays.
  • Concurrency — cancel superseded runs on the same branch (concurrency: group) so pushes don't pile up.
  • Redundant steps — duplicated checkouts/setups, re-running the same gate in multiple jobs.

Tempo specifics: CI runs on pull_request and pushes to main only (never feature-branch pushes); the mutation job dominates runtime. Optimise around those.

Output — surface, then apply

A table: win · the workflow/script file:line · saving (why) · the change. AskUserQuestion which to apply; apply only the confirmed. Don't trade away coverage/mutation thresholds for speed — those are fixed (CLAUDE.md); optimise how they run, not whether.

Where it sits

Infra, not app code. In check-everything it belongs to Housekeeping. Distinct from qa-tests (test gaps) — this is the pipeline's speed/cost, not what it asserts.

How this gets triggered

Invoke directly — "CI is slow", "optimise the pipeline". Not hook-fired.