Hook Developer
Complete Claude Code hooks reference - input/output schemas, registration, testing patterns
- Skill ID
- parcadei/continuous-claude-v3/hook-developer
- Publisher
- parcadei
- Repository
- continuous-claude-v3
- Installs
- 0
- Files
- 1
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
parcadei/continuous-claude-v3/hook-developerInstalls these files- SKILL.md
What this skill tells the agent
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:
{
"session_id": "string",
"transcript_path": "string",
"cwd": "string",
"permission_mode": "default|plan|acceptEdits|bypassPermissions",
"hook_event_name": "PreToolUse",
"tool_name": "string",
"tool_input": {
"file_path": "string",
"command": "string"
},
"tool_use_id": "string"
}Output (JSON):
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow|deny|ask",
"permissionDecisionReason": "string",
"updatedInput": {}
},
"continue": true,
"stopReason": "string",
"systemMessage": "string",
"suppressOutput": true
}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:
{
"session_id": "string",
"transcript_path": "string",
"cwd": "string",
"permission_mode": "string",
"hook_event_name": "PostToolUse",
"tool_name": "string",
"tool_input": {},
"tool_response": {
"filePath": "string",
"success": true,
"output": "string",
"exitCode": 0
},
"tool_use_id": "string"
}CRITICAL: The response field is tool_response, NOT tool_result.
Output (JSON):
{
"decision": "block",
"reason": "string",
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "string"
},
"continue": true,
"stopReason": "string",
"suppressOutput": true
}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:
{
"session_id": "string",
"transcript_path": "string",
"cwd": "string",
"permission_mode": "string",
"hook_event_name": "UserPromptSubmit",
"prompt": "string"
}Output (Plain text):
Any stdout text is added to context for Claude.Output (JSON):
{
"decision": "block",
"reason": "string",
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "string"
}
}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:
{
"session_id": "string",
"transcript_path": "string",
"cwd": "string",
"permission_mode": "string",
"hook_event_name": "PermissionRequest",
"tool_name": "string",
"tool_input": {}
}Output:
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow|deny",
"updatedInput": {},
"message": "string",
"interrupt": false
}
}
}SessionStart
Purpose: Initialize session, load context, set environment variables.
Input:
{
"session_id": "string",
"transcript_path": "string",
"cwd": "string",
"permission_mode": "string",
"hook_event_name": "SessionStart",
"source": "startup|resume|clear|compact"
}Environment variable: CLAUDE_ENV_FILE - write export VAR=value to persist env vars.
Output (Plain text or JSON):
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "string"
},
"suppressOutput": true
}Plain text stdout is added as context.
SessionEnd
Purpose: Cleanup, save state, log session.
Input:
{
"session_id": "string",
"transcript_path": "string",
"cwd": "string",
"permission_mode": "string",
"hook_event_name": "SessionEnd",
"reason": "clear|logout|prompt_input_exit|other"
}Output: Cannot affect session (already ending). Use for cleanup only.
Stop
Purpose: Control when Claude stops, force continuation.
Input:
{
"session_id": "string",
"transcript_path": "string",
"cwd": "string",
"permission_mode": "string",
"hook_event_name": "Stop",
"stop_hook_active": false
}CRITICAL: Check stop_hook_active: true to prevent infinite loops!
Output:
{
"decision": "block",
"reason": "string"
}Blocking: "decision": "block" forces Claude to continue with "reason" as prompt.
SubagentStart
Purpose: Run when a subagent (Task tool) is spawned.
Input:
{
"session_id": "string",
"transcript_path": "string",
"cwd": "string",
"permission_mode": "string",
"hook_event_name": "SubagentStart",
"agent_id": "string"
}Output: Context injection only (cannot block).
SubagentStop
Purpose: Control when subagents (Task tool) stop.
Input:
{
"session_id": "string",
"transcript_path": "string",
"cwd": "string",
"permission_mode": "string",
"hook_event_name": "SubagentStop",
"stop_hook_active": false
}Output: Same as Stop.
PreCompact
Purpose: Save state before context compaction.
Input:
{
"session_id": "string",
"transcript_path": "string",
"cwd": "string",
"permission_mode": "string",
"hook_event_name": "PreCompact",
"trigger": "manual|auto",
"custom_instructions": "string"
}Matchers: manual, auto
Output:
{
"continue": true,
"systemMessage": "string"
}Notification
Purpose: Custom notification handling.
Input:
{
"session_id": "string",
"transcript_path": "string",
"cwd": "string",
"permission_mode": "string",
"hook_event_name": "Notification",
"message": "string",
"notification_type": "permission_prompt|idle_prompt|auth_success|elicitation_dialog"
}Matchers: permission_prompt, idle_prompt, auth_success, elicitation_dialog, *
Output:
{
"continue": true,
"suppressOutput": true,
"systemMessage": "string"
}Registration in settings.json
Standard Structure
{
"hooks": {
"EventName": [
{
"matcher": "ToolPattern",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/my-hook.sh",
"timeout": 60
}
]
}
]
}
}Matcher Patterns
| Pattern | Matches | |
|---|---|---|
Bash | Exactly Bash tool | |
| `Edit\ | Write` | Edit OR Write |
Read.* | Regex: Read* | |
mcp__.*__write.* | MCP write tools |
More from parcadei
Use this skill in a project
Open any RiverX project, search the Skills panel for parcadei/continuous-claude-v3/hook-developer, and install it in one click.
