Problem
The CI workflow builds and caches the Ghostty framework keyed by the submodule SHA, but the cache is only populated on pull_request runs. Because of GitHub Actions cache scoping, each PR branch gets its own isolated cache namespace — so a Ghostty build done on PR A is not visible to PR B, even when both PRs target the same Ghostty SHA.
Every PR's first CI run is therefore a cold build of Ghostty on a macos-15 runner, which is the most expensive step in the pipeline.
Background: cache scope in GitHub Actions
A workflow run can restore caches from:
- Its own ref (branch/PR), and
- The repository's default branch (
main).
Caches created on other feature branches or PR refs are NOT accessible. This is why PR-only cache writes don't help sibling PRs — but a cache written on main is readable by every PR targeting main.
Reference: https://docs.github.com/en/actions/how-tos/write-workflows/choose-what-workflows-do/cache-dependencies#restrictions-for-accessing-a-cache
Current state
.github/workflows/ci.yml triggers only on pull_request: [main]. Main never runs the build, so the shared cache slot on main is always empty. Every PR pays the Ghostty build cost on its first run.
Proposal
Add a push: branches: [main] trigger (or a dedicated cache-warm workflow) that runs after each merge and populates the Ghostty cache on main. Keep the existing cache key (ghostty-\${os}-\${arch}-\${sha}) so PRs with an unchanged submodule SHA get a hit.
Two options:
-
Add push: main to ci.yml — simplest; main re-runs the full build+test after each merge, repopulating the cache. Cost is one extra macOS run per merge to main.
-
Dedicated cache-warm.yml on push: main — only does checkout + make ghostty + cache save; skips swift build and tests. Cheaper than option 1, and only actually builds on Ghostty SHA changes (cache hit short-circuits). Probably the right tradeoff.
Since the cache key is keyed on the submodule SHA, option 2 is basically free on merges that don't bump Ghostty.
Impact
Eliminates the cold Ghostty build on every first PR CI run where the Ghostty submodule hasn't changed — which is the common case. Should cut typical PR CI time significantly and reduce macOS runner minutes.
Problem
The CI workflow builds and caches the Ghostty framework keyed by the submodule SHA, but the cache is only populated on
pull_requestruns. Because of GitHub Actions cache scoping, each PR branch gets its own isolated cache namespace — so a Ghostty build done on PR A is not visible to PR B, even when both PRs target the same Ghostty SHA.Every PR's first CI run is therefore a cold build of Ghostty on a
macos-15runner, which is the most expensive step in the pipeline.Background: cache scope in GitHub Actions
A workflow run can restore caches from:
main).Caches created on other feature branches or PR refs are NOT accessible. This is why PR-only cache writes don't help sibling PRs — but a cache written on
mainis readable by every PR targetingmain.Reference: https://docs.github.com/en/actions/how-tos/write-workflows/choose-what-workflows-do/cache-dependencies#restrictions-for-accessing-a-cache
Current state
.github/workflows/ci.ymltriggers only onpull_request: [main]. Main never runs the build, so the shared cache slot onmainis always empty. Every PR pays the Ghostty build cost on its first run.Proposal
Add a
push: branches: [main]trigger (or a dedicated cache-warm workflow) that runs after each merge and populates the Ghostty cache onmain. Keep the existing cache key (ghostty-\${os}-\${arch}-\${sha}) so PRs with an unchanged submodule SHA get a hit.Two options:
Add
push: maintoci.yml— simplest; main re-runs the full build+test after each merge, repopulating the cache. Cost is one extra macOS run per merge to main.Dedicated
cache-warm.ymlonpush: main— only does checkout +make ghostty+ cache save; skipsswift buildand tests. Cheaper than option 1, and only actually builds on Ghostty SHA changes (cache hit short-circuits). Probably the right tradeoff.Since the cache key is keyed on the submodule SHA, option 2 is basically free on merges that don't bump Ghostty.
Impact
Eliminates the cold Ghostty build on every first PR CI run where the Ghostty submodule hasn't changed — which is the common case. Should cut typical PR CI time significantly and reduce macOS runner minutes.