name: creating-claude-hooks description: 在创建或发布Claude Code钩子时使用 - 涵盖可执行格式、事件类型、JSON输入输出、退出代码、安全要求和PRPM包结构 skillType: skill allowed-tools: Read, Write, Edit, Grep, Glob, Bash
创建Claude Code钩子
在创建、改进或发布Claude Code钩子时使用此技能。提供关于钩子格式、事件处理、输入输出约定和包结构的基本指导。
何时使用此技能
在以下情况下激活此技能:
- 用户要求创建新的Claude Code钩子
- 用户想要将钩子发布为PRPM包
- 用户需要了解钩子格式或事件
- 用户正在排查钩子执行问题
- 用户询问钩子、技能和命令之间的区别
快速参考
钩子文件格式
| 方面 | 要求 |
|---|---|
| 位置 | .claude/hooks/<事件名称> |
| 格式 | 可执行文件(shell、TypeScript、Python等) |
| 权限 | 必须可执行(chmod +x) |
| Shebang | 必需(#!/bin/bash 或 #!/usr/bin/env node) |
| 输入 | 通过标准输入接收JSON |
| 输出 | 通过标准输出显示文本(给用户看) |
| 退出代码 | 0 = 成功,2 = 阻止,其他 = 错误 |
可用事件
| 事件 | 触发时机 | 常见用例 |
|---|---|---|
session-start |
新会话开始时 | 环境设置、日志记录、检查 |
user-prompt-submit |
用户输入处理前 | 验证、增强、过滤 |
tool-call |
工具执行前 | 权限检查、日志记录、修改 |
assistant-response |
助手响应后 | 格式化、日志记录、清理 |
钩子格式要求
文件位置
项目钩子:
.claude/hooks/session-start
.claude/hooks/user-prompt-submit
用户全局钩子:
~/.claude/hooks/session-start
~/.claude/hooks/tool-call
可执行要求
每个钩子必须:
- 有shebang行:
#!/bin/bash
# 或
#!/usr/bin/env node
# 或
#!/usr/bin/env python3
- 可执行:
chmod +x .claude/hooks/session-start
- 处理来自标准输入的JSON输入:
#!/bin/bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty')
- 以适当的代码退出:
exit 0 # 成功
exit 2 # 阻止操作
exit 1 # 错误(记录但继续)
输入/输出格式
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": "..."
}
}
标准输出
- 正常输出显示在对话记录中
- 空输出静默运行
- 使用标准错误输出(
>&2)记录错误
退出代码
| 代码 | 含义 | 行为 |
|---|---|---|
0 |
成功 | 正常继续 |
2 |
阻止 | 停止操作,显示错误 |
1 或其他 |
错误 | 记录错误,继续 |
模式验证
钩子应根据JSON模式进行验证:
模式URL: https://github.com/pr-pm/prpm/blob/main/packages/converters/schemas/claude-hook.schema.json
必需的前言字段:
name- 钩子标识符(仅小写,连字符)description- 钩子功能描述event- 事件类型(可选,从文件名推断)language- bash、typescript、javascript、python、binary(可选)hookType: "hook"- 用于往返转换
常见错误
| 错误 | 问题 | 解决方案 |
|---|---|---|
| 变量未加引号 | 空格导致中断 | 始终使用 "$VAR" |
| 缺少shebang | 无法执行 | 添加 #!/bin/bash |
| 不可执行 | 权限被拒绝 | 运行 chmod +x hook-file |
| 日志输出到标准输出 | 污染对话记录 | 使用标准错误输出:echo "log" >&2 |
| 错误的退出代码 | 需要阻止时未阻止 | 使用 exit 2 阻止 |
| 无输入验证 | 安全风险 | 始终验证JSON字段 |
| 操作缓慢 | 阻塞Claude | 在后台运行或使用PostToolUse |
| 缺少绝对路径 | 找不到脚本 | 使用 $CLAUDE_PLUGIN_ROOT |
基本钩子示例
Shell脚本钩子
#!/bin/bash
# .claude/hooks/session-start
# 记录会话开始
echo "Session started at $(date)" >> ~/.claude/session.log
# 检查环境
if ! command -v node &> /dev/null; then
echo "Warning: Node.js not installed" >&2
fi
# 输出给用户
echo "Development environment ready"
exit 0
TypeScript钩子
#!/usr/bin/env node
// .claude/hooks/user-prompt-submit
import { readFileSync } from 'fs';
// 从标准输入读取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);
最佳实践
1. 保持钩子快速
PreToolUse钩子目标<100毫秒:
- 尽可能缓存结果
- 在后台运行繁重操作
- 使用特定匹配器,而非通配符
2. 优雅处理错误
# 检查依赖是否存在
if ! command -v jq &> /dev/null; then
echo "jq not installed, skipping" >&2
exit 0
fi
# 验证输入
FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty')
if [[ -z "$FILE" ]]; then
echo "No file path provided" >&2
exit 1
fi
3. 使用Shebang
始终以shebang开头:
#!/bin/bash
#!/usr/bin/env node
#!/usr/bin/env python3
4. 保护敏感文件
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. 引用所有变量
# 错误 - 空格导致中断
prettier --write $FILE
# 正确 - 处理空格
prettier --write "$FILE"
6. 记录调试信息
LOG_FILE=~/.claude-hooks/debug.log
# 记录到文件
echo "[$(date)] Processing $FILE" >> "$LOG_FILE"
# 记录到标准错误输出(显示在对话记录中)
echo "Hook running..." >&2
发布为PRPM包
包结构
my-hook/
├── prpm.json # 包清单
├── HOOK.md # 钩子文档
└── hook-script.sh # 钩子可执行文件
prpm.json
{
"name": "@username/hook-name",
"version": "1.0.0",
"description": "搜索中显示的简短描述",
"author": "您的姓名",
"format": "claude",
"subtype": "hook",
"tags": ["automation", "security", "formatting"],
"main": "HOOK.md"
}
HOOK.md格式
---
name: session-logger
description: 记录会话开始/结束时间以进行跟踪
event: SessionStart
language: bash
hookType: hook
---
# 会话记录器钩子
记录Claude Code会话活动以进行跟踪和调试。
## 安装
此钩子将安装到 `.claude/hooks/session-start`。
## 行为
- 将会话开始时间记录到 `~/.claude/session.log`
- 显示环境状态
- 静默运行依赖检查
## 要求
- bash 4.0+
- 对 `~/.claude/` 的写访问权限
## 源代码
\`\`\`bash
#!/bin/bash
echo "Session started at $(date)" >> ~/.claude/session.log
echo "Environment ready"
exit 0
\`\`\`
发布流程
# 首先本地测试
prpm test
# 发布到注册表
prpm publish
# 版本更新
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
安全要求
输入验证
# 安全解析JSON
INPUT=$(cat)
if ! FILE=$(echo "$INPUT" | jq -r '.input.file_path // empty' 2>&1); then
echo "JSON parse failed" >&2
exit 1
fi
# 验证字段存在
[[ -n "$FILE" ]] || exit 1
路径清理
# 防止目录遍历
if [[ "$FILE" == *".."* ]]; then
echo "Path traversal detected" >&2
exit 2
fi
# 保持在项目目录内
if [[ "$FILE" != "$CLAUDE_PROJECT_DIR"* ]]; then
echo "File outside project" >&2
exit 2
fi
用户确认
Claude Code自动:
- 安装钩子前需要确认
- 向用户显示钩子源代码
- 警告钩子执行
- 在对话记录中显示钩子输出
钩子 vs 技能 vs 命令
| 特性 | 钩子 | 技能 | 命令 |
|---|---|---|---|
| 格式 | 可执行代码 | Markdown | Markdown |
| 触发 | 自动(事件) | 自动(上下文) | 手动(/command) |
| 语言 | 任何可执行文件 | 不适用 | 不适用 |
| 用例 | 自动化、验证 | 参考、模式 | 快速任务 |
| 安全 | 需要确认 | 无特殊权限 | 继承自会话 |
示例:
- 钩子: 保存时自动格式化文件
- 技能: 测试模式参考指南
- 命令:
/review-pr快速代码审查
相关资源
- claude-hook-writer技能 - 详细的钩子开发指导
- typescript-hook-writer技能 - TypeScript特定的钩子开发
- Claude Code文档
- 模式
新钩子检查清单
发布前:
- [ ] 包含shebang行
- [ ] 文件可执行(
chmod +x) - [ ] 验证所有标准输入
- [ ] 引用所有变量
- [ ] 优雅处理缺失依赖
- [ ] 使用适当的退出代码
- [ ] 将错误记录到标准错误输出或文件
- [ ] 使用边缘情况测试(空格、Unicode、缺失字段)
- [ ] 在HOOK.md中记录依赖
- [ ] 包含安装说明
- [ ] 文档中包含源代码
- [ ] prpm.json中有清晰的描述和标签
- [ ] 版本号符合语义化版本