## What broke
After `hermes gateway install --system`, the systemd service ExecStart
uses the uv-managed Python path instead of the venv Python path. This
causes immediate crash with `ModuleNotFoundError: No module named 'yaml'`
because the uv Python has no packages installed.
ExecStart=/root/.local/share/uv/python/cpython-3.11.15-linux-x86_64-gnu/bin/python3.11
Should be:
ExecStart=/root/.hermes/hermes-agent/venv/bin/python3.11
## Root cause
`get_python_path()` in hermes_cli/gateway.py fell back to `sys.executable`
when `_detect_venv_dir()` returned None. In uv-managed environments,
`sys.executable` returns the uv Python path which has no packages.
Meanwhile, `generate_systemd_unit()` already uses `PROJECT_ROOT/venv` as
fallback for `venv_dir` (line 819), creating an inconsistency:
- `venv_dir` = PROJECT_ROOT/venv (correct)
- `python_path` = sys.executable (wrong - uv path)
## Why this fix is minimal
Added 11 lines to `get_python_path()` to add a middle fallback tier:
1. detected_venv/bin/python (existing - highest priority)
2. PROJECT_ROOT/venv/bin/python (NEW - matches generate_systemd_unit)
3. sys.executable (existing - final fallback)
This makes `get_python_path()` consistent with `venv_dir` calculation
in `generate_systemd_unit()`. No behavior change when venv is detected.
## What I tested
Added test suite tests/hermes_cli/test_gateway_python_path.py with 8 tests:
- test_fallback_to_project_root_venv_when_detect_fails
- test_detect_venv_dir_returns_valid_venv
- test_fallback_chain_order
- test_consistency_with_venv_dir_in_systemd_unit
- test_windows_fallback_uses_scripts_python_exe
- test_execstart_not_uv_python_path
- test_system_unit_execstart_uses_venv_python
- test_user_unit_execstart_uses_venv_python
All verify ExecStart uses venv/bin/python, not uv Python path.
## What I intentionally did not change
- No changes to _detect_venv_dir() logic
- No changes to generate_systemd_unit() venv_dir calculation
- No opportunistic refactoring
- No changes to launchd plist generation (similar pattern)
Fixes#9201