fix(gateway): replace deprecated launchctl start/stop with kickstart/kill#4892
Closed
tmchow wants to merge 2 commits into
Closed
fix(gateway): replace deprecated launchctl start/stop with kickstart/kill#4892tmchow wants to merge 2 commits into
tmchow wants to merge 2 commits into
Conversation
…kill launchctl load/unload/start/stop are deprecated on macOS since 10.10 and fail silently on modern versions. This replaces them with the current equivalents: - load -> bootstrap gui/<uid> <plist> - unload -> bootout gui/<uid>/<label> - start -> kickstart gui/<uid>/<label> - stop -> kill SIGTERM gui/<uid>/<label> Adds _launchd_domain() helper returning the gui/<uid> target domain. Updates test assertions to match the new command signatures. Fixes NousResearch#4820
Replace the two-step stop/start restart with a single launchctl kickstart -k call. When the gateway triggers a restart from inside its own process tree, the old stop command kills the shell before the start half is reached. kickstart -k lets launchd handle the kill+restart atomically.
Contributor
Author
|
Updated based on @boobutler's analysis. The restart path now uses The two other items @boobutler raised (approval.py guard for |
Contributor
Tommyeds
pushed a commit
to Tommyeds/hermes-agent
that referenced
this pull request
Apr 12, 2026
- Fix GatewayApp → GatewayRunner import in api_server.py (PR NousResearch#4976) - Update launchd test assertions for new bootstrap/bootout/kickstart commands (PR NousResearch#4892) - Add nonlocal message declaration in run_sync() to fix UnboundLocalError (pre-existing scoping bug)
angelburgosrosado
pushed a commit
to angelburgosrosado/hermes-agent
that referenced
this pull request
Apr 27, 2026
- Fix GatewayApp → GatewayRunner import in api_server.py (PR NousResearch#4976) - Update launchd test assertions for new bootstrap/bootout/kickstart commands (PR NousResearch#4892) - Add nonlocal message declaration in run_sync() to fix UnboundLocalError (pre-existing scoping bug)
angelburgosrosado
pushed a commit
to angelburgosrosado/hermes-agent
that referenced
this pull request
Apr 28, 2026
- Fix GatewayApp → GatewayRunner import in api_server.py (PR NousResearch#4976) - Update launchd test assertions for new bootstrap/bootout/kickstart commands (PR NousResearch#4892) - Add nonlocal message declaration in run_sync() to fix UnboundLocalError (pre-existing scoping bug)
02356abc
pushed a commit
to 02356abc/hermes-agent
that referenced
this pull request
May 14, 2026
- Fix GatewayApp → GatewayRunner import in api_server.py (PR NousResearch#4976) - Update launchd test assertions for new bootstrap/bootout/kickstart commands (PR NousResearch#4892) - Add nonlocal message declaration in run_sync() to fix UnboundLocalError (pre-existing scoping bug)
olympus-terminal
pushed a commit
to olympus-terminal/hermes-agent
that referenced
this pull request
May 16, 2026
- Fix GatewayApp → GatewayRunner import in api_server.py (PR NousResearch#4976) - Update launchd test assertions for new bootstrap/bootout/kickstart commands (PR NousResearch#4892) - Add nonlocal message declaration in run_sync() to fix UnboundLocalError (pre-existing scoping bug)
gweeteve
pushed a commit
to gweeteve/hermes-agent
that referenced
this pull request
Jun 2, 2026
- Fix GatewayApp → GatewayRunner import in api_server.py (PR NousResearch#4976) - Update launchd test assertions for new bootstrap/bootout/kickstart commands (PR NousResearch#4892) - Add nonlocal message declaration in run_sync() to fix UnboundLocalError (pre-existing scoping bug)
Egavasyug
pushed a commit
to Egavasyug/hermes-agent
that referenced
this pull request
Jun 10, 2026
- Fix GatewayApp → GatewayRunner import in api_server.py (PR NousResearch#4976) - Update launchd test assertions for new bootstrap/bootout/kickstart commands (PR NousResearch#4892) - Add nonlocal message declaration in run_sync() to fix UnboundLocalError (pre-existing scoping bug)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Replaces all deprecated
launchctlsubcommands inhermes_cli/gateway.pywith their modern equivalents. On current macOS,launchctl startandlaunchctl stopsilently fail (printing "Not privileged to start service" and exiting 0), which meanshermes gateway startreports success while the gateway never actually starts.The migration:
launchctl load <plist>launchctl bootstrap gui/<uid> <plist>launchctl unload <plist>launchctl bootout gui/<uid>/<label>launchctl start <label>launchctl kickstart gui/<uid>/<label>launchctl stop <label>launchctl kill SIGTERM gui/<uid>/<label>Additionally,
launchd_restart()now useslaunchctl kickstart -kfor an atomic kill+restart instead of a two-step stop/start. This fixes the case where the gateway triggers a restart from inside its own process tree (e.g. via Telegram). The old approach killed the shell before the start command was reached, leaving the gateway stranded offline. Credit to @boobutler for the detailed analysis that surfaced this.Related Issue
Fixes #4820
Type of Change
Changes Made
hermes_cli/gateway.py: Added_launchd_domain()helper (returnsgui/<uid>target domain). Updatedrefresh_launchd_plist_if_needed(),launchd_install(),launchd_uninstall(),launchd_start(), andlaunchd_stop()to usebootstrap/bootout/kickstart/killinstead ofload/unload/start/stop. Replaced the two-steplaunchd_restart()with a singlelaunchctl kickstart -kcall.tests/hermes_cli/test_gateway_service.py: Updated test assertions for the repair path and start-retry path to match the new command signatures.launchctl listcalls (instatus.py,main.py) are unchanged, they're not deprecated.How to Test
hermes gateway startand verify the gateway actually starts (check withhermes gateway status)hermes gateway stopand confirm it stopshermes gateway restartand confirm it cycles correctlypytest tests/hermes_cli/test_gateway_service.py -q(40 tests pass)Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passDocumentation & Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/AThis contribution was developed with AI assistance (Codex).