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 字符)。