From claude-plugins-validation
Add a new hook entry to hooks/hooks.json in an existing plugin (idempotent — skips duplicate entries; cross-platform-aware so the hook command runs identically on Linux/macOS/Windows).
npx claudepluginhub emasoft/emasoft-plugins --plugin claude-plugins-validation<plugin-path> <event-name> <command># /cpv-create-hook
Add a new hook entry to a plugin's `hooks/hooks.json`. The scaffold is
idempotent — re-running with the same event+command is a no-op.
The new hook command MUST be cross-platform: Python or Node.js
delegation. Bash-only constructs (`set -euo pipefail`, `[[ ]]`,
`$(<file)`, process substitution, brace expansion) will trigger
validate_hook MAJOR findings. POSIX-only tools (`jq`, `sed`, `awk`,
`shellcheck`) used directly trigger MINOR. The recommended pattern is
to delegate to `python3 "${CLAUDE_PLUGIN_ROOT}/scripts/<your-hook>.py"`.
## Usage
## Under the hood
## Be...Share bugs, ideas, or general feedback.
Add a new hook entry to a plugin's hooks/hooks.json. The scaffold is
idempotent — re-running with the same event+command is a no-op.
The new hook command MUST be cross-platform: Python or Node.js
delegation. Bash-only constructs (set -euo pipefail, [[ ]],
$(<file), process substitution, brace expansion) will trigger
validate_hook MAJOR findings. POSIX-only tools (jq, sed, awk,
shellcheck) used directly trigger MINOR. The recommended pattern is
to delegate to python3 "${CLAUDE_PLUGIN_ROOT}/scripts/<your-hook>.py".
# Cross-platform Python delegation (recommended)
/cpv-create-hook /path/to/my-plugin PostToolUse 'python3 "${CLAUDE_PLUGIN_ROOT}/scripts/post_tool.py"'
# Cross-platform Node delegation
/cpv-create-hook /path/to/my-plugin SessionStart 'node "${CLAUDE_PLUGIN_ROOT}/scripts/init.js"'
uv run "${CLAUDE_PLUGIN_ROOT}/scripts/add_component.py" <plugin-path> \
--type hook --event <event-name> --command "<command>"
hooks/hooks.json is created if missing, otherwise merged.validate_hook.check_hook_command_cross_platform before being
written. Bash-isms are rejected (the agent prompts to convert).${CLAUDE_PLUGIN_ROOT} (state
lost on every plugin update). Use ${CLAUDE_PLUGIN_DATA} instead.PreToolUse, PostToolUse, PostToolUseFailure, PostToolBatch, PermissionRequest, PermissionDenied, UserPromptSubmit, UserPromptExpansion, Notification, Stop, StopFailure, SubagentStop, SubagentStart, SessionStart, SessionEnd, PreCompact, PostCompact, TeammateIdle, TaskCompleted, TaskCreated, ConfigChange, WorktreeCreate, WorktreeRemove, InstructionsLoaded, Elicitation, ElicitationResult, CwdChanged, FileChanged.
${CLAUDE_PLUGIN_DATA}/log.jsonl).