全项目 Skills 适配:把「会写代码的 Agent」变成「会按你们规范干活的同事」
以 Cursor Agent Skills 和一套 B 端前端自测技能为例,讲清楚怎么把公司级规范接到具体项目里,而不是只堆一份永远读不完的提示词。
如果你最近也在用 Cursor / Claude Code 这类 Agent 写业务代码,大概会遇到同一类问题:
- 它很会写 Vue,但不会按你们的目录、接口封装、权限指令来写。
- 它能补一个表单,但提交按钮没有 loading、失败会清空输入、查询后页码还停在第 3 页。
- 你把规范贴进对话,下一轮又忘了;写成超长 Rule,上下文被占满,真正写代码时反而变钝。
我们在人力资源后台(Vue 3 + Vite + TypeScript + Element Plus,基于 vue-pure-admin 演进)里,把这件事拆成了两层:
- 项目宪法 :
AGENTS.md只放「这个仓库永远成立」的约束。 - 按需技能:把「提测自测」「交互走查」这类流程做成 Skill,需要时再加载。
下面以已经落地的 frontend-self-test(前端自测) 为例,讲全项目适配怎么做。
一、先分清:Rule、AGENTS.md、Skill 各管什么
很多人一上来就把所有规范塞进 .cursorrules 或 Always Apply 的 Rule。短期有效,长期一定胀。
| 载体 | 加载时机 | 适合放什么 | 不适合放什么 |
|---|---|---|---|
AGENTS.md / Always Rule |
几乎每次对话都在 | 技术栈、目录职责、最小改动、包管理器、禁止事项 | 几十页交互细则、某次需求的验收清单 |
.cursor/rules/*.mdc |
可按文件 glob 触发 | 某类文件的局部约定(例如只约束 src/api/**) |
跨页面的完整工作流 |
| Agent Skill | Agent 判断相关,或你手动 /skill-name |
可复用流程:怎么自测、怎么发版、怎么对表 | 项目定位、默认技术选型 |
Cursor 官方对 Skill 的定位也很清楚:它是可版本管理、可按需展开 的能力包。一个 Skill 就是一个目录,核心是 SKILL.md,细则可以拆到 reference.md、scripts/。Agent 先看到 name + description,真正执行时才读正文和引用文件。这叫 progressive disclosure(渐进披露):主文件保持短,细节按需打开。
一句话:
- AGENTS.md 告诉 Agent「你在哪个项目」。
- Skill 告诉 Agent「这类活按什么流程干」。
两者叠在一起,才叫全项目适配,而不是「多写了一份 Markdown」。
二、全项目适配的目标,不是「多几个技能文件」
适配做成之后,团队里任意一个人打开这个仓库,应该出现下面这些结果:
- 新同事不用先背规范。 说一句「帮我自测这次改动」,Agent 会自己读规范、圈范围、出报告。
- 公司和项目不互相污染。 公司级 B 端交互规范可以复用到多个后台;本仓库的 Vue / 目录 / 权限写法只写在项目层。
- 触发词稳定。 「自测」「提测自查」「交互规范检查」都能打到同一个 Skill,而不是靠某个人记得完整文件名。
- 上下文不爆炸。 日常改一个离职表单,不会把 14 章交互规范整页灌进 System Prompt。
我们最终落成的结构是这样:
text
hr-web/
├── AGENTS.md # 项目宪法 + 自定义 Skill 清单
├── .gitmodules # 公司 Skills 仓库作为 submodule
├── skills/ # 上游:通用 Skill 源
├── .cursor/skills/
│ └── frontend-self-test/
│ ├── SKILL.md # 流程:怎么自测、怎么汇报
│ └── reference.md # 细则:14 类交互必须/禁止
└── package.json
├── update:skills # 拉取 submodule
└── skills:sync:cursor # 同步到 .cursor/skills
这是一条很重要的链路:
text
公司 Skills 仓库 → git submodule → 同步进 .cursor/skills → Cursor 自动发现
↑
AGENTS.md 登记触发词
.cursor/skills/ 才是 Cursor 真正会扫描的项目级目录。submodule 里的源文件如果不同步过来,Agent 是看不到的。Cloud Agent、远程 SSH 也读不到你本机 ~/.cursor/skills/,所以要让全组、全环境一致,Skill 必须进仓库。
三、项目宪法怎么写:AGENTS.md 只写「永远成立」的事
以本仓库为例,AGENTS.md 没有复述交互规范全文,只锁住 Agent 在这个人力资源后台里「默认会怎么做」:
- 技术基线:Vue 3、
script setup+ TypeScript、Vite 5、Pinia、vue-i18n、只用 pnpm。 - 目录职责:页面在
src/views,接口在src/api,状态在src/store/modules,静态路由走src/router/modules。 - 请求层:禁止在页面里手写 axios,统一走
@/utils/request。 - 修改边界:最小改动、不覆盖别人未提交代码、不顺手重构无关模块。
- 验证要求:只改文档不必构建;改了代码先做静态自检;不主动
pnpm dev/ 全量 build。
这些内容每次对话都该生效,所以放宪法层。
Skill 清单则单独成节,只做「路由表」:
markdown
## 项目自定义 SKILLS 清单
当用户输入包含以下关键词时,自动调用对应自定义技能:
- **frontend-self-test**(前端自测)
- 触发关键词:自测、前端自测、提测自查、交互规范检查、
B 端后台前端代码走查、自查清单检查、后台项目自测
- 目录:skills/skills/frontend-self-test
这里有两个容易忽略的点:
- 触发词要写人话。 Agent 匹配的是 description 和对话意图,不是你脑子里的内部代号。只写
frontend-self-test,同事说「提测前帮我过一遍」,经常打不中。 - 目录可以指向源仓库,但 Cursor 消费的是同步后的
.cursor/skills。 清单是给人看的索引,发现机制仍以 Cursor 官方目录为准。
四、以自测技能为例:一个合格 Skill 长什么样
frontend-self-test 解决的不是「这段代码丑不丑」,而是:
对照《B 端后台前端通用交互实现规范》,对本次改动做提测前走查,并在对话里给出可执行的结论。
它刻意做成两层文件,对应前面说的渐进披露。
1. SKILL.md:只放流程,不放百科
Frontmatter 同时写清 做什么 和 何时做:
yaml
---
name: frontend-self-test
description: >
依据《B 端后台前端通用交互实现规范》对前端改动代码进行提测前自测:
分析 git diff 或指定文件,逐项走查请求状态、防重复提交、数据刷新、
表单校验、列表分页、弹窗抽屉、状态区分、异步任务、权限、搜索竞态、
上传下载、操作反馈等交互规则,并在对话中汇报自测结果。
Use when 用户要求前端自测、提测自查、交互规范检查、
B 端后台前端代码走查、自查清单检查。
---
description 会被注入 Agent 的技能目录,相当于「招工启事」。写第三人称、带触发场景,比「我可以帮你自测」有用得多。
正文只规定五步,并要求复制清单跟踪进度:
- 确定范围 :优先
git diff master...HEAD,有未提交改动再并上工作区 diff。 - 识别类别:12 类交互里只走查改动真正碰到的,其余标「不适用」。
- 对照细则:每条只给三种结论------通过 / 风险 / 需人工验证。
- 跑已有工程检查 :有 lint、typecheck、test 才跑;不擅自装依赖,不主动 build。
- 按固定模板汇报:不另存一份报告文件,避免仓库被 Markdown 污染。
这五步里,最值钱的不是「要检查 loading」,而是把 Agent 的自由度锁死:
- 只依据读过的改动下结论,禁止臆测没打开的文件。
- 规范里标了「判定口径」的,按口径判,不准自行加严。
- 页面结构、字段文案、业务流程归产品,Skill 只约束交互实现。
- PRD 或对话里声明过的例外,直接采纳。
没有这些边界,Agent 很容易变成「什么都想评一下的代码审查员」。
2. reference.md:细则外置,用时再读
SKILL.md 开头就写:走查前必须先读 reference.md。规范正文大约 14 类,包括:
- 请求必须有状态
- 防止重复提交
- 成功后及时更新页面
- 失败后不要丢用户输入
- 表单校验定位到字段
- 列表查询和分页
- 返回列表保留现场
- 弹窗和抽屉
- 加载 / 空数据 / 失败 / 无权限分开
- 异步长任务
- 权限
- 搜索与竞态
- 上传下载
- 操作反馈
关键设计是:必须做到 / 禁止 成对出现,能量化的写成【判定口径】。例如:
- 新增成功:以「列表已重新请求」为准,不因为排序导致新数据不在当前页就报缺陷。
- 删除当前页最后一条:页码大于 1 时必须回退上一页再加载。
- 无权限按钮:隐藏或置灰均可,同一产品内一致就不判缺陷。
Agent 最怕的是「体验不好」「不够优雅」这种不可判定句子。口径越像测试用例,走查结果越稳定。
五、通用规范接到具体项目:适配发生在哪一层
公司级 Skill 不会写「你们用 Element Plus 的哪个组件」。它只说「提交期间按钮要进入加载状态」。真正接到人力资源后台,靠的是项目宪法 + 仓库里已有实现。
下面用本仓库里已经存在的写法,说明 Agent 应该「翻译」成什么。
1. 请求状态和防重复:对上 loading + 公共弹窗
规范说:点击后按钮立刻 loading,请求结束再恢复,失败也要恢复。
项目里离职申请弹窗是典型写法:LoadingDialog 接 :loading,确认按钮也绑同一份状态,finally 里关闭。
vue
<LoadingDialog
v-model="dialog.visible"
:loading="loading"
:title="dialog.title"
destroy-on-close
>
<!-- 表单 -->
<el-button type="primary" :loading="loading" @click="saveForm">提交</el-button>
</LoadingDialog>
ts
function handleSubmit() {
loading.value = true
const request = dialog.title === "离职申请" ? leaveAdd : leaveDirect
request(params)
.then(() => {
ElMessage.success("提交成功")
close()
emits("ok")
})
.finally(() => {
loading.value = false
})
}
自测时 Agent 不该发明一套新的「全局满屏 Loading」,而应检查:
- 按钮和弹窗是不是共用
loading。 - 失败分支有没有漏掉
finally。 - 表格查询是不是只锁表格区域,而不是
v-loading整页。
二次确认也很常见。本仓库在提交前可能先弹 ElMessageBox;如果用户点取消,必须把已经置为 true 的 loading 扳回去,否则按钮会永久转圈。这就是规范里「请求失败 / 取消后页面恢复可操作」在项目中的具体形态。
2. 成功后刷新:对上「关闭弹窗 + 抛 ok」
规范要求新增/编辑/删除后页面立即更新。本仓库大量抽屉、弹窗并不在自身里改列表,而是:
ts
ElMessage.success("提交成功")
close()
emits("ok")
父列表听到 ok 再重新拉分页。自测时要顺着 emit 看一眼父页,不能只看子组件「弹了成功 Toast」就判通过。这是「只依据改动代码下结论」和「相关调用链要读到」之间的平衡:改了表单,至少要打开它的父级 index.vue。
3. 接口层:对上 src/api + 统一 request
AGENTS.md 禁止页面手写 axios。自测技能本身不审架构,但项目适配后,Agent 看到页面里新出现 axios.post,就应该当作风险:它既违反项目宪法,也绕开了统一的 401、错误提示、silent、unloading 等约定。
本仓库的 @/utils/request 已经处理了 token、登录失效跳转、权限时间戳刷新。Skill 不需要把拦截器源码抄进去,项目宪法点名「复用 request」就够了。
4. 权限:对上 v-auth / hasPerms,不要自己写角色
规范写:前端权限只控制展示和入口,不能当安全校验;不要前端写死角色。
项目里对应的是指令,而不是 if (user.role === 'admin'):
ts
// src/directives/perms/index.ts
!hasPerms(value) && el.parentNode?.removeChild(el)
走查「权限」类时,应检查:
- 按钮是否用已有指令或
hasPerms。 - 没权限时是否还发了请求。
- 无权限、加载失败、空列表是不是三种 UI。
不必要求全站统一「隐藏」或「置灰」,因为规范已经把这条例成判定口径。
5. 表单校验和失败保留:对上 el-form 的字段规则
规范要求错误打到字段旁边,提交失败不清空。Element Plus 的 el-form-item + :rules 就是项目默认解。
离职表单里,「是否加入黑名单」为是时,才出现拉黑原因、拉黑说明,并带必填规则。这是条件字段校验,自测时应看:隐藏字段被重新展示后,规则是否还在;提交失败后 formData 是否还在。
项目里有一处值得 Agent 学会的「翻译」:有的页面校验失败会额外 ElMessage.error('请完善表单信息')。规范禁止的是「只在顶部说表单有误、用户找不到字段」。字段旁已有 el-form 错误,再给一条总提示,一般不判缺陷;只有只弹全局 Toast、字段无提示,才记风险。
6. 工程检查:对上这个仓库真实有的脚本
Skill 第四步要求先读 package.json。本仓库实际是:
| 脚本 | 自测时 |
|---|---|
pnpm lint:eslint |
只对改动文件跑,可以 |
pnpm typecheck |
可以 |
pnpm test |
没有,跳过并写明 |
pnpm build |
仅用户明确要求才跑 |
「存在才运行,没有就跳过」写进 Skill,是为了防止 Agent 在人力资源后台里突然执行 npm test 或安装 Vitest。这就是项目适配:通用流程 + 本地脚本事实。
六、一次真实触发,应该长什么样
假设你改完「离职申请」和列表导出,对 Agent 说:
帮我做一下前端自测,提测前过一遍交互规范。
按适配后的行为,它不该直接改代码,而该:
第一步,圈范围:
bash
git --no-pager diff master...HEAD
git status --porcelain
# 有未提交再补:
git --no-pager diff
第二步,识别类别。以上面离职模块为例,通常会命中:请求与加载、防重复提交、表单校验、弹窗抽屉、操作反馈、上传下载;权限、搜索竞态、异步任务可能标不适用。
第三步 ,对照 reference.md 逐条给结论,风险必须带 文件:行号。
第四步 ,对改动文件跑 eslint / tsc --noEmit。
第五步 ,按模板汇报,而不是生成一份新的 自测报告.md:
markdown
## 自测结果
范围:employeeRelations/leave 下 index / addForm / exportForm
涉及类别:请求与加载、防重复提交、表单校验、弹窗、上传下载、操作反馈
### 通过(n)
- 【请求与加载】提交按钮绑定 loading,finally 关闭
- 【表单校验】必填落在 el-form-item rules
### 风险(n)
- 【防重复提交】xxx.vue:408 --- 二次确认前已置 loading,
若确认框逻辑分叉未复位,按钮可能卡住 --- 取消分支补 loading = false
### 需人工/运行时验证(n)
- 【弹窗】destroy-on-close 后再次打开是否残留校验红字 --- 打开、填错、关闭、再打开看一眼
### 不适用(n)
- 【搜索竞态】本次无输入即搜
- 【异步长任务】导出仍是同步下载,未走任务中心
工程检查:eslint 已跑改动文件;typecheck 通过;无 test 脚本已跳过
结论:存在 1 条待修复风险,修复前未达提测标准
风险按严重程度排序:重复提交导致脏数据、丢失用户输入、页面卡死,永远排在「文案不够友好」前面。
这套输出有两个好处:测试同学能当提测清单用;你补完风险后,可以让 Agent 只重走对应条目,而不是整页重审。
七、全项目铺开时,我们踩过的坑
1. 把规范全文塞进 Always Rule
交互规范很长。Always 加载会挤掉业务代码和 git diff。正确切法是:AGENTS.md 只留「有自测技能、触发词是这些」;细则留在 Skill 的 reference.md,走查当天才读。
2. 只有 submodule,不同步到 .cursor/skills
公司仓库适合当单一事实源 ,用 git submodule 升级。但 Cursor 扫描的是 .cursor/skills/ 和 .agents/skills/。我们用:
bash
pnpm update:skills # git submodule update --init --remote
pnpm skills:sync:cursor # 同步到 Cursor 能发现的目录
新克隆仓库的人如果只 pnpm install、忘了拉 submodule,就会出现「文档里写了自测技能,对话里 Agent 死活不用」。
3. description 太抽象
「帮助提高代码质量」不会被触发。「依据某某规范走查 diff,在用户说自测/提测自查时使用」才会。把团队内部已经在用的口令写进去,比写一套漂亮英文摘要有用。
4. Skill 和项目宪法抢权
自测规范是公司级、跨项目的;「不要新增依赖」「不要改 vite.config.ts」「用户可见文案要同步 locales/zh-CN.yaml 和 en.yaml」是本仓库的。不要把后者写进通用 Skill,否则同步到别的项目会误伤。反过来,也不要在 AGENTS.md 复制 14 章交互细则,升级规范时会漏改。
5. 让 Agent 顺手改业务
Skill 里写了:用户没要求修,就只汇报。这和本仓库「最小改动、不顺手重构」是对齐的。否则一次「帮我自测」会变成一次范围失控的重构。
6. 把个人 Skill 当成项目适配
~/.cursor/skills/ 只在你这台机器生效。Cloud Agent、同事、CI 里的 Agent 都看不到。全项目适配的标志是:克隆仓库 + 同步脚本之后,行为可复现。
八、一套可直接抄的适配清单
如果你要把同一套公司 Skills 接到下一个后台项目,可以按这个顺序做,不必一次发明新规范。
1. 先写项目宪法(半小时到半天)
- 技术栈、包管理器、目录职责、请求/权限/国际化入口。
- 修改边界和验证边界(什么时候允许 build,什么时候禁止装包)。
- 明确「优先复用哪些现成能力」:本仓库是
src/api、@/utils/request、v-auth/hasPerms、人员选择、组织选择、字典 Store。
2. 接入 Skill 源,而不是复制粘贴
- 公司仓库用 submodule 或包发布。
- 提供一键同步到
.cursor/skills/。 - 在
AGENTS.md登记 Skill 名、人话触发词、源目录。
3. 每个 Skill 遵守「短流程 + 外置细则」
SKILL.md控制在可扫完的篇幅(官方建议主文件不要膨胀到几百行还不停加概念)。description写第三人称,包含 WHAT + WHEN。- 判定写成通过 / 风险 / 不适用 / 需人工验证,拒绝「建议优化一下」。
- 输出模板固定,减少每次发挥。
4. 做一次项目翻译,但不要改通用规范正文
翻译发生在宪法和示例里,例如:
| 通用规范 | 本项目对应物 |
|---|---|
| 按钮加载、防重复 | loading + :loading + finally |
| 表格区域加载 | 表格 / 列表容器 v-loading,不要锁 layout |
| 字段级校验 | el-form + el-form-item rules |
| 权限控制 | v-auth / hasPerms,不写死角色 |
| 成功刷新 | emits('ok') 后父页重新拉列表 |
| 下载反馈 | 按钮 loading + downFile,长任务再升异步 |
| 工程检查 | lint:eslint、typecheck,无测试则跳过 |
5. 用真实需求打样
选一个同时有列表、弹窗、导出的模块(我们用的是员工关系里的离职),对 Agent 只说「自测」,看它会不会:
- 自己读
reference.md - 自己 diff
- 自己跳过无关类别
- 风险带行号
- 不主动改代码、不主动全量 build
这一步不过,说明触发词、目录或流程指令还没接上,先别继续铺更多 Skill。
九、自测技能之后,还可以接什么
frontend-self-test 适合做第一个项目级 Skill,因为它满足三个条件:
- 高频:几乎每个需求提测前都要做。
- 可判定:比「代码优雅」容易写成口径。
- 和项目宪法互补:一个管怎么改仓库,一个管改完像不像能提测的后台。
同一套分层上,后面很好接:
- 接口字段对齐 :只允许改
src/api的类型和页面映射,不准顺手改交互。 - i18n 补全:新增用户可见文案必须同步中英 YAML,和本仓库约束一致。
- 权限点核对:新增按钮时提示前后端权限字、指令是否成对。
- 列表页脚手架:默认带分页回第一页、空/失败分离、返回保留筛选。
仍然建议:一个 Skill 只做一类活。全项目适配是「宪法 + 技能目录」,不是「一个超级提示词包打天下」。
十、结语
Agent 不会自动变成熟悉你们后台的同事。它缺的不是更多形容词,而是三样被写进仓库的东西:
- 这个项目是什么 ------
AGENTS.md - 这类活怎么干 ------
SKILL.md里的流程和输出模板 - 对错怎么判 ------
reference.md里带口径的必须/禁止
公司规范放上游,项目通过 submodule 同步和宪法层翻译接入;Cursor 只消费 .cursor/skills。以自测技能为例,我们没有让 Agent 学习「人力资源业务」,只让它在每次提测前,按同一张清单看 loading、重复提交、刷新、校验、分页和权限。
这就是全项目 Skills 适配真正要交付的结果:换一个同事、换一台机器、换一次对话,走查标准还在。