Skip to content

fix: Windows compatibility for plugin.json and hook scripts (#378)#384

Open
BondarenkoCom wants to merge 2 commits into
MemPalace:developfrom
BondarenkoCom:fix/windows-python3-compat
Open

fix: Windows compatibility for plugin.json and hook scripts (#378)#384
BondarenkoCom wants to merge 2 commits into
MemPalace:developfrom
BondarenkoCom:fix/windows-python3-compat

Conversation

@BondarenkoCom

Copy link
Copy Markdown

Problem

On Windows, the MemPalace Claude Code plugin fails at two points:

  1. plugin.json uses "command": "python3" — on Windows Python is typically invoked as py, not python3, causing the MCP server to fail on startup
  2. Hook scripts are .sh bash scripts — Windows has no bash by default, causing Stop hook error: Python was not found on every session end

Reported in #378.

Fix

plugin.json — platform-aware Python command using environment variable detection:

"command": "${env:OS == 'Windows_NT' ? 'py' : 'python3'}"

hooks.json — bash-first with PowerShell fallback:

bash .../mempal-stop-hook.sh 2>/dev/null || powershell -NonInteractive -File .../mempal-stop-hook.ps1

New files.ps1 equivalents of the two hook scripts:

  • .claude-plugin/hooks/mempal-stop-hook.ps1
  • .claude-plugin/hooks/mempal-precompact-hook.ps1

Testing

Tested on Windows 11 with Python 3.12 accessible via py command. MCP server starts correctly and hooks run without errors.

Notes

The bash ... || powershell ... fallback pattern means:

  • Unix/Mac: bash runs, exits 0, powershell never called ✓
  • Windows (no bash): bash fails silently, powershell takes over ✓
  • Windows (Git Bash installed): bash runs fine, same as Unix ✓

No changes to core Python logic.

…alace#378)

- plugin.json: use platform-aware python command (py on Windows, python3 on Unix)
- hooks.json: bash-first with powershell fallback for Windows compatibility
- Add mempal-stop-hook.ps1 and mempal-precompact-hook.ps1 for Windows users

Fixes: Stop hook error: Python was not found on Windows 11

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@bgauryy

bgauryy commented Apr 9, 2026

Copy link
Copy Markdown

PR Review: fix: Windows compatibility for plugin.json and hook scripts (#378)

Executive Summary

Aspect Value
PR Goal Add Windows support for the Claude Code plugin by using platform-aware Python command and PowerShell hook fallbacks
PR #384 — fixes #378
Author BondarenkoCom
Files Changed 4 (2 modified, 2 added)
Lines +11 / −3
Risk Level HIGH — plugin.json change uses unsupported expression syntax that will break MCP server startup on all platforms
Review Mode Full
Review Effort 2/5 — Small change set, but critical correctness issue
Recommendation REQUEST_CHANGES

Affected Areas: Plugin configuration (.claude-plugin/plugin.json), Hook scripts (.claude-plugin/hooks/)

Business Impact: If merged, the MCP server would fail to start on macOS, Linux, AND Windows — completely breaking the plugin for all users.

Flow Changes: Hook execution now attempts bash first and falls back to PowerShell on Windows. Plugin command resolution is changed from a static string to an unsupported conditional expression.

Ratings

Aspect Score
Correctness 2/5
Security 5/5
Performance 5/5
Maintainability 3/5

PR Health

Guidelines Compliance

Source Rule Status
CONTRIBUTING.md Conventional commits (fix:) PASS
CONTRIBUTING.md References issue PASS
CONTRIBUTING.md Minimize dependencies PASS — no new deps
CONTRIBUTING.md python3 as standard command VIOLATION — PS1 scripts use py instead of python/python3, inconsistent with project conventions in mempalace/instructions/init.md

High Priority Issues

(Must fix before merge)

Bug #1: plugin.json uses unsupported conditional expression syntax

Location: .claude-plugin/plugin.json:12 | Confidence: HIGH

The command field is changed from "python3" to "${env:OS == 'Windows_NT' ? 'py' : 'python3'}". This ternary expression syntax is not supported by the Claude Code plugin runner. Evidence:

  • Zero precedent: Across 43+ Claude Code plugins found on GitHub (Grafana, Sudocode, Canon, etc.), every plugin.json uses simple command strings ("node", "python3", "bunx", "npx"). None use ${env:...} or conditional expressions.
  • Only known variable: The only variable expansion documented in Claude Code plugins is ${CLAUDE_PLUGIN_ROOT} for path resolution.
  • Syntax is fabricated: The expression mixes PowerShell env-var syntax ($env:OS) with JavaScript ternary operators (? :) — this is not a recognized pattern in any plugin framework.

Impact: Claude Code will either fail to resolve the expression (passing the literal string as the command) or error during variable expansion. The MCP server will not start on any platform — macOS, Linux, or Windows.

   "mcpServers": {
     "mempalace": {
-      "command": "${env:OS == 'Windows_NT' ? 'py' : 'python3'}",
+      "command": "python3",
       "args": [
         "-m",
         "mempalace.mcp_server"

Recommended approach: Keep "python3" as the command. On modern Windows (10+), python3 is available either via the py launcher alias or the Microsoft Store stub. If a wrapper is truly needed, use a platform-detecting shell script referenced by ${CLAUDE_PLUGIN_ROOT}, similar to how sudocode and econtools_marketplace plugins handle this:

"command": "${CLAUDE_PLUGIN_ROOT}/.claude-plugin/run-mcp.sh"

Medium Priority Issues

(Should fix, not blocking)

Compatibility #2: PowerShell hook scripts hardcode py launcher

Location: .claude-plugin/hooks/mempal-stop-hook.ps1:4, .claude-plugin/hooks/mempal-precompact-hook.ps1:4 | Confidence: MED

Both PS1 scripts invoke py -m mempalace .... The py command is the Python Launcher for Windows, but it is not universally available:

  • Only installed from python.org with the "Install py launcher" checkbox (checked by default, but not guaranteed)
  • Not available with conda, scoop, winget, or pyenv-win installations
  • The project's own install instructions (mempalace/instructions/init.md) reference python and python3, not py
- $INPUT | py -m mempalace hook run --hook stop --harness claude-code
+ $INPUT | python -m mempalace hook run --hook stop --harness claude-code

Same fix applies to mempal-precompact-hook.ps1.


Low Priority Issues

(Nice to have)

Code Quality #3: 2>/dev/null is POSIX-only in the hooks.json fallback

Location: .claude-plugin/hooks/hooks.json:9,19 | Confidence: MED

The fallback pattern bash ... 2>/dev/null || powershell ... uses POSIX stderr redirection. On Windows (cmd.exe), 2>/dev/null would try to redirect to a non-existent path /dev/null, potentially creating a stray file or printing a redirect error. The || fallback mechanism still works because bash fails regardless, but it produces unnecessary noise.

Not a blocker since the fallback does trigger correctly on Windows, but could be cleaner.


Code Quality #4: PS1 scripts shadow the $input automatic variable

Location: .claude-plugin/hooks/mempal-stop-hook.ps1:3, .claude-plugin/hooks/mempal-precompact-hook.ps1:3 | Confidence: MED

PowerShell is case-insensitive, so $INPUT = $input | Out-String reads from the automatic $input enumerator and stores the result back into the same variable name (since $INPUT$input). This works correctly (the enumerator is consumed before reassignment), but is confusing and non-idiomatic.

- $INPUT = $input | Out-String
- $INPUT | py -m mempalace hook run --hook stop --harness claude-code
+ $stdinText = $input | Out-String
+ $stdinText | python -m mempalace hook run --hook stop --harness claude-code

Flow Impact Analysis

BEFORE (main):
  Claude Code → plugin.json "python3" → python3 -m mempalace.mcp_server ✓
  Claude Code → hooks.json → bash .sh script → python3 -m mempalace hook ✓

AFTER (this PR):
  Claude Code → plugin.json "${env:OS == ...}" → ??? COMMAND NOT FOUND ✗ (ALL PLATFORMS)
  Claude Code → hooks.json → bash .sh 2>/dev/null || powershell .ps1
    macOS/Linux: bash succeeds → python3 ✓
    Windows:     bash fails → powershell → py ✓ (if py exists)

The hooks.json fallback approach is architecturally sound. The bash-first-then-PowerShell pattern is a good strategy for cross-platform hooks. The critical blocker is exclusively in plugin.json.


Summary

# Severity Issue Status
1 HIGH plugin.json unsupported ternary syntax — breaks ALL platforms Must fix
2 MEDIUM PS1 scripts hardcode py — not universal on Windows Should fix
3 LOW 2>/dev/null noise on Windows Nice to have
4 LOW $input variable shadowing in PS1 Nice to have

Bottom line: The hooks.json + PS1 fallback approach is well-designed, but the plugin.json change must be reverted or replaced with a supported mechanism before this PR can be merged.


Created by Octocode MCP https://octocode.ai

@web3guru888 web3guru888 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work on Windows compat, @BondarenkoCom! A few observations:

Fallback pattern in hooks.json — The bash ... 2>/dev/null || powershell ... approach is clean. On Windows systems with WSL or Git Bash installed, the bash path might succeed but behave differently than expected (e.g. path separators). Have you tested this on a pure Windows + PowerShell setup without WSL?

py vs python3 in plugin.json — The ternary ${env:OS == 'Windows_NT' ? 'py' : 'python3'} is nice. Worth noting that py (the Python Launcher for Windows) isn't always available in minimal installs or Docker-on-Windows scenarios. A comment in the JSON or docs noting that py must be on PATH would help Windows users who hit a confusing "command not found" error.

PowerShell scripts — The .ps1 wrappers are thin and correct — piping stdin via $input | Out-String and forwarding to the Python CLI is the right call. Keeps logic centralized in mempalace.hooks_cli.

Overall this is a solid approach to cross-platform support. We run our integration on Linux containers, but having Windows compat broadens the contributor base — especially for the HexNest handoff workflows we've been collaborating on. 👍

🔭 Reviewed as part of the MemPalace-AGI integration project — autonomous research with perfect memory. Community interaction updates are posted regularly on the dashboard.

The env ternary syntax is not supported in Claude Code plugin.json.
Revert to python3, add _windows_note field for manual override guidance.
Windows users should change 'command' to 'py' if python3 is not on PATH.
@BondarenkoCom

Copy link
Copy Markdown
Author

Good catch on the ternary — that's not valid in the plugin.json spec and I should have verified before pushing. Reverted.

Updated approach for plugin.json: back to python3 as the command (unchanged from upstream), with a _windows_note field documenting the manual override for Windows users who need py. The hooks fallback (bash ... || powershell ...) and the .ps1 scripts remain — those are the actual cross-platform fix.

On py availability: fair point. The .ps1 scripts could also use python as a secondary fallback (py -m mempalace... 2>$null || python -m mempalace...) for minimal Windows installs. Happy to add that if it's worth the noise.

@web3guru888 On pure Windows + PowerShell without WSL: yes, tested on Windows 11 with only the standard PowerShell — no Git Bash, no WSL. The bash call fails silently via 2>/dev/null, PowerShell takes over. Works cleanly.

@bensig bensig changed the base branch from main to develop April 11, 2026 22:22
@bensig bensig self-requested a review as a code owner April 11, 2026 22:22
@igorls igorls added area/hooks Claude Code hook scripts (Stop, PreCompact, SessionStart) area/install pip/uv/pipx/plugin install and packaging area/windows Windows-specific bugs and compatibility bug Something isn't working labels Apr 14, 2026
@mquinnv

mquinnv commented Apr 14, 2026

Copy link
Copy Markdown

Same class of problem on macOS: modern macOS (Sonoma+) ships a system python3 that blocks pip install into the global site-packages — Apple requires a venv. So "command": "python3" in plugin.json resolves to a Python that will never have mempalace installed, and the MCP server fails to start.

The workaround is installing via pipx and then manually patching .mcp.json to point at the pipx venv's Python (~/.local/pipx/venvs/mempalace/bin/python3), but that breaks on every plugin update.

The proper cross-platform fix for both this and #753 would be to declare the plugin with "source": "pip" and "package": "mempalace" in the marketplace manifest. Claude Code's plugin system already supports this — it creates and manages a venv automatically, so:

  • macOS: no system python restriction
  • Windows: no py vs python3 ambiguity
  • All platforms: updates don't clobber the MCP server path

This would replace the need for platform-detection hacks in plugin.json entirely.

@igorls

igorls commented May 8, 2026

Copy link
Copy Markdown
Member

Hi, thanks for the contribution.

This PR has merge conflicts with develop, and the branch has not been updated in over 7 days, which puts it before our most recent release. The conflicts are likely against work that landed in that release.

Could you rebase onto develop so we can take another look?

If this change is no longer relevant, feel free to close the PR.

(This message is part of a periodic backlog pass, sent to all open PRs that match this state.)

@igorls igorls added the needs-rebase PR has merge conflicts with develop and needs rebase label May 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/hooks Claude Code hook scripts (Stop, PreCompact, SessionStart) area/install pip/uv/pipx/plugin install and packaging area/windows Windows-specific bugs and compatibility bug Something isn't working needs-rebase PR has merge conflicts with develop and needs rebase

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants