Skip to content

feat: ship a Universal 2 (arm64 + x86_64) darwin release binary - #112

Open
chrisl10 wants to merge 1 commit into
mvanhorn:mainfrom
chrisl10:feat/universal-darwin-binary
Open

feat: ship a Universal 2 (arm64 + x86_64) darwin release binary#112
chrisl10 wants to merge 1 commit into
mvanhorn:mainfrom
chrisl10:feat/universal-darwin-binary

Conversation

@chrisl10

Copy link
Copy Markdown

Problem

Releases only ship a darwin-arm64 asset, so Intel Macs have no signed,
notarized binary to install. On an Intel sink that matters beyond
convenience: the sink daemon needs a Developer-ID-signed binary to read
Chrome Safe Storage via the teamid path, so an unsigned go install
build is stuck in degraded delivery (mode=sidecar+adapter+cdp) and can
never write the real Chrome profile. Intel users effectively can't get
universal cookie delivery.

The install-beta.sh downloader is also hardcoded to
--pattern '*darwin-arm64.tar.gz', so even if an Intel asset existed the
installer wouldn't fetch it.

Approach

Ship a single Universal 2 (arm64 + x86_64) binary rather than two
per-arch assets. One lipo-fused binary runs natively on both
architectures and is signed + notarized once — the maintainer's release
ritual (and notarization time) stays the same, but Intel is covered.

  • Makefile: new build-universal target. Each slice cross-compiles
    with CGO_ENABLED=1 (the code links C for SQLite + the Keychain),
    pinning the target arch through CC="clang -arch ..." so the build host
    is irrelevant, then lipo -creates them. release now depends on
    build-universal instead of build. Plain make build stays native for
    fast local dev.
  • scripts/release-tarball.sh: name the asset from the binary's real
    archs via lipo -archsdarwin-universal (or darwin-arm64 /
    darwin-amd64 for a single-arch dev build).
  • scripts/install-beta.sh: prefer the darwin-universal asset, fall
    back to an arch-matched asset for older releases (maps uname -m
    x86_64amd64).
  • .github/workflows/release.yml: upload the darwin-universal bundle.
  • docs: update download filenames; note Intel is supported.

scripts/sign.sh and scripts/notarize.sh are unchanged and already
arch-agnostic (a universal Mach-O signs and notarizes as one file). No
new CI secrets are required.

Testing

Verified locally on Apple Silicon (macOS, Go 1.26):

  • Both slices cross-compile with CGO: GOARCH=amd64 CC="clang -arch x86_64"
    and GOARCH=arm64 CC="clang -arch arm64".
  • make build-universal produces bin/agentcookie as
    Mach-O universal binary with 2 architectures [x86_64] [arm64], runs on
    this host, and is version-stamped.
  • release-tarball.sh's lipo -archs detection resolves
    universal → darwin-universal, arm64-only → darwin-arm64, amd64-only
    darwin-amd64.
  • bash -n clean on both edited scripts.

Signing/notarization couldn't be exercised without the Developer ID cert;
those steps run unchanged in the maintainer's release environment.

Notes

  • Backward compatible: install-beta.sh still installs older
    darwin-arm64-only releases via the fallback path.
  • .goreleaser.yaml already lists amd64, but releases are cut through the
    make release + release-tarball.sh beta-bundle path, which is what this
    PR updates. The goreleaser path is left untouched to keep scope tight.

The release pipeline builds and ships only the maintainer's native arch
(arm64), so Intel Macs have no signed/notarized binary to install and are
stuck on unsigned `go install` builds. That blocks universal cookie
delivery on Intel sinks, since the sink daemon needs a signed binary to
read Chrome Safe Storage via teamid.

Build one Universal 2 binary (arm64 + x86_64) with lipo, signed and
notarized once, so a single asset runs natively on both architectures:

- Makefile: add `build-universal` (cross-compiles each slice with CGO on,
  pinning the target arch via CC="clang -arch ..." so the build host is
  irrelevant, then lipo-fuses them). `release` now depends on it.
- release-tarball.sh: detect the binary's archs via `lipo -archs` and name
  the asset darwin-universal (or darwin-arm64 / darwin-amd64 for a
  single-arch dev build).
- install-beta.sh: prefer the darwin-universal asset, fall back to an
  arch-matched asset for older releases.
- release.yml: upload the darwin-universal bundle.
- docs: update download filenames and note Intel is supported.

Signing/notarization scripts are unchanged and arch-agnostic; no new
secrets are required. Verified locally on Apple Silicon: both slices
cross-compile with CGO, lipo produces a working universal binary, and the
tarball arch-detection resolves universal / arm64 / amd64 correctly.
@greptile-apps

greptile-apps Bot commented Jul 10, 2026

Copy link
Copy Markdown

Greptile Summary

This PR changes the Darwin release flow to ship one Universal 2 beta binary. The main changes are:

  • Adds a build-universal Make target for arm64 and x86_64 slices.
  • Makes make release sign and notarize the universal binary.
  • Names beta tarballs from the binary architecture.
  • Updates the installer to prefer darwin-universal assets with an arch fallback.
  • Updates release notes and beta docs to use the universal filename.

Confidence Score: 5/5

This looks safe to merge after a small release-upload guard.

  • The universal build, signing, notarization, and installer paths are consistent.
  • The release upload step can miss a misnamed tarball without a clear guard.
  • No workflow security rule violations were introduced.

.github/workflows/release.yml

Important Files Changed

Filename Overview
Makefile Adds the Universal 2 build target and routes releases through it.
.github/workflows/release.yml Uploads the universal beta bundle and keeps the workflow permissions unchanged.
scripts/release-tarball.sh Detects binary slices with lipo -archs and names the tarball accordingly.
scripts/install-beta.sh Downloads the universal asset first and falls back to an arch-specific tarball.
docs/quickstart-beta.md Updates beta install docs for the universal Darwin asset.
.github/RELEASE_NOTES_TEMPLATE.md Updates release-note install commands for the universal tarball.

Fix All in Codex Fix All in Claude Code Fix All in Cursor Fix All in Conductor

Reviews (1): Last reviewed commit: "feat: ship a Universal 2 (arm64 + x86_64..." | Re-trigger Greptile

@@ -102,7 +103,7 @@ jobs:
- name: attach beta bundle to release
run: |
gh release upload "${{ github.ref_name }}" \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Universal Asset Can Be Skipped

If scripts/release-tarball.sh ever names the bundle darwin-arm64 or darwin-amd64 instead of darwin-universal, this glob matches no local files and the release can be published without the beta tarball. The tarball script has a silent fallback when lipo -archs fails, so this path needs an explicit file existence check before upload.

Fix in Codex Fix in Claude Code Fix in Cursor Fix in Conductor

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