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
Open questions
- 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.
- 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?
- Keep the same bundle id
dev.uq.munkel for the MAS build, or fork it so a user can run both side by side?
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)
CLIInstaller(apps/macos/Sources/MunkelApp/CLIInstaller.swift) symlinks the embeddedmunkelbinary into/opt/homebrew/bin·/usr/local/bin·~/.local/binand 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.~/Library/Application Support/Munkel/control.sock(MunkelControl.socketURLinControlProtocol.swift, served byControlServer.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.Bundler.toml(SUFeedURL,SUPublicEDKey); the appcast is generated in.github/workflows/release.yml.NotchPresenterNSEvent.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)
SMAppService.mainApp(LoginItem.swift) — OK in sandbox.NSWindow.sharingType) — OK in sandbox.com.apple.security.network.cliententitlement.Work
Munkel.entitlements(app-sandbox,network.client, App Group if IPC is kept).pkg(productbuild --sign), upload via Transporter — Swift Bundler likely can't do MAS packaging, so an Xcode target or manualpkgbuild/productbuildstep may be neededdev.uq.munkel, screenshots, review notes (explain the notch UI + screen-capture exclusion + ephemeral messaging)ITSAppUsesNonExemptEncryption+ self-classification / annual report)release.yml)Open questions
dev.uq.munkelfor the MAS build, or fork it so a user can run both side by side?