fix(desktop): avoid uv venv pythonw launcher console flash on Windows - #53344
Closed
luntion wants to merge 1 commit into
Closed
fix(desktop): avoid uv venv pythonw launcher console flash on Windows#53344luntion wants to merge 1 commit into
luntion wants to merge 1 commit into
Conversation
The desktop spawns the dashboard backend via venv\Scripts\pythonw.exe. For uv-created venvs that path is a launcher shim that re-execs the base CONSOLE python.exe, flashing a cmd window on every spawn even with windowsHide / CREATE_NO_WINDOW on the parent. The CLI gateway hit the same bug and was fixed in NousResearch#41028 by detecting uv via pyvenv.cfg and using the base pythonw.exe directly with venv site-packages on PYTHONPATH. This ports the same fix to the desktop spawn path. Changes: - Refactor pyvenv.cfg reading into readPyvenvCfg(); add isUvVenv(). - getNoConsoleVenvPython(): for uv venvs, prefer base pythonw.exe over the venv launcher shim. Non-uv venvs keep the old behaviour. - createPythonBackend / createActiveBackend: add venv Lib/site-packages to PYTHONPATH so the base interpreter can still resolve imports when we bypass the venv launcher (harmless dedup for non-uv venvs). - Lock the new logic via source-pattern assertions in the existing windows-child-process.test.cjs. Closes NousResearch#53016.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix(desktop): avoid uv venv pythonw launcher console flash on Windows
Summary
On Windows, the Hermes desktop app spawns the dashboard backend via
venv\Scripts\pythonw.exe. When the venv is created by uv (which ishow every standard
install.ps1install builds it), that path is a uvlauncher shim — not a real
pythonw.exe. The shim re-execs the baseconsole
python.exe, so acmd.exewindow flashes every time thedesktop spawns or respawns a backend. Setting
windowsHide: trueon theparent spawn can't suppress this — the second process allocates its own
conhost.
This PR teaches
apps/desktop/electron/main.cjsto detect uv venvs andfall back to the base interpreter's
pythonw.exedirectly, matchingwhat
hermes_cli/gateway_windows.py::_resolve_detached_pythonalreadydoes for the CLI gateway path (landed in #41028).
Symptoms
cmd.exewindowsflashing every few minutes during normal use.
evicts each profile backend after 600s, so every profile switch /
reactivation re-spawns and re-flashes.
desktop.logshows the spawn loop clearly:Each
Starting Hermes backendline = one console flash.Root cause
getNoConsoleVenvPython(venvRoot)returnedvenv\Scripts\pythonw.exeunconditionally if the file existed. On a uv-managed venv that file is
a ~44KB launcher shim that internally spawns the base
python.exe(console subsystem), not the base
pythonw.exe. That second processopens a visible conhost regardless of
CREATE_NO_WINDOW/windowsHideon the parent.Confirmed via
pyvenv.cfg:The base
pythonw.exeexists at<home>\pythonw.exe(~90KB, real GUI-subsystem binary).
The CLI gateway hit the exact same bug and was fixed in #41028 —
_resolve_detached_python()detects uv viapyvenv.cfgand switchesto the base
pythonw.exe, then adds the venv'sLib\site-packagesto
PYTHONPATHso imports still resolve. This PR ports that fix to thedesktop spawn path.
Changes
apps/desktop/electron/main.cjsRefactor
readVenvHome()to share a commonreadPyvenvCfg()helper (no behaviour change).
Add
isUvVenv(venvRoot)— checks foruv =line inpyvenv.cfg(matches the same detection used by the CLI side).
getNoConsoleVenvPython(): when the venv is uv-created, preferthe base interpreter's
pythonw.exe(read frompyvenv.cfg.home)instead of
venv\Scripts\pythonw.exe. Non-uv venvs (stdlibvenv,virtualenv, etc.) keep the old behaviour — they ship a realpythonw.exe.createPythonBackend()andcreateActiveBackend(): includegetVenvSitePackagesEntries(venvRoot)inpythonPathEntries.When we bypass the uv launcher, the base interpreter has no venv
awareness, so we must put the venv's
Lib\site-packagesonPYTHONPATHfor imports to work. For non-uv venvs this is aharmless duplicate entry (the venv's own pythonw.exe adds
site-packages on startup, and
appendUniquePathEntriesdedupes).This matches what
unwrapWindowsVenvHermesCommand()already doesfor the Windows venv hermes.exe path — the new behaviour brings
createPythonBackend/createActiveBackendinto parity.apps/desktop/electron/windows-child-process.test.cjsLock in the new uv-detection logic and PYTHONPATH wiring via
source-pattern assertions, consistent with the existing test style.
Why source-pattern tests (not a behaviour test)
Existing helper modules in
electron/*.cjsare independent CommonJSmodules with their own behaviour tests (
backend-env.test.cjs,update-relaunch.test.cjs, etc.). The Windows-spawn helpers(
getNoConsoleVenvPython,applyWindowsNoConsoleSpawnHints,createPythonBackend,createActiveBackend) currently live inline inmain.cjsand are not exported, so the existingwindows-child-process.test.cjscovers them via source-stringmatching.
A follow-up could extract these helpers to a
venv-resolver.cjsmodulewith a real fixture-based behaviour test (build a fake uv
pyvenv.cfgpythonw.exe, assert which path is returned). Happy to dothat in this PR if reviewers prefer — kept it minimal here to match
the surrounding test conventions and minimise unrelated diff.
Testing
Locally on Windows 10 (the reporter's environment):
The two relevant tests pass:
(
bootstrap PowerShell runner hides Windows console childrenfailson plain
maintoo — pre-existing and unrelated to this PR.)Relationship to other issues / PRs
issue's "Suggested fix" (
add CREATE_NO_WINDOW to subprocess.Popen)catches a different family of flashes (terminal-tool subprocesses),
which fix: add CREATE_NO_WINDOW to Windows subprocess Popen calls to prevent cmd.exe flashing #53119 is addressing in
hermes_cli/main.pyandagent/copilot_acp_client.py. fix: add CREATE_NO_WINDOW to Windows subprocess Popen calls to prevent cmd.exe flashing #53119 does not touch the desktopelectron backend spawn path — that's what this PR fixes.
CLI gateway
Hermes_Gateway.cmdpath). This PR ports the same fixto the desktop spawn path.
shim console-window issues on Windows.
Risk / blast radius
IS_WINDOWSguard preserved).commandfromvenv\Scripts\pythonw.exe(shim) to basepythonw.exe, and addsthe venv
Lib\site-packagestoPYTHONPATH. The CLI gateway hasbeen doing exactly this since fix(gateway): avoid Windows uv pythonw launcher console #41028 in production without
regressions, so the import resolution side of it is proven.
pyvenv.cfgis missing orunreadable, or if the resolved base
pythonw.exedoesn't exist.