#22224: fix(launchd/macos): prevent restart loop by using KeepAlive.SuccessfulExit + ThrottleInterval
channel: matrix
app: macos
gateway
size: M
Cluster:
Gateway Restart Improvements
## Summary\n\nFixes LaunchAgent restart-loop behavior when both launchd and the app touch gateway lifecycle.\n\n### What changed\n- **Daemon LaunchAgent plist** now uses:\n - KeepAlive = { SuccessfulExit = true }\n - ThrottleInterval = 5\n- **Service audit** now validates:\n - KeepAlive dict form with SuccessfulExit: true\n - ThrottleInterval = 5\n- **macOS app LaunchAgent plist** updated to match the same KeepAlive/Throttle semantics (prevents app/launchd lifecycle conflicts).\n\n### Why\nA bare KeepAlive=true can fight app-managed lifecycle operations and trigger repeated relaunch behavior. Using SuccessfulExit + throttle aligns restart policy and avoids rapid loops.\n\n## Validation\n- daemon tests (launchd plist + audit + install) included in branch\n- macOS LaunchAgent plist write-path updated in app code\n\n## Issues\n- Closes #20257 (Workshop #474)
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR fixes a LaunchAgent restart-loop issue on macOS by changing `KeepAlive` from a simple boolean to a dictionary with `SuccessfulExit: true`, and adds a 5-second `ThrottleInterval`. The changes apply to both the daemon LaunchAgent plist and the macOS app's LaunchAgent plist, preventing conflicts when both launchd and the app manage gateway lifecycle.
**Key changes:**
- Updated `buildLaunchAgentPlist` to emit `KeepAlive` as `<dict><key>SuccessfulExit</key><true/></dict>` instead of bare `<true/>`
- Added `ThrottleInterval` set to 5 seconds in both daemon and app LaunchAgent plists
- Enhanced service audit to validate the new KeepAlive structure and ThrottleInterval
- Added comprehensive tests for plist generation, installation, and audit validation
- Also includes Matrix extension changes for LaTeX rendering with `data-mx-maths` attributes (commits 8f2a0018, 5819263d)
**Matrix changes context:**
The Matrix changes add support for rendering LaTeX math expressions using the `data-mx-maths` format for KaTeX support in Element clients. The implementation extracts LaTeX before markdown processing, preserves it during rendering, then converts to the appropriate HTML format.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The changes are well-tested with comprehensive test coverage for both the launchd plist generation and service audit validation. The fix addresses a specific, documented issue (#20257) with a targeted solution. All tests validate the new KeepAlive dictionary structure and ThrottleInterval. The Matrix changes include thorough test coverage for LaTeX rendering edge cases. No breaking changes or risky refactoring detected.
- No files require special attention
<sub>Last reviewed commit: 85d8c6a</sub>
<!-- greptile_other_comments_section -->
<sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#20272: fix: LaunchAgent KeepAlive causes restart loop (fixes #20257)
by MisterGuy420 · 2026-02-18
89.1%
#16845: fix(daemon): gateway auto-restart on SIGTERM + agent restart guidel...
by kiminbean · 2026-02-15
82.9%
#11327: fix(launchd): reload plist from disk on restartLaunchAgent
by caiop91 · 2026-02-07
79.0%
#19857: fix(launchd): self-heal restart when service is unloaded
by vibecodooor · 2026-02-18
76.9%
#6273: fix: handle EPIPE errors gracefully in daemon operations
by batumilove · 2026-02-01
76.9%
#13084: fix(daemon): multi-layer defense against zombie gateway processes
by openperf · 2026-02-10
75.3%
#15619: fix: clean up orphan LaunchAgent plist on bootstrap failure
by superlowburn · 2026-02-13
75.2%
#22304: Gateway: fix launchd start after stop
by apethree · 2026-02-21
75.2%
#21591: fix(update): prevent double restart when refreshing service env
by irchelper · 2026-02-20
75.0%
#18236: macOS daemon: bootstrap LaunchAgent on gateway start after stop
by agisilaos · 2026-02-16
74.3%