cc-hooks

star 392

Configure Claude Code hooks for PreToolUse, PostToolUse, Stop, Notification. Use when blocking commands, auto-formatting, custom permissions, or writing hooks.

boshu2 By boshu2 schedule Updated 6/7/2026

name: cc-hooks user-invocable: false skill_api_version: 1 hexagonal_role: supporting metadata: tier: execution description: >- Configure Claude Code hooks for PreToolUse, PostToolUse, Stop, Notification. Use when blocking commands, auto-formatting, custom permissions, or writing hooks. practices:

  • pragmatic-programmer

Claude Code Hooks

Shell commands that fire at specific points in Claude Code's lifecycle.

Quick Start

Add to ~/.claude/settings.json (user) or .claude/settings.json (project):

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "my-validator.sh" }
        ]
      }
    ]
  }
}

Hook Events

Event When Blocks? Common Use
PreToolUse Before tool runs Yes Block/modify commands
PostToolUse After tool succeeds Feedback Auto-format, lint
PermissionRequest Permission dialog Yes Auto-approve/deny
UserPromptSubmit Prompt submitted Yes Add context, validate
Stop Claude finishes Yes Force continue
SessionStart Session begins No Load context, set env
Notification Notifications No Desktop alerts

Full schemas: HOOK-EVENTS.md

Matchers

"Bash"              → exact match
"Edit|Write"        → regex OR
"mcp__.*__write"    → MCP tools
"*" or ""           → all tools

Tools: Bash, Read, Write, Edit, Glob, Grep, Task, WebFetch, WebSearch

Exit Codes

Code Effect
0 Success - JSON parsed from stdout
2 Block - stderr fed to Claude
Other Non-blocking error

Blocking a Tool

Simple (exit 2):

echo "Blocked: reason" >&2 && exit 2

JSON (exit 0):

{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"Blocked"}}

Decisions: "allow" (auto-approve), "deny" (block), "ask" (show dialog)

Modifying Input

{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow",
  "updatedInput":{"command":"modified-command"}}}

Real-World: DCG + RCH

{"hooks":{"PreToolUse":[{"matcher":"Bash","hooks":[
  {"type":"command","command":"dcg"},
  {"type":"command","command":"rch"}
]}]}}
  • DCG: Blocks git reset --hard, rm -rf, git push --force
  • RCH: Routes builds to remote workers

Details: DCG-RCH.md

Writing Your Own Hook

Minimal Python:

#!/usr/bin/env python3
import json, sys

data = json.load(sys.stdin)
cmd = data.get('tool_input', {}).get('command', '')

if 'dangerous' in cmd:
    print("Blocked: dangerous", file=sys.stderr)
    sys.exit(2)

sys.exit(0)  # Allow

Hook input (stdin):

{"tool_name":"Bash","tool_input":{"command":"npm test"},"session_id":"...","cwd":"..."}

Environment Variables

Variable Scope Purpose
CLAUDE_PROJECT_DIR All Project root
CLAUDE_ENV_FILE SessionStart/Setup Persist env vars

Stop Hook (Force Continue)

{"decision":"block","reason":"Tests failing. Fix before stopping."}

Critical: Check stop_hook_active to prevent infinite loops.

Anti-Patterns

Don't Do
Old object format Array format with matcher
Unquoted $VAR "$VAR"
Exit 2 with JSON Exit 2 uses stderr only
Skip stop_hook_active check Always check in Stop hooks

Debugging

claude --debug  # Hook execution details
/hooks          # View/edit in REPL

References

Install via CLI
npx skills add https://github.com/boshu2/agentops --skill cc-hooks
Repository Details
star Stars 392
call_split Forks 40
navigation Branch main
article Path SKILL.md
More from Creator