Skip to content

Conversation

@simnJS
Copy link

@simnJS simnJS commented Oct 16, 2025

This adds native Windows support to the superpowers plugin by creating PowerShell equivalents of the bash scripts.

Changes:

  • Add hooks/session-start.ps1 for Windows SessionStart hook
  • Add lib/initialize-skills.ps1 for Windows skills initialization
  • Update hooks/hooks.json to detect platform and use appropriate script
    • Windows (win32): uses PowerShell scripts
    • macOS/Linux (darwin/linux): uses existing bash scripts

The PowerShell scripts provide the same functionality as the bash versions:

  • Load and inject skills context on session start
  • Clone and update the superpowers-skills repository
  • Handle legacy installation migration
  • Offer GitHub fork option when gh CLI is available

Tested on Windows 10/11 with successful JSON output generation.

Motivation and Context

Windows users were unable to use the superpowers plugin because it relied on bash scripts that cannot be executed natively on Windows. The SessionStart hook would fail, preventing the plugin from loading skills context.

How Has This Been Tested?

  • Tested on Windows 10/11 with PowerShell
  • Verified session-start.ps1 generates correct JSON output with skills context
  • Confirmed platform detection in hooks.json works correctly
  • Existing bash scripts remain untouched and functional on macOS/Linux

Breaking Changes

None. This is fully backward compatible:

  • Existing macOS/Linux users continue using bash scripts
  • Windows users now have working PowerShell scripts
  • Platform detection is automatic

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

PowerShell was chosen over batch files because:

  • Native JSON handling with ConvertTo-Json
  • Better error handling and modern syntax
  • Closer to bash scripting patterns
  • Available by default on Windows 10/11

Summary by CodeRabbit

  • New Features
    • Added Windows PowerShell support for session hooks with a runtime fallback to the existing shell path.
    • Added a session-start flow that validates and surfaces skill guidance and warnings at startup.
    • Added a skills initialization and sync flow to set up, migrate, and update the local skills repository with remote tracking and user prompts.

@coderabbitai
Copy link

coderabbitai bot commented Oct 16, 2025

Walkthrough

The pull request adds Windows PowerShell support and a runtime PowerShell-vs-shell selection for superpowers hooks, implements a SessionStart PowerShell hook that validates and assembles skill content into a JSON payload, and adds a PowerShell script to initialize or update the local skills repository with git and optional gh CLI integration.

Changes

Cohort / File(s) Summary
Platform-specific/runtime hook selection
hooks/hooks.json
Replaces a single static Windows command with a runtime conditional: if PowerShell (pwsh or powershell) is available, invoke hooks/session-start.ps1 with -ExecutionPolicy Bypass; otherwise fall back to executing hooks/session-start.sh via bash. Darwin/Linux entries retain the shell path.
SessionStart hook implementation (Windows)
hooks/session-start.ps1
New PowerShell SessionStart hook: locates plugin root, checks for skills/using-superpowers/SKILL.md, reads content, detects legacy skills config path to optionally include a warning, outputs a JSON payload with hookEventName "SessionStart" and assembled additionalContext, exits 0 on success and 1 with an error payload if SKILL.md is missing.
Skills repository initialization (Windows)
lib/initialize-skills.ps1
New PowerShell script to initialize or update the local skills repository: handles existing git repo fetch/fast-forward logic, backups and migration from legacy locations, cloning when missing, sets upstream remote, and optionally forks via gh CLI when available; emits user-facing messages and exits 0 on completion.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant HookRunner as Hook Runner
    participant SessionStartPS as session-start.ps1
    participant SessionStartSH as session-start.sh
    participant FS as File System
    participant Output as JSON Output

    User->>HookRunner: Start session
    HookRunner->>HookRunner: Check for pwsh/powershell
    alt PowerShell available
        HookRunner->>SessionStartPS: Execute PowerShell hook
        SessionStartPS->>FS: Check skills/using-superpowers/SKILL.md
        alt File exists
            FS-->>SessionStartPS: Return content
            SessionStartPS->>Output: Produce JSON with hookEventName "SessionStart" and additionalContext
            note right of SessionStartPS: Exit 0
        else File missing
            SessionStartPS->>Output: Produce error JSON and exit 1
        end
    else PowerShell not available
        HookRunner->>SessionStartSH: Execute shell hook via bash
        SessionStartSH->>FS: (shell flow) check/read SKILL.md
        SessionStartSH->>Output: Produce JSON or error
    end
Loading
sequenceDiagram
    actor User
    participant InitSkills as initialize-skills.ps1
    participant FS as File System
    participant Git as Git
    participant GH as gh CLI
    participant Remote as Remote Repository

    User->>InitSkills: Run initialize/update
    InitSkills->>FS: Check skills directory
    alt Directory exists & is git repo
        FS-->>InitSkills: Repo found
        InitSkills->>Git: Determine tracking remote & fetch
        Git->>Remote: Fetch
        Git-->>InitSkills: Compare local vs remote
        alt Local behind remote
            InitSkills->>Git: Fast-forward update
            note right of InitSkills: Exit 0
        else Up-to-date
            note right of InitSkills: Exit 0
        end
    else Missing or not a repo
        FS-->>InitSkills: Not present
        InitSkills->>FS: Backup legacy install (if any) and create config dirs
        InitSkills->>Git: Clone repository
        InitSkills->>GH: Check gh CLI
        alt gh available
            InitSkills->>User: Prompt to fork
            alt User confirms
                GH-->>InitSkills: Fork created (remote added)
            else
                InitSkills->>Git: Add upstream remote
            end
        else
            InitSkills->>Git: Add upstream remote
        end
        note right of InitSkills: Exit 0
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped in PowerShell, nose a-twitch with cheer,

Found skills and warnings, brought their stories near.
I cloned and I fetched, nudged remotes in line,
Session starts sing JSON, all tidy and fine.
Hooray for tiny scripts that help the codebase steer!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "Add Windows support via PowerShell scripts" accurately reflects the main changes in the changeset. The PR introduces three key modifications: updates to hooks/hooks.json for platform-aware script selection, a new Windows PowerShell script (hooks/session-start.ps1), and another PowerShell script (lib/initialize-skills.ps1) for skills initialization. The title is concise, specific, and clearly conveys the primary objective—adding native Windows support through PowerShell implementations—without using vague terminology or misleading descriptions.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
hooks/session-start.ps1 (1)

14-25: Verify JSON output format consistency.

The error case uses ConvertTo-Json -Compress (single-line JSON), while the success case on Line 50 uses ConvertTo-Json -Depth 10 (multi-line JSON). Ensure this difference is intentional for your parsing requirements.

If consistent formatting is preferred, apply this diff:

-    $output | ConvertTo-Json -Compress
+    $output | ConvertTo-Json -Depth 10
     exit 1
lib/initialize-skills.ps1 (2)

3-3: Use Join-Path for cross-platform path construction.

Line 3 hardcodes backslashes in the path, while Line 72 uses Join-Path which is more robust and handles path separators correctly. Consider applying the same approach consistently.

Apply this diff for consistency:

-$skillsDir = Join-Path $env:USERPROFILE ".config\superpowers\skills"
+$skillsDir = Join-Path $env:USERPROFILE ".config" | Join-Path -ChildPath "superpowers" | Join-Path -ChildPath "skills"

Or more concisely:

-$skillsDir = Join-Path $env:USERPROFILE ".config\superpowers\skills"
+$skillsDir = Join-Path $env:USERPROFILE ".config/superpowers/skills"

Note: PowerShell accepts forward slashes and Join-Path normalizes them.


32-50: Remove unused variable assignment.

Line 38 assigns git merge output to $mergeOutput but never uses it. This variable can be removed to simplify the code.

Apply this diff:

-            $mergeOutput = git merge --ff-only '@{u}' 2>&1
+            git merge --ff-only '@{u}' 2>&1 | Out-Null
             if ($LASTEXITCODE -eq 0) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 10afd4e and bff22cd.

📒 Files selected for processing (3)
  • hooks/hooks.json (1 hunks)
  • hooks/session-start.ps1 (1 hunks)
  • lib/initialize-skills.ps1 (1 hunks)
🔇 Additional comments (8)
hooks/session-start.ps1 (3)

1-6: LGTM!

The script setup correctly determines the plugin root directory using standard PowerShell patterns.


27-40: LGTM!

The context building correctly uses PowerShell's here-string syntax to construct the multi-line payload with embedded content and optional warning.


42-51: LGTM!

The JSON output structure correctly matches the expected hook format, and the depth parameter ensures proper serialization of nested objects.

hooks/hooks.json (2)

9-10: Verify the ExecutionPolicy Bypass security consideration.

Using -ExecutionPolicy Bypass allows unsigned PowerShell scripts to execute, which is necessary for the hook but bypasses Windows security policies. Ensure this aligns with your security requirements and consider documenting this behavior for users.


12-15: LGTM!

The Unix/Linux command configuration correctly preserves existing functionality while explicitly defining platform constraints.

lib/initialize-skills.ps1 (3)

71-79: LGTM!

The repository cloning logic correctly creates necessary directories and clones the skills repository.


101-102: LGTM!

The script properly concludes with a success message and clean exit.


81-99: No changes needed—GitHub CLI flag is well-established.

The --remote=true flag for gh repo fork has been available since GitHub CLI v0.6 (released March 2020) and is widely supported across all modern installations. This code will work reliably with any reasonably current version of GitHub CLI.

Comment on lines +9 to +11
$legacySkillsDir = Join-Path $env:USERPROFILE ".config\superpowers\skills"
if (Test-Path $legacySkillsDir) {
$warningMessage = "`n`n⚠️ **WARNING:** Superpowers now uses Claude Code's skills system. Custom skills in ~/.config/superpowers/skills will not be read."
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clarify the path in the warning message for Windows users.

The warning message displays ~/.config/superpowers/skills, but Windows users may not be familiar with tilde notation. The actual path being checked uses $env:USERPROFILE\.config\superpowers\skills.

Apply this diff to use a Windows-friendly path format:

 $legacySkillsDir = Join-Path $env:USERPROFILE ".config\superpowers\skills"
 if (Test-Path $legacySkillsDir) {
-    $warningMessage = "`n`n⚠️ **WARNING:** Superpowers now uses Claude Code's skills system. Custom skills in ~/.config/superpowers/skills will not be read."
+    $warningMessage = "`n`n⚠️ **WARNING:** Superpowers now uses Claude Code's skills system. Custom skills in $legacySkillsDir will not be read."
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$legacySkillsDir = Join-Path $env:USERPROFILE ".config\superpowers\skills"
if (Test-Path $legacySkillsDir) {
$warningMessage = "`n`n⚠️ **WARNING:** Superpowers now uses Claude Code's skills system. Custom skills in ~/.config/superpowers/skills will not be read."
$legacySkillsDir = Join-Path $env:USERPROFILE ".config\superpowers\skills"
if (Test-Path $legacySkillsDir) {
$warningMessage = "`n`n⚠️ **WARNING:** Superpowers now uses Claude Code's skills system. Custom skills in $legacySkillsDir will not be read."
}
🤖 Prompt for AI Agents
In hooks/session-start.ps1 around lines 9 to 11, the warning message shows the
Unix-style path (~/.config/superpowers/skills) which is unclear for Windows
users; change the message to display the actual Windows-friendly path being
checked (use $env:USERPROFILE\.config\superpowers\skills or the resolved
$legacySkillsDir) so users see the real location, and update the string
accordingly to interpolate or insert the resolved path instead of the tilde
notation.

Comment on lines +17 to +25
# Fetch from tracking remote if set, otherwise try upstream then origin
if ($trackingRemote) {
git fetch $trackingRemote 2>$null | Out-Null
} else {
git fetch upstream 2>$null | Out-Null
if ($LASTEXITCODE -ne 0) {
git fetch origin 2>$null | Out-Null
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Improve error handling consistency and verify origin fetch success.

The error handling patterns are inconsistent:

  • Line 19: git fetch $trackingRemote 2>$null | Out-Null
  • Lines 21, 23: git fetch upstream/origin 2>$null | Out-Null

Additionally, the fallback logic checks if upstream fetch fails (Line 22) but doesn't verify whether the origin fetch succeeds. If both fail, the script continues without confirmation that remote refs are available.

Apply this diff to verify the origin fetch and unify error suppression:

     # Fetch from tracking remote if set, otherwise try upstream then origin
     if ($trackingRemote) {
-        git fetch $trackingRemote 2>$null | Out-Null
+        git fetch $trackingRemote 2>&1 | Out-Null
     } else {
-        git fetch upstream 2>$null | Out-Null
+        git fetch upstream 2>&1 | Out-Null
         if ($LASTEXITCODE -ne 0) {
-            git fetch origin 2>$null | Out-Null
+            git fetch origin 2>&1 | Out-Null
+            if ($LASTEXITCODE -ne 0) {
+                Write-Host "Warning: Unable to fetch remote updates"
+            }
         }
     }
🤖 Prompt for AI Agents
In lib/initialize-skills.ps1 around lines 17 to 25, the git fetch error handling
is inconsistent and the fallback doesn't verify origin succeeded; change all
fetch calls to consistently suppress output with "2>$null | Out-Null" and check
$LASTEXITCODE after each fetch: if $trackingRemote is set, run "git fetch
$trackingRemote 2>$null | Out-Null" and if it fails (check $LASTEXITCODE) exit
with a clear error; if no trackingRemote, attempt "git fetch upstream 2>$null |
Out-Null" and if that fails attempt "git fetch origin 2>$null | Out-Null" and if
origin also fails exit with an error message so the script never continues
without successful remote fetch.

Comment on lines +58 to +68
# Handle migration from old installation
$oldGitDir = Join-Path $env:USERPROFILE ".config\superpowers\.git"
if (Test-Path $oldGitDir) {
Write-Host "Found existing installation. Backing up..."
Move-Item $oldGitDir "$oldGitDir.bak" -Force -ErrorAction SilentlyContinue

$oldSkillsDir = Join-Path $env:USERPROFILE ".config\superpowers\skills"
if (Test-Path $oldSkillsDir) {
Move-Item $oldSkillsDir "$oldSkillsDir.bak" -Force -ErrorAction SilentlyContinue
Write-Host "Your old skills are in $env:USERPROFILE\.config\superpowers\skills.bak"
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Prevent accidental backup overwrites.

Lines 62 and 66 use Move-Item -Force, which will silently overwrite existing .bak files if the initialization script runs multiple times. This could lead to loss of previous backups.

Consider one of these approaches:

  1. Check for existing backups before moving:
 if (Test-Path $oldGitDir) {
     Write-Host "Found existing installation. Backing up..."
+    $backupPath = "$oldGitDir.bak"
+    if (Test-Path $backupPath) {
+        Write-Host "Warning: Backup already exists at $backupPath"
+        $reply = Read-Host "Overwrite existing backup? (y/N)"
+        if ($reply -notmatch '^[Yy]$') {
+            Write-Host "Skipping backup of .git directory"
+            $backupPath = $null
+        }
+    }
+    if ($backupPath) {
+        Move-Item $oldGitDir $backupPath -Force -ErrorAction SilentlyContinue
+    }
-    Move-Item $oldGitDir "$oldGitDir.bak" -Force -ErrorAction SilentlyContinue
  1. Or use timestamped backups:
-    Move-Item $oldGitDir "$oldGitDir.bak" -Force -ErrorAction SilentlyContinue
+    $timestamp = Get-Date -Format 'yyyyMMdd_HHmmss'
+    Move-Item $oldGitDir "$oldGitDir.bak.$timestamp" -Force -ErrorAction SilentlyContinue
🤖 Prompt for AI Agents
In lib/initialize-skills.ps1 around lines 58 to 68, the script uses Move-Item
-Force to rename existing .git and skills dirs to .bak which will overwrite
prior backups; change this to detect if the target .bak already exists and avoid
overwriting by either (a) if a .bak exists, append a timestamp (or incremental
suffix) to the backup name before moving, or (b) if a .bak exists, skip the move
and warn the user; remove -Force so Move-Item will not silently overwrite and
implement a small helper to generate a safe unique backup filename (e.g.,
basename + yyyyMMddHHmmss or + -1/-2) and use that when calling Move-Item.

@obra obra mentioned this pull request Oct 19, 2025
2 tasks
@obra
Copy link
Owner

obra commented Oct 20, 2025

I'd love to hear a report or two from windows users on this PR

@joegoldin
Copy link

joegoldin commented Oct 21, 2025

@obra @simnJS This is not working for me under Windows 11, and I don't see anything in the claude code docs about platform for startup hooks? I think I actually saw some hallucinations (or at least, what I thought were hallucinations) about platform in my original attempt at this feature...

On my machine, under Powershell and CMD, claude just opens the .sh file in my editor (because that's the explorer.exe default for .sh files). Made sure to npm update claude to the latest version, but no luck.

@dalito
Copy link

dalito commented Oct 21, 2025

On Windows I typically run Claude Code in git bash to avoid such problems.

@joegoldin
Copy link

joegoldin commented Oct 21, 2025

On Windows I typically run Claude Code in git bash to avoid such problems.

It's really convenient for certain projects to be in a Windows native terminal and not git bash, but that does work. Doing so would also defeat the purpose of the windows platform support in this script 🤷

@dalito
Copy link

dalito commented Oct 21, 2025

I agree having both supported would be nice. Supporting only powershell not so.

This adds native Windows support to the superpowers plugin by creating PowerShell equivalents of the bash scripts.

Changes:
- Add hooks/session-start.ps1 for Windows SessionStart hook
- Add lib/initialize-skills.ps1 for Windows skills initialization
- Update hooks/hooks.json to detect platform and use appropriate script
  - Windows (win32): uses PowerShell scripts
  - macOS/Linux (darwin/linux): uses existing bash scripts

The PowerShell scripts provide the same functionality as the bash versions:
- Load and inject skills context on session start
- Clone and update the superpowers-skills repository
- Handle legacy installation migration
- Offer GitHub fork option when gh CLI is available

Tested on Windows 10/11 with successful JSON output generation.
@simnJS simnJS force-pushed the feature/windows-support branch from bff22cd to 48430ca Compare October 21, 2025 19:04
@simnJS
Copy link
Author

simnJS commented Oct 21, 2025

My bad, the first hook was vibe-coded and didn’t work correctly, this one is the right solution.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
hooks/session-start.ps1 (1)

9-11: The warning message still uses Unix-style path notation.

As previously noted, Windows users may not recognize ~/.config/superpowers/skills. The actual path being checked is $env:USERPROFILE\.config\superpowers\skills.

Apply this diff to use the resolved Windows path:

 $legacySkillsDir = Join-Path $env:USERPROFILE ".config\superpowers\skills"
 if (Test-Path $legacySkillsDir) {
-    $warningMessage = "`n`n⚠️ **WARNING:** Superpowers now uses Claude Code's skills system. Custom skills in ~/.config/superpowers/skills will not be read."
+    $warningMessage = "`n`n⚠️ **WARNING:** Superpowers now uses Claude Code's skills system. Custom skills in $legacySkillsDir will not be read."
 }
🧹 Nitpick comments (3)
hooks/session-start.ps1 (3)

15-15: Consider using path-separator-agnostic approach.

While the current approach works, hardcoding backslashes is less idiomatic. PowerShell's Join-Path is designed to handle path separators cross-platform.

Apply this diff for a more robust approach:

-$skillFile = Join-Path $pluginRoot "skills\using-superpowers\SKILL.md"
+$skillFile = Join-Path (Join-Path (Join-Path $pluginRoot "skills") "using-superpowers") "SKILL.md"

23-23: Use consistent JSON output formatting.

The error path (line 23) uses -Compress while the success path (line 50) uses -Depth 10. For consistency and to prevent potential truncation in error messages, both should use the same flags.

Apply this diff to make the error output consistent:

-    $output | ConvertTo-Json -Compress
+    $output | ConvertTo-Json -Depth 10

Also applies to: 50-50


29-40: Empty warning adds unnecessary blank lines.

When the legacy skills directory doesn't exist, $warningMessage is empty and line 38 will add extra blank lines to the output. Consider conditionally constructing the context.

Here's a cleaner approach:

 # Build the additional context
+$contextParts = @(
+    "<EXTREMELY_IMPORTANT>"
+    "You have superpowers."
+    ""
+    "**The content below is from skills/using-superpowers/SKILL.md - your introduction to using skills:**"
+    ""
+    $usingSuperpowersContent
+)
+
+if ($warningMessage) {
+    $contextParts += @("", $warningMessage)
+}
+
+$contextParts += "</EXTREMELY_IMPORTANT>"
+
-$additionalContext = @"
-<EXTREMELY_IMPORTANT>
-You have superpowers.
-
-**The content below is from skills/using-superpowers/SKILL.md - your introduction to using skills:**
-
-$usingSuperpowersContent
-
-$warningMessage
-</EXTREMELY_IMPORTANT>
-"@
+$additionalContext = $contextParts -join "`n"
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bff22cd and 48430ca.

📒 Files selected for processing (3)
  • hooks/hooks.json (1 hunks)
  • hooks/session-start.ps1 (1 hunks)
  • lib/initialize-skills.ps1 (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/initialize-skills.ps1
  • hooks/hooks.json

@spxangelo
Copy link

@obra @joegoldin @dalito I tried direct PowerShell, direct bash, the conditional wrapper from @simnJS, running from Git Bash vs PowerShell, paths with/without spaces - all failed identically. The error "-v was unexpected at this time" is a CMD error, not bash. Even though Claude detects Git Bash correctly, hook execution appears to spawn Windows CMD internally, which can't parse bash command -v syntax. The hooks match but fail validation before execution regardless of terminal or wrapper approach.

Conditional wrapper used:

"command": "if command -v pwsh &>/dev/null || command -v powershell &>/dev/null; then powershell -ExecutionPolicy Bypass -File \"${CLAUDE_PLUGIN_ROOT}/scripts/inject-design-context.ps1\"; else bash \"${CLAUDE_PLUGIN_ROOT}/scripts/inject-design-context.sh\"; fi"

Debug output:

[DEBUG] Using bash path: "C:\Program Files\Git\bin\bash.exe"
[DEBUG] Registered 4 hooks from 1 plugins ✓
[DEBUG] Matched 2 unique hooks for query "no match query" ✓
[DEBUG] Found 0 total hooks in registry ✗  ← hooks fail validation here

@z925835
Copy link

z925835 commented Oct 23, 2025

@obra @joegoldin @dalito I tried direct PowerShell, direct bash, the conditional wrapper from @simnJS, running from Git Bash vs PowerShell, paths with/without spaces - all failed identically. The error "-v was unexpected at this time" is a CMD error, not bash. Even though Claude detects Git Bash correctly, hook execution appears to spawn Windows CMD internally, which can't parse bash command -v syntax. The hooks match but fail validation before execution regardless of terminal or wrapper approach.

Conditional wrapper used:

"command": "if command -v pwsh &>/dev/null || command -v powershell &>/dev/null; then powershell -ExecutionPolicy Bypass -File \"${CLAUDE_PLUGIN_ROOT}/scripts/inject-design-context.ps1\"; else bash \"${CLAUDE_PLUGIN_ROOT}/scripts/inject-design-context.sh\"; fi"

Debug output:


[DEBUG] Using bash path: "C:\Program Files\Git\bin\bash.exe"

[DEBUG] Registered 4 hooks from 1 plugins ✓

[DEBUG] Matched 2 unique hooks for query "no match query" ✓

[DEBUG] Found 0 total hooks in registry ✗  ← hooks fail validation here

I didn't try everything the way @spxangelo did, but experienced the same thing

@dizzlkheinz
Copy link

for me, just changing the line in "C:\Users\username.claude\plugins\cache\superpowers\hooks\hooks.json" from
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh"
to

"command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh"

has it working fine as far as I can tell (claude will show me that the session start hook injected the prompt). I have git-bash installed on my system and it is in path and I suspect that most people running claude on windows will too.

@obra
Copy link
Owner

obra commented Oct 23, 2025

@dizzlkheinz Is that bash always going to be available on windows these days? That'd be a nice change

@dizzlkheinz
Copy link

@obra when you install git on windows it ?optionally installs bash for you
https://www.atlassian.com/git/tutorials/git-bash

Git Bash is a package that installs Bash, some common bash utilities, and Git on a Windows operating system.

I'm pretty certain it is installed by default when you install git using winget
winget install --id Git.Git -e --source winget

Screenshot 2025-10-23 180811

you can see here that it ends up as a profile in the windows terminal app as well

So I think that most anyone who has claude installed on windows also has bash available as well and probably the easiest thing to do is just to have the hook call bash explicitly. You could just list bash on windows as a requirement in the readme. It seems to work for me at least.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants