Stop hook: $CLAUDE_PLUGIN_ROOT not injected when running plugin hooks
Description
Plugin hooks that reference ${CLAUDE_PLUGIN_ROOT} in their command fail because the variable is never set by the hook runner. The variable resolves to a literal empty/unset string, producing a path like /hooks/stop-hook.sh which doesn't exist.
Affected hook
Plugin: ralph-loop (claude-plugins-official)
Hook type: Stop
Hook command from hooks.json:
{
"type": "command",
"command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/stop-hook.sh\""
}
Error observed
Stop hook error: Failed with non-blocking status code: bash: ${CLAUDE_PLUGIN_ROOT}/hooks/stop-hook.sh: No such file or directory
The literal string ${CLAUDE_PLUGIN_ROOT} appears in the error, confirming the variable is not being expanded.
Scope
CLAUDE_PLUGIN_ROOT is referenced in hooks.json across at least these plugins in the official marketplace:
ralph-loopvercelsemgrepremembersecurity-guidancehookifyrailway
This means the Stop (and potentially other) hooks for all of these plugins are silently failing on every session.
Expected behavior
When Claude Code runs a plugin hook, it should inject CLAUDE_PLUGIN_ROOT as an environment variable set to the resolved absolute path of that plugin's root directory (e.g. C:/Users/<user>/.claude/plugins/cache/claude-plugins-official/ralph-loop/261ce4fba4f2). The value must be per-plugin — a single global env var in settings.json cannot substitute since each plugin needs a different path.
Impact
Non-blocking (Claude Code does not crash), but ralph-loop's stop-continuation behavior is entirely broken — it cannot intercept the Stop event to requeue the loop prompt. Other affected plugins likely have similar silent failures.
Environment
- OS: Windows 11 Pro
- Claude Code: latest
- Shell: PowerShell / bash (WSL)
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗