Summary
The installed LaunchAgent does not automatically recover either component after a crash. The Python server is backgrounded outside launchd supervision, and the menubar LaunchAgent has RunAtLoad but no KeepAlive policy.
Tested with the package built from main at fb265549480ff0d3ad8b14b28007370539b70cf3.
Reproduction
- Install the package and wait for
GET http://127.0.0.1:8722/health to report ready.
- Send
TERM to the exact Python PID listening on port 8722.
- Wait 12 seconds: no listener returns; the menubar process remains.
- Relaunch manually with
launchctl kickstart -k gui/$UID/com.token-meter.menubar.
- Send
TERM to the exact menubar PID.
- Wait 12 seconds: the menubar does not return, and the server listener also disappears.
Manual launchctl kickstart restores the service, confirming the installation itself is still usable.
Root cause
packaging/payload/bin/start-token-meter:79-93 backgrounds Python with nohup.
- The same script then
execs the menubar binary at line 97.
packaging/scripts/postinstall:74-101 generates one LaunchAgent with RunAtLoad but no KeepAlive.
Suggested fix
Prefer two explicit LaunchAgents:
- A server job that runs Python in the foreground and uses
KeepAlive/SuccessfulExit=false plus ThrottleInterval.
- A menubar job that runs the Swift app in the foreground and restarts independently.
- Make both jobs log separately and ensure uninstall removes both labels.
- If a single job is retained, use a real foreground supervisor that monitors/reaps/restarts both children; do not detach Python with
nohup.
- Avoid restart storms on deterministic configuration failures.
Regression tests
- Kill only the server and assert a new PID is healthy within 10 seconds while exactly one listener exists.
- Kill only the menubar and assert it restarts without replacing a healthy server.
- Repeat each crash several times and assert there are no duplicate processes or orphaned listeners.
- Verify logout/login and uninstall behavior for both jobs.
Summary
The installed LaunchAgent does not automatically recover either component after a crash. The Python server is backgrounded outside launchd supervision, and the menubar LaunchAgent has
RunAtLoadbut noKeepAlivepolicy.Tested with the package built from
mainatfb265549480ff0d3ad8b14b28007370539b70cf3.Reproduction
GET http://127.0.0.1:8722/healthto report ready.TERMto the exact Python PID listening on port 8722.launchctl kickstart -k gui/$UID/com.token-meter.menubar.TERMto the exact menubar PID.Manual
launchctl kickstartrestores the service, confirming the installation itself is still usable.Root cause
packaging/payload/bin/start-token-meter:79-93backgrounds Python withnohup.execs the menubar binary at line 97.packaging/scripts/postinstall:74-101generates one LaunchAgent withRunAtLoadbut noKeepAlive.Suggested fix
Prefer two explicit LaunchAgents:
KeepAlive/SuccessfulExit=falseplusThrottleInterval.nohup.Regression tests