Note
🤖 Claude Opus 5.5 responding on behalf of Sam
Triage on main at ffefedfa: the root cause is that syncLoginItem treats the login item as on or off, but macOS has four states.
There is no running defect to reproduce yet, because no installed copy exists on this Mac and a log out ends every live session.
Root cause
syncLoginItem in Sources/Miri/AppModel.swift compares SMAppService.mainApp.status only with .enabled.
The SDK has four states: .notRegistered, .enabled, .requiresApproval, and .notFound.
The macOS 27 SDK header SMAppService.h says .requiresApproval means "the user has denied execution".
The same header says register() then fails with kSMErrorLaunchDeniedByUser.
From the code and the header, not observed on a running app:
- With the toggle on and the item turned off in System Settings, Miri calls
register()again. It fails, and Settings shows "Launch at login could not be changed." followed by the macOS error text. That text does not say that Miri will not start at login, and Settings has no way to open Login Items. - Miri reads the status only at launch and on a toggle change, so a change in System Settings while Miri runs never reaches Settings.
- With the toggle off and the status
.requiresApproval, Miri skipsunregister(), so the item stays listed in Login Items. It does not start Miri, but it stays in the list.
The Applications-folder guard and the .enabled and .notRegistered paths match criteria 1 and 2 on paper.
They have not been run through a log out and log in.
What I checked
- No Miri copy is in
/Applicationsor~/Applications, and Spotlight finds noio.github.samanyudas.miri*bundle there. The running Miri Developer is in/tmp, sosyncLoginItemstops at the Applications guard. sfltool dumpbtmwaits for an administrator password, so I stopped it and did not read the system's login item list.- #199 is closed, so criterion 4 checks that its fix also holds for a start at login.
Criteria
Criteria 1, 2, and 4 need a real log out and log in. An agent cannot run that check on this Mac, because a log out ends every agent session and live test. They are hand checks for Sam. Criterion 3 can have a unit test over the status-to-message mapping, plus one live check in which the item is turned off in System Settings > General > Login Items.
Proposed wording changes, so that the criteria name the build that exists:
- Criterion 1: "Miri Developer, copied from the DMG to
/Applications, registers itself at first launch..." - Criterion 3: "...Settings says Miri will not start at login and shows a button that opens Login Items. Settings shows the current state when it opens, without a Miri restart."
Fix options
- Model the state (recommended).
Map all four
SMAppService.Statusvalues to one login item state inMiriCore. The state gives the Settings message and the Open Login Items button, which callsSMAppService.openSystemSettingsLoginItems(). Read it again each time Settings opens or Miri becomes active. Turning the toggle off unregisters every registered state, not only.enabled. - Special-case
.requiresApprovalonly. This is a smaller diff, but.notFoundand the stale status after a change in System Settings stay unhandled.
Setup could also warn on a first launch from outside Applications, which is open point 3. The criteria do not ask for this, so I left it out of both options.