[BUG] Learning output style plugin lose execute permission on reload
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Summary
Specifically, plugin hooks with type: "command" lose execute permission on reload
The learning-output-style plugin's SessionStart hook fails with a "SessionStart:resume hook error" because /reload-plugins (and presumably plugin updates) re-downloads plugin files from git without preserving the execute bit on shell scripts referenced by type: "command" hooks.
Root Cause
The plugin's hooks.json references a shell script handler:
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks-handlers/session-start.sh"
}
]
}
]
}
}
When the plugin manager syncs/updates the plugin cache from the git repository, the session-start.sh file is written with 644 permissions (rw-rw-r--) instead of 755 (rwxrwxr-x). Since the hook uses type: "command", the shell tries to execute the script directly, which fails without the execute bit.
The explanatory-output-style plugin (which has an identical hook structure) does not have this issue because its cached version (2cd88e7947b7) retained the execute bit — likely because it was installed at an earlier time when the plugin manager handled permissions differently, or because its version was pinned and not re-downloaded.
Additional Observations
- The script itself is valid — running it manually with
bash session-start.shproduces correct JSON output and exits 0 chmod +xon the script fixes it temporarily, but/reload-pluginsre-downloads the file and resets permissions to644- The plugin's
plugin.jsonis also missing aversionfield, causing the install path to useunknown/as the version directory — cosmetic but potentially related to the update/re-download behavior - Multiple version-hash directories accumulate in the cache (e.g.,
b10b583de281,79caa0d824ac, etc.) alongsideunknown/, butinstalled_plugins.jsonalways referencesunknown
Workaround
Move the hook content into ~/.claude/settings.json as a user-level hook using cat (which reads the file without needing execute permission):
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "cat ~/.claude/hooks/learning-output-style.json"
}
]
}
]
}
}
Then disable the plugin in settings.json:
{
"enabledPlugins": {
"learning-output-style@claude-plugins-official": false
}
}
Environment
- Claude Code CLI on Linux (Ubuntu, kernel 6.5.0-41-generic)
- Plugin source:
claude-plugins-officialmarketplace - Plugin:
learning-output-style(no version field in plugin.json)
What Should Happen?
The plugin manager should either:
- Preserve the execute bit from the git repository when writing files to the plugin cache, or
- Automatically set the execute bit on files referenced by
type: "command"hooks, or - Use
bash <script>instead of direct execution for shell script hooks
Error Messages/Logs
"SessionStart:resume hook error" appears on starting claude-code session
Steps to Reproduce
- Install the
learning-output-styleplugin (user scope) - Verify the plugin works on first install
- Run
/reload-pluginsor wait for an automatic plugin update - Start a new session or resume an existing one
- Observe "SessionStart:resume hook error"
Claude Model
Opus
Is this a regression?
Yes, this worked in a previous version
Last Working Version
2.1.82
Claude Code Version
2.1.84
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Other
Additional Information
- Claude Code CLI on Linux (Ubuntu, kernel 6.5.0-41-generic)
- Plugin source:
claude-plugins-officialmarketplace - Plugin:
learning-output-style(no version field in plugin.json)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗