字节笔记本
2026年8月29日
Skills 和 Cursor Rules 其实是同一套抽象
很多人把 Skills 和 Cursor Rules 当成两套互相替代的产品。底层其实是同一件事:一段带触发条件的 Markdown,在对的时候被塞进代理的上下文。差别几乎只在「什么时候塞进去」,以及旁边能不能挂脚本和参考文件。
搞清这件事,仓库里的规则就不会一边写 .mdc、一边再抄一份 SKILL.md。
同一套东西,两套文件名
两边都是「元数据 + 正文」:
- 元数据告诉运行时什么时候该加载(始终、按文件、按描述、手动)
- 正文是给模型看的说明,加载之后就是普通上下文
Cursor 的 Project Rule 是 .cursor/rules/*.mdc:
---
description: 后端 RPC 服务约定
alwaysApply: false
---
- 每个服务单独放 `src/services/`
- 边界处校验输入,再往里传
- 错误返回带 `code` 和 `message` 的对象,不要抛裸字符串Agent Skill 是一个目录加 SKILL.md,开放标准在 agentskills.io,参考实现在 anthropics/skills:
---
name: rpc-conventions
description: 写或改后端 RPC 服务时用。覆盖目录、校验和错误格式。
---
- 每个服务单独放 `src/services/`
- 边界处校验输入,再往里传
- 错误返回带 `code` 和 `message` 的对象,不要抛裸字符串正文可以一字不差。换的是包装:Rule 是单文件加 alwaysApply / globs;Skill 是文件夹,还可以带 scripts/、references/、assets/。Cursor 文档也把 Skills 写成按需发现的步骤型 how-to,Rules 写成始终生效的声明式约束。见 Cursor Rules 和 Cursor Agent Skills。
真正差在加载时机
模型不会跨请求记住你昨天说过的规矩。Rules 和 Skills 都是在补这块,只是付费方式不同。
| 触发 | Cursor Rule | Agent Skill |
|---|---|---|
| 每条对话都带 | alwaysApply: true | 不这么干(只有 name + description 常驻) |
| 打开某些文件才带 | globs: src/**/*.tsx | paths(Cursor 扩展字段,按文件才露出) |
| 代理自己判断 | alwaysApply: false + description | description 对上任务再读全文 |
| 你手动点名 | 聊天里 @rule-name | /skill-name |
Skill 的加载分三步,规范里叫渐进披露:启动时只读 name 和 description;任务对上了再读 SKILL.md 全文;需要时再打开旁边的脚本或参考文件。一百个技能只占一小段目录,不会把窗口撑满。
alwaysApply: true 的 Rule 没有这层缓冲:全文每次都进上下文。所以长流程、检查清单、带脚本的发版步骤不该写成 Always Apply。Cursor 自己也提供 /migrate-to-skills:把「Apply Intelligently」、没有 glob 的动态 Rule,以及 slash command,收成 Skill。alwaysApply: true 和带 glob 的 Rule 不会被迁走,因为它们的触发条件和 Skill 不一样。
仓库里怎么放
常见位置(项目级优先于用户级):
| 用途 | 路径 |
|---|---|
| Cursor 项目规则 | .cursor/rules/*.mdc |
| Cursor 技能 | .cursor/skills/<name>/SKILL.md |
| 跨客户端技能 | .agents/skills/<name>/SKILL.md |
| 用户级技能 | ~/.cursor/skills/ 或 ~/.agents/skills/ |
| 短全局说明 | 仓库根的 AGENTS.md(或嵌套目录里的同名文件) |
新技能优先写进 .agents/skills,Claude Code、Cursor、Codex、Gemini CLI 这类兼容客户端都能扫到,不必维护三份拷贝。旧的 .cursor/rules 不用删光:该常驻的继续当 Rule。
Team Rules(Cursor 团队后台)是另一条线:纯文本、可强制、优先级高于项目规则。它不走 .mdc 目录,也不被 /migrate-to-skills 处理。组织级红线放那里,项目流程放仓库。
怎么选:四条就够
按「这次对话必须带着吗」选,不要按品牌选。
- 每次请求都要守住的短约束 → Always Apply Rule。版权头、禁止改
dist/、提交信息格式。控制在几十行,官方建议单条 Rule 别超过 500 行,大了就拆。 - 只在某类文件上成立 → 带
globs的 Rule。组件命名、CSS 模块位置、migration 必须有up/down。打开匹配文件才注入,比 Always Apply 便宜。 - 偶尔才走的多步流程 → Skill。发版检查、修某个内部 SDK、按仓库规矩开 PR。正文可以长,旁边可以挂脚本;用不到时几乎不占窗口。
- 你想自己决定何时跑、代理不许自作主张 → Skill,并加上
disable-model-invocation: true,只用/skill-name触发。部署、发消息、任何有副作用的清单都适合。
AGENTS.md 留给 clone 下来就要知道的短事实:测试命令、分支策略、绝对不要做的事。专项流程塞进去,无关任务也会一直背着。
动手:把一条动态 Rule 收成 Skill
假设你已经有一条「智能应用」的发版规则,没有 glob。frontmatter 只写 description(例如「把当前分支发到 staging 时用」),alwaysApply 为 false。正文三步:跑测试、打 tag 推到 origin、CI 绿了再切 staging。
这正是 Cursor 内置 /migrate-to-skills 会收走的类型。也可以手写:在仓库建 .agents/skills/ship-staging/SKILL.md,name 用 ship-staging,description 写清何时用、何时不要用(不要在只改文案时触发)。正文同样三步,失败就停,不要自己发明回滚。
description 是路由键。写「什么时候该用」,最好带一句「什么时候不该用」。代理只靠这句话决定要不要打开全文。空泛的「帮助部署」几乎等于没写。
需要脚本就放在同目录的 scripts/ 下,正文用相对路径指过去,例如 ship-staging/SKILL.md 旁边放 scripts/smoke.sh。Cursor 还可以给 Skill 加 paths 字段(如 src/**/*.ts),只在碰这些文件时才露出,行为和带 glob 的 Rule 接近,但全文仍然是按需加载。
常见踩坑
- Always Apply 里贴完整风格指南。模型本来就会常见风格,重复的约定交给 linter。Rule 只写你们仓库特有的、而且反复踩过的坑。
- 同一段说明既当 Rule 又当 Skill。迁完删掉旧的动态 Rule,否则描述对上时会加载两次。
- Skill 正文复述代理已经会的工具。别写「用 git 提交」这种常识。写你们团队的验收:测哪些、谁有权推、失败怎么回。
- 密钥写进文件。Rule 和 Skill 都会进 Git。地址和 token 走环境变量,文件里只写怎么读。
- description 写成长文案。目录阶段只看这一段。太长会被截断,关键词丢了就不会被点到。把触发场景放第一句。
改完在一次干净会话里试两句:一句应该触发(把这支分支发 staging),一句不该触发(把 README 错别字改了)。Skill 只在第一句被打开,才算路由写对了。Cursor 里也可以问它当前加载了哪些 Rule / Skill,对上文档再提交。
和 MCP、命令怎么并列
三层别搅在一起:
- MCP:给代理新的手,连数据库、浏览器、内部 API。
- Rules / Skills:给代理说明书。前者常驻或按文件,后者按任务。
- Slash command:在 Cursor 里正在收进 Skill(加上 disable-model-invocation 就能保留「只有你能点」)。Claude Code 也把 .claude/commands/ 和 Skill 合成同一套斜杠命令。
所以「Skills 取代了 Rules」这句不成立。被收走的是那种其实是流程、却写成了动态 Rule 的文件。真正的常驻约束还该是 Rule。开放标准那一层,则让同一份 SKILL.md 能在 Cursor、Claude Code 和其他兼容客户端里复用,官方目录见 anthropics/skills。
落地时按这个顺序就行:先把 Always Apply 砍短,再把带步骤的动态 Rule 迁成 Skill,新流程直接写进 .agents/skills。同一套抽象,两套触发,仓库里只维护一份正文。