Repository navigation
Description
Summary
On a machine that already has a PyTorch stack in its user site-packages, Cortex 4.x
fails to start. The MCP server exits during import and the host reports
CONNECTION_CLOSED. The lifecycle hooks survive but lose semantic embeddings.
The cause is that deps/ vendors its own torch while scripts/launcher.py leaves
the user's site-packages on sys.path. torchvision and torchaudio are not
vendored, so they resolve from user site-packages — where they are built against a
different torch than the one deps/ ships.
3.x was not affected. Its deps/ vendored only psycopg_pool and
typing_extensions, so the whole torch stack came from user site-packages and stayed
internally consistent.
Environment
- Cortex
hypermnesia-mcp4.23.1, installed viaclaude plugin install(upgraded from 3.24.1) - Windows 11 Pro 26200, Python 3.13.4
- Backend: PostgreSQL 15.6 + pgvector (all Postgres checks pass)
Vendored in deps/:
| Package | Version |
|---|---|
| torch | 2.13.0+cpu |
| transformers | 5.16.1 |
| sentence-transformers | 6.0.1 |
| torchvision | absent |
| torchaudio | absent |
Present in user site-packages (a coherent CUDA set):
| Package | Version |
|---|---|
| torch | 2.11.0+cu128 |
| torchvision | 0.26.0+cu128 |
| torchaudio | 2.11.0+cu128 |
Symptoms
scripts/setup.py reports:
[ok] PostgreSQL connection
[ok] Extensions (pgvector, pg_trgm)
[ok] PL/pgSQL recall_memories()
[FAIL] sentence-transformers
[ok] FlashRank reranker
The MCP server never completes startup, so the host closes the connection.
Root cause
scripts/launcher.py puts deps/ first on the path:
for p in [plugin_root, deps_dir]:
if p not in sys.path:
sys.path.insert(0, p)torch then comes from deps/ (2.13.0+cpu) but torchvision still comes from user
site-packages (0.26.0+cu128, built for torch 2.11.0). Importing them together aborts:
RuntimeError: operator torchvision::nms does not exist
transformers resolves PreTrainedModel lazily and re-raises the cause as a
ModuleNotFoundError, which hides the real error:
ModuleNotFoundError: Could not import module 'PreTrainedModel'.
Are this object's requirements defined correctly?
Reproduce with the vendored deps on the path:
PYTHONPATH="<plugin_root>/deps" python -c "import sentence_transformers"Two fixes that do not work
Vendoring a matching torchvision. Installing torchvision==0.28.0+cpu (pip's
own resolution for torch 2.13.0) into deps/ clears the nms error. The next
package in the chain then fails:
OSError: Could not load this library:
...\AppData\Roaming\Python\Python313\site-packages\torchaudio\lib\libtorchaudio.pyd
Every torch-ecosystem package in user site-packages leaks in turn. Matching versions
one by one does not converge.
Disabling user site-packages alone (python -s, or PYTHONNOUSERSITE=1 in the
plugin's mcpServers.env). sentence-transformers then imports correctly, but the
server dies earlier:
[cortex-launcher] Failed to run mcp_server: No module named 'pywintypes'
deps/ does contain pywin32, including deps/win32/lib/pywintypes.py and
deps/pywin32_system32/pywintypes313.dll. It is reached through deps/pywin32.pth:
win32
win32\lib
pythonwin
import pywin32_bootstrap
.pth files are only processed for site directories. A directory added through
PYTHONPATH or sys.path.insert does not get them. So cutting off user
site-packages removes the only pywin32 that was actually reachable.
Fix that works
Both halves are needed: make deps/ a real site directory so its .pth files run,
then drop user site-packages. In scripts/launcher.py, right after the existing
sys.path.insert loop:
import site as _site
_site.addsitedir(deps_dir)
try:
_user_site = _site.getusersitepackages()
except Exception:
_user_site = None
if _user_site:
_dropped = os.path.normcase(os.path.abspath(_user_site))
sys.path[:] = [
q for q in sys.path
if os.path.normcase(os.path.abspath(q)) != _dropped
]Placing it in the launcher covers the MCP server and all 11 lifecycle hooks at once,
without depending on the shell. A PYTHONNOUSERSITE entry in mcpServers.env does
not reach the hooks, which inherit the host's environment.
Verified on the environment above, after the change:
- MCP
initializehandshake returns the full capability set mcp_server.hooks.session_startexits 0 and injects memory contextSentenceTransformer.encode()produces a real 384-dimension vector
This is a local workaround, not a design proposal. A dedicated virtualenv for deps/
would achieve the same isolation more conventionally.
Secondary: the installer blames the wrong component
When the verification above fails on sentence-transformers, install-plugin.sh
still ends with:
scripts/setup.py failed. PostgreSQL must be installed and running first
All four PostgreSQL checks had passed in the same run. The message sends the reader
to a working component. Reporting the check that actually failed would help.
Activity
fix(installer): keep setup.py output live, report a failed user-site …
fix(launcher): isolate the vendored deps/ from user site-packages (#621)
fix(installer): keep setup.py output live, report a failed user-site …
fix(installer): strip CRLF from the failed-check name, widen the user…
test(scripts): split the launcher_site suite under the 300-line cap (#…
docs(launcher_site): state the widened cut in the isolate_deps postco…
fix(launcher): isolate the vendored deps/ from user site-packages (cd…
fix(setup): persist backend marker before setup.py can fail; close ML…
ci(windows): target the Windows leg at what actually broke on Windows (…
fix(hooks): start the SessionEnd dream cycle through the launcher (#667…