# NousResearch/hermes-agent · Gateway systemd service Python environment path issues

## Open now

- Nothing open on GitHub.

Most items concern the gateway's systemd service unit pointing to the wrong Python executable—system Python, hardcoded paths, or uv Python instead of the virtualenv's Python. A handful of adjacent items touch Nix/Hermes wrapper handling, startup exit codes, and minor unrelated fixes bundled into the same PRs.

## TL;DR

- 15 member(s): 0 open issue(s), 8 closed issue(s), 0 open PR(s), 2 merged PR(s), 5 PR(s) closed without merging.
- A fix was merged to main in PR #8861. Verify it addresses your case.
- **Recommended:** read PR #8861 (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: `partially_resolved` · deciding PR(s): `pr-10093`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_PARTIAL`): some members are connected by structural evidence (shared changed files, or a closing/superseded reference); the rest are joined by an automated relevance judgement over their text.
- Members outside that structural core may belong to a different underlying problem.
- Pairwise link density `0.12`: 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

- #7976: \[Bug\]: gateway install --system ExecStart skips project venv
- #8475: \[Setup\]: gateway startup seems to fail with an error exit code
- #8519: Systemd service uses resolved Python path instead of venv symlink, breaking module imports
- #8620: Gateway restart failures: wrong Python env in systemd, immediate exit after --replace, context_length not read, compression model 503
- #9013: gateway install --system uses system Python instead of venv Python in ExecStart
- #9021: PR: fix system service venv python path (Issue #9013)
- #9201: \[Bug\]: systemd system service fails on boot: ExecStart uses uv Python instead of venv Python
- #48071: \[Bug\]: Nix level-1 gateway install generates systemd unit that bypasses Hermes wrapper

## Prior & competing PRs

- **#8861: fix(gateway): keep venv python symlink unresolved in systemd unit**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`; implication `superseded`
  - files: `hermes_cli/gateway.py`
  - fix hunks:
  - `hermes_cli/gateway.py`

    ```diff
    @@ -768,14 +768,22 @@ def _remap_path_for_user(path: str, target_home_dir: str) -> str:
     
           /root/.hermes/hermes-agent  -> /home/alice/.hermes/hermes-agent
           /opt/hermes                 -> /opt/hermes  (kept as-is)
    +
    +    Note: this function intentionally does NOT resolve symlinks. A venv's
    +    ``bin/python`` is typically a symlink to the base interpreter (e.g. a
    +    uv-managed CPython at ``~/.local/share/uv/python/.../python3.11``);
    +    resolving that symlink swaps the unit's ``ExecStart`` to a bare Python
    +    that has none of the venv's site-packages, so the service crashes on
    +    the first ``import``. Keep the symlinked path so the venv activates
    +    its own environment. Lexical expansion only via ``expanduser``.
         """
    -    current_home = Path.home().resolve()
    -    resolved = Path(path).resolve()
    +    current_home = Path.home()
    +    p = Path(path).expanduser()
         try:
    -        relative = resolved.relative_to(current_home)
    +        relative = p.relative_to(current_home)
             return str(Path(target_home_dir) / relative)
         except ValueError:
    -        return str(resolved)
    +        return str(p)
     
     
     def _hermes_home_for_target_user(target_home_dir: str) -> str:
    ```
- **#9230: fix(gateway): use venv Python for systemd ExecStart instead of sys.executable (#9201)**. closed without merge · fix tier `suggested`
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `73ed09e145826c3521dc770ffefeb33b3efa1a9f`, `#9629`
  - _suggested-tier fix detail withheld; re-request with `?tier=all` to include it._
- **#10093: fix: compression model falls back to main model on permanent 503/404 (#8620)**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`; implication `superseded`
  - files: `agent/context_compressor.py`
  - fix hunks:
  - `agent/context_compressor.py`

    ```diff
    @@ -693,6 +693,7 @@ def _generate_summary(self, turns_to_summarize: List[Dict[str, Any]], focus_topi
                 # Store for iterative updates on next compaction
                 self._previous_summary = summary
                 self._summary_failure_cooldown_until = 0.0
    +            self._summary_model_fallen_back = False
                 return self._with_summary_prefix(summary)
             except RuntimeError:
                 # No provider configured — long cooldown, unlikely to self-resolve
    ```

    ```diff
    @@ -703,6 +704,34 @@ def _generate_summary(self, turns_to_summarize: List[Dict[str, Any]], focus_topi
                                 _SUMMARY_FAILURE_COOLDOWN_SECONDS)
                 return None
             except Exception as e:
    +            # If the summary model is different from the main model and the
    +            # error looks permanent (model not found, 503, 404), fall back to
    +            # using the main model instead of entering cooldown that leaves
    +            # context growing unbounded.  (#8620 sub-issue 4)
    +            _status = getattr(e, "status_code", None) or getattr(getattr(e, "response", None), "status_code", None)
    +            _err_str = str(e).lower()
    +            _is_model_not_found = (
    +                _status in (404, 503)
    +                or "model_not_found" in _err_str
    +                or "does not exist" in _err_str
    +                or "no available channel" in _err_str
    +            )
    +            if (
    +                _is_model_not_found
    +                and self.summary_model
    +                and self.summary_model != self.model
    +                and not getattr(self, "_summary_model_fallen_back", False)
    +            ):
    +                self._summary_model_fallen_back = True
    +                logging.warning(
    +                    "Summary model '%s' not available (%s). "
    +                    "Falling back to main model '%s' for compression.",
    +                    self.summary_model, e, self.model,
    +                )
    +                self.summary_model = ""  # empty = use main model
    +                self._summary_failure_cooldown_until = 0.0  # no cooldown
    +                return self._generate_summary(messages, summary_budget)  # retry immediately
    +
                 # Transient errors (timeout, rate limit, network) — shorter cooldown
                 _transient_cooldown = 60
                 self._summary_failure_cooldown_until = time.monotonic() + _transient_cooldown
    ```
- **#7985: fix(gateway): fall back to python3 when venv lacks bare python symlink**. closed without merge
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `#8861`, `#7735`
- **#8522: fix: preserve venv symlink in systemd service ExecStart path**. closed without merge
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `#8861`, `#7735`
- **#9629: fix(gateway): systemd Python path fallback**. closed without merge
  - maintainer direction: category `duplicate_of`; implication `duplicate`; refs `#9230`
- **#48086: fix(gateway): use hermes wrapper as systemd ExecStart on Nix installs (#48071)**. closed without merge
  - maintainer direction: category `duplicate_of`; implication `duplicate`; refs `#48071`, `#33663`, `#33663`

## Fix status

- Merged to main in PR #8861 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-04-15`. This confirmation is old and may be out of date (a revert/reopen would not have invalidated it here); re-verify.
- Subsystem: `environments`
