Stop hook: $CLAUDE_PLUGIN_ROOT not injected when running plugin hooks

Resolved 💬 2 comments Opened Jun 9, 2026 by Zelys-DFKH Closed Jun 25, 2026

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-loop
  • vercel
  • semgrep
  • remember
  • security-guidance
  • hookify
  • railway

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)

View original on GitHub ↗

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