[BUG] Plugin installation does not preserve executable permissions on shell script hooks
Description
When Claude Code installs plugins from a marketplace (GitHub or other sources), executable permissions are not preserved on shell script files (.sh). This causes hooks to fail silently on macOS and Linux.
Steps to Reproduce
- Create a marketplace plugin with a hook script:
``bash``
# In your plugin's hooks/session-start.sh (with +x permission in git)
#!/bin/bash
echo '{"continue": true, "systemMessage": "Hello from hook"}'
- Ensure the file has executable permission in git:
``bash``
chmod +x hooks/session-start.sh
git add hooks/session-start.sh
git commit -m "Add hook with executable permission"
- Install the plugin via Claude Code:
``bash``
claude plugin marketplace add github:your-org/your-marketplace
claude plugin install your-plugin@your-marketplace
- Check file permissions after installation:
``bash``
ls -la ~/.claude/plugins/marketplaces/your-marketplace/plugins/your-plugin/hooks/
# Expected: -rwxr-xr-x session-start.sh
# Actual: -rw-r--r-- session-start.sh
- The hook fails to execute because the OS won't run a script without the execute bit.
Expected Behavior
After plugin installation, shell scripts should retain their executable permissions (chmod +x), matching the source repository.
Actual Behavior
All files are installed with read/write permissions only (-rw-r--r--), losing the executable bit. Hooks silently fail to execute.
Impact
- macOS: Affected ✓
- Linux: Affected ✓
- Windows: Not affected (Windows doesn't use Unix permissions; hooks run via Git Bash)
This affects any third-party marketplace that uses shell script hooks. Users experience:
- Hooks not firing despite being correctly configured
- Silent failures with no error messages
- Difficult debugging (permissions aren't the first thing users check)
Workaround
Third-party marketplaces must provide a post-install script that runs chmod +x on hook files:
// SpecWeave's workaround in refresh-marketplace.ts
function fixHookPermissions(marketplacePath: string) {
if (process.platform === 'win32') return; // Skip on Windows
const hookFiles = findAllShellScripts(marketplacePath);
for (const hookFile of hookFiles) {
fs.chmodSync(hookFile, 0o755); // Make executable
}
}
Suggested Fix
During plugin installation, preserve executable permissions from the source:
Option A: Check git metadata for executable bit and apply it
git ls-files -s | grep "^100755" # Files with executable permission
Option B: Auto-chmod .sh files in hooks/ directories after extraction
if (file.endsWith('.sh') && file.includes('/hooks/')) {
fs.chmodSync(file, 0o755);
}
Environment
- Claude Code version: 2.1.x
- OS: macOS 15.x, Ubuntu 24.04
- Shell: bash, zsh
Related
This issue affects the SpecWeave marketplace and likely any other third-party marketplace with shell script hooks.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗