creating-claude-hooks

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Creating Claude Code Hooks

创建Claude Code Hooks

Use this skill when creating, improving, or publishing Claude Code hooks. Provides essential guidance on hook format, event handling, I/O conventions, and package structure.
本技能适用于创建、改进或发布Claude Code hooks时使用,提供关于hook格式、事件处理、I/O约定和包结构的核心指导。

When to Use This Skill

何时使用本技能

Activate this skill when:
  • User asks to create a new Claude Code hook
  • User wants to publish a hook as a PRPM package
  • User needs to understand hook format or events
  • User is troubleshooting hook execution
  • User asks about hook vs skill vs command differences
在以下场景激活本技能:
  • 用户请求创建新的Claude Code hook
  • 用户希望将hook发布为PRPM包
  • 用户需要了解hook格式或事件
  • 用户正在排查hook执行问题
  • 用户询问hook、skill和command之间的区别

Quick Reference

快速参考

Hook File Format

Hook文件格式

AspectRequirement
Location
.claude/hooks/<event-name>
FormatExecutable file (shell, TypeScript, Python, etc.)
PermissionsMust be executable (
chmod +x
)
ShebangRequired (
#!/bin/bash
or
#!/usr/bin/env node
)
InputJSON via stdin
OutputText via stdout (shown to user)
Exit Codes
0
= success,
2
= block, other = error
方面要求
位置
.claude/hooks/<event-name>
格式可执行文件(Shell、TypeScript、Python等)
权限必须具备可执行权限(
chmod +x
Shebang必填(
#!/bin/bash
#!/usr/bin/env node
输入通过stdin传入JSON
输出通过stdout输出文本(展示给用户)
退出码
0
= 成功,
2
= 阻止操作, 其他值 = 错误

Available Events

可用事件

EventWhen It FiresCommon Use Cases
session-start
New session beginsEnvironment setup, logging, checks
user-prompt-submit
Before user input processesValidation, enhancement, filtering
tool-call
Before tool executionPermission checks, logging, modification
assistant-response
After assistant respondsFormatting, logging, cleanup
事件触发时机常见用例
session-start
新会话开始时环境设置、日志记录、检查
user-prompt-submit
用户输入处理前验证、增强、过滤
tool-call
工具执行前权限检查、日志记录、修改
assistant-response
助手响应后格式化、日志记录、清理

Hook Format Requirements

Hook格式要求

File Location

文件位置

Project hooks:
.claude/hooks/session-start
.claude/hooks/user-prompt-submit
User-global hooks:
~/.claude/hooks/session-start
~/.claude/hooks/tool-call
项目级hooks:
.claude/hooks/session-start
.claude/hooks/user-prompt-submit
用户全局hooks:
~/.claude/hooks/session-start
~/.claude/hooks/tool-call

Executable Requirements

可执行要求

Every hook MUST:
  1. Have a shebang line:
bash
#!/bin/bash
每个hook必须满足:
  1. 包含Shebang行:
bash
#!/bin/bash

or

#!/usr/bin/env node
#!/usr/bin/env node

or

#!/usr/bin/env python3

2. **Be executable:**
```bash
chmod +x .claude/hooks/session-start
  1. Handle JSON input from stdin:
bash
#!/bin/bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty')
  1. Exit with appropriate code:
bash
exit 0  # Success
exit 2  # Block operation
exit 1  # Error (logs but continues)
#!/usr/bin/env python3

2. **具备可执行权限:**
```bash
chmod +x .claude/hooks/session-start
  1. 处理来自stdin的JSON输入:
bash
#!/bin/bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty')
  1. 返回合适的退出码:
bash
exit 0  # 成功
exit 2  # 阻止操作
exit 1  # 错误

Input/Output Format

输入/输出格式

JSON Input Structure

JSON输入结构

Hooks receive JSON via stdin with event-specific data:
json
{
  "event": "tool-call",
  "timestamp": "2025-01-15T10:30:00Z",
  "session_id": "abc123",
  "current_dir": "/path/to/project",
  "input": {
    "file_path": "/path/to/file.ts",
    "command": "npm test",
    "old_string": "...",
    "new_string": "..."
  }
}
Hooks通过stdin接收包含事件特定数据的JSON:
json
{
  "event": "tool-call",
  "timestamp": "2025-01-15T10:30:00Z",
  "session_id": "abc123",
  "current_dir": "/path/to/project",
  "input": {
    "file_path": "/path/to/file.ts",
    "command": "npm test",
    "old_string": "...",
    "new_string": "..."
  }
}

Stdout Output

Stdout输出

  • Normal output shows in transcript
  • Empty output runs silently
  • Use stderr (
    >&2
    ) for errors
  • 正常输出会显示在对话记录中
  • 空输出会静默运行
  • 使用stderr (
    >&2
    ) 输出错误信息

Exit Codes

退出码

CodeMeaningBehavior
0
SuccessContinue normally
2
BlockStop operation, show error
1
or other
ErrorLog error, continue
代码含义行为
0
成功正常继续
2
阻止停止操作,显示错误
1
或其他值
错误记录错误,继续执行

Schema Validation

Schema验证

Hooks should validate against the JSON schema:
Required frontmatter fields:
  • name
    - Hook identifier (lowercase, hyphens only)
  • description
    - What the hook does
  • event
    - Event type (optional, inferred from filename)
  • language
    - bash, typescript, javascript, python, binary (optional)
  • hookType: "hook"
    - For round-trip conversion
Hooks应遵循JSON schema验证:
必填前置字段:
  • name
    - Hook标识符(小写,仅用连字符)
  • description
    - Hook功能说明
  • event
    - 事件类型(可选,从文件名推断)
  • language
    - bash、typescript、javascript、python、binary(可选)
  • hookType: "hook"
    - 用于往返转换

Common Mistakes

常见错误

MistakeProblemSolution
Not quoting variablesBreaks on spacesAlways use
"$VAR"
Missing shebangWon't executeAdd
#!/bin/bash
Not executablePermission deniedRun
chmod +x hook-file
Logging to stdoutClutters transcriptUse stderr:
echo "log" >&2
Wrong exit codeDoesn't block when neededUse
exit 2
to block
No input validationSecurity riskAlways validate JSON fields
Slow operationsBlocks ClaudeRun in background or use PostToolUse
Absolute paths missingCan't find scriptsUse
$CLAUDE_PLUGIN_ROOT
错误问题解决方案
变量未加引号遇到空格时出错始终使用
"$VAR"
缺少Shebang无法执行添加
#!/bin/bash
无执行权限权限被拒绝运行
chmod +x hook-file
日志输出到stdout混乱对话记录使用stderr:
echo "log" >&2
错误的退出码需要阻止时无法生效使用
exit 2
来阻止操作
无输入验证安全风险始终验证JSON字段
操作缓慢阻塞Claude后台运行或使用PostToolUse
缺少绝对路径无法找到脚本使用
$CLAUDE_PLUGIN_ROOT

Basic Hook Examples

基础Hook示例

Shell Script Hook

Shell脚本Hook

bash
#!/bin/bash
bash
#!/bin/bash

.claude/hooks/session-start

.claude/hooks/session-start

Log session start

记录会话开始

echo "Session started at $(date)" >> ~/.claude/session.log
echo "Session started at $(date)" >> ~/.claude/session.log

Check environment

检查环境

if ! command -v node &> /dev/null; then echo "Warning: Node.js not installed" >&2 fi
if ! command -v node &> /dev/null; then echo "Warning: Node.js not installed" >&2 fi

Output to user

向用户输出

echo "Development environment ready" exit 0
undefined
echo "Development environment ready" exit 0
undefined

TypeScript Hook

TypeScript Hook

typescript
#!/usr/bin/env node
// .claude/hooks/user-prompt-submit

import { readFileSync } from 'fs';

// Read JSON from stdin
const input = readFileSync(0, 'utf-8');
const data = JSON.parse(input);

// Validate prompt
if (data.prompt.includes('API_KEY')) {
  console.error('Warning: Prompt may contain secrets');
  process.exit(2); // Block
}

console.log('Prompt validated');
process.exit(0);
typescript
#!/usr/bin/env node
// .claude/hooks/user-prompt-submit

import { readFileSync } from 'fs';

// 从stdin读取JSON
const input = readFileSync(0, 'utf-8');
const data = JSON.parse(input);

// 验证提示词
if (data.prompt.includes('API_KEY')) {
  console.error('Warning: Prompt may contain secrets');
  process.exit(2); // 阻止操作
}

console.log('Prompt validated');
process.exit(0);

Best Practices

最佳实践

1. Keep Hooks Fast

1. 保持Hook快速

Target < 100ms for PreToolUse hooks:
  • Cache results where possible
  • Run heavy operations in background
  • Use specific matchers, not wildcards
PreToolUse hooks目标耗时<100ms:
  • 尽可能缓存结果
  • 后台运行重操作
  • 使用特定匹配器,而非通配符

2. Handle Errors Gracefully

2. 优雅处理错误

bash
undefined
bash
undefined

Check dependencies exist

检查依赖是否存在

if ! command -v jq &> /dev/null; then echo "jq not installed, skipping" >&2 exit 0 fi
if ! command -v jq &> /dev/null; then echo "jq not installed, skipping" >&2 exit 0 fi

Validate input

验证输入

FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty') if [[ -z "$FILE" ]]; then echo "No file path provided" >&2 exit 1 fi
undefined
FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty') if [[ -z "$FILE" ]]; then echo "No file path provided" >&2 exit 1 fi
undefined

3. Use Shebangs

3. 使用Shebang

Always start with shebang:
bash
#!/bin/bash
#!/usr/bin/env node
#!/usr/bin/env python3
始终以Shebang开头:
bash
#!/bin/bash
#!/usr/bin/env node
#!/usr/bin/env python3

4. Secure Sensitive Files

4. 保护敏感文件

bash
BLOCKED=(".env" ".env.*" "*.pem" "*.key")
for pattern in "${BLOCKED[@]}"; do
  case "$FILE" in
    $pattern)
      echo "Blocked: $FILE is sensitive" >&2
      exit 2
      ;;
  esac
done
bash
BLOCKED=(".env" ".env.*" "*.pem" "*.key")
for pattern in "${BLOCKED[@]}"; do
  case "$FILE" in
    $pattern)
      echo "Blocked: $FILE is sensitive" >&2
      exit 2
      ;;
  esac
done

5. Quote All Variables

5. 所有变量加引号

bash
undefined
bash
undefined

WRONG - breaks on spaces

错误 - 遇到空格时失效

prettier --write $FILE
prettier --write $FILE

RIGHT - handles spaces

正确 - 处理空格

prettier --write "$FILE"
undefined
prettier --write "$FILE"
undefined

6. Log for Debugging

6. 日志用于调试

bash
LOG_FILE=~/.claude-hooks/debug.log
bash
LOG_FILE=~/.claude-hooks/debug.log

Log to file

记录到文件

echo "[$(date)] Processing $FILE" >> "$LOG_FILE"
echo "[$(date)] Processing $FILE" >> "$LOG_FILE"

Log to stderr (shows in transcript)

记录到stderr(显示在对话记录中)

echo "Hook running..." >&2
undefined
echo "Hook running..." >&2
undefined

Publishing as PRPM Package

发布为PRPM包

Package Structure

包结构

my-hook/
├── prpm.json          # Package manifest
├── HOOK.md            # Hook documentation
└── hook-script.sh     # Hook executable
my-hook/
├── prpm.json          # 包清单
├── HOOK.md            # Hook文档
└── hook-script.sh     # Hook可执行文件

prpm.json

prpm.json

json
{
  "name": "@username/hook-name",
  "version": "1.0.0",
  "description": "Brief description shown in search",
  "author": "Your Name",
  "format": "claude",
  "subtype": "hook",
  "tags": ["automation", "security", "formatting"],
  "main": "HOOK.md"
}
json
{
  "name": "@username/hook-name",
  "version": "1.0.0",
  "description": "Brief description shown in search",
  "author": "Your Name",
  "format": "claude",
  "subtype": "hook",
  "tags": ["automation", "security", "formatting"],
  "main": "HOOK.md"
}

HOOK.md Format

HOOK.md格式

markdown
---
name: session-logger
description: Logs session start/end times for tracking
event: SessionStart
language: bash
hookType: hook
---
markdown
---
name: session-logger
description: Logs session start/end times for tracking
event: SessionStart
language: bash
hookType: hook
---

Session Logger Hook

Session Logger Hook

Logs Claude Code session activity for tracking and debugging.
Logs Claude Code session activity for tracking and debugging.

Installation

Installation

This hook will be installed to
.claude/hooks/session-start
.
This hook will be installed to
.claude/hooks/session-start
.

Behavior

Behavior

  • Logs session start time to
    ~/.claude/session.log
  • Displays environment status
  • Runs silent dependency checks
  • Logs session start time to
    ~/.claude/session.log
  • Displays environment status
  • Runs silent dependency checks

Requirements

Requirements

  • bash 4.0+
  • write access to
    ~/.claude/
  • bash 4.0+
  • write access to
    ~/.claude/

Source Code

Source Code

```bash #!/bin/bash echo "Session started at $(date)" >> ~/.claude/session.log echo "Environment ready" exit 0 ```
undefined
bash
#!/bin/bash
echo "Session started at $(date)" >> ~/.claude/session.log
echo "Environment ready"
exit 0
undefined

Publishing Process

发布流程

bash
undefined
bash
undefined

Test locally first

先本地测试

prpm test
prpm test

Publish to registry

发布到注册表

prpm publish
prpm publish

Version bumps

版本升级

prpm publish patch # 1.0.0 -> 1.0.1 prpm publish minor # 1.0.0 -> 1.1.0 prpm publish major # 1.0.0 -> 2.0.0
undefined
prpm publish patch # 1.0.0 -> 1.0.1 prpm publish minor # 1.0.0 -> 1.1.0 prpm publish major # 1.0.0 -> 2.0.0
undefined

Security Requirements

安全要求

Input Validation

输入验证

bash
undefined
bash
undefined

Parse JSON safely

安全解析JSON

INPUT=$(cat) if ! FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty' 2>&1); then echo "JSON parse failed" >&2 exit 1 fi
INPUT=$(cat) if ! FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty' 2>&1); then echo "JSON parse failed" >&2 exit 1 fi

Validate field exists

验证字段存在

[[ -n "$FILE" ]] || exit 1
undefined
[[ -n "$FILE" ]] || exit 1
undefined

Path Sanitization

路径清理

bash
undefined
bash
undefined

Prevent directory traversal

防止目录遍历

if [[ "$FILE" == ".." ]]; then echo "Path traversal detected" >&2 exit 2 fi
if [[ "$FILE" == ".." ]]; then echo "Path traversal detected" >&2 exit 2 fi

Keep in project directory

限制在项目目录内

if [[ "$FILE" != "$CLAUDE_PROJECT_DIR"* ]]; then echo "File outside project" >&2 exit 2 fi
undefined
if [[ "$FILE" != "$CLAUDE_PROJECT_DIR"* ]]; then echo "File outside project" >&2 exit 2 fi
undefined

User Confirmation

用户确认

Claude Code automatically:
  • Requires confirmation before installing hooks
  • Shows hook source code to user
  • Warns about hook execution
  • Displays hook output in transcript
Claude Code自动执行以下操作:
  • 安装hooks前需要用户确认
  • 向用户展示hook源代码
  • 警告hook执行风险
  • 在对话记录中显示hook输出

Hooks vs Skills vs Commands

Hooks vs Skills vs Commands

FeatureHooksSkillsCommands
FormatExecutable codeMarkdownMarkdown
TriggerAutomatic (events)Automatic (context)Manual (
/command
)
LanguageAny executableN/AN/A
Use CaseAutomation, validationReference, patternsQuick tasks
SecurityRequires confirmationNo special permissionsInherits from session
Examples:
  • Hook: Auto-format files on save
  • Skill: Reference guide for testing patterns
  • Command:
    /review-pr
    quick code review
特性HooksSkillsCommands
格式可执行代码MarkdownMarkdown
触发方式自动(事件)自动(上下文)手动(
/command
语言任意可执行语言N/AN/A
用例自动化、验证参考、模式快速任务
安全需要确认无特殊权限继承会话权限
示例:
  • Hook: 保存时自动格式化文件
  • Skill: 测试模式参考指南
  • Command:
    /review-pr
    快速代码审查

Related Resources

相关资源

  • claude-hook-writer skill - Detailed hook development guidance
  • typescript-hook-writer skill - TypeScript-specific hook development
  • Claude Code Docs
  • Schema
  • claude-hook-writer skill - 详细的hook开发指南
  • typescript-hook-writer skill - TypeScript专属hook开发
  • Claude Code Docs
  • Schema

Checklist for New Hooks

新Hook检查清单

Before publishing:
  • Shebang line included
  • File is executable (
    chmod +x
    )
  • Validates all stdin input
  • Quotes all variables
  • Handles missing dependencies gracefully
  • Uses appropriate exit codes
  • Logs errors to stderr or file
  • Tests with edge cases (spaces, Unicode, missing fields)
  • Documents dependencies in HOOK.md
  • Includes installation instructions
  • Source code included in documentation
  • Clear description and tags in prpm.json
  • Version number is semantic
发布前确认:
  • 包含Shebang行
  • 文件具备可执行权限(
    chmod +x
  • 验证所有stdin输入
  • 所有变量加引号
  • 优雅处理缺失依赖
  • 使用合适的退出码
  • 错误日志输出到stderr或文件
  • 测试边缘情况(空格、Unicode、缺失字段)
  • 在HOOK.md中记录依赖
  • 包含安装说明
  • 文档中包含源代码
  • prpm.json中有清晰的描述和标签
  • 版本号符合语义化规范