用Cursor项目规则约束AI代码风格
文章介绍Cursor Custom Rules、项目规则与.mdc文件的配置方法,并覆盖使用场景和实践建议。目标是让AI生成的代码遵循团队命名、目录结构与API调用规范。
AI 深度解读
让 Cursor 写出能运行的代码,和让它遵守团队约定,是两回事。原文讨论的 Custom Rules,就是把反复出现在提示词里的要求保存下来,让 Agent 在合适的任务中读取:服务层怎么校验、功能目录怎么组织、工具函数怎么补测试,都可以提前交代。
作者的结论是,这些规则能减少重复提醒,改善生成代码的一致性。不过,文章没有提供对照实验,配置示例也有容易误读的地方。值得带走的是规则的组织方法,以及它与工程检查之间的边界。
团队约定应该放在哪里
原文区分了两种规则。Project Rules 存放在 .cursor/rules/,使用 .mdc 文件,可以提交到版本控制,供仓库协作者共同使用。User Rules 保存在个人 Cursor 设置中,适合个人偏好,并可跨项目使用。
这一区分解决的是约定归谁管理。服务层必须使用 Zod,属于项目规范;个人希望 Agent 如何组织回答,适合留在用户设置中。把团队要求只放在个人配置里,其他成员就无法随着仓库一起获得它。
规则也不只是几句提示词。原文列出了四类信息:description 解释用途,文件模式确定目标范围,正文描述具体做法,文件引用补充项目上下文。例如,@src/lib/validators.ts 可以把现有校验实现作为参考。
引用现有文件的价值,在于减少描述上的歧义。「遵循项目风格」很模糊,指向一个已有实现,Agent 才有可模仿的对象。但参考文件也需要维护,否则规则可能持续引导它复制过时写法。
对于简单的项目级说明,原文还提到 AGENTS.md。如果只需要交代共同约定,它可以作为入口;需要按文件或手动触发时,.cursor/rules/*.mdc 提供更细的控制。两者的取舍,主要看指令需要多细的作用范围。
规则什么时候生效,比写了什么同样重要
原文列出四种应用模式:
Always Apply:持续应用的通用要求。Apply Intelligently:根据任务相关性选择,规则描述参与判断。Apply to Specific Files:面向特定文件模式。Apply Manually:由开发者明确选择触发。
例如,服务层校验适合关联服务文件;某项只在特定任务中需要、又不对应固定文件的工作流程,可以考虑智能应用。description 因而需要讲清适用条件,不能只写一个含糊的名称。
Cursor Rules 提供给 Agent 的是指令,不是确定性的执行约束。
原文明确提醒,规则不会自动覆盖 Cursor 的所有 AI 功能,例如 Tab 补全和行内编辑。即使 Agent 读取了「必须校验响应」,也不能据此认定生成结果已经满足要求。测试、lint、类型检查、CI、安全检查和代码审查仍然需要承担各自的检查职责。
创建入口是 Customize → Rules → Add Rule,也可以在 Agent 中使用 /create-rule,从当前对话创建规则。命令面板同样提供入口,但原文没有给出各操作系统的具体快捷键。规则创建后,可以在 Customize → Rules 中按作用范围管理。
这里有个配置细节需要打问号:文章的多个示例同时包含 globs 和 alwaysApply: true,却又把它们描述为针对特定文件。读者不能直接从这些示例推断,最终一定只在匹配文件时生效。配置时应明确选择所需模式,再检查生成的规则内容。
四类重复劳动,最适合先写成规则
作者给出的用例都比较具体:它们已有明确约定,只是开发时容易遗漏。
第一类是服务层的 Zod 校验。规则要求请求和响应都经过校验,并引用已有模板:
description: Enforce Zod schemas in service layer globs: ["src/services/**/*.ts"] alwaysApply: true referencedFiles: ["src/lib/zod-templates.ts"]
Always use Zod to validate both request and response payloads. Reuse schema patterns from zod-templates.ts. Do not allow untyped or loosely typed data to go through the service layer.
重点看正文中的 both request and response payloads:要求覆盖两个方向,而不只是给函数参数补类型。对于 TypeScript 项目,声明一个接口,并不会自动验证运行时收到的数据;这正是校验规则要补上的环节。
不过,这段应当作为原文示例阅读。文章前面称需要 JSON 文件,后面实际介绍的是 Markdown .mdc,示例又把元数据挤在同一行,没有展示清晰的完整文件格式。它还使用了 referencedFiles,而另一处介绍的是 @filename 引用,两者的关系没有说清。因此,不宜把这段直接当成可复制的配置模板。
第二类是功能目录结构。作者希望 src/features 下的新功能统一包含 index.tsx、hooks.ts、types.ts 和 api.ts,分别承载入口、自定义 Hook、局部类型和 API 调用。它能减少 Agent 每次自由决定目录布局的情况,前提是团队已经认可这套拆分方式。
第三类是 Vitest 测试。规则面向 src/utils/**/*.ts,要求新增或修改工具函数时,同时创建对应的 .test.ts,并遵循现有测试的命名和组织方式。这能提醒 Agent 把测试纳入任务,但测试文件存在,不代表断言有效,更不代表覆盖率已经达到某个目标。原文没有提供覆盖率数据。
第四类是 tRPC 路由。下面是原文的指令正文,用于约束新 procedure 的类型和包装方式:
When generating new procedures, use z.infer for input/output types. Use the protectedProcedure or publicProcedure wrapper from the existing router setup. Refer to src/server/api/_utils.ts for common logic.
重点看 protectedProcedure 和 publicProcedure 所在的一句:它要求复用现有 router 的封装。至于某条路由应当选择哪个包装器,仍然需要结合业务权限判断,文章没有给出自动判断标准。
这几个例子的共同做法,是把规则写成可操作的动作,并指向已有代码。相比「保持高质量」「遵循最佳实践」,这种指令更容易检查,也更容易在输出不符合预期时修改。
我的判断
我认同作者把规则纳入团队协作的方向。项目已经存在稳定模式时,把约定提交到仓库,可以减少每个人重复描述同一件事,也让规则修改有机会经过评审。
但文章对效果的表述偏乐观。它使用了「每次」「无需返工」一类说法,却没有给出规则启用前后的错误率、返工次数或其他对照数据。作者表达了个人使用感受,这仍然属于经验之谈,不能据此承诺一般团队会获得同样结果。
它的适用前提也很明确:团队得先有可复用的约定。若目录结构仍在争论,或者不同服务采用不同校验方式,先写一条覆盖全仓库的强指令,可能只是把分歧传播得更快。
与每次手写提示词相比,规则适合保存稳定、重复的上下文;临时任务要求仍然可以放在当次对话里。与 lint、测试和 CI 相比,规则能引导生成过程,却不能提供相同程度的确定性验证。两类手段配合使用,才符合原文后半部分给出的边界。
原文注明文章最初发表于 2025 年 5 月,并在 2026 年 10 月更新。不过,更新时间无法消除示例里的格式歧义。阅读这篇文章时,我会采纳它的组织思路,对具体配置字段保持核对意识。
能拿来做什么
- 从项目里最常被重复提醒的一条要求开始,例如服务请求与响应使用 Zod 校验,同时引用现有实现。先观察 Agent 的实际输出,再逐步补充规则。
- 为团队共享要求创建 Project Rules,并在评审中同时检查正文和应用范围,尤其要核对是否确实需要
alwaysApply: true。 - 如果项目已经统一功能目录或 Vitest 测试布局,就把具体文件名、放置位置和参考文件写清楚,避免只留下「保持一致」这样的抽象要求。
- 在 tRPC 项目中,把现有 router 包装器和公共逻辑路径加入指令,并继续通过测试、类型检查与代码审查核验生成结果。