Summary
On v0.43.0, reinstalling OpenWispr can leave the Homebrew service and menu-bar process running while dictation never becomes ready. The installer waits for Accessibility: granted, and AppDelegate blocks in its Accessibility polling loop, even though System Settings still shows OpenWispr enabled.
This appears to be a regression from the resolution of #17: both the reinstall path and the app's upgrade path reset Accessibility, but the replacement app is ad-hoc signed and has a different CDHash. TCC can retain/display an allow row associated with the previous binary while AXIsProcessTrusted() remains false for the running binary.
Observed on v0.43.0
- Installed through the official Homebrew installer
brew services reports OpenWispr started and the menu-bar process remains alive
- Microphone permission is granted
- System Settings → Privacy & Security → Accessibility shows OpenWispr ON
AXIsProcessTrusted() is still false
- The old TCC grant referenced CDHash
75B88CD0…; the running binary had CDHash 8aced679…
Ready. is never logged
install.sh waits up to five minutes for Accessibility: granted
- Relaunching/reinstalling repeats the same permission flow instead of recovering
Why it loops
There are two blocking pieces:
scripts/install.sh runs tccutil reset Accessibility com.human37.open-wispr on every reinstall, then synchronously waits for the app to log Accessibility: granted.
AppDelegate also resets Accessibility when Permissions.didUpgrade() is true, then blocks in:
while !AXIsProcessTrusted() {
Thread.sleep(forTimeInterval: 0.5)
}
With the stale visible TCC row, users reasonably see the switch already ON and have no indication that macOS expects it to be rebound to the new binary. The app never reaches startListening() or logs Ready., while the installer waits on a state that cannot resolve by itself.
Reproduction
- Install and grant Accessibility to one OpenWispr v0.43.0 binary.
- Reinstall/replace it through the official installer so the ad-hoc binary CDHash changes.
- Observe that Accessibility still appears ON in System Settings.
- Start OpenWispr and check
AXIsProcessTrusted() / the OpenWispr log.
- The service stays alive, trust remains false, and the installer/app wait indefinitely (or until the installer's five-minute timeout).
Expected behavior
- Routine reinstall/upgrade should not blindly reset a working permission grant.
- The app should launch into an explicit waiting-for-permission state without blocking the rest of initialization indefinitely.
- The installer should use a bounded wait and explain the stale-row recovery: toggle OpenWispr OFF, then ON, to bind the grant to the current binary.
- The installer should clearly report “installed but Accessibility not confirmed” rather than appearing hung or claiming dictation readiness.
Suggested fix
- Remove the unconditional Accessibility and Microphone resets from the reinstall path.
- Stop resetting Accessibility automatically from
AppDelegate on every detected version change.
- Replace the blocking
while !AXIsProcessTrusted() loop with a non-blocking timer/poller that keeps the menu-bar UI responsive and starts hotkey listening once trust becomes true.
- Bound the installer's Accessibility wait and print the OFF → ON recovery instruction when the row is visible but stale.
- Longer term, use a stable signing identity so upgrades do not present as unrelated ad-hoc binaries to TCC.
I have a narrow local patch implementing the first four changes and can open a PR with tests separately.
Summary
On v0.43.0, reinstalling OpenWispr can leave the Homebrew service and menu-bar process running while dictation never becomes ready. The installer waits for
Accessibility: granted, andAppDelegateblocks in its Accessibility polling loop, even though System Settings still shows OpenWispr enabled.This appears to be a regression from the resolution of #17: both the reinstall path and the app's upgrade path reset Accessibility, but the replacement app is ad-hoc signed and has a different CDHash. TCC can retain/display an allow row associated with the previous binary while
AXIsProcessTrusted()remainsfalsefor the running binary.Observed on v0.43.0
brew servicesreports OpenWispr started and the menu-bar process remains aliveAXIsProcessTrusted()is stillfalse75B88CD0…; the running binary had CDHash8aced679…Ready.is never loggedinstall.shwaits up to five minutes forAccessibility: grantedWhy it loops
There are two blocking pieces:
scripts/install.shrunstccutil reset Accessibility com.human37.open-wispron every reinstall, then synchronously waits for the app to logAccessibility: granted.AppDelegatealso resets Accessibility whenPermissions.didUpgrade()is true, then blocks in:With the stale visible TCC row, users reasonably see the switch already ON and have no indication that macOS expects it to be rebound to the new binary. The app never reaches
startListening()or logsReady., while the installer waits on a state that cannot resolve by itself.Reproduction
AXIsProcessTrusted()/ the OpenWispr log.Expected behavior
Suggested fix
AppDelegateon every detected version change.while !AXIsProcessTrusted()loop with a non-blocking timer/poller that keeps the menu-bar UI responsive and starts hotkey listening once trust becomes true.I have a narrow local patch implementing the first four changes and can open a PR with tests separately.