
Hook Creator
- 2 installs
- 1 repo stars
- Updated July 28, 2026
- evanfang0054/cc-system-creator-scripts
Creates and configures Claude Code hooks that run shell commands on lifecycle events like PreToolUse and PostToolUse for formatting, logging, or file protection.
About
Guides building Claude Code hooks by choosing an event, writing a stdin-JSON shell command, configuring matchers, and picking user or project settings scope. A developer uses it to add auto-formatting, logging, notifications, or file-protection hooks.
- Covers PreToolUse/PostToolUse/Notification events and matchers
- Writes hooks to user or project settings.json with test guidance
Hook Creator by the numbers
- 2 all-time installs (skills.sh)
- Ranked #1,839 of 2,715 Automation & Workflows skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/evanfang0054/cc-system-creator-scripts --skill hook-creatorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2 |
|---|---|
| repo stars | ★ 1 |
| Last updated | July 28, 2026 |
| Repository | evanfang0054/cc-system-creator-scripts ↗ |
What it does
Creates and configures Claude Code hooks that run shell commands on lifecycle events like PreToolUse and PostToolUse for formatting, logging, or file protection.
Files
Hook 钩子创建器
创建在特定生命周期事件中执行 shell 命令的 Claude Code 钩子。
钩子创建工作流程
1. 确定使用场景 - 明确钩子需要完成的功能 2. 选择合适的事件 - 从可用的钩子事件中选择(参见 references/hook-events.md) 3. 设计钩子命令 - 编写从 stdin 处理 JSON 输入的 shell 命令 4. 配置匹配器 - 设置工具/事件过滤器(使用 * 匹配所有,或指定工具名称如 Bash、Edit|Write) 5. 选择存储位置 - 用户设置(~/.claude/settings.json)或项目(.claude/settings.json) 6. 测试钩子 - 使用简单测试用例验证行为
钩子配置结构
{
"hooks": {
"<事件名称>": [
{
"matcher": "<工具模式>",
"hooks": [
{
"type": "command",
"command": "<shell命令>"
}
]
}
]
}
}常用模式
读取输入数据
钩子通过 stdin 接收 JSON。使用 jq 提取字段:
# 提取工具输入字段
jq -r '.tool_input.file_path'
# 带默认值的提取
jq -r '.tool_input.description // "无描述"'
# 条件处理
jq -r 'if .tool_input.file_path then .tool_input.file_path else empty end'PreToolUse 的退出代码
0- 允许工具继续执行2- 阻止工具并向 Claude 提供反馈
匹配器模式
*- 匹配所有工具Bash- 仅匹配 Bash 工具Edit|Write- 匹配 Edit 或 Write 工具Read- 匹配 Read 工具
快速示例
记录所有 bash 命令:
jq -r '"\(.tool_input.command)"' >> ~/.claude/bash-log.txt编辑后自动格式化 TypeScript:
jq -r '.tool_input.file_path' | { read f; [[ "$f" == *.ts ]] && npx prettier --write "$f"; }阻止编辑 .env 文件:
python3 -c "import json,sys; p=json.load(sys.stdin).get('tool_input',{}).get('file_path',''); sys.exit(2 if '.env' in p else 0)"资源文档
- 钩子事件参考:查看
references/hook-events.md了解详细的事件文档,包含输入/输出架构 - 示例配置:查看
references/examples.md获取完整的、经过测试的钩子配置
Hook 钩子示例
针对常见使用场景的完整、经过测试的钩子配置。
日志记录钩子
记录所有 Bash 命令
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '\"\\(.tool_input.command) - \\(.tool_input.description // \"无描述\")\"' >> ~/.claude/bash-command-log.txt"
}
]
}
]
}
}记录所有文件编辑
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '\"[\\(now | strftime(\"%Y-%m-%d %H:%M:%S\"))] \\(.tool_name): \\(.tool_input.file_path)\"' >> ~/.claude/edit-log.txt"
}
]
}
]
}
}自动格式化钩子
格式化 TypeScript 文件
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | { read file_path; if echo \"$file_path\" | grep -q '\\.tsx\\?$'; then npx prettier --write \"$file_path\" 2>/dev/null; fi; }"
}
]
}
]
}
}使用 Black 格式化 Python 文件
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | { read f; [[ \"$f\" == *.py ]] && black \"$f\" 2>/dev/null; }"
}
]
}
]
}
}格式化 Go 文件
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | { read f; [[ \"$f\" == *.go ]] && gofmt -w \"$f\"; }"
}
]
}
]
}
}文件保护钩子
阻止编辑敏感文件
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "python3 -c \"import json, sys; data=json.load(sys.stdin); path=data.get('tool_input',{}).get('file_path',''); blocked=['.env', 'package-lock.json', '.git/', 'secrets']; sys.exit(2 if any(p in path for p in blocked) else 0)\""
}
]
}
]
}
}阻止修改生产目录
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write|Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input | .file_path // .command // \"\"' | grep -q '/prod/' && echo 'BLOCKED: 无法修改生产文件' && exit 2 || exit 0"
}
]
}
]
}
}通知钩子
macOS 桌面通知
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "jq -r '.message' | xargs -I{} osascript -e 'display notification \"{}\" with title \"Claude Code\"'"
}
]
}
]
}
}Linux 桌面通知
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "jq -r '.message' | xargs -I{} notify-send 'Claude Code' '{}'"
}
]
}
]
}
}声音通知 (macOS)
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "afplay /System/Library/Sounds/Glass.aiff"
}
]
}
]
}
}验证钩子
写入前验证 JSON
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "jq -e '.tool_input | select(.file_path | endswith(\".json\")) | .content' | jq . > /dev/null 2>&1 || { echo 'JSON 内容无效'; exit 2; }"
}
]
}
]
}
}提交前检查 TypeScript 代码规范
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.command' | grep -q 'git commit' && npx eslint . --max-warnings 0 || exit 0"
}
]
}
]
}
}会话钩子
会话开始时初始化环境
{
"hooks": {
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "[ -f .claude-env ] && source .claude-env"
}
]
}
]
}
}会话结束时清理
{
"hooks": {
"SessionEnd": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "rm -f /tmp/claude-session-* 2>/dev/null; exit 0"
}
]
}
]
}
}多钩子示例
在一个配置中组合多个钩子:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "python3 -c \"import json,sys; p=json.load(sys.stdin).get('tool_input',{}).get('file_path',''); sys.exit(2 if '.env' in p else 0)\""
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | { read f; [[ \"$f\" == *.ts ]] && npx prettier --write \"$f\" 2>/dev/null; exit 0; }"
}
]
}
],
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "afplay /System/Library/Sounds/Glass.aiff"
}
]
}
]
}
}Hook 钩子事件参考
事件概览
| 事件 | 触发时机 | 可阻塞 | 典型用途 |
|---|---|---|---|
| PreToolUse | 工具执行前 | 是(退出代码 2) | 验证、阻塞 |
| PostToolUse | 工具完成后 | 否 | 格式化、日志记录 |
| PermissionRequest | 显示权限对话框时 | 是 | 自动允许/拒绝 |
| UserPromptSubmit | 用户提交提示时 | 否 | 预处理 |
| Notification | Claude 发送通知时 | 否 | 自定义提醒 |
| Stop | Claude 完成响应时 | 否 | 后处理 |
| SubagentStop | 子代理任务完成时 | 否 | 子代理清理 |
| PreCompact | 压缩操作前 | 否 | 压缩前操作 |
| SessionStart | 会话开始/恢复时 | 否 | 初始化 |
| SessionEnd | 会话结束时 | 否 | 清理 |
PreToolUse
在工具调用前运行。可以阻塞执行。
输入架构:
{
"tool_name": "Bash",
"tool_input": {
"command": "ls -la",
"description": "列出文件"
}
}退出代码:
0- 允许工具继续执行2- 阻塞工具,stdout 作为反馈发送给 Claude
各工具的常见 tool_input 字段:
Bash:command,descriptionEdit:file_path,old_string,new_stringWrite:file_path,contentRead:file_pathGlob:pattern,pathGrep:pattern,path
PostToolUse
在工具调用完成后运行。
输入架构:
{
"tool_name": "Edit",
"tool_input": {
"file_path": "/path/to/file.ts"
},
"tool_response": "文件编辑成功"
}使用场景:
- 自动格式化编辑的文件
- 记录工具结果
- 触发相关操作
PermissionRequest
显示权限对话框时运行。
输入架构:
{
"tool_name": "Bash",
"tool_input": {
"command": "npm install"
},
"permission_type": "execute"
}退出代码:
0- 让用户决定1- 自动拒绝2- 自动允许
Notification
Claude 发送通知时运行。
输入架构:
{
"message": "等待您的输入",
"type": "input_required"
}使用场景:
- 自定义桌面通知
- Slack/Discord 警报
- 声音通知
UserPromptSubmit
用户提交提示时运行,Claude 处理之前。
输入架构:
{
"prompt": "帮我修复这个 bug",
"session_id": "abc123"
}使用场景:
- 提示日志记录
- 预处理
- 上下文注入
Stop
Claude 完成响应时运行。
输入架构:
{
"stop_reason": "end_turn",
"session_id": "abc123"
}使用场景:
- 会话日志记录
- 清理任务
- 指标收集
SubagentStop
子代理(Task 工具)任务完成时运行。
输入架构:
{
"subagent_type": "Explore",
"result": "找到 5 个匹配文件"
}PreCompact
Claude 压缩对话上下文之前运行。
输入架构:
{
"reason": "context_limit",
"current_tokens": 50000
}SessionStart
Claude Code 开始或恢复会话时运行。
输入架构:
{
"session_id": "abc123",
"is_resume": false,
"project_dir": "/path/to/project"
}使用场景:
- 环境设置
- 加载项目配置
- 启动后台服务
SessionEnd
Claude Code 会话结束时运行。
输入架构:
{
"session_id": "abc123",
"end_reason": "user_exit"
}使用场景:
- 清理资源
- 保存会话状态
- 停止后台服务