Skip to content

fix(cli): don't resolve venv python into Linux desktop Exec= - #97992

Open
flowersjus wants to merge 1 commit into
NousResearch:mainfrom
flowersjus:fix/linux-desktop-exec-no-resolve
Open

flowersjus wants to merge 1 commit into
NousResearch:mainfrom
flowersjus:fix/linux-desktop-exec-no-resolve

Conversation

@flowersjus

Copy link
Copy Markdown

Bug Description

After hermes desktop (and after every rebuild/update), the Linux menu entry is rewritten with an Exec= that launches system Python. The icon does nothing. hermes desktop from a TTY still works.

Reproduced on EndeavourOS / Hyprland, git install, venv/bin/python -> /usr/bin/python3.11:

Exec=/usr/bin/python3.11 ~/.hermes/hermes-agent/venv/bin/hermes desktop

That command exits 1 with ModuleNotFoundError: No module named 'hermes_cli'. Terminal=false, so the DE shows nothing.

Related: #90292 (partially addressed by #90492), #92095, #94110, #94058.

There are already open PRs on the same class of bug (#92090, #94051, #96685). This one is the smallest delta that also closes a #90292 hole the others still have: substring-matching the interpreter dir against the shebang, so /usr/bin matches #!/usr/bin/env python3 and skips the venv prefix.

Root Cause

  1. Path(sys.executable).resolve() follows venv/bin/python (symlink) to /usr/bin/python3.N or the uv store. CPython only activates a venv via the unresolved argv[0] + pyvenv.cfg.
  2. _needs_interpreter used exe_dir not in shebang. After (1), exe_dir is /usr/bin, which is not in #!…/venv/bin/python3, so a correct venv console-script was classified as foreign and got the system interpreter prefixed. The same substring also matches #!/usr/bin/env python3, which would skip the Linux desktop entry generated with non-runnable Exec; icon launch always fails #90292 prefix.

Fix

  • Prefix sys.executable without following the symlink.
  • Treat env shebangs as always needing that prefix.
  • Compare the unresolved interpreter dir against the shebang program, not the whole line.

How to Verify

  1. Linux git/uv install where venv/bin/python is a symlink to a base interpreter.
  2. Run hermes desktop once from a TTY.
  3. awk -F= '/^Exec=/{print substr($0,6)}' ~/.local/share/applications/hermes.desktop
    • must not start with /usr/bin/python or ~/.local/share/uv/python/…
    • good: …/venv/bin/hermes desktop or ~/.local/bin/hermes desktop or …/venv/bin/python …/hermes desktop
  4. Launch from the app menu. Window opens.

Test Plan

  • Added regression test: venv python symlink must not appear as the resolved base interpreter in Exec=
  • Existing tests still pass (tests/hermes_cli/test_linux_desktop_entry.py: 16 passed, 2 skipped)
  • Manual verification of the fix (menu Exec rewritten; ~/.local/bin/hermes --version works)

Risk Assessment

Low — Linux .desktop writer only. macOS/Windows unchanged. Shell-wrapper launchers still left alone. #90292 env-shebang prefix still applied, now with the venv path instead of the base interpreter.

Path(sys.executable).resolve() follows venv/bin/python to the base
interpreter (/usr/bin/python3.N or the uv store). The .desktop entry
then launches that interpreter, dies on ModuleNotFoundError:
hermes_cli, and shows nothing because Terminal=false.

Also stop substring-matching the interpreter dir against the shebang:
/usr/bin sits inside #!/usr/bin/env python3 and would skip the NousResearch#90292
prefix. Treat env shebangs as always needing the running interpreter.
@alt-glitch alt-glitch added type/bug Something isn't working comp/cli CLI entry point, hermes_cli/, setup wizard comp/desktop Electron desktop app (apps/desktop/*) area/install-update Installer, updater, packaging, wheels, doctor P2 Medium — degraded but workaround exists needs-decision Awaiting maintainer decision before any implementation sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 29, 2026
@alt-glitch

Copy link
Copy Markdown

This was generated by AI during triage.

Related: #92090, #92516, and #94115 address the same Linux desktop Exec= / symlinked-venv family. This PR uses program-level shebang parsing and treats env shebangs as requiring the venv prefix; maintainers should select a consolidated repair.

@andrexibiza andrexibiza left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact head 9d268ffe5224ee8176b82c450d4daa7dbed2c189 against main@3f36c87e1ebdfbf7d14a88229dc9be222c12ea89.

Keeping sys.executable lexical rather than resolving through the venv symlink is the correct repair for the reported uv escape, and the new symlink regression binds that positive case. One runtime blocker remains in the broadened shebang classification; I left it inline.

Fresh-state adversarial receipt, using real interpreters and a clean desktop-style environment:

uv symlink positive control: candidate needs prefix = False
env -S absolute-venv shebang: baseline needs prefix = False
env -S absolute-venv shebang: candidate needs prefix = True
direct valid shebang under env -i: exit 0, stdout = venv-ok
candidate-emitted /usr/bin/python3 <script>: exit 1, ModuleNotFoundError

The parser must distinguish PATH-dependent #!/usr/bin/env python... from env -S forms that already pin an absolute interpreter, preserve path case, and retain interpreter flags. Add the executable regression, not only a rendered-string assertion.

Before merge, consolidate the existing implementation graph rather than landing another synonymous repair. Prior work by GitTradWang in #94058/#94051, jackulau in #92090, and gokhanyildirimlar in #94874 already covers parts of this exact parser and verification matrix; mojtabazn's #97983 is the new duplicate report. Preserve those credits and add the repo-template closing interlock to the selected canonical issue.

Exact-head CI is not green evidence yet: the CI run is action_required with zero jobs executed: https://github.com/NousResearch/hermes-agent/actions/runs/33261474514

# it. Do not substring-match the interpreter dir against the shebang:
# ``/usr/bin`` is inside ``/usr/bin/env python3`` and would skip the
# prefix (#90292) *and* is the follow-symlink target of venv/bin/python.
if Path(prog).name == "env":

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocker — this blanket env branch converts a valid launcher into a broken one. env does not always mean PATH-dependent env python3: GNU env -S can pin an absolute venv interpreter and its required flags, e.g. #!/usr/bin/env -S /opt/hermes/venv/bin/python -I.

At this head, with sys.executable == /usr/bin/python3, the baseline classifier leaves that launcher direct, but this branch returns True solely because prog is env and emits /usr/bin/python3 <script>. In an isolated executable repro, the direct shebang exits 0 and imports a dependency installed only in the pinned venv; the emitted command exits 1 with ModuleNotFoundError. It also discards -I because Python is now handed the script as an argument.

Parse the original-case shebang tokens. Prefix only PATH-dependent env python* forms; for env -S with an absolute Python target, compare that target by path components/environment identity and preserve its flags. Add the clean-environment subprocess regression.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/install-update Installer, updater, packaging, wheels, doctor comp/cli CLI entry point, hermes_cli/, setup wizard comp/desktop Electron desktop app (apps/desktop/*) needs-decision Awaiting maintainer decision before any implementation P2 Medium — degraded but workaround exists sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants