Skip to main content
Generalbendrucker

claude-code:hook

Use this skill when you need to configure, create, or troubleshoot Claude Code hooks. This includes setting up PreToolUse hooks, PostToolUse hooks, UserPromptSubmit hooks, debugging hook failures, or any automation within Claude Code. Examples include "I want to run tests before every file edit", "My hook isn't firing", "1 out of 2 hooks ran", or "How do I create a hook that formats JSON output with jq?"

Stars
13
Source
bendrucker/claude
Updated
2026-05-31
Slug
bendrucker--claude--hook
View on GitHubRaw SKILL.md

// install — copy + paste into any project

mkdir -p .claude/skills && curl -fsSL https://raw.githubusercontent.com/bendrucker/claude/HEAD/plugins/claude-code/skills/hook/SKILL.md -o .claude/skills/hook.md

Drops the SKILL.md into .claude/skills/hook.md. Works with Claude Code, Cursor, and any agent that loads SKILL.md files from .claude/skills/.

Claude Code Hooks

Reference for creating and configuring Claude Code hooks. When uncertain about syntax or features, use the Task tool with subagent_type='claude-code-guide' to consult official documentation.

Hook Types

Type Trigger Use Cases
PreToolUse Before tool execution Validate inputs, block operations, modify parameters
PostToolUse After tool completes Check results, run linters, provide feedback
UserPromptSubmit When user sends message Pre-process input, add context
Stop Session ends Cleanup, save state
SubagentStop Subagent completes Process results
PreCompact Before context compaction Save important state
Notification System notification Log events

Configuration Files

  • ~/.claude/settings.json - User-level (global)
  • .claude/settings.json - Project-level
  • .claude/settings.local.json - Local (not committed)
  • Plugin hooks: plugins/<name>/hooks/hooks.json

Hook Structure

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "bun ./hooks/biome"
          }
        ]
      }
    ]
  }
}

Matcher Patterns:

  • Simple: "Write", "Edit"
  • Multiple: "Edit|Write|MultiEdit"
  • With args: "Bash(npm:*)", "Bash(osascript:*)|Bash(open:*)"
  • MCP tools: "mcp__linear__create_issue"
  • Plugin MCP tools: "mcp__plugin_<plugin>_<namespace>__<tool>"
  • Claude AI MCP tools: "mcp__claude_ai_<DisplayName>__<tool>"
  • All three patterns: "mcp__linear__create_issue|mcp__plugin_linear_linear__create_issue|mcp__claude_ai_Linear__save_issue"

Hook Input

Commands receive JSON on stdin:

{
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.ts",
    "content": "..."
  },
  "cwd": "/project/root",
  "session_id": "...",
  "transcript_path": "..."
}

Parse in shell:

input=$(cat)
file_path=$(echo "$input" | jq -r '.tool_input.file_path')

Or use @constellos/claude-code-kit/runners:

import { readStdinJson, writeStdoutJson } from "@constellos/claude-code-kit/runners";
const input = await readStdinJson<PreToolUseHookInput>();

Hook Output

PreToolUse - Control execution:

{"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "Use gh cli instead"}}
{"hookSpecificOutput": {"hookEventName": "PreToolUse", "updatedInput": {"state": "Todo"}}}

PostToolUse - Provide feedback:

{"hookSpecificOutput": {"hookEventName": "PostToolUse", "additionalContext": "Lint errors found..."}}

Exit with no output to allow without modification.

Script Storage

Store complex hooks in .claude/hooks/ or project hooks/ directory:

.claude/
├── settings.json
└── hooks/
    └── my-hook.ts

Reference with:

"command": "bun $CLAUDE_PROJECT_DIR/.claude/hooks/my-hook.ts"

Examples

See these repositories for hook implementations:

Debugging

For troubleshooting hook failures, see debugging.