Skip to content

Gateway leaks VIRTUAL_ENV into subprocesses; agent's uv sync in any project bricks Hermes' own venv #23473

@TheoLong

Description

@TheoLong

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High — major feature broken, no workaroundbackend/localLocal shell executioncomp/gatewayGateway runner, session dispatch, deliverytool/terminalTerminal execution and process managementtype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions