惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
博客园 - 司徒正美
Last Week in AI
Last Week in AI
博客园 - 聂微东
Jina AI
Jina AI
月光博客
月光博客
爱范儿
爱范儿
美团技术团队
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Hugging Face - Blog
Hugging Face - Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 叶小钗
T
Tailwind CSS Blog
博客园 - 【当耐特】
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Apple Machine Learning Research
Apple Machine Learning Research
有赞技术团队
有赞技术团队
罗磊的独立博客
小众软件
小众软件
雷峰网
雷峰网
IT之家
IT之家
大猫的无限游戏
大猫的无限游戏
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V
Visual Studio Blog

定の栈

AI 写得出功能,写不好 Dockerfile:Next.js 自托管踩坑记录 多个 AI 一起写代码时,我给它们划的边界 9 个 commit,没有一个人类作者:AI 独自写完一个项目之后 Next.js 渲染模式排查笔记:force-dynamic、hydration 与构建期没有数据库 让 Claude 少写错数据层:Prisma、Drizzle 和几条结构化做法 同一个月,把主页搬出 Next.js,又把 Hugo 站搬进来 macOS Tahoe 如何用自己的视频做动态壁纸(替换 Aerial 方法) Podman Compose 常用命令速查 创建 Swap 文件 Cursor 2025 Hugo 中文阅读时间计算模版 手动重加载不蒜子计数 入坑舞萌 DX 历时两月终抵 w0 与首鸟加 多邻国 600 天连胜 原神五周年纪念 Asuna 成年生日 告别绝区零 站长18周岁啦! 一位动漫迷的追番日志与热情之旅 起飞日志 Reflector 镜像列表更新常用命令与配置文件 个人自用 rsync 文件同步常用命令 历时千日原神,深渊终抵满星 Arch Linux 个人常用命令记录 《三体III:死神永生》 《三体II:黑暗森林》 《千恋*万花》与现代物理学概念奇妙碰撞后产生出的糟糕想法 Minecraft 15 周年骨折价补票入正 网页添加 Live2D 看板娘 记第二次清醒控梦体验
我的 CLAUDE.md 只有一行:约定文件到底该写多少
Asuna · 2026-07-21 · via 定の栈

最近把一个 Galgame 资源站从 Hugo 整个重写成了 Next.js,仓库是 vns-next。从 create-next-app 那个初始 commit 到能挂上线,一共 13 个 commit,时间跨度不到 20 小时。

事后翻仓库的时候发现一件挺好笑的事——我给 Claude 写的那份约定文件,全文只有一行。而且那一行还不是我写的喽…

这篇不聊渲染模式也不聊部署,就只说「项目起步时该给 AI 留什么约定」这一件事。记录下我在几个项目里来回试出来的结论…

我的 CLAUDE.md 全文就一行

先上原文,vns-next 根目录的 CLAUDE.md 全文:

@AGENTS.md

对,就这一行,用 import 语法指向隔壁的 AGENTS.md。那再看 AGENTS.md,全文 5 行:

<!-- BEGIN:nextjs-agent-rules -->
# This is NOT the Next.js you know

This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
<!-- END:nextjs-agent-rules -->

注意那对 BEGIN / END 标记——这段不是我写的,是 create-next-app 自己塞进来的。核心就一句话:别信你训练数据里的 Next.js,写代码前先去读 node_modules/next/dist/docs/

之前开 thdl(东方同人资源站)的时候就是这套,CLAUDE.md 一模一样,也是一行 import 指向 AGENTS.md,内容一字不差。好处很明显:单一事实源,两份规则不会打架~

就这么点,够不够用?我一开始也觉得肯定不够…

另一个极端:一个仓库三套约定文件

之前那个项目 mikiacg 走的是完全相反的路——同时维护三套:

  • 根目录 CLAUDE.md,111 行
  • .cursor/rules/ 下 9 个 .mdc,其中 project.mdclibrary-versions.mdcalwaysApply: true
  • .github/copilot-instructions.md,开篇就把自己降级成索引:「完整约定见项目根目录 CLAUDE.md

CLAUDE.md 第 3 行是这么开场的:

时效性提示:本项目使用大量前沿版本的库,AI 训练数据很可能覆盖不到。遇到不确定的 API 用法时,务必查询最新文档(Cursor 中可用 Context7 MCP)。

然后专门开了一节「关键版本差异(AI 常见错误)」,6 条:

- `params` / `searchParams` 在 Next.js 16 中是 **Promise**,服务端用 `await`,客户端用 `use()`
- Tailwind v4 用 **CSS 配置**`@import "tailwindcss"` + `@theme {}`),无 `tailwind.config.ts`
- Prisma 7 generator 为 `"prisma-client"`(不是 `"prisma-client-js"`),导入路径 `@/generated/prisma/client`
- Zod 4 导入 `import { z } from "zod"`(不是 `zod/v4`- 日期用 `dayjs`,不用 `date-fns`
- 认证用 Better Auth(`@/lib/auth-client`),不是 next-auth

.cursor/rules/library-versions.mdc 结尾还有一张 ❌→✅ 对照表,7 条:

1.`params.id` → ✅ `(await params).id``use(params).id`
2.`tailwind.config.ts``theme.extend` → ✅ `globals.css``@theme { }`
3.`import { PrismaClient } from "@prisma/client"` → ✅ `import { PrismaClient } from "@/generated/prisma/client"`
4.`provider = "prisma-client-js"` → ✅ `provider = "prisma-client"`
5.`import { z } from "zod/v4"` → ✅ `import { z } from "zod"`
6. ❌ 用 `date-fns` 处理日期 → ✅ 用 `dayjs`
7. ❌ 用 `next-auth` API → ✅ 用 Better Auth(`@/lib/auth-client`

这份是真有用的。因为它写的全是 AI 不可能知道的东西——版本差异。Prisma 7 的 generator 名字变了、Zod 4 的导入路径变了,这种事没写进去,模型就会按记忆里的老写法糊一版给你,然后你花二十分钟 debug 一个根本不存在的 import。这钱我付过好几次了…

三套文件的代价是漂移

commit 519e5a7 那次我更新文档,把 CLAUDE.md 里一条写错的说明拆开了——原文写「pnpm lint — ESLint + TypeScript 检查」,但 package.jsonlint 只跑 eslint .,根本不含类型检查。改完是三条:

- `pnpm lint` — 仅 ESLint
- `pnpm typecheck` — 仅 TypeScript 类型检查(`tsc --noEmit`- `pnpm check` — ESLint + TypeScript 类型检查(提交前完整校验)

同一个 commit 还把版本号补齐了:tRPC 11.15 → 11.17、Zod 4.3 → 4.4、Prisma 7.6 → 7.8、Better Auth 1.5 → 1.6。

然后呢?.cursor/rules/project.mdc 至今仍写着 tRPC 11.15、Zod 4.3、Prisma 7.6、Better Auth 1.5,连那条错的 lint 说明都原样躺在那儿。改了一份,忘了另一份,这不就漂移了嘛…

在多人协作的仓库里这事会更糟:两个 AI 工具各读各的目录,拿到的上下文根本不是同一份。那个场景我在另一篇里单独写过,这里就不展开了。

约定文件也是代码,会过期。而且没有 CI 会告诉你它过期了…

那知识实际落在哪

回头看 vns-next:没有 .claude/、没有 .cursor/、没有 .github/、没有 docs/、没有任务清单也没有规格文档。但它一点都不缺上下文。

因为知识全写在代码注释和 commit body 里了呢~

next.config.tstrailingSlash 那一段,把「为什么要」和「为什么还要关掉内置的」一起写死了:

// 与旧站(Hugo)URL 完全一致:尾斜杠必须保留,
// Artalk/Valine 历史评论按 /p/{id}/ 路径存储,去掉斜杠会丢评论
trailingSlash: true,
// 但内置的尾斜杠 308 会把 POST /api/auth/* 重定向成 /api/auth/*/ 导致 404(Better Auth 全挂),
// 故关掉内置重定向,由 src/proxy.ts 只对页面 GET 请求补尾斜杠
skipTrailingSlashRedirect: true,

src/proxy.ts:21-23 是一条纯警告,写给下一个想「优化」这段代码的人(大概率是 AI):

// 注意:不能用 nextUrl.clone() 再改 pathname——NextURL 的 setter 会按
// trailingSlash 配置把尾斜杠再规范化掉,Location 指回自身造成死循环。
// 官方 skipTrailingSlashRedirect 示例即用裸 new URL() 构造。

src/lib/cache.ts:1-5 写明了这个文件将来会怎么被替换:

/**
 * 内存 TTL 缓存 helper
 *
 * 接口对齐 acgn-flow 的 redis helper(getCache/setCache/deleteCache/deleteCachePattern),
 * 将来若要换 ioredis 可以无痛替换本文件实现,调用方不需要改动。
 */

commit b07e20d 的 message 则连验证手段都写了——这个坑本身(构建期没有数据库)我在另一篇里细说过,这里只看它往 commit body 里塞了什么:

fix(deploy): 全站 force-dynamic——Docker 构建环境无数据库,静态预渲染必然失败

根 layout 声明 dynamic='force-dynamic'(查库页面请求时渲染,内存缓存兜底),
sitemap/feed.xml/llms.txt/index.xml 同步声明。已用死库 DATABASE_URL 本地复现
构建通过。

这些位置的共同点是:下次一定会被读到。改 proxy.ts 的人必然会看到那条死循环警告,看 next.config.ts 的人必然会看到尾斜杠的来龙去脉。而 docs/architecture.md 会不会被打开,全看运气啦…

我现在的分法

内容类型放哪使用频率
框架版本差异与 API 陷阱CLAUDE.md★★★★★
某一行代码为什么这么写代码注释★★★★★
某次改动的动机与验证手段commit body★★★★
部署与运维步骤单独一份 README★★★
项目介绍、目录结构别写,会过期

只有第一类是模型不可能从代码里推出来的,不写就是不知道。至于「本项目采用 App Router,目录结构如下……」这种,模型 ls 一下就有了呢~

顺便自嘲一下 README

说到会过期的东西。vns-next 的 README 至今是 create-next-app 的默认模板,36 行,讲 npm/yarn/pnpm/bun run dev 和 Deploy on Vercel,从初始 commit 85aa812 起没改过一个字。

而这个项目实际是 bun + Docker Compose 自托管的,部署压根没走 Vercel(next.config.ts 里那个 VERCEL 分支只是留个后路)。README 和现实完全脱节…

不过 .dockerignore:13-19 是这么写的:

# 内容导出快照 / 文档 / 部署自身
content-export
deploy
README.md
AGENTS.md
CLAUDE.md
.claude

README、AGENTS.mdCLAUDE.md.claude 一起被排除出了镜像上下文(.claude 是顺手防着的,这项目实际压根没建过那个目录哦)。所以我干脆懒得改了,反正它也进不了镜像…

顺带一提,那 13 个 commit 里有 12 个带 Co-Authored-By: Claude Opus 4.8 的 trailer,唯一没有的是 create-next-app 生成的初始 commit。全部 commit 的 author 都是我自己——署名归署名,锅还是我的啦~

反正我下个项目大概还是只写一行,等踩到坑再往里加就行~