[BUG] Marketplace plugin sync overwrites .sh file permissions, stripping execute bit

Resolved 💬 2 comments Opened Mar 27, 2026 by ochanism Closed Mar 27, 2026

Description

When Claude Code syncs marketplace plugins, all .sh files are written with default 644 (-rw-r--r--) permissions, stripping the execute bit. This causes hook execution to fail with:

Stop hook error: Failed with non-blocking status code: /bin/sh: /Users/ochan/.claude/plugins/marketplaces/claude-plugins-official/plugins/ralph-loop/hooks/stop-hook.sh: Permission denied

Steps to Reproduce

  1. Install a marketplace plugin that uses shell script hooks (e.g., ralph-loop)
  2. Observe hook fails with "Permission denied"
  3. Fix manually: chmod +x .../stop-hook.sh
  4. Wait for next marketplace sync (appears to happen on session start or periodically)
  5. Permission reverts to 644 — error recurs

Evidence

Every .sh file in the marketplace directory has the same modification timestamp and identical 644 permissions, confirming they're all written by the same sync process without execute bit:

-rw-r--r--  stop-hook.sh              (Mar 27 09:10)
-rw-r--r--  setup-ralph-loop.sh       (Mar 27 09:10)
-rw-r--r--  session-start.sh          (Mar 27 09:10)  ← different plugin
-rw-r--r--  validate-settings.sh      (Mar 27 09:10)  ← different plugin
-rw-r--r--  hook-linter.sh            (Mar 27 09:10)  ← different plugin
... (all .sh files in marketplace have same timestamp and perms)

Expected Behavior

Marketplace sync should preserve or set execute permissions on .sh files, especially those referenced as hook commands in hooks.json.

Suggested Fix

Either:

  1. Set +x on .sh files during marketplace sync/download
  2. Execute hooks via bash <script> instead of direct execution, so execute permission is not required
  3. Run a post-sync chmod +x on all .sh files in the plugin directory

Environment

  • OS: macOS
  • Claude Code: Latest (installed via claude update)
  • Plugin: ralph-loop (from claude-plugins-official marketplace)
  • Hook type: Stop hook defined in hooks.json

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗