Skip to content

ghostty-next: sync to upstream Ghostty c7f68a7f4 (Zig 0.17.0), fixes the CVDisplayLinkStop freeze - #35478

Merged
lawrencecchen merged 34 commits into
feat-cmux-nextfrom
next-ghostty-upstream-sync
Nov 5, 2026
Merged

lawrencecchen merged 34 commits into
feat-cmux-nextfrom
next-ghostty-upstream-sync

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Review (fable subagent): SHIP at 22deae8

Fixes #35300.

Why

cmux-next NIGHTLY froze with no "Not Responding": the main thread waited in ghostty_surface_free -> pthread_join on a Ghostty renderer stuck in CVDisplayLinkStop. Upstream Ghostty fixed this in ffaaf5d7a (start and stop the display link only on the main thread). ghostty-next main took it with v1.4.0, but cmux-next pinned 7d43bb68b on an older release line. Per Lawrence: take upstream instead of custom patches.

What

  • ghostty-next gitlink and GhosttyNextKit move together to a6b9048e9 (Upstream sync to c7f68a7f4 (2026-11-03) + cmux release line ghostty-next#74, release/cmux-sync-20261104): upstream main c7f68a7f4 (2026-11-03) + the release line (PRs Add PostHog analytics to web, remove docs-site #66–Multi-tab notifications #73).
  • Zig 0.17.0 now builds every shipped ghostty-next binary: reviewed toolchain record + LICENSE, tarball sha256s, the iOS Threaded.zig std fix in install-zig-ci.sh (same as ghostty-next's), workflows read the version from the ghostty-next manifest. 0.16.0 stays reviewed for the classic ghostty submodule.
  • Upstream's assume_nonnull in ghostty.h (0e067ded7): Swift callers in CmuxNext, cmux-next-ios and ios/CmuxiOS follow the new non-null types.
  • OSC 7501 support reply is upstream revision 0.4 (?:states=…:kinds=…): test + live scripts.
  • Linux terminal-corpus digests regenerated (round trip equal; snapshot version stays 1; old v1 fixtures unchanged).

Status

  • Fleet build of the macOS app at the pin (job 49c2d44d, tag gn-sync-v2); cmux-ci iOS device + simulator build (job 88f465ba)
  • Notices regenerated from the pin's artifacts (ghosttykit_repin.py, vt-link-graph, package-notices Darwin review for Zig 0.17.0); terminal corpus digests for Linux and macOS (restore equal)
  • Review subagent, findings and fixes posted
  • Source archive (run 41880174496) and the required clippy check pass
  • ghostty-next#74 merged; the pin is ghostty-next main 383b27d73 (forward from feat-cmux-next's 12ec155e1)

Zig 0.17.0 fixes found on the way: the Linux macOS-cross libSystem.tbd (arm64e.x1), the installer's lib_dir check (build_runner.zig is gone), a non-classic Zig installs job-locally (never over the system zig), Windows CodeView relative paths in the link graph.

Base reds, not from this PR: r2-upload-tests (every branch), acpmux dispatch_durable / native_store_move in cmux-tui.yml.

Changelog

  • Fixed: the app no longer freezes when a terminal pane closes or changes focus while macOS reconfigures a display.

Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Syncs ghostty-next and GhosttyNextKit to upstream Ghostty c7f68a7f4 (pin 383b27d73), fixing #35300: terminal pane closes and focus changes no longer freeze the app during macOS display reconfiguration. The pin is ghostty-next main after #74 merged, with the same source tree as the earlier 706c6963a sync pin; moving forward was required because 12ec155e1 → 706c6963a diverged and failed the forward-only submodule guard.

  • Zig 0.17.0 builds ghostty-next; Zig 0.16.0 remains reviewed for classic Ghostty.
  • CI installs each tree's Zig without touching PATH or the system zig: a job that builds both isolates the ghostty-next Zig in a job-local install so concurrent classic jobs are never raced.
  • The Zig installer applies and verifies the iOS standard-library fix required by Zig 0.17.0, and its completeness check now uses lib/std/std.zig instead of Zig 0.17.0's removed lib/compiler/build_runner.zig.
  • Swift callers follow upstream's non-null pointer types. The iOS runtime config is built in a nonisolated static func: formed inside the @MainActor init, the callbacks carried main-actor isolation and Ghostty's renderer thread trapped on wakeup_cb.
  • The iOS CI build retries once after clearing stale precompiled modules, which a GhosttyNextKit pin change leaves behind; the unit-test step already did this.
  • OSC 7501 replies now list supported states and kinds; regenerated Linux and macOS corpus snapshots retain version 1 and remain compatible with older v1 fixtures.
  • Ghostty license notices reviewed for the new pin: new iterm2-themes and zig-gobject releases resolve through byte-equal pinned texts, z2d 0.13.2 ships its own license files so the collector now adds a reviewed MPL-2.0 source offer for packages with license files too, the vt-link-graph is regenerated (uucode moves to upstream, Zig 0.17.0 links fewer compiler_rt files, and its relative CodeView paths attribute correctly, including the Windows generated files), the Zig 0.17.0 Darwin review keeps no musl text, and GhosttyNextKit's link sets and iOS Acknowledgements pane come from the pinned xcframework.
  • The macOS cross build strips Zig 0.17.0's arm64e.x1 targets from the libSystem stub, which ld64.lld 20 rejected before linking.

Status

  • Fleet build of the macOS app at the pin (job 49c2d44d, tag gn-sync-v2); cmux-ci iOS device + simulator build (job 88f465ba)
  • Notices regenerated from the pin's artifacts (ghosttykit_repin.py, vt-link-graph, package-notices Darwin review for Zig 0.17.0); terminal corpus digests for Linux and macOS
  • ghostty-next#74 merged, so the pin is an ancestor of ghostty-next main

Base reds, not from this PR: r2-upload-tests (every branch), acpmux dispatch_durable / native_store_move in cmux-tui.yml.

Changelog

  • Fixed: the app no longer freezes when a terminal pane closes or changes focus while macOS reconfigures a display.
  • Fixed: iOS no longer traps when Ghostty's renderer thread wakes the runtime.

Written for commit 22deae8. Summary will update on new commits.

View guided diff Turn on auto-fix

ghostty-next#74 (upstream Ghostty main c7f68a7f4 merged with 7d43bb68b)
needs Zig 0.17.0. Record its LICENSE (zig-0.17.0.tar.xz from
ziglang.org, sha256 b6c7f172...; the text is byte-identical to 0.16.0's)
as a second reviewed Zig with no ghostty_sources, so CI may install it
and the app bundles its text while ghostty-next stays on 0.16.0.

toolchains.json may now hold several Zig entries: at most one per
version and per Ghostty source. Manifest.zig_for("ghostty-next") is the
Zig of the shipped binaries; package_notices.py and the browser-host
notices use it instead of unpacking a single entry, and the Darwin
review must name exactly that Zig (another reviewed Zig no longer
passes). hand-written.md names the bundled 0.17.0 text.

Checks: test_toolchain_notices.py (22 OK), test_package_notices.py (31
OK), test_linux_release_notices.py, test_check_bundle_notices.py,
test_compose_notices.py OK; toolchain_notices.py check-repo and
package_notices.py check-data clean.
Pin the 0.17.0 tarball sha256s (aarch64/x86_64 macOS and Linux, from
ziglang.org/download/index.json). For 0.17.0, install-zig-ci.sh applies
Zig master 0bfd34342b to lib/std/Io/Threaded.zig, the same one-line edit
and the same before/after sha256 (1a770001... -> 1d7bdb0d...) as
ghostty-next's next/install-zig.sh: without it no iOS slice of
libghostty-vt compiles. The file is identical in the source and every
platform tarball. An existing 0.17.0 Zig without the patched file is not
reused; a verified copy is installed instead.

Checks: test_install_zig_ci_reviewed_version.py (an unpatched existing
0.17.0 is refused and the run goes to download), test_install_zig_ci_no_sudo.sh,
test_install_zig_ci_download_resume.sh, test_ghostty_zig_version_sync.sh
pass; the sed edit reproduces the patched sha256 on the real 0.17.0 file.
….16.0

cmux-tui-headless-debug.yml and cmux-tui-sdks.yml (conformance) set up
the Zig that ghostty-next's build.zig.zon names through
ghostty-zig-version.sh, check it, and drop the zig0.16.0 key token: the
ghostty-next gitlink in the key already determines the Zig (key v2).

cmux-terminal-client-xcframework.yml built the iOS and macOS slices of
cmux-terminal-client, whose ghostty-vt dependency builds libghostty-vt
from ghostty-next, after initializing only the classic ghostty submodule
and installing its Zig. It now initializes ghostty-next and installs
that Zig with install-zig-ci.sh, which applies the iOS std fix.

Checks: actionlint on the three workflows (only the pre-existing SC2129
style note in the xcframework version step), test_check_ghostty_zig_workflows.py,
check_ghostty_zig_workflows.py --require-setup-zig,
test_cmux_tui_headless_debug_workflow.py pass.
Name the source of the version instead of 0.16.0, so the ghostty-next
move to Zig 0.17.0 (manaflow-ai/ghostty-next#74) needs no doc edit.
ghostty-next now takes upstream's OSC 7501 parser, whose support reply is
'?' plus the accepted states and kinds. The ghostty-vt test and the two live
scripts matched the old bare '?' reply and read a fixed 10 or 16 bytes.
…ream c7f68a7f4

Regenerated on rbx (Zig 0.17.0, ghostty-next 3f637268c) with
CMUX_TERMINAL_CORPUS_UPDATE's output. The READY restore round trip stays
equal for every case. The digests change because upstream adds optional
Kitty image records (kitty-graphics gets record kinds 8 and 9), sizes the
hyperlink map on its own (hyperlinks, styles page records) and splits the
scrollback case's pages differently. Snapshot version stays 1, and every
older v1 fixture in ghostty-next's snapshot testdata is unchanged, so
snapshots saved by today's builds still decode.
…null)

ghostty-next a6b9048e9 imports unmarked pointers as non-optional. Match the
C callback types exactly (app, clipboard state, mimes, confirm, contents,
io_write bytes, link filter text), build ghostty_runtime_config_s with its
memberwise initializer, read the now non-null strings (titles, pwd, search
needle, diagnostic message, version, clipboard mime/data) directly, and pass
the clipboard request's state and content pointers as non-null.
ghostty-next a6b9048e9: build ghostty_runtime_config_s with its memberwise
initializer (its callbacks are non-null now) and drop the optional handling
of the now non-null io_write bytes, write_clipboard contents and snapshot
bytes, in cmux-next-ios and ios/CmuxiOS.
…CVDisplayLinkStop freeze

Moves the ghostty-next gitlink and GhosttyNextKit together to a6b9048e9
(manaflow-ai/ghostty-next#74, release/cmux-sync-20261104): upstream Ghostty
main c7f68a7f4 merged with the release line (PRs #66-#73). Upstream's
main-thread CVDisplayLink start/stop (ffaaf5d7a) fixes #35300: NIGHTLY froze
with ghostty_surface_free joining a renderer stuck in CVDisplayLinkStop.

Zig 0.17.0 now builds every shipped ghostty-next binary (toolchains.json
moves ghostty-next and the binaries note to 0.17.0; 0.16.0 stays reviewed
for the classic ghostty submodule). Zig 0.17.0 bundles the same musl 1.2.5.

Notice files regenerated from this pin's artifacts follow in the next
commits (ghosttykit_repin.py, package-notices darwin review).
@lawrencecchen lawrencecchen added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Nov 4, 2026
@blacksmith-sh

blacksmith-sh Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Found 2 test failures on Blacksmith runners:

Failures

Test View Logs
test_base_passes (main.NoticesPairTests.test_base_passes)/
test_base_passes (main.NoticesPairTests.test_base_passes)
View Logs
test_notices_for_another_ghostty_next_commit_fail (main.NoticesPairTests.test_notic
es_for_another_ghostty_next_commit_fail)/
test_notices_for_another_ghostty_next_commit_fail (main.NoticesPairTests.test_notic
es_for_another_ghostty_next_commit_fail)
View Logs

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

ghostty-next now needs Zig 0.17.0; the classic ghostty stays on 0.16.0.
cmux-next-source-archive.yml run 41844813482 failed with "Your Zig version
v0.16.0 does not meet the required build version of v0.17.0" because its
install steps used the default (classic) source.

- install-zig-ci.sh: ZIG_PUBLISH_ENV publishes a second Zig under another
  variable without touching PATH or CMUX_ZIG (requires
  ZIG_FORCE_LOCAL_INSTALL=1 so the system zig is not replaced).
- zig-fetch-all.sh takes ZIG; build-ghostty-source-archive.sh and
  check-ghostty-fetch-list.sh vt use CMUX_VT_ZIG for the libghostty-vt tree.
- cmux-next-source-archive.yml: archive job installs both Zigs (classic on
  PATH for the CLI helper, 0.17.0 as CMUX_VT_ZIG); fetch-list-linux and
  vt-link-graph build only libghostty-vt and use ghostty-next.
- nightly.yml: the helper job installs both (helper + source archive); the
  fast cmux-tui client install uses ghostty-next.
- cmux-next-skew-matrix.yml: N uses ghostty-next; N-1 gets its own Zig as
  OLD_ZIG when its ghostty-next needs another version.

Checks (local, no builds): actionlint on the three workflows;
check_ghostty_zig_workflows.py .github/workflows; test_check_ghostty_zig_workflows,
test_ghostty_zig_version_sync, test_install_zig_ci_{no_sudo,download_resume,
reviewed_version}, test_zig_fetch_all, test_nightly_next_source_archive,
test_cmux_next_checks_workflow, test_workflow_file_size,
test_ci_nightly_off_blacksmith: all pass. Not run: the workflows themselves.
The nightly-next mini also runs classic jobs that use the Zig 0.16.0 in
/usr/local/bin; a global install of 0.17.0 there could race them.
@github-actions github-actions Bot added risk:high Risk tier (docs/ci/risk-tiers.md) and removed risk:normal Risk tier (docs/ci/risk-tiers.md) labels Nov 4, 2026
Zig 0.17.0's lib/libc/darwin/libSystem.tbd adds arm64e.x1-macos and
arm64e.x1-maccatalyst to every target list. ld64.lld 20 rejects the file
("unknown architecture") and then links no libSystem symbol, so the Linux
pool's macOS cross build of cmux-browser-host failed with undefined bind,
fcntl, getuid (fleet job b764232172f11ec7fd85fb2d). Checked with lld 20: the
0.16.0 stub and the filtered 0.17.0 stub link a bind/getuid object; the raw
0.17.0 stub fails the same way.
Zig 0.17.0 replaced lib/compiler/build_runner.zig with Maker.zig and
configurer.zig, so every sudo install of 0.17.0 failed its check with "lib_dir
is incomplete" (PR #35478: cargo check windows-gnu, fast tier, clippy,
r2-upload-tests). lib/std/std.zig exists in 0.16.0 and 0.17.0. The installer
tests' fixtures follow; their placeholder files no longer sit at lib/std.
iterm2-themes release-20261026-153024-27cbbb5 and zig-gobject release
0.11.0-zig-0.17.0-2026-10-02-38-1 ship no license file; their LICENSE at
27cbbb5e and 5c8e70b0 is byte-equal to the pinned texts, so the new
package hashes join the reviewed lists. z2d 0.13.2, zigimg, aro and
translate_c 2.0.0 carry their license files in the fetched tree.
From source-archive run 41995370136. Only the commit changes: the merged
release-line PRs touch the renderer, not libghostty-vt.
@cursor

cursor Bot commented Nov 5, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

Same libghostty-vt sources and link graph as a6b9048e9 (the merged release-line
PRs change only the renderer), so the Zig 0.17.0 Darwin and Windows binary
reviews of run 41861545663 still apply; the shipped commit and its license tree
(run 41995370136) move.
Link sets from the pinned xcframework, app_link from the repin's cmux-ci iOS
build, Acknowledgements from source-archive run 41995370136.
@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Review (fable subagent): BLOCK at f917599 — the ghostty-next gitlink 12ec155e1 -> 706c6963a is diverged (12ec155e1 is not an ancestor; its PRs #75 #77 #79 are present only as patch-equivalent ports #76 #78 #80), so workflow-guard-submodule-forward-only fails and main-submodule-pin-watch would go red after merge.

Everything else in that review passed: pin/checksum integrity, nightly.yml (no runner, concurrency or if: changes; 0.17.0 job-local, /usr/local/bin/zig 0.16.0 never replaced), install-zig-ci.sh, Swift nullability (no escaping pointers; two unreachable null paths), macos-cross filter verified on the real 0.17.0 libSystem.tbd, vt_link_graph paths.

Resolution in progress: manaflow-ai/ghostty-next#74 is merged; its main tip 383b27d73 contains both 12ec155e1 and 706c6963a (same source tree as 706c6963a). Publishing GhosttyNextKit for 383b27d73 (ghostty-next run 42000652256), then the pin moves to 383b27d73 (a forward move from 12ec155e1) and gets a new review on the new head.

Self-verification on the gn-sync-v3 build of this head (capture mini, 5 rounds of split/focus/close panes, then the app sampled itself): app responsive, 1 renderer thread left (every closed pane's renderer thread was joined), 0 frames in CVDisplayLink::stop, 0 in pthread_join.

…s 12ec155e1

Review BLOCK at f917599: 12ec155e1 -> 706c6963a was diverged (the forward-only
submodule guard fails). 383b27d73 is ghostty-next main after #74 and contains
both 12ec155e1 and 706c6963a with the same source tree as 706c6963a. Its
GhosttyNextKit is published from main (run 42000652256).
From source-archive run 42004729138; same libghostty-vt sources as 706c6963a,
only the commit changes.
@cursor

cursor Bot commented Nov 5, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

The nullability change (df35515) built ghostty_runtime_config_s with its
memberwise initializer inside the @mainactor init. Closures formed there
carry main-actor isolation, and Swift's runtime check trapped when Ghostty's
renderer thread called wakeup_cb: CmuxiOS TerminalSurfaceKeyBytesTests
crashed the test host (EXC_BREAKPOINT in _swift_task_checkIsolatedSwift ->
dispatch_assert_queue, closure #2 in GhosttyNextApp.init, thread
'renderer'; test-ios run 41998927120 at f917599). Build the config in a
nonisolated static func in both iOS apps; macOS already uses nonisolated
global callbacks.
@lawrencecchen

Copy link
Copy Markdown
Contributor Author

CI finding at f917599 (missed by both reviews), fixed in c95d833:

test-ios run 41998927120: CmuxiOS TerminalSurfaceKeyBytesTests crashed the test host. The crash report on the runner (cmux10s mini, xctest-2026-11-05-011324.ips): EXC_BREAKPOINT on thread renderer, _swift_task_checkIsolatedSwift -> dispatch_assert_queue in closure #2 in GhosttyNextApp.init(). Cause: the nullability change built ghostty_runtime_config_s with its memberwise initializer inside the @MainActor init, so the C callbacks carried main-actor isolation and Swift's runtime check trapped when Ghostty's renderer thread called wakeup_cb. Fix: both iOS apps (ios/CmuxiOS GhosttyNextApp, cmux-next-ios CmuxMobileGhosttyApp) build the config in a nonisolated static func; macOS already used nonisolated global callbacks (and the macOS stress run passed). Red: TerminalSurfaceKeyBytesTests at f917599; green expected on c95d833's test-ios run.

Also at f917599: Check the app FFI pin failed on HTTP 504s from its download (infrastructure), not on this change.

The pin is now ghostty-next main 383b27d73 (forward from 12ec155e1; submodule_forward_only.py --base origin/feat-cmux-next passes locally).

The owned Mac's kept DerivedData holds explicit precompiled modules built
against the previous ghostty.h; after a GhosttyNextKit pin change the app
build stops with "has been modified since the module file ... was built"
(run 42011060253 on glaeda-1, the only error). The unit-test step already
clears the module caches and retries on that message; the build step now does
the same. Any other failure stands.
@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Landing at 22deae8.

  • Review (fable subagent): SHIP at 22deae8 (and SHIP at 50a8a6b for the full diff; only test-ios.yml changed since).
  • Compile: fleet macOS app build at 50a8a6b (job 7fef7756, done); iOS device + simulator builds at c95d833 (repin job); cmux-tui all targets earlier at this pin's source tree.
  • iOS fix: CmuxMobileKit CmuxMobileTerminalTests on an iPhone 17 Pro simulator at 22deae8 (cmux-ci step 29ac3668): 321 passed, 0 failed, no crash. The test-ios CmuxiOS run could not run: 24 of the 26 runners labeled glaeda-std-xcode-26.6 + glaeda-ios-sim are offline, so the job waited out its slot three times.
  • cmux-next swift test reds are base reds: HoverCardMachineColorTests (2), AppSceneKitTests (1), FocusedPanePresentedFirstTests (1) fail identically at the merge base fd1a2ed (cmux-ci step 5f86105b, run cmuxterm-hq 42028671162) and at this head (step 563f4d17).
  • submodule_forward_only.py: ghostty-next 12ec155e1 -> 383b27d73 forward. merge_freeze.py check: exit 0.
  • Self-verification on the macOS app at this pin: 5 rounds of split/focus/close panes, then the app sampled itself: 1 renderer thread left, 0 frames in CVDisplayLink::stop, 0 in pthread_join.

This branch was previously deployed

3 inactive (2 outdated) deployments
ci-routing-agent — 22deae8f Deployed Nov 5, 2026 by lawrencecchen via wait for same-key tree publisher #115657
sentry-dsyms — 374ba0e4 Deployed Nov 5, 2026 by lawrencecchen via upload cmux-tui dSYMs to Sentry #115492
artifacts — 374ba0e4 Deployed Nov 5, 2026 by lawrencecchen via publish to R2 #115492
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:high Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant