con un clic
register-hook
Create and register hook scripts with proper error handling and settings
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Menú
Create and register hook scripts with proper error handling and settings
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Basado en la clasificación ocupacional SOC
Guide for writing clear, descriptive commit messages
Merge task branch to base branch with linear history (works from task worktree)
MANDATORY: Use instead of `git rebase` - provides automatic backup and conflict recovery
MANDATORY: Use instead of `git rebase -i` for squashing - unified commit messages
Analyze mistakes with conversation length as potential cause (CAT-specific)
Run scheduled retrospective analysis, derive action items, and track effectiveness
| name | register-hook |
| description | Create and register hook scripts with proper error handling and settings |
| allowed-tools | Bash, Write, Read, Edit |
Purpose: Create hook scripts with mandatory error handling patterns and register them in settings.json with proper matcher syntax.
Performance: Ensures hooks work correctly, prevents registration errors, enforces restart requirement
# Creates script with mandatory pattern:
#!/bin/bash
set -euo pipefail
# Error handler - output helpful message to stderr on failure
trap 'echo "ERROR in <script-name>.sh at line $LINENO: Command failed: $BASH_COMMAND" >&2; exit 1' ERR
# Hook logic...
chmod +x ~/.claude/hooks/{hook-name}.sh
{
"hooks": {
"{TriggerEvent}": [
{
"matcher": "{tool-pattern}",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/{hook-name}.sh"
}
]
}
]
}
}
⚠️ Please restart Claude Code for hook changes to take effect
After restart, test hook with:
[specific command to trigger hook]
SessionStart: Runs when session starts or resumes after compaction
"SessionStart": [
{
"hooks": [{"type": "command", "command": "~/.claude/hooks/my-hook.sh"}]
}
]
UserPromptSubmit: Runs when user submits a prompt
"UserPromptSubmit": [
{
"hooks": [{"type": "command", "command": "~/.claude/hooks/my-hook.sh"}]
}
]
PreToolUse: Runs before tool execution (supports matchers)
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{"type": "command", "command": "~/.claude/hooks/my-hook.sh"}]
}
]
PostToolUse: Runs after tool execution (supports matchers)
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [{"type": "command", "command": "~/.claude/hooks/my-hook.sh"}]
}
]
PreCompact: Runs before context compaction
"PreCompact": [
{
"hooks": [{"type": "command", "command": "~/.claude/hooks/my-hook.sh"}]
}
]
Matcher patterns filter by tool name only. Command/path filtering must be done inside hook scripts.
✅ CORRECT Matcher Syntax:
"matcher": "Bash" // Single tool
"matcher": "Write|Edit" // Multiple tools (regex)
"matcher": "Notebook.*" // Pattern matching
"matcher": "*" // All tools
// No matcher field = all tools
❌ WRONG Matcher Syntax:
"matcher": "tool:Bash && command:*git*" // ❌ 'tool:' prefix not supported
"matcher": "command:*echo*" // ❌ command filtering not in matcher
"matcher": "path:**/*.java" // ❌ path filtering not in matcher
# Inside hook script - parse JSON input
JSON_INPUT=$(cat)
COMMAND=$(echo "$JSON_INPUT" | jq -r '.tool_input.command // empty')
# Now filter based on command content
if [[ "$COMMAND" == *"git filter-branch"* ]]; then
echo "Blocking dangerous command" >&2
exit 2
fi
# Create hook that logs all bash commands
HOOK_NAME="log-bash-commands"
TRIGGER="PreToolUse"
MATCHER="Bash"
~/.claude/scripts/register-hook.sh \
--name "$HOOK_NAME" \
--trigger "$TRIGGER" \
--matcher "$MATCHER" \
--script-content "$(cat <<'SCRIPT'
#!/bin/bash
set -euo pipefail
trap 'echo "ERROR in log-bash-commands.sh at line $LINENO: Command failed: $BASH_COMMAND" >&2; exit 1' ERR
# Log bash command to file
JSON_INPUT=$(cat)
COMMAND=$(echo "$JSON_INPUT" | jq -r '.tool_input.command // "unknown"')
echo "[$(date -Iseconds)] $COMMAND" >> /tmp/bash-log.txt
SCRIPT
)"
# Create hook that blocks dangerous git commands
HOOK_NAME="block-dangerous-git"
TRIGGER="PreToolUse"
MATCHER="Bash"
~/.claude/scripts/register-hook.sh \
--name "$HOOK_NAME" \
--trigger "$TRIGGER" \
--matcher "$MATCHER" \
--can-block true \
--script-content "$(cat <<'SCRIPT'
#!/bin/bash
set -euo pipefail
trap 'echo "ERROR in block-dangerous-git.sh at line $LINENO: Command failed: $BASH_COMMAND" >&2; exit 1' ERR
JSON_INPUT=$(cat)
COMMAND=$(echo "$JSON_INPUT" | jq -r '.tool_input.command // empty')
# Block dangerous commands
if [[ "$COMMAND" == *"git filter-branch"* ]] || [[ "$COMMAND" == *"--all"* ]]; then
echo '{"permissionDecision": "deny"}'
echo "❌ BLOCKED: Dangerous git command detected" >&2
exit 2
fi
SCRIPT
)"
# Create hook that runs on session start
HOOK_NAME="inject-session-context"
TRIGGER="SessionStart"
~/.claude/scripts/register-hook.sh \
--name "$HOOK_NAME" \
--trigger "$TRIGGER" \
--script-content "$(cat <<'SCRIPT'
#!/bin/bash
set -euo pipefail
trap 'echo "ERROR in inject-session-context.sh at line $LINENO: Command failed: $BASH_COMMAND" >&2; exit 1' ERR
# Inject context at session start
echo "## Session Context"
echo "Working directory: $(pwd)"
echo "Git branch: $(git branch --show-current)"
echo "Planning state: $(cat .planning/STATE.md 2>/dev/null | head -5 || echo 'No planning context')"
SCRIPT
)"
set -euo pipefail1. ✅ Identify hook need (what to trigger on)
2. ✅ Invoke register-hook skill
3. ✅ Skill creates script with error handling
4. ✅ Skill registers in settings.json
5. ✅ Skill warns about restart requirement
6. ✅ User restarts Claude Code
7. ✅ Test hook triggers correctly
8. ✅ Commit hook and settings.json together
Script returns JSON:
{
"status": "success",
"message": "Hook registered successfully",
"hook_name": "log-bash-commands",
"hook_path": "~/.claude/hooks/log-bash-commands.sh",
"trigger_event": "PreToolUse",
"matcher": "Bash",
"executable": true,
"registered": true,
"restart_required": true,
"test_command": "Bash tool with any command",
"timestamp": "2025-11-11T12:34:56-05:00"
}
# Most common cause: Forgot to restart
# Fix: Restart Claude Code
# Verify hook registered:
cat ~/.claude/settings.json | jq '.hooks.PreToolUse'
# Verify hook executable:
test -x ~/.claude/hooks/my-hook.sh
echo $? # Should be 0
# Check hook error output (stderr)
# Look for trap error message with line number
# Test hook manually:
echo '{"tool_name": "Bash", "tool_input": {"command": "echo test"}}' | \
~/.claude/hooks/my-hook.sh
# Remember: Matcher is tool-level only
# ✅ CORRECT: "matcher": "Bash"
# ❌ WRONG: "matcher": "Bash && command:git"
# For command filtering, parse JSON inside hook:
JSON_INPUT=$(cat)
COMMAND=$(echo "$JSON_INPUT" | jq -r '.tool_input.command')
# Validate JSON syntax:
jq empty ~/.claude/settings.json
# If invalid, fix manually:
# 1. Open settings.json
# 2. Find syntax error (trailing comma, missing bracket, etc.)
# 3. Fix error
# 4. Validate: jq empty settings.json
# 5. Restart Claude Code
# Validate something before tool execution
PreToolUse + can-block = validation hook
# Log tool usage for audit
PostToolUse + no blocking = logging hook
# Add context at session start
SessionStart + echo statements = context injection
# React to user input
UserPromptSubmit + parse prompt = prompt hook
The register-hook script performs:
Validation Release
Script Creation Release
Registration Release
Verification Release
Documentation Release