Skip to content

Supervisor spawn opens a visible console window on Windows despite DETACHED_PROCESS #9

Closed

Description

@AVeryTastyRaspberry

Summary

On Windows 11 (rtfm-ai 0.37.1, Python 3.12), every time the supervisor is spawned — via rtfm worker start, rtfm sync, or any hook/MCP call that triggers ensure_worker_running() — a visible console window briefly pops up. Over a session with repeated spawns (retrying after kills, testing, etc.) I accumulated 32 orphaned conhost.exe processes that never got cleaned up.

Root cause

rtfm/core/portable.py:

def detached_popen_kwargs() -> dict:
    if sys.platform == "win32":  # pragma: no cover - Windows only
        return {"creationflags": (subprocess.DETACHED_PROCESS
                                  | subprocess.CREATE_NEW_PROCESS_GROUP)}
    return {"start_new_session": True}

DETACHED_PROCESS prevents the child from inheriting the parent's console, but depending on how the parent itself was launched (e.g. from within a Node.js child_process.spawn, or a shell that's itself conhost-backed), Windows can still allocate a new console for the child rather than truly running it headless — which is what produces the visible popup and the orphaned conhost.exe.

Suggested fix

Add subprocess.CREATE_NO_WINDOW to the creation flags:

return {"creationflags": (subprocess.DETACHED_PROCESS
                          | subprocess.CREATE_NEW_PROCESS_GROUP
                          | subprocess.CREATE_NO_WINDOW)}

This is the standard combination for a fully headless background process on Windows — CREATE_NO_WINDOW specifically suppresses console allocation regardless of the parent's own console state, which DETACHED_PROCESS alone doesn't guarantee.

Repro

  1. Windows 11, rtfm-ai 0.37.1.
  2. From a terminal (in my case, invoked indirectly via a Node-based process — Claude Code's Bash tool), run rtfm worker start or trigger any hook that calls ensure_worker_running().
  3. Observe a console window flash/open briefly.
  4. Repeat several times (e.g. testing, restarting after a kill) — check tasklist /FI "IMAGENAME eq conhost.exe" afterward; orphaned entries accumulate with no owning visible window left.

Impact

Cosmetic/annoying rather than functionally broken — the supervisor itself works correctly — but it's a visible, repeated distraction for anyone driving rtfm from an agent/automation context (Claude Code, CI, etc.) where a popping-up console window is unexpected and alarming, and the orphaned conhost.exe processes are a minor resource leak over a long session.

Happy to test a fix if useful — reporting this alongside separate testing of the Windows worker/lock fixes in #8.

Activity

  1. roomi-fields commented on Sep 3, 2026

    @roomi-fields
    Owner

    Fixed in 0.37.2, on PyPI now — but not the way you proposed, and the difference matters, so here is the reasoning.

    CreateProcess documents CREATE_NO_WINDOW as ignored when it is used with DETACHED_PROCESS. Adding it to detached_popen_kwargs() would have compiled, shipped, and changed nothing. Your symptom was real, so I went looking for what else could produce it.

    It is one level down, and worse than the report assumed. DETACHED_PROCESS means the supervisor has no console at all — and a console program started by a parent that has none is handed a brand new console by Windows, window and conhost.exe and all. The supervisor spawns a child interpreter for every PDF it reads, to keep pdfium's segfaults out of its thread pool (that isolation is why 0.29.0 exists). Marker and djvutxt are spawned the same way.

    So the flashes were never one per worker start. They were one per document. Your 32 orphans came from three worker start calls doing nothing wrong and a handful of files being indexed behind them; on a PDF corpus it would have been thousands.

    Two rules now:

    • A detached background process runs under pythonw.exe — the windowed build of the same interpreter, shipped beside python.exe, which never gets a console in the first place. Falls back to python.exe where it is absent, because a console flash is a nuisance and no indexing at all is not. The supervisor writes to ~/.rtfm/supervisor.log, never to a terminal, so nothing is lost.
    • A short-lived helper — pdfium child, marker, djvutxt — carries CREATE_NO_WINDOW. There your flag is exactly right and is not ignored, because nothing detaches those children: they are waited on and their streams are pipes.

    A test now walks every subprocess call in the package and fails on any that carries neither policy, since this package spawns children as a matter of course. I verified it catches a bare spawn by removing one flag and watching it name the file and line.

    Still unverified on Windows, as ever — I'd be glad to know whether the flashes are actually gone, and whether tasklist /FI "IMAGENAME eq conhost.exe" stays flat while a PDF-heavy repo indexes. That second one is the real test; worker start alone would only have exercised the easy path.

    And: you are in the README now. Every command of this thing was broken on Windows and RTFM is developed on Linux, so without your reporting and the testing you did on real hardware it would simply have stayed broken. Thank you.

  2. roomi-fields commented on Oct 30, 2026

    @roomi-fields
    Owner

    Closing: the fix shipped in 0.37.2 (pythonw.exe for the detached supervisor, CREATE_NO_WINDOW for short-lived helpers) and nothing has come back since. If the console windows or the conhost.exe orphans reappear on a current version, please reopen with the version and I'll dig in. Thanks again for the Windows testing.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions