Skip to content

build: build stock Ghostty v1.4.0 ourselves, arm64 only - #549

Merged
joelmoss merged 5 commits into
masterfrom
chore/drop-libghostty-spm
Oct 31, 2026
Merged

joelmoss merged 5 commits into
masterfrom
chore/drop-libghostty-spm

Conversation

@joelmoss

@joelmoss joelmoss commented Oct 31, 2026 •

Copy link
Copy Markdown
Owner

Provisional body: /ship opened this early so the review bots run alongside its own review. The final description replaces this.

Replaces libghostty-spm with stock Ghostty v1.4.0, built from source with no patches, for the app and the daemon. This takes the CVDisplayLink wake-freeze fix. It also drops Intel. See docs/adr/0061-build-stock-ghosttykit-from-source.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QxGw2etg1TBHiW4s3Xnu37

Summary

Terminals froze after a Mac woke from sleep. Upstream fixed that, but libghostty-spm could not ship the fix because its patch stack no longer applies to that engine, and an open request for a release (Lakr233/libghostty-spm#92) gave us no date.

We now build stock Ghostty v1.4.0 ourselves, with no patches, for the app and the daemon. One pin, GHOSTTY_SHA in vcs/scripts/build-ghostty-vt.sh, drives both, and xcodegen generate builds and links GhosttyKit before SwiftPM resolves.

The app is now Apple silicon only. The appcast marks each new item arm64-only, so Intel installs stay on their last version instead of being offered an app they cannot launch. Zig moves to 0.17.0, and the two shell integration scripts that changed upstream are regenerated. ADR 0061 supersedes ADR 0001's decision not to build the xcframework.

Given up on purpose, by the owner: patches 0010, 0014, 0015 and 0019, so a TUI or shell prompt can blink during a resize, and ghostty-org/ghostty#14444, which stays out until it merges upstream.

Known risk before merging

The pane-close freeze (#547) can fail CI, not only hang the app. On 03c27b866, AppStoreCreateWorkroomTests.testRunIsRefusedWhileTheSetupDialogStillCoversThePane hit its 300-second limit. The spindump shows the main thread inside ghostty_surface_free from GhosttySurfaceView deinit, with the io and io-reader threads blocked. The Ghostty frames are not symbolicated, so this matches #547 but does not prove it. The fix is not in the old engine either. The test passed on the next completed run, so that is one hang in two completed app runs on this branch, and there is no data yet on whether v1.4.0 makes it more frequent.

Blast radius

Every app build now needs Zig and Xcode's Metal toolchain, and every xcodegen generate runs the script, which is a cache check once the kit exists. A release build, the Linux daemons and a live old-engine to new-engine daemon hand-off all ran; that hand-off is safe because sessions cross as VT bytes, not engine snapshots (vcs/crates/workroomd/src/handoff.rs, script ran).

Nightly and release have no Ghostty cache, so each run now builds GhosttyKit, about 12 minutes on the xcode-27 runner.

Test Coverage

Coverage on the audit before the new test: 56% value-weighted, 81% with any test, 3 gaps. macapp/Scripts/build-ghostty-vt_test.sh then covered the --kit cache paths and was proven red by removing the Info.plist check.

Rejected as tests: check_arm64 in release.sh (needs a production seam), the missing-Metal branch (needs stubs and fails loudly), and vendored shell scripts (pinned by CHECKSUMS). Weak paths: the --kit build, preGenCommand and the local package, each proven only by the app building.

  • Tests ran: app-test 3539 passed, 0 failed, 105 skipped (the same skip count as before)
  • Tests ran: app-uitest 121 passed, 0 failed, on 0754981b9; later commits changed no Swift
  • Tests ran: vcs-test, app-scripts, app-packages count unavailable, exit 0

Pre-Landing Review

Fixed: concurrent --kit runs could overwrite each other in the shared source checkout, so the kit now builds in a scratch worktree; the xcbuild CI cache now keys on the engine pin, because Xcode does not recompile Swift for a changed binary target header; the Metal check reads the component status; a stale doc reference.

Gate edits: 20 listed, 17 read, 1 finding, 1 kept, 0 restored, 0 open.

  • RH-1 macapp/WorkroomAppTests/GhosttyResourcesTests.swift: kept. The package tag and second pin these checks guarded no longer exist; one pin remains and the build asserts its sha. The owner chose this. The two-pin invariant went with it, and release.sh now requires arm64 rather than both slices.

Outside review: Codex's structured review found nothing actionable, and its PR bot reported no findings on b482a6fa7. The native adversarial pass raised two pre-gate policy rules that were looser than needed; both are narrowed in 04d1c7016.

Review notes

  • Nightly and release could gain a Ghostty cache; left as an accepted cost.
  • The CI kit cache key hashes the whole script, so a comment edit rebuilds the kit.
  • A cold clone in build-ghostty-vt.sh is check-then-act, and its publish removes then moves. Both predate this PR.
  • build-ghostty-vt_test.sh needs Zig, which every developer now needs anyway.

Verification

rust failed once on 04d1c7016 in the_wall_clock_kills_the_tree_including_a_setsid_escaper, a pidfile race in a test this PR does not touch, and passed on rerun. Local pre-gate is failing on this tree with no Info.plist for Sparkle and Sentry inside its own lane, while make app-test on the same tree passes 3539 of 3644 with the other 105 skipped. CI is green on 04d1c7016. The pre-gate's policy fixes are on this branch, so it ran with the branch's unreviewed policy.

Not tested: ssh to a real host, a notarized release, an Intel install's update check, or Sparkle reading the new element on a real feed. The Debug arm64 build was smoke tested by the owner.

Documentation

Audit status: current, no edits needed. Scope: README, CONTRIBUTING, docs, docs-site, macapp/README.md and macapp/QA-libghostty.md. Dated design notes and QA results stay as history.

Test plan

  • make app-test: 3539 passed, 0 failed, 105 skipped
  • make app-uitest: 121 passed
  • make vcs-test, make vcs-lint, vcs/scripts/test-linux.sh: exit 0, with one earlier hand_off connection-refused flake under load
  • make app-test-scripts, make app-package-test, make actions-lint, make app-lint: exit 0
  • Release build: Workroom binaries arm64, no libintl in the debug map, ghostty +version reports 1.4.0
  • Old-engine to new-engine daemon hand-off keeps pid and sessions
  • CI green on 04d1c7016

🤖 Generated with Claude Code

https://claude.ai/code/session_01QxGw2etg1TBHiW4s3Xnu37

joelmoss and others added 3 commits October 31, 2026 00:27
Replaces the libghostty-spm package with GhosttyKit built from the same
pinned upstream commit as the daemon's libghostty-vt. Takes the
CVDisplayLink wake fix, which the package could not ship because its
patch stack no longer applies to that engine.

build-ghostty-vt.sh gains --kit and is now the one engine pin, so the
two-pin invariant and GhosttyPinIntegrityTests go. project.yml's
preGenCommand links the build into macapp/GhosttyKit, because SwiftPM
needs a binary target at resolve time. The daemon's vendored 0014 goes
too: no patches on either side. Zig moves to 0.17.0 and the two changed
shell integration scripts are regenerated from v1.4.0.

Intel goes with it: ARCHS is arm64, release.sh asserts arm64, and the
appcast marks items arm64-only so Intel installs stay on their last
version rather than download an app they cannot launch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QxGw2etg1TBHiW4s3Xnu37
ADR 0061 supersedes ADR 0001's choice not to build the xcframework. The
bump procedure, setup notes and install requirements follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QxGw2etg1TBHiW4s3Xnu37
The local GhosttyKit package runs the app lane. A changed actions/cache
key reads as a credential to the secrets scan, and the runner refused
the Rust files the Rust gate already covers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QxGw2etg1TBHiW4s3Xnu37
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-31T08:55:38.824678Z b482a6f New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

joelmoss and others added 2 commits October 31, 2026 01:48
Two workrooms regenerating on a cold cache shared the source checkout,
so one could delete or publish the other's half-built xcframework, and
--kit wrote into a checkout passed through WR_GHOSTTY_SRC. Keys the
xcbuild cache on the engine pin, which left project.yml with this
change, because Xcode does not recompile Swift for a changed binary
target's header. Checks the Metal toolchain by its component status,
and tests the kit's cache.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QxGw2etg1TBHiW4s3Xnu37
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QxGw2etg1TBHiW4s3Xnu37
@joelmoss
joelmoss merged commit fe58906 into master Oct 31, 2026
19 of 20 checks passed
@joelmoss
joelmoss deleted the chore/drop-libghostty-spm branch October 31, 2026 09:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant