# NousResearch/hermes-agent · Gateway --system CLI reads wrong HERMES_HOME

## Open now

- Nothing open on GitHub.

A bug where gateway --system operations (e.g. restart) incorrectly read status from root's HERMES_HOME instead of the unit's, causing false failure reports. The members include the bug report and related fix attempts.

## TL;DR

- 3 member(s): 0 open issue(s), 1 closed issue(s), 0 open PR(s), 1 merged PR(s), 1 PR(s) closed without merging.
- A fix was merged to main in PR #22803. Verify it addresses your case.
- **Recommended:** read PR #22803 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `resolved` · deciding PR(s): `pr-22803`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_SPANNING`): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
- Pairwise link density `0.67`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Closed / duplicate issues

- #22035: \[Bug\]: gateway restart --system always reports failure (60s timeout × 2) — wrapper reads runtime status from root's HERMES_HOME

## Prior & competing PRs

- **#22803: fix(gateway): adopt unit's HERMES_HOME for --system CLI ops (salvage #22533)**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `hermes_cli/gateway.py`, `scripts/release.py`
  - fix hunks:
  - `hermes_cli/gateway.py`

    ```diff
    @@ -635,6 +635,66 @@ def _probe_systemd_service_running(system: bool = False) -> tuple[bool, bool]:
         return selected_system, result.stdout.strip() == "active"
     
     
    +def _read_systemd_unit_environment(system: bool = False) -> dict[str, str]:
    +    """Parse the gateway unit's ``Environment=`` directives.
    +
    +    ``systemctl show -p Environment`` returns a single line of
    +    space-separated ``KEY=VALUE`` pairs; values are not quoted in the output
    +    even when the unit file quoted them. We split on whitespace and ``=``.
    +    """
    +    selected_system = _select_systemd_scope(system)
    +    try:
    +        result = _run_systemctl(
    +            [
    +                "show",
    +                get_service_name(),
    +                "--no-pager",
    +                "--property",
    +                "Environment",
    +            ],
    +            system=selected_system,
    +            capture_output=True,
    +            text=True,
    +            timeout=10,
    +        )
    +    except (RuntimeError, subprocess.TimeoutExpired, OSError):
    +        return {}
    +    if result.returncode != 0:
    +        return {}
    +    parsed: dict[str, str] = {}
    +    for line in result.stdout.splitlines():
    +        if not line.startswith("Environment="):
    +            continue
    +        body = line[len("Environment="):].strip()
    +        for token in body.split():
    +            if "=" not in token:
    +                continue
    +            key, value = token.split("=", 1)
    +            parsed[key] = value
    +    return parsed
    +
    +
    +def _sync_hermes_home_from_systemd_unit(system: bool) -> None:
    +    """When acting on a system-scope unit, adopt its ``HERMES_HOME``.
    +
    +    Under ``sudo``, ``HERMES_HOME`` is stripped and ``HOME=/root``, so
    +    :func:`get_hermes_home` falls back to ``/root/.hermes`` — the wrong
    +    profile. The unit file pins ``HERMES_HOME`` for the actual gateway
    +    process, so we mirror that into our own environment to make
    +    ``read_runtime_status`` / ``get_running_pid`` read the correct files.
    +    """
    +    if not system:
    +        return
    +    env = _read_systemd_unit_environment(system=True)
    +    unit_home = env.get("HERMES_HOME", "").strip()
    +    if not unit_home:
    +        return
    +    current = os.environ.get("HERMES_HOME", "").strip()
    +    if current == unit_home:
    +        return
    +    os.environ["HERMES_HOME"] = unit_home
    +
    +
     def _read_systemd_unit_properties(
         system: bool = False,
         properties: tuple[str, ...] = (
    ```

    ```diff
    @@ -2380,6 +2440,7 @@ def systemd_stop(system: bool = False):
         if system:
             _require_root_for_system_service("stop")
         _require_service_installed("stop", system=system)
    +    _sync_hermes_home_from_systemd_unit(system=system)
         try:
             from gateway.status import get_running_pid, write_planned_stop_marker
             pid = get_running_pid(cleanup_stale=False)
    ```

    ```diff
    @@ -2408,6 +2469,7 @@ def systemd_restart(system: bool = False):
             _preflight_user_systemd()
         _require_service_installed("restart", system=system)
         refresh_systemd_unit_if_needed(system=system)
    +    _sync_hermes_home_from_systemd_unit(system=system)
         from gateway.status import get_running_pid
     
         pid = get_running_pid() or _systemd_main_pid(system=system)
    ```

    ```diff
    @@ -2503,6 +2565,8 @@ def systemd_status(deep: bool = False, system: bool = False, full: bool = False)
             print(f"  Run: {'sudo ' if system else ''}hermes gateway install{scope_flag}")
             return
     
    +    _sync_hermes_home_from_systemd_unit(system=system)
    +
         if has_conflicting_systemd_units():
             print_systemd_scope_conflict_warning()
             print()
    ```
  - `scripts/release.py`

    ```diff
    @@ -66,6 +66,7 @@
         "[redacted:email]": "qWaitCrypto",
         "[redacted:email]": "Qwinty",
         "[redacted:email]": "CalmProton",
    +    "308068+mbac@users.noreply.github.com": "mbac",
         "[redacted:email]": "wesleysimplicio",
         "[redacted:email]": "SiliconID",
         "[redacted:email]": "xieNniu",
    ```
- **#22533: fix(gateway): adopt unit's HERMES_HOME for --system CLI ops**. closed without merge
  - maintainer direction: category `merged_via`; implication `superseded`; refs `#22803`

## Fix status

- Merged to main in PR #22803 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-05-09`.
