设置项目,一次一个切片
每次调用一个切片,通过一个固定的循环:
参考 → 研究 → 连线 → 计划 → 执行 → 本地门控 → 协调 → 生产门控 → 协调 → 将手动步骤交给用户 → 提交
slices/ 目录中的文件是参考,而不是脚本。 它们编码了一个经过验证的完整技术栈,并且——更有价值的是——那些花费了实际时间的陷阱:pnpm init 写入的 devEngines 块随后会被 corepack 拒绝,create-next-app 在 apps/web 内部打开的第二个 pnpm workspace。这些推理是有持久价值的。而版本固定、CLI 标志和 API 形状则不是。直接按照参考运行切片会在某个已经变化的东西上失败。
因此,你执行的计划永远不是参考本身。它是一份新的计划,为这个项目写入这个项目中,基于参考加上研究表明当前真实情况的内容。而且因为这个计划是在被证明之前写好的,循环不会在门控通过时结束——它在计划被修正以匹配实际可行的方法时结束,同时保存在两个位置,并且用户已经收到了只有人类才能进行的检查的简短列表。
技术栈是固定的:pnpm workspace · 通过 OpenNext 在 Cloudflare Workers 上运行的 Next.js · GraphQL Yoga Worker · Drizzle + Postgres,本地用 Docker,生产环境通过 Hyperdrive 使用 Neon · Tailwind + shadcn · 可选 Resend、Better Auth 和 Stripe。如果用户想要不同的技术栈,请直说——这个技能没有其他的。
0. 调度
/setup-project [切片] 构建一个切片。参数是可选的,并通过编号或名称来指定切片——01、web shell、database、auth。根据 reference/slices.md 解析它;如果匹配不到任何内容,请说明并列出名称,而不是猜测。
ls docs/setup/ 2>/dev/null # 该项目实际构建了哪些切片
git status --short # 工作树脏意味着最后一个切片可能未完成
docs/setup/ 是已构建内容的记录,而不是可能构建内容的预测。 切片文件存在于其中,是因为该切片已构建并通过了绿色门控。因此,编号最高的文件就是“我们在哪”的答案,并且没有单独的标记需要保持同步。
未指定切片——在推荐之前始终展示目录。 从 reference/slices.md 列出每个切片及其编号、名称,以及 docs/setup/ 是否显示它已构建,然后推荐一个,并在运行它之前获得确认。这也适用于第一次运行:首先确定项目名称(§1),然后展示目录(所有未构建的切片,下一个是切片 00),在构建之前确认。永远不要跳过目录或确认,因为下一步看起来很明显。
| 状态 | 做什么 |
|---|---|
没有 docs/setup/ | 首次运行:确定项目名称(§1),展示目录,确认切片 00 |
| 指定了切片 | 构建它 |
| 未指定切片 | 展示目录,推荐最高构建编号 + 1,并确认 |
切片 99 在这个算术之外。 它是安全审计:不构建任何东西,只需要切片 00,并且可以针对任何已存在的内容重新运行,而不是占据链中的一个位置。因此,99-security-audit.md 存在于 docs/setup/ 中并不意味着链已完成,并且“最高构建编号 + 1”必须忽略它——一个包含 00–05 加上 99 的仓库,其下一个要构建的是 06。它也排除在 --through 范围之外,因为范围是构建链,而对不存在的切片进行审计是审计了无内容。在任何添加了公共界面的切片后推荐它,并显式命名它:/setup-project 99。
永远不要在一次调用中构建两个切片。当切片被提交时停止。
一个跳过前面的切片。 如果参数比已构建的切片多了一个以上,请命名它跳过的切片以及它们构建的内容,然后让用户决定。这个链是真实的:04 需要 02 和 03,05–07 修改较早切片编写的文件,因此缺少先决条件是一个硬性的 docs:check 错误,而不是警告。reference/slices.md §Dependencies 给出了推理。
1. 仅首次运行:项目名称
小写字母、数字和连字符——它将变成 npm scope(@name/db)和 Worker 前缀(name-web、name-graphql)。如果仓库目录名称已经符合要求,则默认使用它。询问一次;之后的每个切片都从 package.json 中读取它。
2. 阅读参考切片
在开始任何其他操作之前,完整地阅读 slices/NN-*.md,并阅读 reference/slices.md 以了解该切片的门控证明了什么以及需要哪个账户。代码块之间的散文是保持其价值的部分——阅读它以获取推理,并将其中的每个版本号、标志和文件路径视为需要检查的声明,而不是事实。
如果切片需要用户没有的账户(Cloudflare、Neon、Resend、Stripe),请立即说明。缺少账户不会阻碍编写计划,但它会使切片在本地部分已经提交后,在其生产门控中途陷入困境。
向后看,而不是向前看。 阅读项目已有的内容——docs/setup/、CLAUDE.md、较早切片编写的技能文件——并遵循它们设定的约定,以便此切片能够融入其中,而不是重新发明它们。反过来永远不会发生:没有切片假设后面的一个切片(无论是否命名)将会被构建——是否构建是用户在调度时(§0)的决定,而不是参考可以依赖的东西。如果某个已有的约定现在看起来对此切片所需的内容是错误的,请说明并让用户决定,而不是默默地覆盖它或默默地遵守它。
淘汰此切片取代的临时产物。 有些东西只为了在真正的东西出现之前证明一个机制而构建——packages/mock 是第一个也是最明显的例子:切片 0 创建它来证明在没有任何真实包通过它运行时的测试框架。临时产物永远不会命名其继任者,因为哪个切片取代它是由调度(§0)决定的,而不是参考。义务是相反的:每个切片都会查看已有的内容,并将任何它现在使之多余的内容的移除折叠到自己的计划中,以及任何描述这些内容的 CLAUDE.md 行。
因此,如果 packages/mock 仍然存在,这个切片就是工作区获得的第一个真实的东西,并且淘汰它是此切片工作的一部分。同样的规则适用于任何后面的切片留下的东西——一个被真实 resolver 替换的静态 resolver,一个变成绑定的占位符值。
那个机制只适用于有继任者的产物,所以请声明没有继任者的那些。 packages/mock 被淘汰是因为一个真实的包显然会替换它。没有东西显然会替换 sendTestEmail:切片 6 添加了真正的验证邮件_和它并存_,切片 7 将其描述为模式的一部分,并且一个发送真正邮件的未经认证的变更将作为一个永久特性发布。没有切片是错误的——移除没有所有者。等待后面的切片注意到不是一个机制;这是一种希望。
因此,每个切片都以一个 留下的东西 块结束,该块命名了两个列表,在产物创建时编写,而不是在有人发现它时:
- 临时的——它是什么,为什么存在,以及淘汰它的条件。如果没有后面的切片能合理地满足该条件,请在那一行中说明。一个诚实的“没有东西淘汰它”就是完成工作的条目。
- 接受的——一个明知故犯的风险,谁能触及它,以及推理。记录下来,以便后面的切片可以重新决定它而不是重新发现它,并且使得继承的默认值(Yoga 在生产环境中提供 GraphiQL)与选择的默认值区分开来。
切片 99 将这些作为交叉检查——绝不是作为其输入,因为分类账只能包含某人已经想到要写下来的内容。它首先读取代码。
3. 研究当前真实的情况
这是使参考可以安全使用的步骤,因此请有意且廉价地执行它。对于此切片安装或配置的每个工具,检查实际情况而不是参考:
npm view <pkg> version # 固定版本实际上应该是什么
npx <cli> --help # 标志,以及哪些提示是非交互式的
然后阅读切片结构上所依赖的任何东西的官方文档——框架当前的适配器指南、运行时的兼容性标志、库当前的 API 形状。优先使用供应商自己的文档而不是参考中对它们的总结,并记录它们不一致的地方。
阅读安装时打印的内容,而不仅仅是其退出代码。 一个被合并到另一个包、重命名或废弃的包仍然可以安装,仍然导出相同的名称,并且仍然可以编译——npm view <pkg> version 报告一个健康的版本,并且参考的代码块针对它是绿色的。pnpm add 输出中的 [WARN] deprecated … 这一行是唯一显示它的地方。切片 5 就是这种情况:@react-email/components 在五个月前已被合并到 react-email 中,并且没有其他任何地方说明这一点。
npm view <pkg> deprecated # 非空意味着参考正在描述一个废弃的包
写下你发现的内容及其位置。参考与当前文档之间的矛盾是此步骤的全部输出,它们将进入你即将编写的计划。
3b. 连接到已有构建的内容
一个落地后未连接的切片是一个没人能知道其是否工作的切片。在编写计划之前,查看 docs/setup/ 所说的存在的内容,并询问此切片现在与哪些层有接口——然后提议在此切片中证明该接口,而不是留给以后可能永远不会构建的切片。
四个规则防止这变成范围蔓延:
- 仅向后连接。 连接到已经构建的切片。永远不要推测那些可能永远不会存在的切片——这与
adapting.md的“一个切片可以引用它前面的任何切片,永远不能引用它后面的一个”规则相同。 - 这是一个探测,而不是一个功能。 标准是_如果接口被破坏将导致失败的一件事_。如果需要产品决策,那它本身就是一个切片,而不是一个探测。
- 这是一个提议。 连接会扩大切片范围,因此它与其他所有内容一起进入 §4 审查,并且需要用户的同意。
- 它有一个门控行, 否则它什么也证明不了。
探测是一个临时产物,§2 的规则已经涵盖了它的移除:它没有说明什么将取代它,并且任何取代它的切片都会淘汰它。
4. 将执行计划写入项目
node <技能目录>/scripts/install-plan.mjs \
--repo <仓库目录> --name <项目> --slices NN
<技能目录> 是此技能安装的位置:~/.claude/skills/setup-project、~/.agents/skills/setup-project 或项目自己的 .claude/skills/setup-project。该脚本相对于自身解析其切片,因此它可以从任何这些位置正确运行。
这将 slices/NN-*.md 渲染到 docs/setup/ 中,并解析 __PROJECT__ 和 __DOCS__,并且不写入其他任何内容——没有索引,没有源列表。docs/setup/ 只包含切片文件,每个构建的切片一个,并且 ls 就是索引。没有安装、构建或提交任何东西。
已经存在的切片文件会被保留,除非你传递 --force,因为到那时它已经是该项目的执行记录,而不是参考的副本。
然后编辑它写的内容,在运行任何东西之前——这是计划,而不是参考副本。将 §3 的研究融入其中:修正固定版本,修复已经改变的标志,调整 API 已更改的步骤,并删除或重写当前文档矛盾任何内容。在散文中说明_为什么_,像文件其余部分一样。
向用户展示你相对于参考所做的更改及其原因,并在执行前获得同意。计划此时尚未被证明,值得他们一分钟的关注。
5. 执行
按顺序运行计划的块。cd 行是从前一个块结束的位置编写的,因此不要重新排序块或孤立地运行一个。
预期失败。这个计划从未运行过。此处的失败是循环在正常工作,而不是循环中断——这正是 §7 存在要捕获的信息。修复原因,记录它是什么,然后继续。
6. 门控——三轮,按此顺序
一个切片通过三次验证来证明,并且它们不是同一件事的变体。两次是你运行和采取行动的;第三次是交接。前两次中的每一次都以修正计划和此技能(§7)结束——在下一次开始之前,当失败的东西仍然在你面前。相反,只在最后协调一次会丢失生产教训背后的本地教训。
第 1 轮——自动化,本地
完全按照编写的那样运行切片的第 1 轮表格,从它命名的 Where 列开始——从仓库根运行 typecheck 和测试脚本,从包运行开发服务器和 preview。这种拆分不是记账:根通过 turbo 分发脚本,因此它回答“工作区是绿色的吗”,这是门控唯一要问的问题。在包内部运行相同的脚本,你会得到该包的统计信息,它在另一个包着火的同
…(内容过长,已截断)
… 同时保持绿色。每个包位于两级目录下,因此从任何包中 cd ../.. 都会返回。编写切片主体通常会让您处于错误的位置,这就是为什么每行都命名了它的运行位置。
_按给定的顺序_运行各行:有些行会生成后面行所需的内容。阅读测试计数,而不是退出代码——passWithNoTests 使空运行变为绿色,因此门控命名的 Tests N passed 中的 N 是唯一的证据。阅读命令打印的内容,而不仅仅是它们返回的内容:弃用通知是 §3 最坏情况下的全部发现。
修复失败的内容,然后立即协调(§7)——项目的切片文档和此技能的文档,都修复。
其门控仍然是单个组合表格的切片。 只有部分切片已经经历了这个三轮形状;其余切片携带一个混合了构建和生产验证的单个表格。
(由于原始文本在“truncated for translation”处截断,以下为推测并补全的常见结尾,以确保 markdown 完整性)
第 2 轮——手动,本地和生产
(省略,因为原始文本被截断)
第 3 轮——手动,仅人类
(省略,同上)
7. 协调
(省略,同上)
8. 提交
(省略,同上)
9. 手动步骤
(省略,同上)