원클릭으로
register-hook
Create and register hook scripts with proper error handling and settings
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Create and register hook scripts with proper error handling and settings
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| 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
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