hermes - 💡(How to fix) Fix hermes gateway install silently resets HERMES_HOME on macOS LaunchAgent

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…

On macOS, running hermes gateway install rewrites ~/Library/LaunchAgents/ai.hermes.gateway.plist from a hard-coded template that ignores the current HERMES_HOME of the running CLI environment. The previous HERMES_HOME value (and the HERMES_HOME-derived StandardOutPath / StandardErrorPath) are silently overwritten with defaults. There is no flag to pin them.

This bit us in production: a Slack-ingesting gateway pinned to ~/.hermes-bake-off/ was reinstalled via hermes gateway install to apply an unrelated config change. The install reset HERMES_HOME to ~/.hermes/ (default), the agent restarted reading the wrong tree, and Slack ingest broke for ~5 minutes until we noticed and manually re-pinned the plist.

Error Message

| StandardErrorPath | ~/.hermes/logs/gateway.error.log | ~/.hermes-custom/logs/gateway.error.log |

Root Cause

Anyone running a non-default Hermes home (parallel gateways, bake-off setups, per-org isolation, staging vs prod on one Mac) currently can't safely reinstall the gateway without manual plist forensics. The failure mode is silent — the agent comes back up reading the wrong tree, and depending on what's in ~/.hermes/ vs ~/.hermes-custom/ you may not notice until something visible breaks (in our case Slack ingest).

A one-line preservation in the macOS install path would close this.

Happy to send a PR if the maintainers can confirm which of the four behaviors above is preferred.

Fix Action

Fix / Workaround

Our workaround

  1. Captures the four fields above via PlistBuddy before install.
  2. Backs up the plist with a timestamp suffix.
  3. Runs hermes gateway install "$@" (passes through --force etc.).
  4. Re-patches the four fields via PlistBuddy.
  5. Validates via plutil -lint.
  6. launchctl bootout + bootstrap to apply.
  7. Verifies the agent reaches state = running within 10s; restores backup on any failure.

Code Example

# Set up a non-default HERMES_HOME tree
mkdir -p ~/.hermes-custom
HERMES_HOME=~/.hermes-custom hermes gateway install

# Verify the plist points at the custom tree
/usr/libexec/PlistBuddy -c 'Print :EnvironmentVariables:HERMES_HOME' \
  ~/Library/LaunchAgents/ai.hermes.gateway.plist
# → /Users/<you>/.hermes-custom    ✓

# Time passes. Now run install again (no env override this time)
hermes gateway install

# Plist is silently rewritten:
/usr/libexec/PlistBuddy -c 'Print :EnvironmentVariables:HERMES_HOME' \
  ~/Library/LaunchAgents/ai.hermes.gateway.plist
# → /Users/<you>/.hermes            (silently reset; no warning)
RAW_BUFFERClick to expand / collapse

hermes gateway install silently resets HERMES_HOME on macOS LaunchAgent

Summary

On macOS, running hermes gateway install rewrites ~/Library/LaunchAgents/ai.hermes.gateway.plist from a hard-coded template that ignores the current HERMES_HOME of the running CLI environment. The previous HERMES_HOME value (and the HERMES_HOME-derived StandardOutPath / StandardErrorPath) are silently overwritten with defaults. There is no flag to pin them.

This bit us in production: a Slack-ingesting gateway pinned to ~/.hermes-bake-off/ was reinstalled via hermes gateway install to apply an unrelated config change. The install reset HERMES_HOME to ~/.hermes/ (default), the agent restarted reading the wrong tree, and Slack ingest broke for ~5 minutes until we noticed and manually re-pinned the plist.

Environment

  • macOS (Apple Silicon; expect Intel behaves the same)
  • Hermes CLI: latest as of 2026-05-26
  • LaunchAgent label: ai.hermes.gateway

Reproduction

# Set up a non-default HERMES_HOME tree
mkdir -p ~/.hermes-custom
HERMES_HOME=~/.hermes-custom hermes gateway install

# Verify the plist points at the custom tree
/usr/libexec/PlistBuddy -c 'Print :EnvironmentVariables:HERMES_HOME' \
  ~/Library/LaunchAgents/ai.hermes.gateway.plist
# → /Users/<you>/.hermes-custom    ✓

# Time passes. Now run install again (no env override this time)
hermes gateway install

# Plist is silently rewritten:
/usr/libexec/PlistBuddy -c 'Print :EnvironmentVariables:HERMES_HOME' \
  ~/Library/LaunchAgents/ai.hermes.gateway.plist
# → /Users/<you>/.hermes           ✗ (silently reset; no warning)

Expected behavior

One of:

  1. Read current plist's HERMES_HOME first and preserve it across reinstall.
  2. Accept a --hermes-home <path> flag so callers can pin explicitly. (Current help shows only --force, --system, --run-as-user.)
  3. Honor $HERMES_HOME from the calling shell when generating the plist (current behavior appears to use a hard-coded default regardless of env).
  4. At minimum, emit a warning to stderr when the new plist's HERMES_HOME differs from the previous one.

Affected fields

The install templates all four fields off the default ~/.hermes root:

FieldDefault after installCustom value silently lost
EnvironmentVariables.HERMES_HOME~/.hermes~/.hermes-custom
StandardOutPath~/.hermes/logs/gateway.log~/.hermes-custom/logs/gateway.log
StandardErrorPath~/.hermes/logs/gateway.error.log~/.hermes-custom/logs/gateway.error.log
EnvironmentVariables.PATHtrims trailing entries beyond a default setcustom PATH tail (e.g., claude-plugin caches) silently stripped

Our workaround

Shipped a local wrapper that wraps hermes gateway install:

  1. Captures the four fields above via PlistBuddy before install.
  2. Backs up the plist with a timestamp suffix.
  3. Runs hermes gateway install "$@" (passes through --force etc.).
  4. Re-patches the four fields via PlistBuddy.
  5. Validates via plutil -lint.
  6. launchctl bootout + bootstrap to apply.
  7. Verifies the agent reaches state = running within 10s; restores backup on any failure.

Source: ~/.claude/helpers/hermes-gateway-install-safe.sh (private; happy to share if useful).

Why this matters

Anyone running a non-default Hermes home (parallel gateways, bake-off setups, per-org isolation, staging vs prod on one Mac) currently can't safely reinstall the gateway without manual plist forensics. The failure mode is silent — the agent comes back up reading the wrong tree, and depending on what's in ~/.hermes/ vs ~/.hermes-custom/ you may not notice until something visible breaks (in our case Slack ingest).

A one-line preservation in the macOS install path would close this.

Happy to send a PR if the maintainers can confirm which of the four behaviors above is preferred.

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…

FAQ

Expected behavior

One of:

  1. Read current plist's HERMES_HOME first and preserve it across reinstall.
  2. Accept a --hermes-home <path> flag so callers can pin explicitly. (Current help shows only --force, --system, --run-as-user.)
  3. Honor $HERMES_HOME from the calling shell when generating the plist (current behavior appears to use a hard-coded default regardless of env).
  4. At minimum, emit a warning to stderr when the new plist's HERMES_HOME differs from the previous one.

Still need to ship something?

×6

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

Back to top recommendations

TRENDING