跳到正文
cccskills
免费在 GitHub 公开

hook-developer

Provides a reference for building Claude Code hooks, scripts or model checks triggered by events. Covers input and output formats, registration, testing, and debugging for tasks such as blocking tool calls, adding context, and checking tests before stopping.

中文简介正在准备中。当前显示英语简介。

原文查看原文说明

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

查看安装方法

适用场景

  • Create a hook that blocks edits to protected files
  • Format files automatically after edits
  • Add Git context when submitting a prompt
  • Check test results before the agent stops
  • Debug hook formats and registration

包含的文件(1)

  • SKILL.md14.5 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

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

HookFires WhenCan Block?Primary Use
PreToolUseBefore tool executesYESBlock/modify tool calls
PostToolUseAfter tool completesPartialReact to tool results
UserPromptSubmitUser sends promptYESValidate/inject context
PermissionRequestPermission dialog showsYESAuto-approve/deny
SessionStartSession beginsNOLoad context, set env vars
SessionEndSession endsNOCleanup/save state
StopAgent finishesYESForce continuation
SubagentStartSubagent spawnsNOPattern coordination
SubagentStopSubagent finishesYESForce continuation
PreCompactBefore compactionNOSave state
NotificationNotification sentNOCustom 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

PatternMatches
BashExactly Bash tool
Edit|WriteEdit 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

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [{ "type": "command", "command": "/path/to/hook.sh" }]
      }
    ]
  }
}

Hook Types

Command Hooks (type: "command")

Default type. Executes bash commands or scripts.

{
  "type": "command",
  "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/my-hook.sh",
  "timeout": 60
}

Prompt-Based Hooks (type: "prompt")

Uses LLM (Haiku) for context-aware decisions. Best for Stop/SubagentStop.

{
  "type": "prompt",
  "prompt": "Evaluate if Claude should stop. Context: $ARGUMENTS. Check if all tasks are complete.",
  "timeout": 30
}

Response schema:

{
  "decision": "approve" | "block",
  "reason": "Explanation",
  "continue": false,
  "stopReason": "Message to user",
  "systemMessage": "Warning"
}

MCP Tool Naming

MCP tools use pattern mcp__<server>__<tool>:

PatternMatches
mcp__memory__.*All memory server tools
mcp__.*__write.*All MCP write tools
mcp__github__.*All GitHub tools

Environment Variables

Available to All Hooks

VariableDescription
CLAUDE_PROJECT_DIRAbsolute path to project root
CLAUDE_CODE_REMOTE"true" if remote/web, empty if local CLI

SessionStart Only

VariableDescription
CLAUDE_ENV_FILEPath to write export VAR=value lines

Plugin Hooks Only

VariableDescription
CLAUDE_PLUGIN_ROOTAbsolute path to plugin directory

Exit Codes

Exit CodeBehaviorstdoutstderr
0SuccessJSON processedIgnored
2Blocking errorIGNOREDError message
OtherNon-blocking errorIgnoredVerbose mode

Exit Code 2 by Hook

HookEffect
PreToolUseBlocks tool, stderr to Claude
PostToolUsestderr to Claude (tool already ran)
UserPromptSubmitBlocks prompt, stderr to user only
StopBlocks stop, stderr to Claude

Shell Wrapper Pattern

#!/bin/bash
set -e
cd "$CLAUDE_PROJECT_DIR/.claude/hooks"
cat | npx tsx src/my-hook.ts

Or for bundled:

#!/bin/bash
set -e
cd "$HOME/.claude/hooks"
cat | node dist/my-hook.mjs

TypeScript Handler Pattern

import { readFileSync } from 'fs';

interface HookInput {
  session_id: string;
  hook_event_name: string;
  tool_name?: string;
  tool_input?: Record<string, unknown>;
  tool_response?: Record<string, unknown>;
  // ... other fields per hook type
}

function readStdin(): string {
  return readFileSync(0, 'utf-8');
}

async function main() {
  const input: HookInput = JSON.parse(readStdin());

  // Process input

  const output = {
    decision: 'block',  // or undefined to allow
    reason: 'Why blocking'
  };

  console.log(JSON.stringify(output));
}

main().catch(console.error);

Testing Hooks

Manual Test Commands

# PostToolUse (Write)
echo '{"tool_name":"Write","tool_input":{"file_path":"test.md"},"tool_response":{"success":true},"session_id":"test"}' | \
  .claude/hooks/my-hook.sh

# PreToolUse (Bash)
echo '{"tool_name":"Bash","tool_input":{"command":"ls"},"session_id":"test"}' | \
  .claude/hooks/my-hook.sh

# SessionStart
echo '{"hook_event_name":"SessionStart","source":"startup","session_id":"test"}' | \
  .claude/hooks/session-start.sh

# SessionEnd
echo '{"hook_event_name":"SessionEnd","reason":"clear","session_id":"test"}' | \
  .claude/hooks/session-end.sh

# UserPromptSubmit
echo '{"prompt":"test prompt","session_id":"test"}' | \
  .claude/hooks/prompt-submit.sh

Rebuild After TypeScript Edits

cd .claude/hooks
npx esbuild src/my-hook.ts \
  --bundle --platform=node --format=esm \
  --outfile=dist/my-hook.mjs

Common Patterns

Block Dangerous Files (PreToolUse)

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

data = json.load(sys.stdin)
path = data.get('tool_input', {}).get('file_path', '')

BLOCKED = ['.env', 'secrets.json', '.git/']
if any(b in path for b in BLOCKED):
    print(json.dumps({
        "hookSpecificOutput": {
            "hookEventName": "PreToolUse",
            "permissionDecision": "deny",
            "permissionDecisionReason": f"Blocked: {path} is protected"
        }
    }))
else:
    print('{}')

Auto-Format Files (PostToolUse)

#!/bin/bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

if [[ "$FILE" == *.ts ]] || [[ "$FILE" == *.tsx ]]; then
  npx prettier --write "$FILE" 2>/dev/null
fi

echo '{}'

Inject Git Context (UserPromptSubmit)

#!/bin/bash
echo "Git status:"
git status --short 2>/dev/null || echo "(not a git repo)"
echo ""
echo "Recent commits:"
git log --oneline -5 2>/dev/null || echo "(no commits)"

Force Test Verification (Stop)

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

data = json.load(sys.stdin)

# Prevent infinite loops
if data.get('stop_hook_active'):
    print('{}')
    sys.exit(0)

# Check if tests pass
result = subprocess.run(['npm', 'test'], capture_output=True)
if result.returncode != 0:
    print(json.dumps({
        "decision": "block",
        "reason": "Tests are failing. Please fix before stopping."
    }))
else:
    print('{}')

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

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

Coordinate background agents through saved files, keeping lengthy work transcripts out of the main conversation. It defines how to pass results between agents, monitor progress, and verify completed work with tests.

中文简介正在准备中。当前显示英语简介。

  • Keeping long agent transcripts out of the main conversation
  • Passing research and plans between agents through files
  • Checking for stalled background agents
parcadei/Continuous-Claude-v339462026年1月27日 更新

Delegate implementation, file reading, and testing to separate agents, then bring concise summaries back to the main conversation. The rules explain when delegation helps and when a small edit is better handled directly.

中文简介正在准备中。当前显示英语简介。

  • Implementing a feature across multiple files
  • Completing a specific phase of an implementation plan
  • Delegating feature development and testing
parcadei/Continuous-Claude-v339462026年1月27日 更新

Organize implementation work across research, planning, validation, implementation, and review agents. Each stage passes files to the next, while implementation starts with failing tests and the main conversation coordinates the workflow.

中文简介正在准备中。当前显示英语简介。

  • Dividing implementation work among specialized agents
  • Checking a plan against research before implementation
  • Writing failing tests before implementing changes
parcadei/Continuous-Claude-v339462026年1月27日 更新

Connect Agentica SDK agents to Claude Code CLI through a proxy, an intermediary server. Use setup and debugging guidance to address file permissions, streamed responses, result formatting, and agents reporting success without performing the requested operations.

中文简介正在准备中。当前显示英语简介。

  • Connecting Agentica agents to Claude Code tools
  • Investigating file write and edit permission errors
  • Debugging streaming and REPL response formats
parcadei/Continuous-Claude-v339462026年1月27日 更新

Consult Agentica APIs when building workflows where multiple AI agents cooperate. This reference covers eleven coordination patterns, agent tracking, shared state, handoffs, and ways to combine results, with pointers to detailed API specifications.

中文简介正在准备中。当前显示英语简介。

  • Choose a coordination pattern for multiple agents
  • Check pattern constructors and methods
  • Implement custom coordination patterns
parcadei/Continuous-Claude-v339462026年1月27日 更新

Write clearer instructions for Agentica and REPL agents by specifying roles, file operations, and output formats. Includes templates for dividing research, coordinating specialists, reviewing solutions, and passing results between agents through files.

中文简介正在准备中。当前显示英语简介。

  • Clarifying instructions for reading and editing files
  • Dividing research among multiple agents
  • Passing findings and plans between agents
parcadei/Continuous-Claude-v339462026年1月27日 更新

查看 parcadei 的全部技能

报告此技能的问题