Windows: fix session-dir slug mismatch and Python detection#29
Conversation
Every post-tool / session-start / save-session invocation needs to locate the current session's JSONL file under ~/.claude/projects/<slug>/, where <slug> is Claude Code's own slug of the project path. On Windows, Claude Code slugs the **native Windows path** with a lowercase drive letter (e.g. D:\Projects\Foo → d--Projects-Foo). Hook scripts on Git Bash / MSYS receive the path in POSIX form (/d/Projects/Foo), which slugs to -d-Projects-Foo — a directory that never exists. post-tool-hook.sh then exits silently at line 46 (no JSONL found), and no save ever runs. Teach session_dir_slug() to detect MSYS/Cygwin (via cygpath), convert the POSIX path back to the native Windows form, lowercase the drive letter, and then slug. No behavior change on macOS/Linux where cygpath is absent. Replace the three inline `sed '[^a-zA-Z0-9]/-/g'` call sites with session_dir_slug() so the fix is centralized. Verified on Windows 11 + MSYS2 bash 5.2: computed slug now matches the actual ~/.claude/projects directory; the save pipeline runs extract → haiku → write end-to-end.
On Windows without Store-installed Python, `python3` and sometimes `python` resolve to a Microsoft Store placeholder — a stub binary in %LOCALAPPDATA%\Microsoft\WindowsApps that only opens the Store. `command -v python3` returns success on the stub, but actually running it prints a "Python was not found" message and exits non-zero. save-session.sh then fails midway with arithmetic errors on unset variables the Python pipeline was supposed to set. Switch detection to a validation loop: for each candidate, check that `<candidate> -V` actually runs successfully. Also add the Windows `py` launcher (`py -3`, `py`) as further fallbacks. $PYTHON is already used unquoted throughout the scripts, so a multi-word value like "py -3" expands as two tokens correctly. Verified on Windows 11 + MSYS2: detection now picks the real Python interpreter instead of the Store stub, save pipeline completes and writes to .remember/now.md.
|
Heads-up on a likely merge conflict — I just opened PR #30 (BSD Suggested merge order to keep both clean:
Happy to coordinate or rebase from my side if helpful — and great work on the Windows fixes, the slug mismatch one in particular is subtle. |
|
Thanks for the heads-up, appreciated. I ran the merge both ways locally to check:
So the merge should be mechanical whichever order the maintainer picks, and no rebase is strictly required from my end. Happy to rebase anyway if you'd prefer to keep history linear — just say the word. Great fix on the BSD |
fdaviddpt
left a comment
There was a problem hiding this comment.
Excellent work @evikzub — this is exactly what the plugin needed for Windows support. Thank you for the thorough approach!
The Python detection improvement is particularly smart: validating with -V to catch the Microsoft Store stub that passes command -v but doesn't actually run is the kind of edge case that only someone debugging on Windows would catch. The py -3 / py launcher fallback covers the common python.org install path too.
The session_dir_slug with cygpath is the correct fix for the slug mismatch — Git Bash receives Unix-style paths but Claude Code slugs the native Windows path. Without this, the plugin can't find session files on Windows at all.
Both changes are well-scoped, well-documented, and the commit messages explain the why clearly.
We just shipped PR #33 which touches some of the same files (bootstrap-dirs.sh, hooks.json, post-tool-hook.sh, session-start-hook.sh) — there may be minor merge conflicts but they should be trivial to resolve. Happy to help if needed.
Thanks again for making the plugin work on Windows — with 20k installs, every platform matters. 🙏
|
Quick update on the items you flagged:
Already fixed in #33 commit 2 — all
Good catch — after your PR merges, we'll update that line to use
Also noted — the Python side might need the same Merging now — thanks again for the thorough testing and the honest checklist! |
) Thanks @kanelavish-a11y — solid diagnosis, the POSIX form was a real gap left by #29. Patched the bash 3.2 compat issue (`^^` → `tr`) so the test runs green on macOS dev machines too.
Summary
Two independent Windows-compatibility fixes. Together, they unblock the memory pipeline on Windows 11 + MSYS2 — on my machine,
.remember/now.mdandtoday-*.mdwere never being written before these changes even though the hooks were registered and running.Independent of #28 (the bootstrap
mkdir -p+ TMPDIR + README PR) — no merge conflicts expected either way. Each commit is also independent and can be cherry-picked.Commit 1 —
fix(windows): match Claude Code's native session-dir slugEvery
post-tool-hook.sh/session-start-hook.sh/save-session.shrun needs to locate the current session's JSONL under~/.claude/projects/<slug>/, where<slug>is Claude Code's own slug of the project path./home/u/p→-home-u-p). Hook scripts see the same path. Works.D:\Projects\Foo→d--Projects-Foo). Hook scripts on Git Bash / MSYS receive the path in POSIX form (/d/Projects/Foo), which slugs to-d-Projects-Foo— a directory that never exists.post-tool-hook.shthen exits silently at line 46 (no JSONL found), and no save ever runs.Teach
session_dir_slug()indetect-tools.shto detect MSYS/Cygwin viacygpath, convert the POSIX path back to Windows form, lowercase the drive letter, and slug. No behavior change wherecygpathis absent (macOS/Linux).Replace three inline
sed '[^a-zA-Z0-9]/-/g'call sites withsession_dir_slug()so the fix is centralized — the helper was already sourced in all three scripts but wasn't being used.Repro
On Windows 11 + MSYS2 + project at
D:\Projects\Foo:```bash
$ echo "$PROJECT" # what the plugin sees
/d/Projects/Foo
$ echo "$PROJECT" | sed 's/[^a-zA-Z0-9]/-/g' # old slug
-d-Projects-Foo
$ ls ~/.claude/projects/ # what actually exists
d--Projects-Foo/
```
Mismatch → `post-tool-hook.sh:46 [ -n "$LATEST_JSONL" ] || exit 0` fires → no save.
Commit 2 —
fix(windows): validate Python interpreter and add py launcher fallbackSeparate failure mode on Windows without Store-installed Python:
python3and sometimespythonresolve to a Microsoft Store placeholder (a stub in%LOCALAPPDATA%\Microsoft\WindowsApps\that only opens the Store).command -v python3returns success on the stub, but actually running it prints "Python was not found" and exits non-zero.save-session.shthen fails midway with arithmetic errors on unset variables the Python pipeline was supposed to set.Switch detection from
command -vto a validation loop: for each candidate, verify<candidate> -Vactually runs. Also add the Windowspylauncher (py -3,py) as further fallbacks.\$PYTHONis already used unquoted throughout the scripts, so multi-word values like"py -3"expand as two tokens correctly.Test plan
~/.claude/plugins/cache/claude-plugins-official/remember/0.5.0/on Windows 11 + MSYS2 + jq + Python 3.10 installed outside Store. Before:.remember/now.mdnever created; log showed only[hook] post-tool:breadcrumbs. After: full pipeline runs —[extract] 187 exchanges,[haiku] calling,[tokens],[write] appended,[ndc] running..remember/now.md+.remember/today-*.mdpopulated correctly.scripts/run-tests.sh— not executed by this contributor on Windows (test harness assumes Unix mktemp paths). Maintainer Unix CI run would be appreciated.Not changed (potential follow-ups)
pipeline/extract.py::_session_dir()uses the same Unix-form slug strategy. It was not exercised in my testing becausesave-session.shpasses the session ID directly, but code paths that call it standalone (e.g., recovery with onlyproject_dir) may still produce the wrong Windows slug. Worth a follow-up.scripts/run-tests.sh:135has the same inlinesedslug pattern. Test-only code; would be trivial to switch tosession_dir_slugfor consistency.