hermes - ✅(Solved) Fix [Bug]: hermes gateway restart --all leaves launchd service unloaded on macOS if interrupted [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#28632Fetched 2026-05-20 04:03:04
View on GitHub
Comments
1
Participants
2
Timeline
7
Reactions
0
Timeline (top)
labeled ×4cross-referenced ×2commented ×1

Error Message

On macOS, hermes gateway restart --all is non-atomic. It runs launchctl bootout (which unloads the service definition) and only later runs launchctl bootstrap. If the CLI process dies between the two — closed terminal pane, Ctrl+C, SIGHUP — the service stays unloaded and KeepAlive cannot revive the gateway. No error is shown.

Root Cause

hermes_cli/gateway.py:5234-5287 — the --all branch on macOS calls launchd_stop() (bootout) → kill_gateway_processeslaunchd_start() (bootstrap). bootout unloads, so the window between the two is unsafe.

The non---all path (launchd_restart, gateway.py:3021) already does the right thing — launchctl kickstart -k cycles the process under the same job, no unload.

Fix Action

Fixed

PR fix notes

PR #28633: fix(gateway): make restart --all atomic on macOS

Description (problem / solution / changelog)

What does this PR do?

Fixes a non-atomic restart path. hermes gateway restart --all on macOS calls launchd_stop() (launchctl bootout → unloads the service) and only later calls launchd_start() (bootstrap). If the CLI dies between the two — closed pane, Ctrl+C, SIGHUP — the launchd service stays unloaded and the gateway can't be revived by KeepAlive.

This PR replaces that path with launchd_restart() (launchctl kickstart -k), which cycles the process atomically under the same launchd job. Other-profile processes are still swept via kill_gateway_processes, with the current PID excluded.

Related Issue

Fixes #28632

Type of Change

  • 🐛 Bug fix

Changes Made

  • hermes_cli/gateway.py:5234-5287 (_gateway_command_inner, restart --all): macOS branch now uses launchd_restart(); systemd/Windows untouched.

How to Test

Repro (without fix):

  1. hermes gateway start; confirm in launchctl list.
  2. hermes gateway restart --all from a closable pane.
  3. Close the pane immediately.
  4. launchctl list | grep ai.hermes.gateway → empty.

Verify (with fix): 1–3 as above. Step 4 → service still loaded with a new PID.

Sanity: scripts/run_tests.sh tests/hermes_cli/test_gateway_service.py tests/hermes_cli/test_update_gateway_restart.py tests/hermes_cli/test_gateway.py — 202 pass, 1 skipped, 6 pre-existing systemd-on-macOS env failures that also fail on origin/main (no D-Bus session).

Checklist

  • Contributing Guide read
  • Conventional Commits
  • No duplicate PR
  • Single focused change
  • Tests pass (gateway-related, on macOS; systemd failures are pre-existing env mismatches)
  • Tests added — happy to add a subprocess-mocked test asserting kickstart -k is used instead of bootout+bootstrap; reviewer's call
  • Tested on macOS 15.4 (Darwin 25.4.0, arm64)
  • Docs / config / cross-platform considered — N/A or unchanged

Logs

12:13:10.159  bootout initiated by: launchctl<-python3.11<-zsh<-zellij
12:13:11.088  removing service: ai.hermes.gateway
(no subsequent bootstrap)

Changed files

  • hermes_cli/gateway.py (modified, +19/-8)

Code Example

12:13:10.159  bootout initiated by: launchctl<-python3.11<-zsh<-zellij
12:13:10.159  signaled service: Terminated: 15
12:13:11.088  exited due to exit(1)
12:13:11.088  removing service: ai.hermes.gateway
12:13:11.088  service state: not running
RAW_BUFFERClick to expand / collapse

Bug Description

On macOS, hermes gateway restart --all is non-atomic. It runs launchctl bootout (which unloads the service definition) and only later runs launchctl bootstrap. If the CLI process dies between the two — closed terminal pane, Ctrl+C, SIGHUP — the service stays unloaded and KeepAlive cannot revive the gateway. No error is shown.

Steps to Reproduce

  1. hermes gateway start → confirm launchctl list | grep ai.hermes.gateway shows a PID.
  2. In a closable pane: hermes gateway restart --all
  3. Close the pane immediately.
  4. launchctl list | grep ai.hermes.gateway → empty. Gateway gone, no auto-recovery.

Expected

Service definition stays loaded; KeepAlive keeps the gateway alive.

Actual

launchctl bootout unloads the service. launchctl bootstrap never runs. Trace from log show --predicate 'process == "launchd"':

12:13:10.159  bootout initiated by: launchctl<-python3.11<-zsh<-zellij
12:13:10.159  signaled service: Terminated: 15
12:13:11.088  exited due to exit(1)
12:13:11.088  removing service: ai.hermes.gateway
12:13:11.088  service state: not running

No subsequent bootstrap event.

Component / Env

  • Gateway
  • macOS 15.4 (Darwin 25.4.0, arm64), Python 3.11.14, Hermes 0.14.0

Root Cause

hermes_cli/gateway.py:5234-5287 — the --all branch on macOS calls launchd_stop() (bootout) → kill_gateway_processeslaunchd_start() (bootstrap). bootout unloads, so the window between the two is unsafe.

The non---all path (launchd_restart, gateway.py:3021) already does the right thing — launchctl kickstart -k cycles the process under the same job, no unload.

Proposed Fix

In the --all macOS branch, use launchd_restart() (kickstart -k) instead of bootout/bootstrap. Exclude the current PID from the sweep so the restart isn't killed. PR follows.

Willing to Submit a PR

Yes.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix [Bug]: hermes gateway restart --all leaves launchd service unloaded on macOS if interrupted [1 pull requests, 1 comments, 2 participants]