Skip to content

fix(gateway): inject PATH into launchd plist for macOS service#2173

Closed
hanai wants to merge 4 commits intoNousResearch:mainfrom
hanai:fix/launchd-path-env
Closed

fix(gateway): inject PATH into launchd plist for macOS service#2173
hanai wants to merge 4 commits intoNousResearch:mainfrom
hanai:fix/launchd-path-env

Conversation

@hanai
Copy link
Copy Markdown
Contributor

@hanai hanai commented Mar 20, 2026

Summary

  • The launchd plist generated for macOS gateway service did not set PATH, so launchd's minimal default (/usr/bin:/bin:/usr/sbin:/sbin) was used at runtime
  • This caused user-installed tools such as ffmpeg (Homebrew) and node to be not found, even though they were available in the user's interactive shell
  • The systemd unit already sets PATH explicitly — this PR applies the same fix to the launchd plist

At plist-generation time (i.e. when the user runs hermes gateway install or hermes gateway start from their terminal), the full shell PATH is captured and baked into the plist, with the venv bin directory prepended. This covers all user-installed tools regardless of where they are installed, without hardcoding platform-specific paths like /opt/homebrew/bin.

PATH components are deduplicated using dict.fromkeys() (preserving order) so that venv/bin appears exactly once even when generate_launchd_plist() is called from within a launchd agent session (e.g. when an AI agent triggers hermes gateway restart). Without deduplication, each in-process restart would prepend an additional venv/bin, causing refresh_launchd_plist_if_needed() to detect a spurious change and rewrite/reload the plist on every restart.

Test plan

  • Added unit tests in tests/hermes_cli/test_update_gateway_restart.py (TestLaunchdPlistPath): plist contains EnvironmentVariables/PATH key, PATH includes venv bin, PATH starts with venv bin, current process PATH is baked in at generation time, venv/bin is deduplicated when already present in PATH
  • On macOS with Homebrew-installed ffmpeg: install gateway service with hermes gateway install, confirm ffmpeg is found when a Discord voice message is transcribed
  • Confirm hermes gateway start detects the plist change via refresh_launchd_plist_if_needed() and reloads the service automatically

Platforms tested

  • macOS (Apple Silicon)

Generated with Claude Code

launchd provides only a minimal default PATH (/usr/bin:/bin:/usr/sbin:/sbin),
causing tools like ffmpeg and node to be not found when the gateway runs as a
launchd agent. The systemd unit already sets PATH explicitly; apply the same
fix to the launchd plist.

Capture the full PATH from the user's interactive shell at plist-generation
time and prepend the venv bin directory, so all user-installed tools and
venv-installed packages are reachable by the agent process.
Copilot AI review requested due to automatic review settings March 20, 2026 14:28
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the macOS launchd plist generation for the Hermes gateway service so the background service runs with an explicit PATH (mirroring the existing systemd approach) and can find user-installed binaries like Homebrew ffmpeg/node.

Changes:

  • Capture the caller’s PATH at plist-generation time and prepend the project venv bin/.
  • Add EnvironmentVariablesPATH to the generated launchd plist.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

hanai and others added 3 commits March 20, 2026 22:45
When gateway restart is triggered from within a launchd agent session
(e.g. by an AI agent calling hermes gateway restart), os.environ['PATH']
already contains venv/bin from the baked-in plist environment.
The previous f-string prepend would add venv/bin again, causing
refresh_launchd_plist_if_needed() to detect a spurious change and
rewrite the plist on every restart, accumulating duplicates over time.

Use dict.fromkeys() to preserve insertion order while deduplicating,
ensuring venv/bin appears first exactly once regardless of the calling
environment.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
teknium1 added a commit that referenced this pull request Mar 28, 2026
…service (#3585)

Salvage of PR #2173 (hanai) and PR #3432 (timknip).

Injects PATH, VIRTUAL_ENV, and HERMES_HOME into the macOS launchd plist so gateway subprocesses find user-installed tools (node, ffmpeg, etc.). Matches systemd unit parity with venv/bin, node_modules/.bin, and resolved node dir in PATH. Includes 7 new tests and docs updates across 4 pages.

Co-Authored-By: Han <ihanai1991@gmail.com>
Co-Authored-By: timknip <timknip@users.noreply.github.com>
@teknium1
Copy link
Copy Markdown
Contributor

Merged via PR #3585. Your implementation was salvaged onto current main with authorship preserved — your commit is the primary author. Tests were updated to handle both venv/ and .venv/ layouts, and we added VIRTUAL_ENV + node_modules/.bin + resolved node dir for full systemd parity, plus docs across 4 pages. Thanks for the solid fix and tests!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants