配合 AI 编程助手
ShipKit 如何为 Claude Code、Codex、Cursor 做好准备:规则文件、处理常见任务的 skill,以及能拦住 agent 失误的测试。
ShipKit 从一开始就考虑了“让编程 agent 来改代码”这件事:约定写在 agent 会读的地方,反复要做的配置工作写成了 agent 能照着执行的步骤,容易踩错的规则由测试来检查,而不是靠记性。这些都不是强制的——它们只是普通的 Markdown 和 TypeScript,人照着读、照着做也一样。
规则文件
| 文件 | 谁会读 | 内容 |
|---|---|---|
CLAUDE.md | Claude Code,自动加载 | 常用命令、代码库地图、硬性规则 |
src/CLAUDE.md | Claude Code,在 src/ 下工作时 | 设计语言:颜色、圆角、按钮、边框 |
AGENTS.md | Codex、Cursor、GitHub Copilot、Windsurf、opencode、Zed、Amp | 指向上面两个文件,外加 skill 列表 |
DESIGN.md | 想知道“为什么”的人 | 架构背后的取舍 |
规则只有一份,放在 CLAUDE.md。AGENTS.md 不重复内容,只让其他 agent 先去读 CLAUDE.md,所以两边不会各说各的。
硬性规则挑的是一旦违反代价最大的那几条:授权检查的是权限,而不是角色;客户端数据只走一条通道(路由 loader → query → server function → Drizzle);D1 没有交互式事务;每个功能都是可删除的垂直切片;支付以事件形式到达;server function 里不做本地化;金额一律用整数分。每一条在文档里都有对应页面,建议从架构和权限读起。
在自己的项目里改了某个约定,记得同步改 CLAUDE.md。agent 只会照文件上写的做,不会猜你的本意。
Skill
那些不只是写代码、还牵涉账号、后台和密钥的常见任务,写成了 skill,放在 .claude/skills/<name>/SKILL.md。在 Claude Code 里每个 skill 就是一条斜杠命令;其他 agent 打开文件照着执行即可,AGENTS.md 里也是这样告诉它们的。
| Skill | 作用 |
|---|---|
/setup | 安装依赖,生成带随机密钥的 .dev.vars,迁移本地数据库,启动开发服务器,设置第一个管理员 |
/google-oauth | 带你走完 Google Console 的操作并把凭据接进来(必需:缺了它环境校验不通过) |
/stripe | 建立 Stripe 商品目录,配置密钥和 webhook secret,填好 src/config/plans.ts,再用 Stripe CLI 在本地跑通一次购买 |
/creem | 同上,针对备选的 Creem |
/deploy | 创建 D1 和 R2、执行远程迁移、推送 secret、部署,并完成部署后的各项对接 |
/add-feature | 生成一个新的垂直切片,各个注册表的接入行和标记一次到位 |
/delete-feature | 用经过机器验证的删除方案移除一个可选模块 |
/seo-audit | 对生产构建跑 Lighthouse,并检查 SEO 相关产物 |
/admin-api | 调用只读的管理数据 API,把返回的 JSON 整理成分析 |
skill 的分工很明确:命令由 agent 来跑,文件由 agent 来改;只有人能做的事留给你——在 Google Console 或 Stripe 后台点击、把值粘贴回来、确认任何会花钱的操作。
/admin-api 特意做成了可移植的。把 .claude/skills/admin-api/ 复制到其他 agent 的 skill 目录,或者让 agent 直接读取 /api/v1/admin/skill.md——部署后的应用会原样提供这份文件。详见 API 密钥。
防护网
agent 读错规则时,写出来的代码通常“看起来没问题”。下面这些检查把最常见的误读变成一条会失败的命令:
| 检查 | 能拦住什么 |
|---|---|
src/core/authz/registry.test.ts | 管理路由没调用 requirePermission;导出的 adminFn 没有 assertPermission;功能的 permissions.ts 没登记到注册表;在会打进客户端包的 core/server/fn.ts 里加了访问数据库的辅助函数 |
src/core/settings/handlers.test.ts | 功能的 settings.ts 引入了仅限服务端的代码(会把 cloudflare:workers 带进浏览器),或者没有登记 |
src/core/settings/i18n.test.ts | 运营设置项缺少翻译好的标签 |
src/config/private-paths.test.ts | 营销页之外新增的路由没加进私有路径列表(robots.txt 由它生成) |
src/config/plans.test.ts | 套餐和积分包的定价违反了 plans.ts 顶部写明的定价规则 |
src/core/payment/money-path.test.ts | 支付处理逻辑在应用了全部迁移的真实内存 D1 上出错 |
bun run verify:deletion | 某个功能的接入方式已经无法干净地删除 |
| CI 的 “Schema and migrations agree” | 改了 schema 却没提交对应的迁移 |
有些规则由构建而不是测试来把关。比如在 src/core/server/cf.ts 之外引入 cloudflare:workers,客户端打包会直接失败;引用了不存在的 m.* 文案键,typecheck 会报错。
推荐的工作方式
-
说清要什么,并点名 skill。“用
/add-feature加一个更新日志功能”等于把清单交给了 agent;只说“加个更新日志”,它就得自己猜要动哪些注册表。 -
配置类工作交给 skill。 Google、Stripe、Creem 和部署,直接运行对应 skill,而不是让 agent 口述步骤。skill 每一步都会用命令验证,而不是相信一行日志。
-
让它自证。 接受改动之前,让 agent 跑:
bun run typecheck bun run check bun run test动了路由、导航、登录守卫或应用外壳,再加上
bun run e2e;新增或接入了功能,再加上bun run verify:deletion <feature>。 -
自己看一遍 diff。 重点看:提交的文件里有没有密钥,有没有新冒出来的
role !== 'admin',有没有db.transaction(),有没有把文案写死在组件里、而不是放进messages/en.json和messages/zh.json。 -
迁移由你来执行。 agent 可以用
bun run db:generate生成迁移,但把它应用到生产库(bun run db:migrate:remote)应该是你有意识地去做的一步。见数据库。
局限
测试检查的是结构,不是意图。它能告诉你某个管理函数检查了权限,却判断不了检查的是不是正确的那个权限。src/CLAUDE.md 里的设计规则完全没有测试覆盖,界面上的改动请在浏览器里亲眼确认。另外,agent 的自信不算证据:所谓“完成”,是上面那些命令都通过了,而不是 agent 说它完成了。