Environment: Windows 11 Pro (build 26200), Python 3.13.13, cortex plugin 4.13.0 installed through the marketplace, Western locale (ANSI code page 1252). Same box as #91–#95.
Symptom
Every Claude Code session start shows:
SessionStart:startup hook error
Failed with non-blocking status code: [cortex-launcher] Failed to run mcp_server.hooks.session_start: 'charmap' codec can't encode character '⟦' in position 25: character maps to <undefined>
and — the actual damage — no memory context is injected at all. The whole SessionStart banner (anchors, hot memories, checkpoint, grooming line) is silently lost on Windows.
Root cause
The generic wrapper at scripts/launcher.py:320 is just reporting an exception raised inside the hook. The real crash site is print(context) in mcp_server/hooks/session_start.py (~line 1089).
The banner header is:
## Cortex Memory Context ⟦rcpt:N⟧
"## Cortex Memory Context " is exactly 25 characters, so position 25 is U+27E6 ⟦ — the injection-receipt marker. The hook's stdout is a pipe (Claude Code's hook runner), so CPython encodes it with the locale/ANSI code page (charmap → cp1252) unless PYTHONUTF8/PYTHONIOENCODING is set, and cp1252 has no ⟦.
The receipt marker makes the crash deterministic on every start, but any non-cp1252 character in injected memory content (→, ✅, non-Latin scripts…) triggers the same failure — and auto_recall emits ⟦rcpt:…⟧ markers too, so the UserPromptSubmit injection path is exposed the same way.
Repro (A/B)
# stdout is a pipe, like under the hook runner
echo '{"session_id":"t","cwd":"C:\\src\\myproject"}' | \
python3 scripts/launcher.py mcp_server.hooks.session_start > out.txt 2>&1
echo $? # 1; out.txt ends with the charmap UnicodeEncodeError
echo '{"session_id":"t","cwd":"C:\\src\\myproject"}' | \
PYTHONUTF8=1 python3 scripts/launcher.py mcp_server.hooks.session_start > out.txt 2>&1
echo $? # 0; out.txt contains the full banner: "## Cortex Memory Context ⟦rcpt:18⟧ …"
Suggested fix
One choke point covers the server and every hook — at the top of main() in scripts/launcher.py:
for stream in (sys.stdout, sys.stderr):
try:
stream.reconfigure(encoding="utf-8", errors="replace")
except Exception:
pass
Claude Code consumes hook stdout as UTF-8, so the ⟦rcpt:N⟧ markers round-trip fine once they can actually be encoded (verified with the PYTHONUTF8=1 run above — the injected banner renders correctly).
Workaround
"env": { "PYTHONUTF8": "1" } in Claude Code's settings.json — works, but every Windows user hits this out of the box until the launcher sets the encoding itself.
Environment: Windows 11 Pro (build 26200), Python 3.13.13, cortex plugin 4.13.0 installed through the marketplace, Western locale (ANSI code page 1252). Same box as #91–#95.
Symptom
Every Claude Code session start shows:
and — the actual damage — no memory context is injected at all. The whole SessionStart banner (anchors, hot memories, checkpoint, grooming line) is silently lost on Windows.
Root cause
The generic wrapper at
scripts/launcher.py:320is just reporting an exception raised inside the hook. The real crash site isprint(context)inmcp_server/hooks/session_start.py(~line 1089).The banner header is:
"## Cortex Memory Context "is exactly 25 characters, so position 25 is U+27E6⟦— the injection-receipt marker. The hook's stdout is a pipe (Claude Code's hook runner), so CPython encodes it with the locale/ANSI code page (charmap→ cp1252) unlessPYTHONUTF8/PYTHONIOENCODINGis set, and cp1252 has no⟦.The receipt marker makes the crash deterministic on every start, but any non-cp1252 character in injected memory content (→, ✅, non-Latin scripts…) triggers the same failure — and
auto_recallemits⟦rcpt:…⟧markers too, so the UserPromptSubmit injection path is exposed the same way.Repro (A/B)
Suggested fix
One choke point covers the server and every hook — at the top of
main()inscripts/launcher.py:Claude Code consumes hook stdout as UTF-8, so the
⟦rcpt:N⟧markers round-trip fine once they can actually be encoded (verified with thePYTHONUTF8=1run above — the injected banner renders correctly).Workaround
"env": { "PYTHONUTF8": "1" }in Claude Code'ssettings.json— works, but every Windows user hits this out of the box until the launcher sets the encoding itself.