creating-claude-hooks
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCreating 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文件格式
| Aspect | Requirement |
|---|---|
| Location | |
| Format | Executable file (shell, TypeScript, Python, etc.) |
| Permissions | Must be executable ( |
| Shebang | Required ( |
| Input | JSON via stdin |
| Output | Text via stdout (shown to user) |
| Exit Codes | |
| 方面 | 要求 |
|---|---|
| 位置 | |
| 格式 | 可执行文件(Shell、TypeScript、Python等) |
| 权限 | 必须具备可执行权限( |
| Shebang | 必填( |
| 输入 | 通过stdin传入JSON |
| 输出 | 通过stdout输出文本(展示给用户) |
| 退出码 | |
Available Events
可用事件
| Event | When It Fires | Common Use Cases |
|---|---|---|
| New session begins | Environment setup, logging, checks |
| Before user input processes | Validation, enhancement, filtering |
| Before tool execution | Permission checks, logging, modification |
| After assistant responds | Formatting, logging, cleanup |
| 事件 | 触发时机 | 常见用例 |
|---|---|---|
| 新会话开始时 | 环境设置、日志记录、检查 |
| 用户输入处理前 | 验证、增强、过滤 |
| 工具执行前 | 权限检查、日志记录、修改 |
| 助手响应后 | 格式化、日志记录、清理 |
Hook Format Requirements
Hook格式要求
File Location
文件位置
Project hooks:
.claude/hooks/session-start
.claude/hooks/user-prompt-submitUser-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-callExecutable Requirements
可执行要求
Every hook MUST:
- Have a shebang line:
bash
#!/bin/bash每个hook必须满足:
- 包含Shebang行:
bash
#!/bin/bashor
或
#!/usr/bin/env node
#!/usr/bin/env node
or
或
#!/usr/bin/env python3
2. **Be executable:**
```bash
chmod +x .claude/hooks/session-start- Handle JSON input from stdin:
bash
#!/bin/bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty')- 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- 处理来自stdin的JSON输入:
bash
#!/bin/bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty')- 返回合适的退出码:
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 () for errors
>&2
- 正常输出会显示在对话记录中
- 空输出会静默运行
- 使用stderr () 输出错误信息
>&2
Exit Codes
退出码
| Code | Meaning | Behavior |
|---|---|---|
| Success | Continue normally |
| Block | Stop operation, show error |
| Error | Log error, continue |
| 代码 | 含义 | 行为 |
|---|---|---|
| 成功 | 正常继续 |
| 阻止 | 停止操作,显示错误 |
| 错误 | 记录错误,继续执行 |
Schema Validation
Schema验证
Hooks should validate against the JSON schema:
Schema URL: https://github.com/pr-pm/prpm/blob/main/packages/converters/schemas/claude-hook.schema.json
Required frontmatter fields:
- - Hook identifier (lowercase, hyphens only)
name - - What the hook does
description - - Event type (optional, inferred from filename)
event - - bash, typescript, javascript, python, binary (optional)
language - - For round-trip conversion
hookType: "hook"
Hooks应遵循JSON schema验证:
Schema地址: https://github.com/pr-pm/prpm/blob/main/packages/converters/schemas/claude-hook.schema.json
必填前置字段:
- - Hook标识符(小写,仅用连字符)
name - - Hook功能说明
description - - 事件类型(可选,从文件名推断)
event - - bash、typescript、javascript、python、binary(可选)
language - - 用于往返转换
hookType: "hook"
Common Mistakes
常见错误
| Mistake | Problem | Solution |
|---|---|---|
| Not quoting variables | Breaks on spaces | Always use |
| Missing shebang | Won't execute | Add |
| Not executable | Permission denied | Run |
| Logging to stdout | Clutters transcript | Use stderr: |
| Wrong exit code | Doesn't block when needed | Use |
| No input validation | Security risk | Always validate JSON fields |
| Slow operations | Blocks Claude | Run in background or use PostToolUse |
| Absolute paths missing | Can't find scripts | Use |
| 错误 | 问题 | 解决方案 |
|---|---|---|
| 变量未加引号 | 遇到空格时出错 | 始终使用 |
| 缺少Shebang | 无法执行 | 添加 |
| 无执行权限 | 权限被拒绝 | 运行 |
| 日志输出到stdout | 混乱对话记录 | 使用stderr: |
| 错误的退出码 | 需要阻止时无法生效 | 使用 |
| 无输入验证 | 安全风险 | 始终验证JSON字段 |
| 操作缓慢 | 阻塞Claude | 后台运行或使用PostToolUse |
| 缺少绝对路径 | 无法找到脚本 | 使用 |
Basic Hook Examples
基础Hook示例
Shell Script Hook
Shell脚本Hook
bash
#!/bin/bashbash
#!/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
undefinedecho "Development environment ready"
exit 0
undefinedTypeScript 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
undefinedbash
undefinedCheck 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
undefinedFILE=$(echo "$INPUT" | jq -r '.input.file_path // empty')
if [[ -z "$FILE" ]]; then
echo "No file path provided" >&2
exit 1
fi
undefined3. 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 python34. 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
donebash
BLOCKED=(".env" ".env.*" "*.pem" "*.key")
for pattern in "${BLOCKED[@]}"; do
case "$FILE" in
$pattern)
echo "Blocked: $FILE is sensitive" >&2
exit 2
;;
esac
done5. Quote All Variables
5. 所有变量加引号
bash
undefinedbash
undefinedWRONG - breaks on spaces
错误 - 遇到空格时失效
prettier --write $FILE
prettier --write $FILE
RIGHT - handles spaces
正确 - 处理空格
prettier --write "$FILE"
undefinedprettier --write "$FILE"
undefined6. Log for Debugging
6. 日志用于调试
bash
LOG_FILE=~/.claude-hooks/debug.logbash
LOG_FILE=~/.claude-hooks/debug.logLog 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
undefinedecho "Hook running..." >&2
undefinedPublishing as PRPM Package
发布为PRPM包
Package Structure
包结构
my-hook/
├── prpm.json # Package manifest
├── HOOK.md # Hook documentation
└── hook-script.sh # Hook executablemy-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-startThis hook will be installed to .
.claude/hooks/session-startBehavior
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
```
undefinedbash
#!/bin/bash
echo "Session started at $(date)" >> ~/.claude/session.log
echo "Environment ready"
exit 0undefinedPublishing Process
发布流程
bash
undefinedbash
undefinedTest 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
undefinedprpm 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
undefinedSecurity Requirements
安全要求
Input Validation
输入验证
bash
undefinedbash
undefinedParse 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
undefinedPath Sanitization
路径清理
bash
undefinedbash
undefinedPrevent 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
undefinedif [[ "$FILE" != "$CLAUDE_PROJECT_DIR"* ]]; then
echo "File outside project" >&2
exit 2
fi
undefinedUser 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
| Feature | Hooks | Skills | Commands |
|---|---|---|---|
| Format | Executable code | Markdown | Markdown |
| Trigger | Automatic (events) | Automatic (context) | Manual ( |
| Language | Any executable | N/A | N/A |
| Use Case | Automation, validation | Reference, patterns | Quick tasks |
| Security | Requires confirmation | No special permissions | Inherits from session |
Examples:
- Hook: Auto-format files on save
- Skill: Reference guide for testing patterns
- Command: quick code review
/review-pr
| 特性 | Hooks | Skills | Commands |
|---|---|---|---|
| 格式 | 可执行代码 | Markdown | Markdown |
| 触发方式 | 自动(事件) | 自动(上下文) | 手动( |
| 语言 | 任意可执行语言 | N/A | N/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中有清晰的描述和标签
- 版本号符合语义化规范