Claude Code 自定义命令及HOOK
一、什么是自定义命令
Claude Code 的自定义命令(Custom Slash Commands)是用户定义的快捷指令,通过 Markdown 文件将常用的 prompt 模板封装成可复用的命令。与内置命令(如 /clear、/init、/compact)类似,自定义命令能够一键调用预定义的工作流。
1.1 核心概念
自定义命令 = Prompt 模板 + 参数化 + 上下文注入
- Markdown 文件:命令定义文件,文件名即命令名
- Frontmatter:YAML 格式的元数据配置
- 动态参数:支持
$1、$2、$ARGUMENTS 等参数传递
- Shell 集成:可执行 shell 命令并嵌入输出(使用
! 前缀)
- 文件引用:通过
@<文件路径> 读取文件内容
1.2 命令类型
Claude Code 支持两种类型的自定义命令:
| 类型 | 存储位置 | 作用域 | 共享方式 |
|---|
| 项目命令 | .claude/commands/ | 仅当前项目 | 通过 Git 仓库共享给团队 |
| 个人命令 | ~/.claude/commands/ | 所有项目 | 仅个人使用 |
二、自定义命令语法详解
2.1 基础语法
最简命令:纯 Prompt
创建文件 .claude/commands/analyze.md:
使用:/analyze
带参数的命令
创建文件 .claude/commands/fix-issue.md:
使用:/fix-issue 123 high
参数说明:
$1, $2, $3 ... - 位置参数
$ARGUMENTS - 捕获所有参数
2.2 执行 Shell 命令
需要在 Frontmatter 中配置 allowed-tools 权限。
创建文件 .claude/commands/git-diff.md:
---
allowed-tools: Bash(git status:*), Bash(git diff:*), Bash(git log:*)
description: 解释当前的 Git 变更
---
# 上下文
- 当前 Git 状态: !`git status`
- 当前差异: !`git diff HEAD`
# 任务
基于上述变更,详细解释 git diff 的内容。
使用:/git-diff
💡Shell 命令执行机制
使用 ! 前缀的命令会在执行时运行,输出自动嵌入到 prompt 中。这对于注入动态上下文非常有用。
2.3 文件引用
创建文件 .claude/commands/compare-versions.md:
比较 @src/old-version.js 和 @src/new-version.js,总结主要差异。
使用:/compare-versions
2.4 Frontmatter 配置
Frontmatter 是命令的元数据配置块,支持以下字段:
| 字段 | 说明 | 示例 |
|---|
allowed-tools | 预授权的工具列表 | Bash(git add:*) |
argument-hint | 参数提示(自动补全) | [message] |
description | 命令描述 | 创建 Git 提交 |
model | 指定使用的模型 | claude-3-5-haiku-20241022 |
完整示例:
---
allowed-tools: Bash(git add:*), Bash(git status:*), Bash(git commit:*)
argument-hint: [message]
description: 创建 Git 提交
model: claude-sonnet-4-5-20250929
---
使用以下消息创建 Git 提交: $ARGUMENTS
三、什么是 Hook(钩子)
Hook 是在 Claude Code 生命周期特定时刻自动执行的 shell 命令。与自定义命令不同,Hook 提供对 Claude Code 行为的确定性控制,确保某些操作总是发生,而不是依赖 LLM 选择运行它们。
3.1 Hook 与自定义命令的区别
| 特性 | 自定义命令 | Hook |
|---|
| 触发方式 | 用户手动调用 /命令 | 事件自动触发 |
| 执行时机 | 用户主动 | 生命周期被动 |
| 用途 | 封装 prompt 模板 | 自动化操作、权限控制 |
| 配置位置 | .claude/commands/ | .claude/settings.json |
3.2 核心 Hook 事件
| Hook 事件 | 触发时机 | 典型用途 |
|---|
| PreToolUse | 工具调用前 | 阻止危险操作、代码格式化 |
| PostToolUse | 工具调用后 | 自动格式化、日志记录 |
| PermissionRequest | 权限请求时 | 自定义权限规则 |
| UserPromptSubmit | 用户提交 prompt 前 | 注入上下文、预处理 |
| Stop | Claude 完成响应时 | 任务完成通知 |
| SubagentStop | 子代理完成时 | 子任务完成通知 |
| Notification | 发送通知时 | 自定义通知方式 |
| SessionStart | 会话启动时 | 初始化环境 |
| SessionEnd | 会话结束时 | 清理资源 |
⚠安全考虑
Hook 使用当前环境凭证自动运行,存在安全风险。在注册 Hook 前务必审查代码,避免数据泄露。
四、Hook 实战示例
4.1 任务完成后发送企业微信通知
当 Claude Code 完成任务时,自动发送企业微信 Webhook 通知。
Stop Hook 在 Claude 完成响应时触发,适合任务完成通知。
步骤 1:获取企业微信 Webhook 地址
在企业微信中创建群机器人,获取 Webhook URL:
https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY
步骤 2:配置 Hook
运行 /hooks 命令,选择 Stop 事件,添加以下配置:
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/wecom_notify.sh"
}
]
}
]
}
}
步骤 3:创建通知脚本
创建文件 ~/.claude/hooks/wecom_notify.sh:
#!/bin/bash
WECOM_WEBHOOK="https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY"
EVENT_DATA=$(cat)
PROJECT_DIR=$(echo "$EVENT_DATA" | jq -r '.working_directory // "Unknown"')
PROJECT_NAME=$(basename "$PROJECT_DIR")
LAST_MESSAGE=$(echo "$EVENT_DATA" | jq -r '.conversation_history[-2].content // "任务已完成"' | head -c 100)
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
MESSAGE=$(cat <<EOF
{
"msgtype": "markdown",
"markdown": {
"content": "## Claude Code 任务完成通知\\n\\n**项目**: $PROJECT_NAME\\n**任务**: $LAST_MESSAGE\\n**时间**: $TIMESTAMP\\n\\n> 任务已完成,请查看结果"
}
}
EOF
)
# 后台发送通知,避免阻塞
(curl -s -X POST "$WECOM_WEBHOOK" \
-H 'Content-Type: application/json' \
-d "$MESSAGE" &) > /dev/null 2>&1
exit 0
步骤 4:赋予执行权限
chmod +x ~/.claude/hooks/wecom_notify.sh
💡测试 Hook
运行一个简单的任务(如 帮我创建一个 hello.txt 文件),完成后应收到企业微信通知。
⚠退出码说明
Hook 脚本的退出码控制执行流程:exit 0 表示成功继续执行,exit 1 表示失败但不阻断(仅记录错误),exit 2 表示阻断工具调用并向 Claude 发送反馈。
五、Hook 配置管理
5.1 配置位置
Hook 配置存储在两个位置:
| 位置 | 作用域 | 配置文件 |
|---|
| 用户级 | 所有项目 | ~/.claude/settings.json |
| 项目级 | 当前项目 | .claude/settings.json |
项目级配置会覆盖用户级配置。
5.2 快速配置
方式一:使用 /hooks 命令(推荐)
- 运行
/hooks
- 选择 Hook 事件类型
- 选择工具匹配器(或输入
* 匹配所有)
- 输入命令
- 选择存储位置(User/Project)
方式二:直接编辑配置文件
编辑 ~/.claude/settings.json 或 .claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "python3 ~/.claude/hooks/auto_format.py"
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/wecom_notify.sh"
}
]
}
]
}
}
5.3 Hook 调试
如果 Hook 未按预期工作,可以使用以下方法调试:
1. 检查 Hook 输出
Hook 的 stdout 和 stderr 会显示在 Claude Code 日志中。
2. 添加调试日志
在 Hook 脚本中添加日志:
#!/bin/bash
echo "Hook triggered: $(date)" >> /tmp/claude-hook-debug.log
cat >> /tmp/claude-hook-debug.log
3. 测试 Hook 脚本
手动测试 Hook 脚本:
echo '{"tool_input":{"file_path":"test.ts"}}' | ~/.claude/hooks/auto_format.py
4. 检查退出码
确保脚本返回正确的退出码:
0 - 成功
1 - 错误(不阻断)
2 - 阻断工具调用
💡Hook 执行顺序
如果同一事件配置了多个 Hook,它们会按配置顺序依次执行。任何一个 Hook 返回退出码 2 都会阻断后续执行。
六、最佳实践
6.1 Hook 设计原则
- 快速执行:Hook 应在 1-2 秒内完成,避免阻塞工作流
- 容错处理:网络请求应设置超时,失败不应阻断 Claude
- 安全优先:避免在 Hook 中执行不可信代码
- 日志记录:使用 stderr 输出调试信息
6.2 常见 Hook 场景
| 场景 | Hook 事件 | 示例 |
|---|
| 代码格式化 | PostToolUse | Prettier, Black, gofmt |
| 任务通知 | Stop, SubagentStop | 企业微信、Slack、邮件 |
| 权限控制 | PreToolUse | 阻止删除生产文件 |
| 审计日志 | PreToolUse, PostToolUse | 记录所有操作 |
| 上下文注入 | SessionStart, UserPromptSubmit | 加载项目配置 |
| 自定义通知 | Notification | 替换默认通知方式 |
6.3 性能优化
异步执行(后台运行):
#!/bin/bash
# 使用 & 将通知放到后台,避免阻塞
(curl -X POST "$WECOM_WEBHOOK" -d "$MESSAGE" &) > /dev/null 2>&1
exit 0
缓存结果:
import functools
import time
@functools.lru_cache(maxsize=128)
def expensive_check(file_path):
# 缓存耗时检查结果
pass
6.4 团队协作
共享项目级 Hook:
将 .claude/settings.json 提交到 Git 仓库,团队成员自动获得相同 Hook 配置。
个性化配置:
在 .gitignore 中排除个人配置:
.claude/settings.json.local
在代码中支持覆盖:
# 优先使用环境变量
WEBHOOK = os.getenv('WECOM_WEBHOOK') or 'default_webhook'
七、完整示例:企业开发工作流
综合使用自定义命令和 Hook 构建完整开发工作流。
7.1 配置文件
.claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "python3 .claude/hooks/auto_format.py"
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/notify_complete.sh"
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/log_command.sh"
}
]
}
]
}
}
7.2 自定义命令
.claude/commands/commit.md:
---
allowed-tools: Bash(git add:*), Bash(git status:*), Bash(git commit:*)
argument-hint: [message]
description: 提交代码到 Git
---
# 上下文
- 当前状态: !`git status --short`
- 最近提交: !`git log --oneline -5`
# 任务
使用以下消息创建符合 Conventional Commits 规范的提交: $ARGUMENTS
步骤:
1. 检查待提交文件
2. 添加到暂存区
3. 创建格式化的提交消息
4. 执行提交
.claude/commands/review.md:
---
description: 代码审查当前分支
---
# 代码审查清单
请审查当前分支的变更,关注:
1. **代码质量**
- 是否符合项目编码规范
- 是否有重复代码
- 命名是否清晰
2. **功能正确性**
- 是否实现了预期功能
- 边界条件处理是否完善
- 错误处理是否合理
3. **性能**
- 是否有性能瓶颈
- 数据库查询是否优化
4. **安全性**
- 是否有SQL注入风险
- 是否有XSS风险
- 敏感信息是否泄露
基于 !`git diff main...HEAD` 提供审查意见。
7.3 使用工作流
# 1. 开发功能
用户: 帮我实现用户登录功能
# 2. Claude 自动格式化(PostToolUse Hook)
# 3. 提交代码
用户: /commit 实现用户登录功能
# 4. 代码审查
用户: /review
# 5. 完成后收到企业微信通知(Stop Hook)
八、常见问题
8.1 Hook 未执行
原因:
- Hook 脚本没有执行权限
- Hook 脚本路径错误
- Matcher 不匹配
解决:
# 检查权限
ls -la ~/.claude/hooks/
# 添加执行权限
chmod +x ~/.claude/hooks/*.sh ~/.claude/hooks/*.py
# 测试脚本
echo '{}' | ~/.claude/hooks/your_hook.sh
8.2 Hook 执行超时
解决:为网络请求添加超时:
requests.post(url, json=data, timeout=5)
8.3 企业微信通知失败
排查步骤:
# 1. 测试 Webhook 地址
curl -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY" \
-H 'Content-Type: application/json' \
-d '{"msgtype":"text","text":{"content":"测试消息"}}'
# 2. 检查返回值
# {"errcode":0,"errmsg":"ok"} - 成功
# {"errcode":93000,"errmsg":"invalid webhook url"} - URL 错误
8.4 Hook 影响性能
解决:使用后台执行:
#!/bin/bash
# 将耗时操作放到后台
(
sleep 2
curl -X POST "$WEBHOOK" -d "$DATA"
) &
exit 0
九、参考资源