博客文章
Cocos 游戏项目的 Claude Code 配置实践(8):自定义命令
Skills 之外,Claude Code 还有更轻量的 .claude/commands/ 机制:一个 Markdown 文件就是一个斜杠命令。分享 Commands 和 Skills 的关系、参数传递、动态 Shell 注入特性,以及我在用的几个命令和踩坑经验。
Cocos 游戏项目的 Claude Code 配置实践(8):自定义命令
系列文章目录:总览 → CLAUDE.md → Rules → Skills → MCP → Hooks → Agents → [自定义命令]
朋友们大家好,我是 bit老宫 呀,一个拥有12年一线开发经验的CocosCreator游戏开发者,代表作 《比特小队》 《宫爆老奶奶家族篇》
系列正篇七篇写完了,本来以为可以收工了。但用了一段时间后发现,有个东西一直在用却没有单独介绍过——自定义命令(Custom Commands)。
第四篇讲 Skills 的时候,重点介绍的是 .claude/skills/ 目录下的完整 Skill 体系:带 YAML 配置、多文件支持、适合封装复杂的 SOP 流程。但 Claude Code 其实还有一套更轻量的机制——.claude/commands/,一个 Markdown 文件就是一个斜杠命令,不需要建目录、不需要写复杂的配置。
如果说 Skills 是「操作手册」,那 Commands 就是「便签纸」——写几行提示词,贴上去就能用。
Commands 和 Skills 是什么关系
先说结论:两者底层是同一套系统。.claude/commands/ 是早期的路径,.claude/skills/ 是后来扩展的路径,frontmatter 支持的配置项完全一致。同名时 Skills 优先。
核心区别在于文件组织方式:
| Commands | Skills | |
|---|---|---|
| 路径 | .claude/commands/name.md |
.claude/skills/name/SKILL.md |
| 文件结构 | 单个 .md 文件 |
目录,可包含辅助文件 |
| 适合场景 | 简单命令、快速创建 | 复杂流程、需要参考文件 |
| 辅助文件 | 不支持 | 支持(reference.md、脚本等) |
什么时候用 Commands?命令逻辑简单,一个 Markdown 文件就能写清楚的时候。
什么时候用 Skills?流程复杂,需要附带参考模板、映射表、辅助脚本的时候。
比如我之前的 /create-window,需要 XML 解析规则、类型映射表、代码模板——内容太多,拆成 Skills 目录更清晰。但像「查一下项目里有多少个 TODO」「帮我格式化一段 JSON 配置」这种简单任务,用 Commands 一个文件搞定。
文件格式
放在 .claude/commands/ 目录下,文件名就是命令名。比如 check-todo.md 对应 /check-todo:
---
description: 扫描项目代码中的 TODO 和 FIXME 注释
---
扫描 assets/script/ 目录下所有 .ts 文件,找出所有 TODO 和 FIXME 注释。
输出格式:
- 按文件分组
- 每条注释显示文件路径、行号、完整内容
- 末尾统计总数
就这么简单。一个 description,加上正文的提示词,保存,就能在对话里输入 /check-todo 触发。
frontmatter 配置项
和 Skills 共用同一套配置,常用的几个:
| 字段 | 说明 | 示例 |
|---|---|---|
description |
命令用途描述 | 创建 ECS 组件脚手架 |
argument-hint |
参数提示,自动补全时显示 | [组件名] [分类] |
allowed-tools |
限制可使用的工具 | Read, Grep, Glob |
disable-model-invocation |
设为 true 则 AI 不会自动触发 | true |
user-invocable |
设为 false 则用户不可见,仅 AI 调用 | false |
model |
指定使用的模型 | sonnet |
大部分情况下只需要 description,其他都是可选的。
项目级 vs 用户级——这个区别很重要
Commands 有两个层级:
| 层级 | 路径 | 作用范围 |
|---|---|---|
| 项目级 | .claude/commands/ |
当前项目,团队共享 |
| 用户级 | ~/.claude/commands/ |
所有项目,个人专属 |
项目级命令跟随仓库提交,团队里每个人都能用。上面的 /check-todo 就适合做项目级——团队统一的代码检查习惯。
用户级命令才是我觉得被严重低估的功能。它是你的个人效率工具箱,不管打开哪个项目都能用。
举个例子:我经常需要在不同项目之间切换,每次开一个新的 Claude Code 会话,都要先问一遍「帮我看看这个项目的结构」。于是我在 ~/.claude/commands/ 里加了一个通用命令:
---
description: 快速了解当前项目的结构和技术栈
argument-hint: [关注点(可选)]
---
快速分析当前项目:
1. 读取 package.json(或等效配置文件),列出项目名称、主要依赖和脚本命令
2. 扫描项目目录结构(只展示前两层)
3. 如果有 README.md,提取项目简介
4. 如果有 CLAUDE.md,读取并总结关键信息
5. 用一段话总结:这是一个什么项目、用了什么技术栈、目录怎么组织的
如果用户指定了关注点($ARGUMENTS),重点分析该方面。
保存为 ~/.claude/commands/scan-project.md,以后任何项目里输入 /scan-project 就行。也可以 /scan-project ECS架构 聚焦到特定方面。
参数传递
Commands 支持通过 $ARGUMENTS 接收用户输入的参数:
| 占位符 | 说明 |
|---|---|
$ARGUMENTS |
全部参数,原样传入 |
$ARGUMENTS[0]、$ARGUMENTS[1] |
按位置获取参数(从 0 开始) |
$0、$1、$2 |
简写形式 |
示例——一个快速查找 API 用法的命令:
---
description: 在项目中搜索指定 API 的所有调用方式
argument-hint: [API名称]
---
在 assets/script/ 下搜索 $0 的所有调用位置。
对每处调用:
- 列出文件路径和行号
- 展示调用上下文(前后各 2 行)
- 简要说明调用目的
最后总结:这个 API 一共被调用了几次,主要用在什么场景。
保存为 .claude/commands/find-api.md,使用 /find-api GlobalEvent.emit 就能快速定位所有事件发送点。
动态 Shell 注入:!`command`
这是一个容易被忽略的高级特性。在命令正文里用 !`shell命令` 语法,可以在命令发送给 AI 之前先执行 shell 命令,把输出结果嵌入到提示词里。
注意:这是预处理,不是让 AI 执行命令,而是在加载命令时就已经跑完了。
实际例子——一个查看当前 Git 变更的 review 命令:
---
description: 审查当前未提交的代码变更
disable-model-invocation: true
---
审查以下代码变更,重点关注:
- 是否有类型错误
- 是否违反 ECS 架构规范(组件不能有逻辑、系统不能有状态)
- 是否有遗留的 console.log
当前 git diff:
!`git diff --cached`
未暂存的变更:
!`git diff`
执行 /review-changes 时,两段 git diff 的输出已经填充好了,AI 直接看到完整的变更内容开始审查。不需要 AI 自己去跑 git 命令,省了一步交互。
安全提醒:disable-model-invocation: true 在这里很重要。带有副作用的命令(比如涉及 git 操作、文件删除的)一定要加这个配置,防止 AI 在不合适的时机自动触发。
游戏项目里我在用的几个 Commands
/quick-component — 最简版 ECS 组件创建
Skills 里的 /create-component 是完整版——读现有组件、确认属性、生成代码。但有时候你就是需要一个空的标记组件,不需要那么多步骤:
---
description: 快速创建一个空的 ECS 标记组件
argument-hint: [组件名] [描述]
---
在 assets/script/ecs/component/mark/ 目录下创建标记组件 $0。
直接生成代码,不需要确认:
```typescript
import { ecs } from "../../../header";
const { ecsclass } = ecs._ecsdecorator;
@ecsclass("$0", { describe: "$1" })
export class $0 extends ecs.Component {
reset(): void {}
}
```
文件名:$0.ts(首字母大写)
/quick-component TagBoss Boss标记 — 3 秒搞定,不需要交互。
/entity-check — 检查实体配置完整性
---
description: 检查实体配置文件中引用的组件是否都已实现
---
1. 读取 extensions-config/entity/ 目录下所有 .json 文件
2. 提取每个实体配置中引用的组件名称
3. 在 assets/script/ecs/component/ 目录下检查对应的组件文件是否存在
4. 列出所有「配置了但代码未实现」的组件,按实体分组显示
/daily-summary(用户级)— 今天写了什么
---
description: 汇总今天的代码变更
disable-model-invocation: true
---
分析今天的 git 提交记录:
!`git log --since="6am" --oneline --stat`
汇总为简报:
- 今天一共提交了几次
- 涉及哪些模块(ECS / UI / 配置 / 其他)
- 每个模块的主要变更内容
- 新增/修改/删除的文件数
这个放在 ~/.claude/commands/ 里,任何项目都能用。
什么时候该用 Commands 而不是 Skills
| 场景 | 用 Commands | 用 Skills |
|---|---|---|
| 逻辑简单,一个文件写得下 | ✅ | |
| 需要附带映射表、模板等参考文件 | ✅ | |
| 个人工具,跨项目通用 | ✅ | |
| 团队共享的复杂 SOP | ✅ | |
| 快速原型,先试试效果 | ✅ | |
| 成熟流程,需要稳定输出 | ✅ |
我的建议:先用 Commands 快速验证想法,好用了再考虑要不要升级成 Skills。 很多命令永远不需要升级——简单就是它的优势。
踩坑经验
坑一:文件名就是命令名,别用中文
命令名从文件名提取。创建组件.md 虽然技术上可以创建,但输入 /创建组件 容易出问题(终端编码、自动补全等)。老老实实用英文加连字符:create-component.md。
坑二:description 不写或写得太模糊
不写 description,AI 会用正文第一段当描述。如果第一段是一大堆具体步骤,AI 就搞不清楚这个命令「大概是干什么的」,自动触发的判断会出问题。哪怕命令很简单,也写一句清晰的 description。
坑三:忘了 disable-model-invocation
有一次我写了一个 /clean-build 命令用来清理构建产物。没加 disable-model-invocation: true,结果 AI 在一次对话中自作主张触发了这个命令,把构建缓存清了……不是什么大事,但白等了一次完整构建。有副作用的命令必须加 disable-model-invocation: true。
坑四:用户级命令里写了项目特定路径
~/.claude/commands/ 里的命令是跨项目的,但我有一次在里面写死了 assets/script/ecs/,换个项目就找不到路径了。用户级命令要保持通用,如果需要项目特定路径,应该放到项目级的 .claude/commands/ 里。
和 Skills 搭配使用
在我的项目里,Commands 和 Skills 是互补的:
- Skills(4 个):
/create-window、/create-component、/create-system、/project-info— 复杂流程,需要读 XML、查映射表、参考现有代码 - Commands(5 个):
/quick-component、/find-api、/entity-check、/review-changes、/check-todo— 简单任务,一个文件搞定
加上用户级的 /scan-project 和 /daily-summary,日常开发中常用的快捷操作基本都覆盖了。
关键是:不要为了用而用。只有你发现自己在对话框里反复输入同样的指令时,才值得封装成命令。一个你用不到的命令,比没有还糟糕——因为它的 description 会占用上下文预算(默认上限是上下文窗口的 2%,约 16000 字符)。