openai / openai/codex-plugin-cc
Plugin hooks fail when CLAUDE_PLUGIN_ROOT is missing on macOS
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_ROOTbefore invoking Node.
Environment
- OS: macOS 26.5.1
- Claude Code: 2.1.203
- Node.js: v25.9.0
- Plugin:
openai-codex/codex-plugin-cc1.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
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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