Skip to content

fix(terminal): strip VIRTUAL_ENV from agent subprocess envs#23474

Open
TheoLong wants to merge 1 commit into
NousResearch:mainfrom
TheoLong:fix/gateway-unset-virtual-env
Open

fix(terminal): strip VIRTUAL_ENV from agent subprocess envs#23474
TheoLong wants to merge 1 commit into
NousResearch:mainfrom
TheoLong:fix/gateway-unset-virtual-env

Conversation

@TheoLong

Copy link
Copy Markdown

Fixes #23473.

Problem

The gateway systemd unit sets VIRTUAL_ENV=<hermes-venv> so the gateway process can find its own .venv. That variable then leaks into every terminal subprocess Hermes spawns.

If the agent runs uv sync, uv pip install, poetry install, or pip install in any project directory other than Hermes' own, those tools see VIRTUAL_ENV pointing at Hermes' venv and treat it as the active install target. They rebuild it against the user's pyproject.toml, wipe every Hermes runtime dependency, and the gateway fails on the next restart.

Reproduced in the wild: cd ~/code/some-project && uv sync wiped ~/.hermes/hermes-agent/venv (Python 3.11 → 3.12, every dep gone) mid-conversation. Full repro and root-cause analysis in #23473.

Fix

Scrub at the subprocess-env boundary in tools/environments/local.py. Add VIRTUAL_ENV and the related package-manager activation markers to _HERMES_PROVIDER_ENV_BLOCKLIST:

  • VIRTUAL_ENV
  • VIRTUAL_ENV_PROMPT
  • UV_PROJECT_ENVIRONMENT
  • POETRY_ACTIVE
  • PIPENV_ACTIVE
  • CONDA_PREFIX
  • CONDA_DEFAULT_ENV

The gateway still receives VIRTUAL_ENV from its unit file — it just stops there.

Why not UnsetEnvironment= in the systemd unit?

That removes VIRTUAL_ENV from the gateway's own environment, which the unit specifically sets for the gateway process. We need it set for the gateway and unset for children of the gateway. The subprocess-env scrub is the right layer.

Opt-out

Users who genuinely want their terminal tools to run inside Hermes' venv can add VIRTUAL_ENV to tools.env_passthrough in config.yaml. The existing passthrough mechanism in tools/env_passthrough.py already handles this — no new plumbing needed.

Tests

Added a TestVirtualEnvIsBlocked class in tests/tools/test_local_env_blocklist.py:

  • test_virtual_env_is_blocked — membership in the blocklist
  • test_related_venv_markers_are_blocked — covers the full set of package-manager markers
  • test_sanitize_strips_virtual_env — end-to-end: _sanitize_subprocess_env strips the var

All 38 tests in tests/tools/test_local_env_blocklist.py + tests/tools/test_env_passthrough.py pass locally.

Out of scope (deferred)

The gateway systemd unit sets VIRTUAL_ENV=<hermes-venv> so the gateway
process can find its own .venv. That variable then leaks into every
terminal subprocess Hermes spawns. If the agent runs 'uv sync',
'uv pip install', 'poetry install', or 'pip install' in any OTHER
project directory, those tools see VIRTUAL_ENV pointing at Hermes' own
venv and treat it as the active install target — they rebuild it
against the user's pyproject.toml, blow away every Hermes runtime
dependency, and the gateway fails to start on the next restart.

Reproduced in the wild: 'cd ~/code/some-project && uv sync' wiped
~/.hermes/hermes-agent/venv (Python 3.11 → 3.12, every dep gone)
mid-conversation. Gateway crashed on restart with ImportError.

Fix: add VIRTUAL_ENV and the related package-manager activation markers
(VIRTUAL_ENV_PROMPT, UV_PROJECT_ENVIRONMENT, POETRY_ACTIVE,
PIPENV_ACTIVE, CONDA_PREFIX, CONDA_DEFAULT_ENV) to the subprocess env
blocklist in tools/environments/local.py. The gateway still gets its
own VIRTUAL_ENV from the unit file; it just stops there.

Opt-out: users who genuinely want their tools to run inside Hermes'
venv can add VIRTUAL_ENV to tools.env_passthrough in config.yaml.

Adds regression tests covering the blocklist membership and
_sanitize_subprocess_env behavior.
@alt-glitch alt-glitch added type/bug Something isn't working P1 High — major feature broken, no workaround tool/terminal Terminal execution and process management backend/local Local shell execution comp/gateway Gateway runner, session dispatch, delivery labels May 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend/local Local shell execution comp/gateway Gateway runner, session dispatch, delivery P1 High — major feature broken, no workaround tool/terminal Terminal execution and process management type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants