☰
Claude Code模板实战:CLAUDE.md、自定义命令与hooks全解析
2026/10/17 5:22:21 网站建设 项目流程

1. 先把这个标题拆明白

看到“claude-code-templates”这个项目名,估计大部分人都能猜个大概:这是给Claude Code用的模板集合。但真正用过Claude Code的人会知道,模板这两个字背后藏的东西远比想象中多——它不是简单的几段提示词,而是一整套让AI助手在项目里“懂规矩、按套路出牌”的机制。

我最早接触Claude Code的时候,跟很多人一样,觉得这玩意儿就是个放在终端里的聊天窗口。你让它改bug,它给你改;你让它写测试,它给你写。但用久了就发现一个问题:同样的需求,今天让它写出来的代码跟明天写的代码,风格、结构、注释习惯完全是两个人。更头疼的是,我明明在对话里强调过“数据库操作必须走事务”,隔了几个小时它就忘了。

后来我才意识到,Claude Code这种带记忆的终端Agent,跟普通的ChatGPT聊天窗口有本质区别。它可以在项目目录下读取你的约定文件,可以挂载自定义命令,甚至能在特定时机自动执行脚本。这些东西组合起来,就是“模板”的真正含义——把团队规范、个人偏好、重复性工作流程,全部固化成一堆可复用的配置文件。

这篇文章我准备从实际落地角度,把我自己维护的这套claude-code-templates完整拆开讲。包括CLAUDE.md怎么写、自定义斜杠命令怎么挂、hooks怎么配、以及踩过的那些坑。适合已经把Claude Code跑起来、但觉得它在真实项目里“不够听话”的人读。

2. Claude Code模板系统的核心构成

2.1 CLAUDE.md:项目的“永久记忆”

很多人把CLAUDE.md当成一个给Claude看的技术文档,写两句“这是一个基于Python的后端项目”就完了。这其实大材小用了。CLAUDE.md是Claude Code在启动时会自动读取的项目级上下文文件,它最大的价值在于:让每一次会话都能继承项目的约定,即使你关掉终端、隔了一周再回来,它依然记得应该用什么风格写代码。

我在自己项目的CLAUDE.md里一般分这么几块:

# 项目:订单服务 ## 技术栈 - Python 3.11 + FastAPI + PostgreSQL - 包管理用 uv,不要用 pip ## 代码规范 - 所有数据库查询必须走 repository 层,禁止在路由里直接写 SQL - 型号名称用单数,表名用复数 - 异常统一抛 domain_error,不允许裸抛 ValueError ## 提交规范 - commit message 格式:`feat|fix|refactor|test(模块): 描述` - 提交前必须跑 ruff 和 pytest ## 环境变量 - 所有配置从 pydantic-settings 读取,禁止硬编码 - 本地开发默认端口 8000

你别小看这几行字。Claude Code读进去之后,写代码时就会不自觉地去遵守。我实测过同一个项目,写了CLAUDE.md跟没写,它生成的代码风格一致性差距非常大。没写的时候,它有时候给你带类型标注,有时候不带,有时候用f-string,有时候用format;写了之后,基本能做到按规范输出。

不过有个细节要注意:CLAUDE.md不是越长越好。Claude Code每次会话启动都会把整个文件作为上下文加载,太长会挤占有限的上下文窗口。我建议控制在100行以内,只放“必须遵守”的内容,那些偶尔提醒一下就行的事情就别往里面塞了。

2.2 自定义斜杠命令:把重复劳动交给模板

这才是我觉得模板体系里最实用的部分。Claude Code支持在项目下建一个.claude/commands/目录,里面每个Markdown文件对应一个斜杠命令。比如你创建一个review.md,然后就可以在对话里输入/review,Claude会立刻按你写好的指令执行。

这个机制特别像给AI装上了“快捷键”。我其实最早被这个东西打动,是因为一个很琐碎的场景——code review。以前我每次让Claude帮我检查代码,都要不厌其烦地描述:“请从安全性、性能、代码风格三个角度检查这段代码,注意数据库N+1查询,注意越权判断,输出格式是问题列表+修改建议”。后来我把它做成了模板:

--- name: review description: 审查当前工作区代码 --- 请对当前分支的改动进行代码审查,重点检查: 1. 安全性:越权、注入、敏感信息泄露 2. 性能:N+1查询、循环内IO、缺少索引的查询 3. 可维护性:函数过长、重复代码、命名混乱 输出要求: - 按严重程度分组:阻塞/建议/可选优化 - 每项必须给到具体文件和行号 - 建议修复方式要给出代码片段

从此以后我只需要敲/review,它就会按这个标准执行。同样思路,我还做了/gen-test——给选中文件生成单测;/explain——用金字塔原理解释一段复杂逻辑;/changelog——根据git log生成变更日志。这些东西本质上都是“命令行式提示词”,但体验完全不一样,因为不需要每次重新组织语言,也不会漏提要求。

2.3 Hooks:在关键时刻自动触发规矩

Hooks这块可能很多人没接触过,但它是把模板从“被动遵守”变“主动执行”的关键一环。Claude Code支持配置事件钩子,比如在工具调用前、在会话启动时、在AI提交消息前等时机,触发外部脚本。

我开发环境里最常用的两个:

  • PreToolUse钩子,监听Edit工具。脚本判断AI改动的文件路径,如果命中“禁止修改”的白名单目录,直接拦截并返回错误信息。
  • Stop钩子,在对话轮次结束时检查工作区状态,如果发现未提交的TODO标记,提醒我一声。

钩子的配置写在.claude/settings.json里,语法类似:

{ "hooks": { "PreToolUse": [ { "matcher": "Edit", "hooks": [ { "type": "command", "command": "python .claude/hooks/check_edit.py", "timeout": 10 } ] } ] } }

如果你跟我一样是Python项目,写个hook脚本并不难。比如我那个拦截脚本的逻辑就是:解析传入的JSON参数,取file_path字段,判断是否以migrations/开头,是的话就打印特定前缀的错误,返回非零退出码。整个脚本不到30行。

hooks真正有意思的地方在于:它把模板从“建议”变成了“强制”。CLAUDE.md写得再好也总有疏漏的时候,钩子就像装了红绿灯的路口,哪怕AI想闯红灯,也会被物理拦下来。

3. 实操:从零搭一套自己的模板

3.1 目录结构设计

网上开源的claude-code-templates仓库有很多,我自己参考过好几个,最后沉淀出来的目录是这样:

.claude/ ├── CLAUDE.md ├── settings.json ├── commands/ │ ├── review.md │ ├── gen-test.md │ ├── commit.md │ └── explain.md └── hooks/ ├── check_edit.py └── stop_check.py

这个布局是我迭代了挺久才定的。起初我把CLAUDE.md放在项目根目录,后来发现它如果每个子目录都有自己的一套上下文约定,根目录那份会被“覆盖”,于是改成了现在这样:根目录放全局规范,子目录再按需放各自的补充约定。

Commands目录是模板的主战场。我强烈建议给每个命令都加上frontmatter块,也就是文件开头那段用三横线包起来的元信息:

--- name: commit description: 根据当前改动生成规范的commit message ---

这个description字段特别重要,因为Claude Code在斜杠菜单里显示的就是它,而且你必须让description足够有辨识度,否则你装了十几个命令之后连自己都分不清哪个是哪个。

3.2 命令模板的写法细节

写自定义命令模板,一开始最容易犯的错误就是“写作文”。有些人会把命令写成几大段描述,巴不得把背景、目标、注意事项全部讲一遍。但实际用下来,效果反而不理想。Claude Code的模型能力足够强,你只需要“定框架、给标准、提约束”,剩下的它会自己发挥。

举一个我写commit命令的模板:

--- name: commit description: 用规范格式生成commit message --- 根据当前git diff生成符合规范的commit message。 要求: - 类型限定为 feat、fix、refactor、test、docs、chore 六种 - 格式:type(scope): 摘要 - 摘要不超过50个字符 - 正文按“为什么改/怎么改/影响范围”三段写 最后输出命令:git commit -m "..." -m "..." (不要实际执行)

注意到玄机没有?最后一句非常关键——“不要实际执行”。我特意让Claude只输出命令、不执行。原因很现实:AI自动提交偶尔会出幺蛾子,要么把没写完的代码提交了,要么commit message里带进去莫名其妙的内容。让它生成命令给我看,我来手动执行,比让它直接动手要稳妥得多。

这和编程里的一个原则很像:让自动化尽量做单向动作,涉及写操作的地方,留一手人工确认。Claude Code虽然支持会话内授权执行命令,但把提交这种敏感行为交给AI自动做,出了事后悔都来不及。

3.3 模板里如何控制输出质量

有些命令模板在执行完任务后,输出会是一大坨杂乱的文本。你原本只想让它总结重点,结果它把整个代码文件都抄给你看。对付这个问题,我的经验是在模板里显式定义“输出格式”。

比如review命令,我要求它按三级列表输出:

### 阻塞级 - [文件路径:行号] 问题描述 ### 建议级 - [文件路径:行号] 问题描述 ### 可选优化 - [文件路径:行号] 问题描述

这样输出出来一目了然,直接可以贴给团队群。类似地,gen-test这个命令我要求它输出“测试用例清单+测试代码块”,不允许输出额外解释。最开始的版本它每写一个测试用例就加一段“这个测试用例的目的是xxx”,看着烦死了。

另外一个技巧是给命令模板加负面约束。比如:

禁止事项: - 不要改动除目标文件之外的任何文件 - 不要在输出中展示全部代码文件内容 - 不要使用 "正如我前面提到的" 这类废话开头

这些负面约束虽然写起来像废话,但实测非常管用。大模型的生成逻辑里,明确禁止的东西大概率会被避开;而不写禁止项的内容,它反而可能自由发挥跑偏。

3.4 多项目管理自己的模板

等你的模板体系在一两个项目里跑通了,接下来会遇到一个现实问题:每个项目都拷贝一份.claude/目录,改起来很痛苦,我今天改进一下review命令,难道要同步到五六个项目里去?

我现在的做法是:把通用模板单独放一个Git仓库管理,各个项目通过工具拉取最新版。最简单的方案是直接软链接,将全局模板目录链接到项目里:

ln -s ~/dotfiles/claude-templates/.claude/commands /your/project/.claude/commands

但如果嫌软链接麻烦,也可以写一个两三行的同步脚本,用rsync把公共目录同步到各项目下。唯一需要注意的就是:项目特有的命令不要放公共仓库,否则会出现A项目的命令跑到B项目里执行,引发各种不可预期行为。

我把公共模板仓库里的命令,都默认设计成“不依赖特定技术栈”。比如review命令,它不会假设你用Python还是Node;而某个项目独有的“检查数据库迁移是否规范”这种命令,就只留在这个项目的.claude目录里,不放进公共模板。分得越清楚,后期维护越省心。

4. 运行中的典型问题与排查实录

4.1 命令出现了,但什么都没发生

这个坑我印象很深。有一阵子我创建了一个/refactor命令,重启Claude Code之后输入命令,它确实匹配到了,但只回了一句类似“好的”的话,然后没有执行任何操作。

后来排查半天才发现问题出在frontmatter上。Claude Code的命令系统对frontmatter里的name字段特别敏感,如果字段名写错,比如误写成title,命令虽然能被菜单列出来,但不会触发对应的内容模板。我那会儿正好是把name写成了Name,大小写不一致导致的。

解决办法很简单:严格按Od白皮书格式写frontmatter,三个字段一个都不能少,name用小写开头:

--- name: refactor description: 对指定文件执行安全重构 ---

另外还有一个常见坑:命令文件的编码格式。如果你在Windows下用记事本编辑,存成了UTF-8 with BOM,Claude Code解析时可能读不出前几行。建议一律用无BOM的UTF-8保存,最好直接在编辑器里设置默认编码。

4.2 CLAUDE.md内容太多,挤占上下文窗口

上下文窗口是Claude Code最宝贵的资源,而CLAUDE.md每次会话都会加载,等于白占一块空间。我有个项目前期工程化做得特别重,CLAUDE.md写到了两百多行,结果后来发现Claude的响应质量明显下降——不是模型变笨了,而是大部分上下文都用在读规范上,留给任务的余量不够了。

后来我做了两件事:一是把CLAUDE.md砍到只剩硬性规范,凡是“建议”“最好”级别的内容全部挪到命令模板里,只在需要时按斜杠命令触达;二是把一些长篇幅的参考文档移到单独文件里,比如AGENTS.md、DETAILED_STANDARDS.md,然后在CLAUDE.md里用一句话引导Claude“需要详细规范时读对应文件”。

经过调整之后,CLAUDE.md从两百多行压缩到六十行,单次会话的上下文占用明显降下来了。有一次我拿同一个任务对比,压缩前后Claude的推理表现差距还真不小,后者明显“更聪明”。

4.3 Hook脚本不生效,但没有任何报错

Hooks机制隐蔽的坑就更多了。有一回我配置了PreToolUse钩子,脚本路径、JSON格式都觉得没问题,但它就是不触发。后来发现是matcher写得太宽泛,监听的是全部工具,而脚本内部判断的是文件路径;问题出在我脚本解析参数时,字段名写错了。

Claude Code的hook事件会给脚本传一段JSON,里面包含工具调用的详细信息。不同版本、不同事件类型,字段名可能会略有差异。所以写hook脚本时,第一行最好先把传入的JSON打印到日志里看一眼,确认结构再往下写:

#!/usr/bin/env python3 import sys, json payload = json.loads(sys.stdin.read()) with open(".claude/hooks/debug.log", "a") as f: f.write(json.dumps(payload, indent=2))

也别迷信官方文档,版本更新后字段可能变。用这种调试方式把真实数据打出来,是最靠谱的排查手段。

另外还要注意退出码的语义。Hook脚本返回非零,表示“阻止本次工具调用”。这是设计好的行为,但如果你在脚本深处抛了个异常被解释成非零退出,结果就是“明明没让它拦,它却给拦了”。所以脚本内部异常建议显式捕获,成功路径一律返回0。

4.4 多项目模板冲突问题

如果你同时打开多个项目,每个项目都有各自的.claude目录,这时候跨项目的命令是会串的。比如我在A项目敲/review,它可能加载的是B项目的模板,因为Claude Code对工作区的判断是以当前打开路径为准的。

建议的做法是:模板同步只做“公共层”,项目特有模板坚决不进公共仓库。前面提到的同步脚本也要加排除规则,把项目独有的命令文件排除掉。我吃过一次亏,公共模板里放了个只适用于某个旧项目的命令,结果新项目里误触发后生成了跟技术栈完全不匹配的代码。

5. 最后分享两个小技巧

模板这套东西,看着简单,真正用好还是需要花时间迭代的。我自己的体会是:别一开始就追求“大而全”,先从一个高频场景做起,比如commit或review,用顺手了再慢慢加。

还有个小技巧,我估计很多人没注意到:Claude Code支持在对话里输入/commands查看所有可用命令;在每个命令文件里,你也可以在frontmatter中加一个argument_hint字段,这样输入命令时它会提示应该带什么参数:

--- name: gen-test description: 为目标文件生成单元测试 argument_hint: 目标文件路径 ---

试着用起来吧。模板的价值不在于“写得多漂亮”,而在于“每天真正会用到”。先把一个命令打磨到自己满意为止,再复制到其他项目里,你会发现这套体系越用越顺手,越用越离不开。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询