openai / openai/codex-plugin-cc

Plugin hooks fail when CLAUDE_PLUGIN_ROOT is missing on macOS

Open
#448 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
33.3k
Forks
2.3k
PR merge metrics
No merged PRs in 30d

Description

Summary

The Claude Code plugin hooks in hooks/hooks.json assume ${CLAUDE_PLUGIN_ROOT} is always populated. On my macOS install it was missing for the plugin hook runner, so the Stop hook expanded to /scripts/stop-review-gate-hook.mjs and failed with MODULE_NOT_FOUND.

This affects all three hook commands in the plugin, not only Stop:

"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/session-lifecycle-hook.mjs\" SessionStart"
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/session-lifecycle-hook.mjs\" SessionEnd"
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/stop-review-gate-hook.mjs\""

Observed behavior

With CLAUDE_PLUGIN_ROOT unset, the command fails before the hook script can run:

env -u CLAUDE_PLUGIN_ROOT sh -c 'printf "{}" | node "${CLAUDE_PLUGIN_ROOT}/scripts/stop-review-gate-hook.mjs"'

Result:

Error: Cannot find module '/scripts/stop-review-gate-hook.mjs'
Node.js v25.9.0
exit=1

With CLAUDE_PLUGIN_ROOT set to the installed plugin cache path, the same hook exits cleanly:

CLAUDE_PLUGIN_ROOT=/Users/junhyeong/.claude/plugins/cache/openai-codex/codex/1.0.3 \
  sh -c 'printf "{}" | node "${CLAUDE_PLUGIN_ROOT}/scripts/stop-review-gate-hook.mjs"'
# exit=0

For the affected workspace, the review gate was disabled / default false, so the hook should have been a no-op. The failure is command path resolution before the hook logic runs, not review-gate logic.

Local workaround that fixed it

I patched both the cache copy and marketplace copy to fall back to the marketplace plugin path when CLAUDE_PLUGIN_ROOT is empty:

"command": "PLUGIN_ROOT=\"${CLAUDE_PLUGIN_ROOT:-/Users/junhyeong/.claude/plugins/marketplaces/openai-codex/plugins/codex}\"; exec node \"$PLUGIN_ROOT/scripts/stop-review-gate-hook.mjs\""

The same fallback was applied to SessionStart and SessionEnd.

After that, all three events passed in both cases:

SessionStart unset exit=0
SessionEnd unset exit=0
Stop unset exit=0
SessionStart set exit=0
SessionEnd set exit=0
Stop set exit=0

Suggested fix

The ideal fix may be in Claude Code host so CLAUDE_PLUGIN_ROOT is always injected for plugin hooks. But the plugin can also be more defensive:

  • provide a fallback root resolution path for hook commands, or
  • fail with a clear diagnostic instead of expanding to /scripts/..., or
  • route hook commands through a small resolver wrapper that checks CLAUDE_PLUGIN_ROOT before invoking Node.

Environment

  • OS: macOS 26.5.1
  • Claude Code: 2.1.203
  • Node.js: v25.9.0
  • Plugin: openai-codex / codex-plugin-cc 1.0.3
  • Marketplace commit: 6a5c2ba53b734f3cdd8daacbd49f68f3e6c8c167
  • Installed path: /Users/junhyeong/.claude/plugins/cache/openai-codex/codex/1.0.3

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with hooks/hooks.json and reproduce the failure using the provided env -u CLAUDE_PLUGIN_ROOT command. Check all three hook commands with the variable unset and set, then verify each event completes successfully or reports a clear diagnostic without attempting /scripts/... paths.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
65/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.