Windows native support - #978
Closed
Anroshka wants to merge 3 commits into
Closed
Conversation
Prime Agent could not reach a working session on a stock Windows box. Launching it produced a burst of console windows that flashed open and shut, and then nothing: no IPython tool, no search helpers, and a daemon logging errors nobody saw. Six platform assumptions were compounding. 1. The kernel venv interpreter was hardcoded to `<venv>/bin/python`. uv creates `<venv>\Scripts\python.exe` on Windows, so every readiness probe failed. The venv was torn down and rebuilt on each launch, and the rebuild then failed at `uv pip install --python <venv>/bin/python`. The IPython tool — the agent's only built-in tool — was never available. 2. Zip archives are the only archive format used on Windows (fd and ripgrep ship `.tar.gz` elsewhere), and they were unpacked with extract-zip. Its yauzl read streams never settle on current Node releases: extraction hangs at the first entry large enough to span more than one chunk. `rg`/`fd` never installed, and every attempt leaked an `extract_tmp_*` directory. Windows ships bsdtar in System32 and it reads zip, so `tar` is now the primary path with a time-boxed extract-zip fallback. Provisioning cleanup no longer masks the real error when antivirus holds a handle on a freshly extracted binary. 3. The daemon and its session workers were spawned detached without `windowsHide`, which leaves them with no console at all. Every console tool they then ran — git, uv, python, powershell — allocated a console of its own, which is the window storm. Spawns whose output is piped or discarded now pass `windowsHide`. 4. `CommandRecoveryJournal.compact` fsynced the containing directory. That is EPERM on Windows and aborted every supervisor `ack_result`. Guarded the way `cron-jobs.ts` already guards the same call. 5. Session leases are claimed by renaming a candidate directory onto the lease path, treating EEXIST/ENOTEMPTY as "already held". Windows reports a directory-over-directory rename as EPERM, so that branch never ran: stale leases were never reclaimed, and a live one surfaced as a raw EPERM instead of SessionAlreadyActiveError. 6. `expandTildePath` concatenated instead of joining, yielding `C:\Users\me/sessions` — a usable path that never compares equal to the same location built with `join()`. Also on Windows: install uv through its PowerShell installer rather than piping `install.sh` into a `sh` that does not exist; widen Git for Windows discovery to per-user installs and Git resolved from PATH (scoop and Chocolatey shims); and rank `System32\bash.exe` last, since the WSL launcher resolves a different filesystem than the paths the agent composes. Off Windows every change is a no-op or unchanged behaviour: `windowsHide` is ignored on POSIX, `getVenvPythonPath` returns the previous path, the zip branch is unreachable where downloads are tar.gz, and the lease and tilde helpers keep their POSIX semantics. Coverage: a `Windows` workflow builds, lints, runs the platform- sensitive suites, and runs an end-to-end kernel smoke test that asserts the venv resolves to `Scripts\python.exe`, that a second bootstrap is a cache hit rather than a rebuild, and that a kernel starts and executes a cell. Symlink and POSIX-permission fixtures now gate on capability probes instead of failing on Windows. The rest of the suite still carries POSIX-only fixtures and is out of scope; docs/windows.md says so explicitly. Verified on Windows 11 / Node 26: the venv bootstraps once and stays ready, the IPython kernel starts and executes, rg and fd install, the daemon log is clean of EPERM, and startup creates no visible console windows.
… venv Two things the IPython tool could not do, both invisible until an agent tried them. **asyncio subprocesses were unavailable on Windows.** ipykernel installs a Windows *selector* event loop policy because pyzmq needs `add_reader`, and a selector loop cannot spawn subprocesses. Anything in the kernel that shells out through asyncio — playwright, `create_subprocess_exec`, any async driver that starts a helper binary — failed with a bare `NotImplementedError`, and the obvious workaround of running it on a fresh loop in a worker thread failed too, because `new_event_loop()` inherits the same policy. There was no way out from inside a cell. Startup now swaps the policy back to the proactor one, so loops created from then on support subprocesses, and re-binds the kernel's own already-running selector loop to the main thread so ipykernel keeps exactly what it needs. Applied through a silent `execute_request` that neither stores history nor leaves names in the user namespace, and failure to apply is logged as a kernel diagnostic rather than failing startup — a kernel without it is still a working kernel. **The kernel could not see its own virtualenv.** The kernel process inherited no `VIRTUAL_ENV` and no venv script directory on `PATH`, so a `uv pip install` or `pip install` issued from a cell resolved against whatever interpreter `PATH` pointed at — usually a system Python — and installed packages somewhere the kernel could not import them from. The spawn env now activates the venv the way `activate` would, and leaves a non-venv interpreter (`PRIME_AGENT_KERNEL_PYTHON` pointing at a system or conda Python) untouched. Explicit per-kernel `env` overrides still win over both. Verified on Windows 11 / Node 26 / CPython 3.11: policy is WindowsProactorEventLoopPolicy while the kernel's main-thread loop stays _WindowsSelectorEventLoop, top-level await still works, an `asyncio.create_subprocess_exec` on a worker thread succeeds, playwright launches Chrome and drives a page from inside a cell, and `VIRTUAL_ENV` matches `sys.prefix` with `uv pip list` resolving to the kernel venv.
Contributor
|
Thank you for the report and proposed work. This root cause is now covered by maintainer-owned stacked PR #1163, authored independently from We did not inspect or reuse this PR's diff, branch, commits, implementation code, or tests; its public description/comments were used only as a bug report. To keep one review surface, this PR is superseded by #1163 and is being closed. The complete review stack is #1158–#1165. It is being left unmerged for human review after CI and review-bot findings are cleared. |
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.
Summary
This PR makes Windows a first-class, fully supported runtime for
prime-agentand fixes fundamental Windowsasynciosubprocess constraints inside the IPython kernel.Previously, running Prime Agent on a native Windows environment failed to reach a stable session due to compounding platform assumptions (venv script path resolution, zip extraction stream hangs, flashing console windows, fsync/rename EPERM errors, and ipykernel subprocess limitations).
With these changes, Prime Agent bootstraps cleanly, provisions binaries reliably without flashing console windows, and allows kernel code to spawn subprocesses (e.g. Playwright, Cargo, external CLI tools) and isolate its python environment.
Key Changes
1. Kernel Subprocess & Venv Isolation (
packages/coding-agent/src/core/kernel/index.ts)ipykerneldefaults toWindowsSelectorEventLoopPolicy(required forpyzmq). However,SelectorEventLoopcannot spawn subprocesses, causingasyncio.create_subprocess_exec(and tools like Playwright or Cargo) to fail withNotImplementedError.ipykernelhappy) and resets the default event loop policy back toWindowsProactorEventLoopPolicy. All worker loops created afterward can spawn subprocesses.VIRTUAL_ENVand updatePATHto include<venv>\Scripts, souv pip installinside cells targets the kernel venv instead of system Python.2. Windows Runtime & Bootstrap Stability
<venv>\Scripts\python.exeon Windows instead of hardcoded<venv>/bin/python, preventing perpetual venv teardown/rebuild cycles (bootstrap.ts).yauzl/extract-zipstream extraction (which hangs on Node 20+ streams for multi-chunk zips) with Windows systemtar(bsdtar.exe), backed by a time-boxed fallback (tools-manager.ts).windowsHide: trueto background process spawns (daemon-launch.ts,exec.ts,shell.ts) to stop console window flashes during tool execution.fsyncdirectory calls inCommandRecoveryJournal.compactand adjusted directory-over-directory rename logic insession-lease.tsto handle Windows-specificEPERMerror codes safely.expandTildePathto usepath.joininstead of string concatenation (config.ts).System32\bash.exe.3. CI Pipeline & Documentation
.github/workflows/windows.yml: Windows CI workflow covering linting, unit tests, and kernel smoke tests.scripts/windows-kernel-smoke.mjs: Automated headless test asserting venv resolution, binary caching, and cell subprocess execution.docs/windows.md&docs/quickstart.mdwith Windows runtime details andasynciosubprocess constraints.Verification & Testing
windows-latest.WindowsProactorEventLoopPolicyactive while_WindowsSelectorEventLoopruns on main thread; top-level await works;asyncio.create_subprocess_execsucceeds.windowsHide(no-op on Unix), and path resolution remain unchanged for macOS/Linux.Note
Add native Windows support to the coding agent
Scripts\python.exe(Windows) vsbin/python(POSIX), installsuvvia PowerShell on Windows, and setsVIRTUAL_ENV/PATHso in-kernel package installs target the correct venv.WindowsProactorEventLoopPolicyfor subprocess-spawning event loops, avoidingNotImplementedError.windowsHide: trueto all child process spawns across the codebase to suppress console window flashes.EPERM/EACCESon an existing target directory as a taken lease rather than a fatal error, and swallows directory-fsync errors in the command recovery journal.Macroscope summarized a68c9da.