Plugin sync from GCS strips execute permission on .sh hook files
Bug Description
Plugin .sh files lose their execute permission (+x) after every session sync. The plugin marketplace syncs plugins from GCS (Google Cloud Storage) on each session start, and since GCS object storage does not preserve POSIX file permissions, all downloaded .sh files default to 644 (-rw-r--r--).
This causes hook scripts to fail with Permission denied errors on every new session.
Reproduction
- Install a plugin that uses
.shhook files (e.g.,ralph-loopwhich hashooks/stop-hook.sh) - Manually fix:
chmod +x ~/.claude/plugins/marketplaces/claude-plugins-official/plugins/ralph-loop/hooks/stop-hook.sh - Start a new Claude Code session
- The permission is reset to
644— the hook fails withPermission denied
Evidence
All .sh files in the plugin directory have identical timestamps and no execute permission after sync:
-rw-r--r--@ aaron staff 7533 Mar 27 13:24 ralph-loop/hooks/stop-hook.sh
-rw-r--r--@ aaron staff 3564 Mar 27 13:24 learning-output-style/hooks-handlers/session-start.sh
-rw-r--r--@ aaron staff 7044 Mar 27 13:24 ralph-loop/scripts/setup-ralph-loop.sh
-rw-r--r--@ aaron staff 1485 Mar 27 13:24 explanatory-output-style/hooks-handlers/session-start.sh
... (all .sh files are 644)
The .gcs-sha file (72b975468071669f5503fd49c37ab657d9212fbd) confirms the sync source is GCS.
Expected Behavior
After syncing plugins from GCS, the plugin system should automatically chmod +x all .sh files (or at minimum, files referenced as command in hooks.json).
Suggested Fix
After downloading/extracting plugin files, run something like:
find "$PLUGIN_DIR" -name "*.sh" -exec chmod +x {} \;
Or parse each plugin's hooks.json and ensure any file referenced in "command" fields has execute permission.
Environment
- Claude Code: 2.1.84
- macOS: 15.6.1 (Darwin 24.6.0)
- Shell: zsh
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗