Skip to content

release: build app against macOS 26 SDK for parity with nightly (port #5077) - #5167

Closed
austinywang wants to merge 1 commit into
mainfrom
fix-release-xcode26-sdk-parity
Closed

austinywang wants to merge 1 commit into
mainfrom
fix-release-xcode26-sdk-parity

Conversation

@austinywang

@austinywang austinywang commented Jun 2, 2026 •

Copy link
Copy Markdown
Contributor

What

Ports the macOS‑26‑SDK Xcode selection from nightly.yml (PR #5077) into release.yml, so the official release builds the app against the macOS 26 SDK (adopting Liquid Glass on Tahoe) instead of whatever Xcode happens to be the runner's default. This gives the official release parity with nightly on the runner/SDK used.

Why

Both workflows run on the macOS 15 runner (MACOS_RUNNER_15) because zig 0.15.2 cannot cross‑link the universal Ghostty CLI helper's x86_64 slice against the macOS 26 SDK.

Net effect today: a release links against whatever Xcode is /Applications/Xcode.app on the runner, with no explicit macOS‑26 selection or hard‑fail guard — so it can ship without Liquid Glass on Tahoe. This PR closes that gap.

Changes to release.yml

  1. Select Xcode — rank every /Applications/Xcode*.app by numeric macOS SDK version; pick the newest ≥26‑SDK Xcode for the app (APP_DEVELOPER_DIR) and the newest pre‑26 Xcode for the helper (HELPER_DEVELOPER_DIR); hard‑fail if either is missing.
  2. Build universal Ghostty CLI helper — new step, built under the pre‑26 Xcode (DEVELOPER_DIR=HELPER_DEVELOPER_DIR), with a lipo arch assertion.
  3. Build app — add CMUX_SKIP_ZIG_BUILD=1 so the in‑Xcode zig helper is skipped and the app inherits the macOS‑26 DEVELOPER_DIR.
  4. Inject universal Ghostty CLI helper — new step, injects the real universal helper over the skip‑build stub, before the existing "Verify binary architectures" step.

Mirrors nightly.yml exactly except: release keeps its own steps.guard_release_assets.outputs.skip_all guards and its release app icon (no AppIcon-Nightly).

Notes

  • Stays on the macOS 15 runner — the two‑Xcode split works because that image ships both an Xcode 26 and a pre‑26 Xcode.
  • The helper is injected before signing/notarization, so the bundle signature stays valid; the existing arch‑verify step now validates the real injected helper.
  • release.yml uses no composite action or reusable workflow, so these four in‑file edits are the complete port.

🤖 Generated with Claude Code


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag @codesmith with what you need. Autofix is disabled.


Note

Medium Risk
Changes only CI packaging for official releases; wrong Xcode selection or a failed helper inject could ship a broken or non-universal ghostty binary before notarization.

Overview
Ports the nightly dual-Xcode macOS release pipeline into release.yml so tagged releases build the app against the macOS 26+ SDK (Liquid Glass on Tahoe) instead of whichever Xcode the runner picks by default.

Select Xcode now scans all Xcode*.app installs, ranks SDK versions numerically, sets DEVELOPER_DIR to the newest 26+ Xcode for the app and HELPER_DEVELOPER_DIR to the newest pre-26 Xcode for Zig, and fails the job if either bucket is missing.

New steps build the universal Ghostty CLI helper under the pre-26 toolchain (with lipo arch checks), set CMUX_SKIP_ZIG_BUILD=1 on the Release xcodebuild so in-Xcode Zig does not cross-link x86_64 against SDK 26, then inject that helper into cmux.app before the existing architecture verification and signing.

Reviewed by Cursor Bugbot for commit ac9284f. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Build the release app with the macOS 26 SDK to match nightly, ensuring Liquid Glass on Tahoe and removing reliance on the runner’s default Xcode. Adds dual-Xcode selection so the app links against 26+ while the Ghostty CLI helper links against a pre-26 SDK.

  • Bug Fixes
    • Select Xcode by SDK version: newest 26+ for the app (DEVELOPER_DIR), newest pre-26 for the helper (HELPER_DEVELOPER_DIR); hard-fail if missing.
    • Build the universal Ghostty CLI helper under the pre-26 Xcode, assert arm64/x86_64 slices, and inject it into the app before arch verification.
    • Set CMUX_SKIP_ZIG_BUILD=1 so the app build inherits the macOS 26 SDK and skips the in-Xcode zig helper.
    • Stays on the macOS 15 runner and mirrors nightly.yml behavior while keeping existing release guards and icon.

Written for commit ac9284f. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Chores
    • Refined macOS release build workflow to use separate Xcode toolchains for app and CLI helper compilation.
    • Added automated universal binary construction for the Ghostty CLI helper with architecture validation.
    • Improved app bundle assembly with injection of prebuilt universal CLI helper binary.

Port the #5077 dual-Xcode selection from nightly.yml into release.yml so the
official release links the app against the macOS 26 SDK (adopting Liquid Glass
on Tahoe) instead of whatever Xcode happens to be the runner default.

Both workflows run on the macOS 15 runner because zig 0.15.2 cannot cross-link
the universal Ghostty CLI helper's x86_64 slice against the macOS 26 SDK. #5022
(c491143) moved both nightly and release off the macOS 26 runner; #5077
(4fdaa0a) added the SDK-aware Xcode selection to nightly only, leaving
release on the pre-#5077 lexicographic `find | sort | tail -n 1` picker with no
macOS 26 guarantee.

- Select Xcode: rank every /Applications/Xcode*.app by numeric macOS SDK
  version; use the newest >=26 SDK Xcode for the app (APP_DEVELOPER_DIR) and the
  newest pre-26 Xcode for the helper (HELPER_DEVELOPER_DIR); hard-fail if either
  is missing.
- Build the universal Ghostty CLI helper separately under the pre-26 Xcode.
- Build the app with CMUX_SKIP_ZIG_BUILD=1 so it inherits the macOS 26 Xcode.
- Inject the real universal helper before the existing arch-verification step.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Building Building Preview, Comment Jun 2, 2026 5:21am
cmux-staging Building Building Preview, Comment Jun 2, 2026 5:21am

@coderabbitai

coderabbitai Bot commented Jun 2, 2026 •

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: eca58261-0d4c-4594-9955-f3fa5724bfd3

📥 Commits

Reviewing files that changed from the base of the PR and between 5c50a38 and ac9284f.

📒 Files selected for processing (1)
  • .github/workflows/release.yml

📝 Walkthrough

Walkthrough

The macOS release workflow is refactored to independently manage Xcode toolchain selection by macOS SDK version, build a universal Ghostty CLI helper binary separately, inject it into the app bundle, and skip redundant in-Xcode compilation.

Changes

macOS Release Workflow Refactor

Layer / File(s) Summary
Xcode Toolchain Selection by SDK Version
.github/workflows/release.yml
Script discovers all Xcode*.app instances, ranks them numerically by SDK version, and selects distinct toolchains: app build requires macOS SDK >= 26, helper build uses newest pre-26 SDK. Exports both as DEVELOPER_DIR and HELPER_DEVELOPER_DIR to GITHUB_ENV and fails the workflow if either is unavailable.
Universal Helper Build and Injection
.github/workflows/release.yml
Builds the Ghostty CLI helper as a universal binary with the selected helper toolchain, validates presence of both arm64 and x86_64 slices. Configures the app build step with CMUX_SKIP_ZIG_BUILD: "1" to skip in-Xcode helper compilation. Injects the prebuilt universal helper into cmux.app/Contents/Resources/bin/ghostty and re-validates its architectures.

Sequence Diagram

sequenceDiagram
  participant Toolchain as Toolchain Selection
  participant Helper as Helper Build
  participant Validate as Validation
  participant App as App Build
  participant Inject as Injection
  
  Toolchain->>Toolchain: Select SDK >= 26 for app
  Toolchain->>Toolchain: Select pre-26 SDK for helper
  Toolchain->>Helper: Provide HELPER_DEVELOPER_DIR
  Helper->>Helper: Compile universal binary
  Helper->>Validate: Output helper
  Validate->>Validate: Verify arm64 + x86_64
  Toolchain->>App: Provide DEVELOPER_DIR
  App->>App: Build app (CMUX_SKIP_ZIG_BUILD=1)
  App->>Inject: App bundle ready
  Inject->>Inject: Copy helper to Resources/bin/ghostty
  Inject->>Validate: Validate injected binary
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • manaflow-ai/cmux#5077: Updates the same macOS workflow to select Xcode toolchains by SDK version, build a universal Ghostty CLI helper separately with dual-architecture validation, skip in-Xcode Zig build, and inject the helper into the app bundle.

Poem

🐰 A rabbit's release rhyme:
Two Xcode paths diverge in the SDK tree,
One build pre, one twenty-six and free,
The helper stands alone, both arm and x,
Then nestles in the bundle—what comes next? ✨

🚥 Pre-merge checks | ✅ 18
✅ Passed checks (18 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: porting macOS 26 SDK selection from nightly to release for parity.
Description check ✅ Passed The description is comprehensive with clear What/Why sections, technical details, and testing context. However, the Testing and Checklist sections are absent.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed PR only modifies .github/workflows/release.yml (a YAML GitHub Actions workflow file), not production Swift code. The custom check applies to "production Swift changes" which this PR does not contain.
Cmux Swift Blocking Runtime ✅ Passed PR only modifies .github/workflows/release.yml (GitHub Actions YAML workflow file); contains no Swift code changes. Custom check applies only to production Swift changes, making it inapplicable here.
Cmux No Hacky Sleeps ✅ Passed PR modifies only GitHub Actions workflow YAML, which is explicitly out of scope per runtime-no-hacky-sleeps.md. No TypeScript, JavaScript, or shell runtime code changed.
Cmux Algorithmic Complexity ✅ Passed CI/CD workflow file only, not production code. Rule targets production code with scalable user data collections. Iterations over tiny fixed system data (1-5 Xcode versions) with O(1) operations.
Cmux Swift Concurrency ✅ Passed PR modifies only .github/workflows/release.yml (GitHub Actions workflow YAML), not cmux Swift source code, so check for Swift concurrency patterns is not applicable.
Cmux Swift @Concurrent ✅ Passed PR modifies only .github/workflows/release.yml (GitHub Actions YAML workflow), not Swift source code; check is not applicable.
Cmux Swift File And Package Boundaries ✅ Passed PR modifies only .github/workflows/release.yml (GitHub Actions workflow), not Swift source files; the Swift file package boundaries check applies only to production Swift changes.
Cmux Swift Logging ✅ Passed PR contains only GitHub Actions workflow changes (.github/workflows/release.yml) with no modifications to Swift code; check applies only to production Swift changes.
Cmux User-Facing Error Privacy ✅ Passed PR modifies .github/workflows/release.yml, a GitHub Actions workflow (operational runbook), which is exempt from user-facing error rules per the allowed cases.
Cmux Full Internationalization ✅ Passed PR modifies only .github/workflows/release.yml with CI/CD build orchestration and operational debug logs, not user-facing content, which are explicitly allowed.
Cmux Swiftui State Layout ✅ Passed PR only modifies .github/workflows/release.yml (a GitHub Actions workflow file) with no SwiftUI code changes, making the swiftui-state-layout check inapplicable.
Cmux Architecture Rethink ✅ Passed PR modifies only .github/workflows/release.yml (GitHub Actions workflow configuration) with no Swift code changes or architectural modifications, making this Swift-focused check not applicable.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR modifies only .github/workflows/release.yml (GitHub Actions workflow YAML); contains zero Swift code changes. The check for cmux Swift auxiliary window close shortcuts is not applicable.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-release-xcode26-sdk-parity
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch fix-release-xcode26-sdk-parity

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@austinywang

Copy link
Copy Markdown
Contributor Author

Superseded by #5042 ("Build release app with macOS 26 SDK", commit 0b4c138), which already landed the macOS-26-SDK release build on main and even asserts SDK_VERSION == 26.* on the app binary.

This PR was drafted against a stale base (89a9bfb, before #5042 merged) and ports nightly's single-runner two-Xcode mechanism, which #5042 deliberately replaced with a cleaner split: a macOS 15 helper-build job that uploads the universal Ghostty CLI helper as an artifact, plus a macOS 26 app-build job (CMUX_SKIP_ZIG_BUILD=1) that installs it. Closing as redundant.

@austinywang austinywang closed this Jun 2, 2026
@austinywang
austinywang deleted the fix-release-xcode26-sdk-parity branch June 2, 2026 05:24
@greptile-apps

greptile-apps Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR ports the macOS 26 SDK Xcode selection from nightly.yml (PR #5077) into release.yml, giving official release builds parity with nightly by building the app against the macOS 26 SDK (Liquid Glass on Tahoe) while using a pre-26 Xcode for the zig-based universal Ghostty CLI helper.

  • Xcode selection: A new sdk_rank() shell function numerically ranks every /Applications/Xcode*.app by SDK version, picks the newest ≥26-SDK Xcode for the app and the newest pre-26 Xcode for the helper, and hard-fails if either is missing — closing the gap left by the old lexicographic sort | tail -1 picker.
  • Two-phase helper build: A new "Build universal Ghostty CLI helper" step builds the helper under the pre-26 Xcode with a lipo arch assertion; CMUX_SKIP_ZIG_BUILD=1 is added to the xcodebuild invocation; a new "Inject universal Ghostty CLI helper" step drops the binary into the app bundle before the existing arch-verify and signing steps.

Confidence Score: 4/5

The two-Xcode split logic and injection flow are a faithful port of the nightly workflow and are safe to merge; the only gap is a missing runtime regression test for the injected helper binary.

The Xcode selection function, arch assertions, injection step, and CMUX_SKIP_ZIG_BUILD guard all mirror nightly exactly and are mechanically correct. The one divergence is that the bundled Ghostty theme picker helper regression test present in nightly was not ported: the release workflow only asserts the helper binary is present and has the right arch slices, not that it actually runs. A structurally valid but broken helper would pass the release gates and ship.

.github/workflows/release.yml — specifically the post-injection verification steps between "Inject universal Ghostty CLI helper" and "Verify binary architectures".

Important Files Changed

Filename Overview
.github/workflows/release.yml New Xcode selection, helper build/inject steps, and CMUX_SKIP_ZIG_BUILD=1 ported from nightly.yml; logic is mechanically identical to nightly with correct guard conditions, but the bundled Ghostty helper regression test present in nightly is not ported.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Select Xcode\nsdk_rank each Xcode*.app] --> B{≥26 SDK found?}
    B -- No --> FAIL1[❌ Hard fail\nno Liquid Glass]
    B -- Yes --> C{Pre-26 SDK found?}
    C -- No --> FAIL2[❌ Hard fail\nzig cross-link impossible]
    C -- Yes --> D[DEVELOPER_DIR=APP_DEVELOPER_DIR\nHELPER_DEVELOPER_DIR=pre-26 Xcode\nwritten to GITHUB_ENV]
    D --> E[Install build deps\nrust / zig / create-dmg]
    E --> F[Build universal Ghostty CLI helper\nDEVELOPER_DIR=HELPER_DEVELOPER_DIR\nlipo arch assertion arm64 + x86_64]
    F --> G[Build universal app via xcodebuild\nDEVELOPER_DIR=APP_DEVELOPER_DIR macOS 26 SDK\nCMUX_SKIP_ZIG_BUILD=1]
    G --> H[Inject universal Ghostty CLI helper\ninstall -m 755 → Contents/Resources/bin/ghostty]
    H --> I[Verify binary architectures\nlipo on app + CLI + helper]
    I --> J[Sign → Notarize → Upload]
    style FAIL1 fill:#f66
    style FAIL2 fill:#f66
Loading

Reviews (1): Last reviewed commit: "release: build app with macOS 26 SDK for..." | Re-trigger Greptile

Comment on lines +230 to +242
- name: Inject universal Ghostty CLI helper
if: steps.guard_release_assets.outputs.skip_all != 'true'
run: |
set -euo pipefail
APP_DIR="build-universal/Build/Products/Release/cmux.app"
if [ ! -d "$APP_DIR" ]; then
echo "Built app not found at $APP_DIR" >&2
exit 1
fi
DEST="$APP_DIR/Contents/Resources/bin/ghostty"
mkdir -p "$(dirname "$DEST")"
install -m 755 /tmp/cmux-ghostty-helper-universal "$DEST"
echo "Injected Ghostty CLI helper architectures: $(lipo -archs "$DEST")"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Missing Ghostty helper regression test after injection

The nightly workflow runs ./tests/test_bundled_ghostty_theme_picker_helper.sh immediately after the inject step to verify the helper actually executes correctly inside the app bundle. The release workflow skips straight to "Verify binary architectures" (which checks arch slices) and then the pre-existing [ -x "$HELPER_BINARY" ] existence check — neither of which exercises the helper's runtime behaviour. The PR description says it "mirrors nightly.yml exactly", so this test appears to have been overlooked during the port. A broken but structurally valid helper binary would pass both checks and ship in a release.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

This branch was successfully deployed

1 active deployment
Preview – cmux — ac9284f2 Deployed Jun 2, 2026 by vercel[bot]
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