Skip to content

Windows: canonical_omind_exe() extension gap pins an orphaned shim, breaking the omi MCP server (CONNECTION_CLOSED) #377

Description

@CryptoJones

Summary

On Windows, canonical_omind_exe() never engages its intended stable pin and silently falls back to shutil.which("omind"). Because the fallback pins whatever omind launcher happens to be first on PATH, omind setup/doctor can bake a path to an orphaned pip shim into the MCP server entry (and every omind hook). When that shim points at a Python interpreter that no longer has the omind package installed, the MCP server dies on launch and Claude Code shows omi (CONNECTION_CLOSED): "Connection closed" on every new session.

This is the exact "pin whatever's first on PATH, then freeze it forever" fragility the function's docstring says it exists to avoid — it just doesn't hold on Windows.

Root cause

src/omind/provision.py:

CANONICAL_OMIND_EXE = Path.home() / ".local" / "bin" / "omind"   # no extension

def canonical_omind_exe() -> str:
    if CANONICAL_OMIND_EXE.exists():
        return str(CANONICAL_OMIND_EXE)
    return shutil.which("omind") or "omind"

Two layers:

  1. Extension gap (concrete bug). On Windows the launcher is omind.exe, but CANONICAL_OMIND_EXE is the extension-less name omind, so .exists() is always False and the canonical pin never engages. It always falls through to which().
  2. Location mismatch + no liveness check (design). ~/.local/bin is a POSIX convention; on Windows pip/uv install the launcher to %APPDATA%\Python\PythonXY\Scripts, and nothing keeps ~/.local/bin current. which() can therefore resolve a stale/orphaned shim, and nothing (including doctor) verifies the resolved exe actually runs before baking it into config/hooks.

Reproduction / evidence

Windows 11, Python 3.14, omind installed editable into the user site (%APPDATA%\Python\Python314), with an older orphaned launcher still present at ~/.local/bin\omind.exe (which is first on PATH):

>>> from pathlib import Path; p = Path.home()/'.local'/'bin'/'omind'
>>> p.exists()
False
>>> import shutil; shutil.which('omind')
'C:\\Users\\<user>\\.local\\bin\\omind.EXE'

Running the pinned shim directly:

C:\Users\<user>\.local\bin\omind.EXE  ->
Traceback (most recent call last):
  File "<frozen runpy>", line 203, in _run_module_as_main
  ...
  File "C:\Users\<user>\.local\bin\omind.EXE\__main__.py", line 4, in <module>
    from omind.cli import main
ModuleNotFoundError: No module named 'omind'

The working launcher at %APPDATA%\Python\Python314\Scripts\omind.exe runs fine — so the package is installed; the wrong (orphaned) launcher was pinned.

Resulting ~/.claude.json entry (broken):

"omi": {
  "type": "stdio",
  "command": "C:\\Users\\<user>\\.local\\bin\\omind.EXE",
  "args": ["node", "--vault", "...", "--folder", "OMI"]
}

Impact

  • MCP server omi fails to connect on every new Claude Code session on affected Windows boxes.
  • Manually repointing the config command at the working launcher is not durable: the next omind setup/doctor/self-update re-runs canonical_omind_exe(), re-resolves to the orphaned shim, and re-breaks it.
  • The same resolution feeds omind hook commands, so hooks are exposed to the same stale-pin failure.

Suggested fix

  • Make canonical resolution extension-aware on Windows (probe omind.exe / honor PATHEXT, not just a bare omind).
  • Treat the pip/uv Scripts dir as the canonical location on Windows (e.g. via sysconfig user scripts path) rather than ~/.local/bin.
  • Add a liveness check: verify the resolved launcher actually runs / imports omind before baking it into the MCP entry and hooks; re-resolve if it doesn't.
  • Have doctor flag a baked-but-dead command (a pinned path whose process exits non-zero / can't import omind) and offer to re-register.

Regression coverage would want a Windows case for canonical_omind_exe() asserting the .exe/Scripts-dir path is chosen and that an orphaned/dead shim is not pinned.

Environment

  • OS: Windows 11 Pro (10.0.26200)
  • Python: 3.14.7
  • omind: 9.4.0 (editable install)
  • Claude Code MCP server name: omi

Activity

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