Environment: macOS, hermes installed as a launchd user agent (~/Library/LaunchAgents/ai.hermes.gateway.plist).
Symptom: Triggering hermes update from within the gateway (e.g. via Telegram chat command) shuts down the gateway but does not bring it back. Manual hermes gateway start is required to recover. Status afterward shows LastExitStatus = 0.
Root cause: Two pieces of code disagree about the exit-code contract.
- The generated plist (
hermes_cli/gateway.py:2846-2850) uses:
<key>KeepAlive</key><dict><key>SuccessfulExit</key><false/></dict>
i.e. only relaunch on a non-zero exit.
launchd_restart() (hermes_cli/gateway.py:3021) prefers a graceful SIGUSR1-driven self-restart via _request_gateway_self_restart(). That path lets the gateway exit cleanly (status 0). launchd reads exit 0 as "success, do not relaunch" and leaves the service down.
Comparison: a SIGTERM-based restart leaves LastExitStatus = 15, which launchd does relaunch. So the "fallback" path works; the "graceful" path silently breaks recovery. The code comment at gateway.py:211 references RestartForceExitStatus=75 for systemd — the launchd side has no equivalent.
Suggested fixes (either is sufficient):
- Have the graceful SIGUSR1 shutdown path exit with a non-zero status (e.g. 75) so it matches the systemd contract, or
- Change the plist template to
<key>KeepAlive</key><true/> (always relaunch unless explicitly bootout'd).
Repro: macOS, gateway installed as launchd agent, send update to gateway via Telegram. Then hermes gateway status → service not loaded.
Environment: macOS, hermes installed as a launchd user agent (
~/Library/LaunchAgents/ai.hermes.gateway.plist).Symptom: Triggering
hermes updatefrom within the gateway (e.g. via Telegram chat command) shuts down the gateway but does not bring it back. Manualhermes gateway startis required to recover. Status afterward showsLastExitStatus = 0.Root cause: Two pieces of code disagree about the exit-code contract.
hermes_cli/gateway.py:2846-2850) uses:launchd_restart()(hermes_cli/gateway.py:3021) prefers a graceful SIGUSR1-driven self-restart via_request_gateway_self_restart(). That path lets the gateway exit cleanly (status 0). launchd reads exit 0 as "success, do not relaunch" and leaves the service down.Comparison: a SIGTERM-based restart leaves
LastExitStatus = 15, which launchd does relaunch. So the "fallback" path works; the "graceful" path silently breaks recovery. The code comment atgateway.py:211referencesRestartForceExitStatus=75for systemd — the launchd side has no equivalent.Suggested fixes (either is sufficient):
<key>KeepAlive</key><true/>(always relaunch unless explicitlybootout'd).Repro: macOS, gateway installed as launchd agent, send
updateto gateway via Telegram. Thenhermes gateway status→ service not loaded.