hook-developer

Complete Claude Code hooks reference - input/output schemas, registration, testing patterns

By parcadei · 499 installs

npx skills add parcadei/continuous-claude-v3 --skill hook-developer

Source repository · Upstream listing

Hook Developer Complete reference for developing Claude Code hooks. Use this to write hooks with correct input/output schemas. When to Use Creating a new hook Debugging hook input/output format Understanding what fields are available Setting up hook registration in settings.json Learning what hooks can block vs inject context Quick Reference Hook Fires When Can Block? Primary Use PreToolUse Before tool executes YES Block/modify tool calls PostToolUse After tool completes Partial React to tool results UserPromptSubmit User sends prompt YES Validate/inject context PermissionRequest Permission dialog shows YES Auto approve/deny SessionStart Session begins NO Load context, set env vars SessionEnd Session ends NO Cleanup/save state Stop Agent finishes YES Force continuation SubagentStart Subagent spawns NO Pattern coordination SubagentStop Subagent finishes YES Force continuation PreCompact Before compaction NO Save state Notification Notification sent NO Custom alerts Hook type options: type: "command" (bash) or type: "prompt" (LLM evaluation) Hook Input/Output Schemas PreToolUse Purpose: Block or modify tool execution before it happens. Input: Output (JSON): Exit code 2: Blocks tool, stderr shown to Claude. Common matchers: Bash , Edit Write , Read , Task , mcp . PostToolUse Purpose: React to tool execution results, provide feedback to Claude. Input: CRITICAL: The response field is tool response , NOT tool result . Output (JSON): Blocking: "decision": "block" with "reason" prompts Claude to address the issue. Common matchers: Edit Write , Bash UserPromptSubmit Purpose: Validate user prompts, inject context before Claude processes. Input: Output (Plain text): Output (JSON): Blocking: "decision": "block" erases prompt, shows "reason" to user only (not Claude). Exit code 2: Blocks prompt, shows stderr to user only. PermissionRequest Purpose: Automate permission dialog decisions. Input: Output: SessionStart Purpose: Initialize session, load context, set environment variables. Input: Environment variable: CLAUDE ENV FILE write export VAR=value to persist env vars. Output (Plain text or JSON): Plain text stdout is added as context. SessionEnd Purpose: Cleanup, save state, log session. Input: Output: Cannot affect session (already ending). Use for cleanup only. Stop Purpose: Control when Claude stops, force continuation. Input: CRITICAL: Check stop hook active: true to prevent infinite loops! Output: Blocking: "decision": "block" forces Claude to continue with "reason" as prompt. SubagentStart Purpose: Run when a subagent (Task tool) is spawned. Input: Output: Context injection only (cannot block). SubagentStop Purpose: Control when subagents (Task tool) stop. Input: Output: Same as Stop. PreCompact Purpose: Save state before context compaction. Input: Matchers: manual , auto Output: Notification Purpose: Custom notification handling. Input: Matchers: permission prompt , idle prompt , auth success , elicitation dialog , Output: Registration in settings.json Standard Structure Matcher Patterns Pattern Matches Bash Exactly Bash tool Edit\ Write Edit OR Write Read. Regex: Read mcp . write. MCP write tools All tools Case sensitive: Bash ≠ bash Events Requiring Matchers PreToolUse YES (required) PostToolUse YES (required) PermissionRequest YES (required) Notification YES (optional) SessionStart YES ( startup resume clear compact ) PreCompact YES ( manual auto ) Events Without Matchers Hook Types Command Hooks (type: "command") Default type. Executes bash commands or scripts. Prompt Based Hooks (type: "prompt") Uses LLM (Haiku) for context aware decisions. Best for Stop/SubagentStop. Response schema: MCP Tool Naming MCP tools use pattern mcp <server <tool : Pattern Matches mcp memory . All memory server tools mcp . write. All MCP write tools mcp github . All GitHub tools Environment Variables Available to All Hooks Variable Description CLAUDE PROJECT DIR Absolute path to project root CLAUDE CODE REMOTE "true" if remote/web, empty if local CLI SessionStart Only Variable Description CLAUDE ENV FILE Path to write export VAR=value lines Plugin Hooks Only Variable Description CLAUDE PLUGIN ROOT Absolute path to plugin directory Exit Codes Exit Code Behavior stdout stderr 0 Success JSON processed Ignored 2 Blocking error IGNORED Error message Other Non blocking error Ignored Verbose mode Exit Code 2 by Hook Hook Effect PreToolUse Blocks tool, stderr to Claude PostToolUse stderr to Claude (tool already ran) UserPromptSubmit Blocks prompt, stderr to user only Stop Blocks stop, stderr to Claude Shell Wrapper Pattern Or for bundled: TypeScript Handler Pattern Testing Hooks Manual Test Commands Rebuild After TypeScript Edits Common Patterns Block Dangerous Files (PreToolUse) Auto Format Files (PostToolUse) Inject Git Context (UserPromptSubmit) Force Test Verification (Stop) Debugging Checklist [ ] Hook registered in settings.json? [ ] Shell script has +x permission? [ ] Bundle rebuilt after TS changes? [ ] Using tool response not tool result ? [ ] Output is valid JSON (or plain text)? [ ] Checking stop hook active in Stop hooks? [ ] Using $CLAUDE PROJECT DIR for paths? Key Learnings from Past Sessions 1. Field names matter tool response not tool result 2. Output format decision: "block" + reason for blocking 3. Exit code 2 stderr goes to Claude/user, stdout IGNORED 4. Rebuild bundles TypeScript source edits don't auto apply 5. Test manually echo '{}' ./hook.sh before relying on it 6. Check outputs first ls .claude/cache/ before editing code 7. Detached spawn hides errors add logging to debug See Also /debug hooks Systematic debugging workflow .claude/rules/hooks.md Hook development rules