Skip to content

fix(installer): build macOS setup DMG as universal binary - #37762

Open
westkite1201 wants to merge 4 commits into
NousResearch:mainfrom
westkite1201:fix/macos-universal-setup-dmg
Open

fix(installer): build macOS setup DMG as universal binary#37762
westkite1201 wants to merge 4 commits into
NousResearch:mainfrom
westkite1201:fix/macos-universal-setup-dmg

Conversation

@westkite1201

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds a dedicated macOS installer workflow for Hermes Setup that builds the Tauri app with --target universal-apple-darwin and fails the workflow unless the bundled executable contains both x86_64 and arm64 slices.

This prevents a release DMG from silently shipping as Apple Silicon-only and causing Bad CPU type in executable on Intel Macs.

Related Issue

Fixes #37505

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • Added .github/workflows/build-macos-installer.yml for an admin-gated macOS installer build.
  • Added tauri:build:macos:universal to apps/bootstrap-installer/package.json.
  • The workflow installs both Apple Rust targets, builds universal-apple-darwin, verifies the app executable with lipo -info, and uploads the DMG/app artifacts with if-no-files-found: error.

How to Test

  1. npm ci
  2. npm --workspace @hermes/bootstrap-installer run build
  3. ruby -e 'require "yaml"; YAML.load_file(".github/workflows/build-macos-installer.yml"); puts "yaml ok"'
  4. git diff --check
  5. Static workflow assertions confirmed the workflow contains universal-apple-darwin, lipo -info, x86_64, arm64, and if-no-files-found: error.

Not tested: the macOS universal Tauri build itself was not run locally because this environment is Linux; actionlint is not installed locally.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: Linux 6.8.0-87-generic; macOS runner build not locally available

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

For New Skills

N/A — this PR does not add or modify skills.

Screenshots / Logs

$ npm --workspace @hermes/bootstrap-installer run build
> @hermes/bootstrap-installer@0.0.1 build
> tsc -b && vite build
✓ 1981 modules transformed.
✓ built in 5.87s

$ ruby -e 'require "yaml"; YAML.load_file(".github/workflows/build-macos-installer.yml"); puts "yaml ok"'
yaml ok

$ git diff --check
# no output

Add a dedicated macOS installer workflow that builds Hermes Setup with the universal Apple target and fails if the bundled executable is not both x86_64 and arm64.

Constraint: keep the existing generic Tauri build script unchanged for other platforms.
Rejected: only renaming the current DMG | it would not prevent arm64-only artifacts from being produced again.
Confidence: medium
Scope-risk: narrow
Tested: npm ci; npm --workspace @hermes/bootstrap-installer run build; ruby YAML.load_file .github/workflows/build-macos-installer.yml; git diff --check; static workflow assertions
Not-tested: macOS universal Tauri build on a macOS runner; actionlint unavailable locally
@westkite1201
westkite1201 requested a review from a team June 3, 2026 01:01
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have labels Jun 3, 2026

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review Summary

Verdict: Approved

Overview

Builds the macOS setup DMG as a universal binary (arm64 + x86_64). Ensures smooth install experience on both Apple Silicon and Intel Macs.

✅ Looks Good

  • 94 additions, 0 deletions
  • Universal binary support is standard practice for macOS distribution
  • No changes to non-macOS build paths
  • No security concerns
  • Follows Apple's recommended packaging approach

Reviewed by Hermes Agent

austinpickett
austinpickett previously approved these changes Jun 10, 2026

@austinpickett austinpickett left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approve.

Verified on main: .github/workflows/build-macos-installer.yml is absent and apps/bootstrap-installer/package.json has no tauri:build:macos:universal script — the bug (no universal-binary build path) is present.

Diff scope (2 files, minimal):

  • New tauri:build:macos:universal npm script: tauri build --target universal-apple-darwin.
  • New dispatch-only workflow that (a) gates on repo-admin permission before producing release artifacts, (b) pins all actions by commit SHA, (c) builds the universal DMG, and (d) verifies universality via lipo -info asserting both x86_64 and arm64 before upload (if-no-files-found: error).

Hygiene: no package-lock.json churn, no version bumps.

Cluster: independent of #38673/#39093 — touches only the Tauri bootstrap-installer + CI, not the Electron desktop app. No conflict.

…etup-dmg

# Conflicts:
#	apps/bootstrap-installer/package.json
@westkite1201

Copy link
Copy Markdown
Contributor Author

Updated this branch with the latest main and resolved the package.json conflict while keeping both the universal macOS build script and the new typecheck script.\n\nLocal checks run:\n- node -e "JSON.parse(require('fs').readFileSync('apps/bootstrap-installer/package.json','utf8'))"\n- ruby -e 'require "yaml"; YAML.load_file(".github/workflows/build-macos-installer.yml")'\n- git diff --check\n- python3 scripts/check-windows-footguns.py --diff origin/main\n\nThe PR is now mergeable again on GitHub.

@stantond

Copy link
Copy Markdown

Would love to see this merged! Estimated 20-25% of Mac users are still using Intel devices.

@teknium1 teknium1 left a comment

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.

Thanks for adding a focused universal-build path; the Intel-macOS packaging gap remains on current main.

Problems

  • .github/workflows/build-macos-installer.yml:63 expects Hermes Setup.app, but current main declares "productName": "Hermes" in apps/bootstrap-installer/src-tauri/tauri.conf.json:3. The rename landed in b34ee8074, whose commit message explicitly identifies the macOS installer rename. The existence check will fail before lipo or either upload step runs.

Suggested changes

  • Update the verification path to .../bundle/macos/Hermes.app/Contents/MacOS/Hermes-Setup, then run the workflow on macOS to validate the generated bundle.

Automated hermes-sweeper review.

workspaces: apps/bootstrap-installer/src-tauri

- name: Build universal macOS DMG
run: npm run tauri:build:macos:universal

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.

Current main renamed the Tauri productName to Hermes (apps/bootstrap-installer/src-tauri/tauri.conf.json:3, commit b34ee8074), so this path will not exist. Use .../bundle/macos/Hermes.app or derive the bundle name from the active Tauri config.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users labels Jul 14, 2026
@ryancalpin

ryancalpin commented Jul 16, 2026

Copy link
Copy Markdown

Tested successfully on a real Intel Mac:

  • macOS 15.7.5 (24G624), x86_64
  • Official Hermes tag v2026.7.7.2
  • Commit 9de9c25f620ff7f1ce0fd5457d596052d5159596
  • Built the Tauri bootstrap installer for x86_64-apple-darwin
  • Installer completed all 11 visible setup stages
  • Full Electron desktop GUI launched successfully
  • Installer executable and all 17 Electron/native Mach-O components verified as x86_64
  • Deep local code-signature verification passed
  • 308 desktop tests passed, 1 platform-specific test skipped
  • All 27 Rust installer tests passed
  • hermes desktop --build-only --force-build rebuilt a working Intel desktop app

The current installer bundle path is:
apps/bootstrap-installer/src-tauri/target/x86_64-apple-darwin/release/bundle/macos/Hermes.app

This validates the Intel build and runtime path, but not the arm64 slice of a universal binary or official Developer ID signing/notarization.

Reproducible build harness and full report: https://github.com/ryancalpin/hermes-agent-intel-build

Unofficial Intel test prerelease (ad-hoc signed and not Apple-notarized): https://github.com/ryancalpin/hermes-agent-intel-build/releases/tag/v2026.7.7.2-intel-test.1

Happy to help update this PR rather than opening another duplicate.

@alt-glitch alt-glitch added comp/desktop Electron desktop app (apps/desktop/*) sweeper:risk-automation Sweeper risk: may affect CI, automerge, label sync, or maintainer automation and removed sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Jul 16, 2026
@teknium1 teknium1 added the area/install-update Installer, updater, packaging, wheels, doctor label Jul 19, 2026
@alt-glitch alt-glitch added the needs-decision Awaiting maintainer decision before any implementation label Jul 19, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related to open #51777: both target universal macOS bootstrap-installer artifacts, but this is a focused manual workflow while #51777 includes a broader release/configuration path. Maintainer selection is needed.

@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Related to #51777: both build universal macOS installer artifacts, but their workflow/release scope differs; a maintainer consolidation choice is needed.

@jeffbax

jeffbax commented Aug 16, 2026

Copy link
Copy Markdown

Would love to see this merged! Estimated 20-25% of Mac users are still using Intel devices.

🙏 Same, was in the middle of trying to set up Hermes on my Intel Mac via Homebrew and ran into the unfortunate news…

There's still a good amount of us left on Intel Macs (OCLP helps), and reusing older hardware to run an agent framework is a great way to avoid it hitting the dumpster (or having to deal with the current SSD and RAM prices for a while longer…)

@alt-glitch alt-glitch removed the needs-decision Awaiting maintainer decision before any implementation label Aug 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/install-update Installer, updater, packaging, wheels, doctor comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-automation Sweeper risk: may affect CI, automerge, label sync, or maintainer automation type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hermes Desktop macOS DMG is arm64-only and fails on Intel Macs

8 participants