Summary
The Hermes gateway leaks its own VIRTUAL_ENV into every terminal subprocess. If the agent runs uv sync, uv pip install, poetry install, or pip install in any project directory other than its own, those tools treat Hermes' venv as the active install target and rebuild it against the user's pyproject.toml — wiping every Hermes runtime dependency and bricking the gateway on the next restart.
Reproducer
# any session where the gateway is running as a systemd service:
cd ~/code/some-other-project # has its own pyproject.toml
uv sync # uv sees VIRTUAL_ENV=~/.hermes/hermes-agent/venv
# and reinstalls THAT venv against this project's deps
sudo systemctl restart hermes-gateway # crashes — Hermes deps gone
What happened in my case
Mid-conversation the agent ran uv sync inside ~/code/fb-mcp. uv honored the inherited VIRTUAL_ENV (set by the gateway systemd unit at hermes_cli/gateway.py:2164 / :2199), reinstalled ~/.hermes/hermes-agent/venv against fb-mcp/pyproject.toml, replaced Python 3.11 with 3.12, and dropped every Hermes dependency. Next gateway restart died with ModuleNotFoundError.
Diagnostic artifacts (Python before/after, dep list before/after, the offending uv invocation) are reproducible by setting VIRTUAL_ENV=/path/to/hermes/venv in any shell and running uv sync in any other project.
Root cause
hermes_cli/gateway.py emits Environment="VIRTUAL_ENV={venv_dir}" in three places:
- line 2164 — system unit template
- line 2199 — user unit template
- line 2807 — launchd plist template
The gateway needs VIRTUAL_ENV set for its own process resolution, but nothing scrubs it when spawning terminal subprocesses. uv (and poetry, pip --user, pipenv) treat inherited VIRTUAL_ENV as an implicit --target.
Proposed fix
Scrub at the subprocess-env boundary, not the unit boundary. Add VIRTUAL_ENV and the other package-manager activation markers (VIRTUAL_ENV_PROMPT, UV_PROJECT_ENVIRONMENT, POETRY_ACTIVE, PIPENV_ACTIVE, CONDA_PREFIX, CONDA_DEFAULT_ENV) to _HERMES_PROVIDER_ENV_BLOCKLIST in tools/environments/local.py. Users who actually want their tools to run inside Hermes' venv can opt back in via tools.env_passthrough.
PR: #PRNUM_HERE
Related
Workaround until the fix lands
# Add to ~/.config/systemd/user/hermes-gateway.service.d/no-venv-leak.conf
[Service]
UnsetEnvironment=VIRTUAL_ENV
Note this only protects against the gateway itself leaking it — it does not protect terminal subprocesses that read VIRTUAL_ENV from the gateway's own environment. The real fix is the subprocess scrub.
Severity
High. Corrupts Hermes' own installation. Recovery requires a manual uv sync --python 3.11 --extra messaging --extra mcp --extra web from outside the agent (because the agent is dead). User has no warning — the symptom is "gateway crashed on restart" hours later.
Summary
The Hermes gateway leaks its own
VIRTUAL_ENVinto every terminal subprocess. If the agent runsuv sync,uv pip install,poetry install, orpip installin any project directory other than its own, those tools treat Hermes' venv as the active install target and rebuild it against the user'spyproject.toml— wiping every Hermes runtime dependency and bricking the gateway on the next restart.Reproducer
What happened in my case
Mid-conversation the agent ran
uv syncinside~/code/fb-mcp.uvhonored the inheritedVIRTUAL_ENV(set by the gateway systemd unit athermes_cli/gateway.py:2164/:2199), reinstalled~/.hermes/hermes-agent/venvagainstfb-mcp/pyproject.toml, replaced Python 3.11 with 3.12, and dropped every Hermes dependency. Next gateway restart died withModuleNotFoundError.Diagnostic artifacts (Python before/after, dep list before/after, the offending uv invocation) are reproducible by setting
VIRTUAL_ENV=/path/to/hermes/venvin any shell and runninguv syncin any other project.Root cause
hermes_cli/gateway.pyemitsEnvironment="VIRTUAL_ENV={venv_dir}"in three places:The gateway needs
VIRTUAL_ENVset for its own process resolution, but nothing scrubs it when spawning terminal subprocesses.uv(andpoetry,pip --user,pipenv) treat inheritedVIRTUAL_ENVas an implicit--target.Proposed fix
Scrub at the subprocess-env boundary, not the unit boundary. Add
VIRTUAL_ENVand the other package-manager activation markers (VIRTUAL_ENV_PROMPT,UV_PROJECT_ENVIRONMENT,POETRY_ACTIVE,PIPENV_ACTIVE,CONDA_PREFIX,CONDA_DEFAULT_ENV) to_HERMES_PROVIDER_ENV_BLOCKLISTintools/environments/local.py. Users who actually want their tools to run inside Hermes' venv can opt back in viatools.env_passthrough.PR: #PRNUM_HERE
Related
VIRTUAL_ENV.venvvsvenvconfusionhermes doctorfeature; a startupsys.prefixself-check would catch this class of failure earlierWorkaround until the fix lands
# Add to ~/.config/systemd/user/hermes-gateway.service.d/no-venv-leak.conf [Service] UnsetEnvironment=VIRTUAL_ENVNote this only protects against the gateway itself leaking it — it does not protect terminal subprocesses that read
VIRTUAL_ENVfrom the gateway's own environment. The real fix is the subprocess scrub.Severity
High. Corrupts Hermes' own installation. Recovery requires a manual
uv sync --python 3.11 --extra messaging --extra mcp --extra webfrom outside the agent (because the agent is dead). User has no warning — the symptom is "gateway crashed on restart" hours later.