Skip to content

Launch Munkel on the Mac App Store #72

Description

@jurij

Ship Munkel through the Mac App Store, alongside (or instead of) the current Developer ID + DMG + Sparkle distribution.

This is not a switch-flip: the Mac App Store mandates the App Sandbox, which several core pieces of the current architecture violate. Capturing the concrete blockers grounded in the code so we can decide scope.

Hard blockers (App Sandbox)

  • CLI can't be installed to PATH. CLIInstaller (apps/macos/Sources/MunkelApp/CLIInstaller.swift) symlinks the embedded munkel binary into /opt/homebrew/bin · /usr/local/bin · ~/.local/bin and edits the user's shell profile. A sandboxed app can't write outside its container, and Apple rejects apps that drop CLIs on PATH / modify shell config. → The MAS build is effectively GUI-only, with the CLI shipped only via the existing direct download / Homebrew.
  • CLI ↔ app IPC breaks. The control socket lives at ~/Library/Application Support/Munkel/control.sock (MunkelControl.socketURL in ControlProtocol.swift, served by ControlServer.swift). Under the sandbox that path redirects into the app's container, unreachable to the non-sandboxed CLI. Reaching it again needs an App Group container + group-relative socket path (and the CLI would have to know it). Tied to the GUI-only decision above.
  • Sparkle must go. App Store apps can't self-update; Apple rejects a bundled updater. The MAS build must strip Sparkle and hide the "Check for Updates" + "Install command line tool" menu items. Sparkle config lives in Bundler.toml (SUFeedURL, SUPublicEDKey); the appcast is generated in .github/workflows/release.yml.
  • Global event monitor. The click-to-reply notch monitor (NotchPresenter NSEvent.addGlobalMonitorForEvents) needs auditing under the sandbox — global mouse monitoring is generally allowed, but confirm no path needs Accessibility (not grantable to a MAS app).

Should be sandbox-compatible (verify)

  • Login-item residency via SMAppService.mainApp (LoginItem.swift) — OK in sandbox.
  • Screen-capture exclusion (NSWindow.sharingType) — OK in sandbox.
  • Relay + R2 networking — needs the com.apple.security.network.client entitlement.

Work

  • Decide distribution model: dual (Developer ID + CLI direct download and a GUI-only MAS build) vs MAS-only
  • Add a sandboxed Munkel.entitlements (app-sandbox, network.client, App Group if IPC is kept)
  • Add a MAS build flavor that strips Sparkle and the CLI-install / update menu items (build-time flag, since Swift Bundler builds the GUI)
  • Producing the MAS package: Apple Distribution + Mac Installer Distribution certs, a sandbox provisioning profile, a signed .pkg (productbuild --sign), upload via Transporter — Swift Bundler likely can't do MAS packaging, so an Xcode target or manual pkgbuild/productbuild step may be needed
  • App Store Connect: app record under dev.uq.munkel, screenshots, review notes (explain the notch UI + screen-capture exclusion + ephemeral messaging)
  • Encryption export compliance for the E2E crypto (ITSAppUsesNonExemptEncryption + self-classification / annual report)
  • Privacy nutrition labels (what the relay/R2 see — should be near-zero given E2E + ephemerality)
  • CI: a separate MAS build+upload job (distinct certs/secrets from the Developer ID release job in release.yml)

Open questions

  1. Dual distribution or MAS-only? MAS-only loses the CLI, which is central to the agent flow — likely a dealbreaker, so dual is the presumed answer.
  2. If the CLI stays out of MAS, is a GUI-only App Store build still worth it (discovery / trust) or do we skip MAS entirely?
  3. Keep the same bundle id dev.uq.munkel for the MAS build, or fork it so a user can run both side by side?

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions