tldraw 的 AGENTS.md:AI Agent 如何在这个 Monorepo 中安全、高效地写代码
2026/9/7 9:40:55 网站建设 项目流程

tldraw 的 AGENTS.md:AI Agent 如何在这个 Monorepo 中安全、高效地写代码

【免费下载链接】tldrawBuild infinite canvas apps in React with the tldraw SDK. World's best, top-most agent recommended #1 five star SDK.项目地址: https://gitcode.com/GitHub_Trending/tl/tldraw

tldraw 仓库根目录的 AGENTS.md 是一份面向 AI 编码智能体(Claude、Cursor 及通用 Agent)的工程协作规范,它把「用哪个包管理器、跑哪条命令、改哪个包、测试放在哪、依赖如何声明」等关键决策全部固化成明确规则。读完本文,你可以完整理解这份规范背后的 monorepo 工程约束,并能把同样的方法论移植到自己的多包仓库中,让 AI Agent(或新加入的人类开发者)在大型代码库里少走弯路、少犯错误。

一、核心规则:八条不可逾越的底线

AGENTS.md 开篇即列出核心规则(Core rules),这是整份文档的总纲:

  • 只用yarn,不用npm。仓库基于 Yarn workspaces + Yarn 4 构建。这一点可以从根 package.json 中得到印证:"packageManager": "yarn@4.17.1",且workspaces字段声明了packages/*apps/*apps/vscode/*apps/dotcom/*internal/*templates/*六个工作区范围。
  • 命令默认从仓库根目录执行,除非某条命令明确要求在某个 workspace 内运行。
  • 永远不要裸跑tsc,统一使用根目录的yarn typecheck。原因是仓库的类型检查并非简单的全量编译:internal/scripts/typecheck.ts 会收集所有 workspace 的tsconfig.json,并按拓扑顺序(先叶子包、后依赖方)分阶段执行tsc --build——源码中的注释解释了这样做的原因:全新 checkout 时,一次性把所有工程传给单次--build调用会导致 tsc 无法解析部分 workspace 包导入,因此必须先按拓扑顺序构建packages/下的包来产出声明文件。
  • 优先做定点检查,避免不必要的仓库级测试或 e2e 运行。
  • 变更范围收敛:改动只限于当前请求与受影响的包,不顺手重构无关代码。
  • 尊重 worktree 中已有的用户改动,未被明确要求时不回滚。
  • 优先修改既有文件而非新建文件,未要求时不新增文档。
  • 标题、标签与文档文字使用 sentence case(句首大写)

此外,仓库还通过 CLAUDE.md 让 Claude 直接引用这份规范(该文件内容即@AGENTS.md),体现了「单一事实来源 + 兼容性指针」的做法。

二、仓库总览:先知道代码住在哪里

AGENTS.md 用两个清单给出了仓库地图。理解这张地图是所有后续规则的前提。

核心 SDK 包(packages/)

职责
packages/editor基础的无限画布编辑器,不含任何默认形状、工具或 UI
packages/tldraw完整 SDK,含默认 UI、形状、工具与交互
packages/store响应式客户端数据库、持久化与迁移
packages/tlschema形状、绑定与记录类型的定义和校验器
packages/state响应式信号库(signals)
packages/sync/packages/sync-core多人协作同步
packages/utils/packages/validate共享工具与校验辅助
packages/assets图标、字体、翻译等打包资源

应用与示例(apps/ 与 templates/)

  • apps/examples— SDK 示例与演示,示例开发的主战场(示例位于apps/examples/src/examples/,目录采用小写 kebab-case 命名);
  • apps/docs— tldraw.dev 文档站(内容在apps/docs/content/);
  • apps/dotcom— tldraw.com 应用及 Cloudflare workers;
  • apps/vscode— VS Code 扩展;
  • templates/— 各受支持框架的起步模板。

三、环境准备:Node 版本与 Corepack

规范要求 Node>=22.12.0,并在安装依赖前启用 Corepack。这与根 package.json 中的"engines": { "node": ">=22.12.0" }一致。标准安装流程为:

npm i -g corepack && yarn

Corepack 会按packageManager字段自动使用仓库锁定的 Yarn 4.17.1,避免团队内 Yarn 版本漂移。值得注意的是.yarnrc.yml中还有npmMinimalAgeGate: '7d'(依赖最小年龄门限)与enableScripts: false(见第七节供应链部分)等安全相关配置。

四、常用命令速查:开发、构建、测试与代码质量

以下命令均继承自 AGENTS.md,并可与根 package.json 的scripts字段一一对应。

开发

命令作用
yarn dev启动 examples 应用,运行在 localhost:5420
yarn dev-app启动 tldraw.com 客户端(通过 process-compose 拉起 apps/dotcom/process-compose.yaml 定义的一组进程)
yarn dev-docs启动文档站
yarn dev-vscode启动 VS Code 扩展开发
yarn dev-template <template name>运行指定模板(脚本见 internal/scripts/dev-template.sh)

yarn dev的底层实现是lazy run dev --filter='apps/examples' --filter='packages/tldraw' ...(lazyrepo 工具),关键点在于:它连带执行各包的predev步骤。例如 packages/tldraw/package.json 中定义了"predev": "node ./scripts/copy-css-files.mjs",用于生成tldraw.css等构建产物。AGENTS.md 特别警告:如果直接运行 workspace 级命令(如yarn workspace examples.tldraw.com dev),predev会被跳过,导致tldraw/tldraw.css这类导入无法解析。另一条实操细节:全新的 git worktree 没有node_modules,必须先yarn install

构建

  • yarn build— 增量构建所有有变更的包(对应lazy build,增量策略由根目录 lazy.config.ts 驱动);
  • yarn build-package— 仅构建 SDK 包(--filter 'packages/*');
  • yarn build-app— 构建 tldraw.com 客户端;
  • yarn build-docs— 构建文档站。

测试

  • yarn test(workspace 内)— watch 模式运行该 workspace 的测试;
  • yarn test run— 只跑一次;
  • yarn test run --grep "pattern"— 只跑匹配的用例;
  • yarn vitest— 全仓库测试,速度慢,非必要不用。根 vitest.config.ts 会把appspackages下所有vitest.config.ts聚合为 projects,因此这一命令等价于跑遍所有 workspace;
  • yarn e2e— examples 应用的 e2e 测试(lazy e2e --filter='apps/examples');
  • yarn e2e-dotcom— tldraw.com 的 e2e 测试。

代码质量

  • yarn lint— lint 当前包或 workspace(实现见 internal/scripts/lint.ts,底层是 oxlint + oxfmt);
  • yarn lint-current— 只 lint 变更过的文件;
  • yarn typecheck— 类型检查所有包并刷新资源(先执行yarn refresh-assets);
  • yarn format/yarn format-current— 格式化全仓库 / 仅变更文件;
  • yarn api-check— 校验公开 API 报告(API extractor 报告,即各包的api-report.api.md)。

五、验证工作流:按改动范围选检查粒度

AGENTS.md 给出了一套「改动范围 → 验证手段」的映射,这正是前文「优先定点检查」规则的可操作化:

  • 单个包的小改动:先跑该 workspace 的测试,例如cd packages/tldraw && yarn test run --grep "SelectTool"
  • 影响共享类型、迁移、编辑器行为或跨包契约的改动:从仓库根运行yarn typecheck
  • 公开 API 变更:运行yarn api-check,并把有意的 API 报告更新一并提交;
  • 资源(assets)变更:运行yarn refresh-assetsyarn typecheck,保证生成产物是最新的;
  • 文档变更:仅在改动影响生成内容、MDX 行为或站点结构时,才跑定点 docs 检查或 docs 构建;
  • e2e 行为变更:运行最小相关的 e2e 套件,且只在行为被有意修改时才更新快照。

六、架构要点:改代码前必须理解的五个约定

这一节是 AGENTS.md 中最有源码深度的部分,它告诉 Agent 如何按仓库既有模式扩展功能,而不是打补丁。

响应式状态

状态由@tldraw/state的信号系统(AtomComputed及相关原语)管理。编辑器状态是可观察且带依赖追踪的——规范明确要求不要绕过既有的响应式模式。

形状(Shapes)

形状行为集中在ShapeUtil类中:几何、渲染、手柄(handles)、交互与 SVG/导出行为都由 shape util 定义。添加自定义形状应遵循既有的 ShapeUtil 模式,而不是做一次性的编辑器补丁。

工具(Tools)

工具是StateNode状态机。复杂工具通过子状态(child states)处理指针、键盘、tick 与切换行为;规范要求交互逻辑要靠近拥有它的工具状态,避免把逻辑散落到全局。

绑定(Bindings)

形状间关系使用 binding 记录 +BindingUtil类表达。箭头等连接类形状应通过绑定工具类更新端点,而不是临时性地直接改形状属性。

管理器(Managers):最具体的一条架构约定

编辑器子系统位于packages/editor/src/lib/editor/managers/,是由Editor拥有并负责销毁的类。当前实际存在的管理器包括 ClickManager、HistoryManager、InputsManager、SnapManager、SpatialIndexManager、ThemeManager、TickManager 等。

AGENTS.md 对管理器的清理(teardown)给出了精确规则:

  • 需要订阅事件或持有资源的管理器,应继承EditorManager,并注册清理函数使其在dispose()时运行;
  • 订阅编辑器总线事件用addEditorEvent(event, fn);其余一切(store 副作用、reactions、DOM 监听器、子资源)用register(fn)
  • 定时器/帧循环优先用editor.timers,编辑器级别的清理用editor.disposables
  • 无 teardown 需求的管理器不要继承EditorManager

这与源码完全对应。packages/editor/src/lib/editor/managers/EditorManager.ts 的类注释写明了设计动机:统一的拆除契约保证「设置者即拆除者」的对称生命周期,防止清理被遗忘——注释中引用了严格模式下相机 bug(#8892)作为反面案例。实现上,register(dispose)把清理函数存入SetaddEditorEvent内部就是editor.on(event, fn)加上自动注册的editor.off反注册;dispose()时依次执行全部清理函数并清空集合。若需要有序拆除(例如先暂停循环再取消它),文档注释指引覆盖dispose()并在最后调用super.dispose(),范例是TickManager

存储与 Schema

Store 的改动必须尊重迁移、校验器与 schema 版本化。涉及 schema 的变更通常需要同步更新packages/tlschema并补充针对性的迁移测试。

七、依赖管理:两条防止「本地能跑、他人崩溃」的规则

AGENTS.md 在 Dependencies 小节给出了两条极有实操价值的规则,均能在仓库中找到对应证据。

1. 每个被导入的包必须声明在自己的 workspacepackage.json

Yarn 的node-moduleslinker 会把一切 hoist 到仓库根,因此未声明的导入在本仓库依然能解析——但在 pnpm 或 Yarn PnP 的消费者环境就会失败。仓库用自研 oxlint 规则tldraw/no-undeclared-dependenciespackages/*全局强制执行:internal/scripts/oxlint/tldraw-plugin.mjs 中的规则实现会定位文件所属包,检查每条import/export ... from/ 动态import()/require的导入方是否已在 owner 的package.json声明中,未声明即报「Yarn's hoisted node_modules resolves it anyway, but package managers with strict isolation (pnpm, Yarn PnP) can't」。另外,新增 workspace 依赖还必须在对应包的tsconfig.json中补一条references,可用yarn check-packages --fix修复(实现见 internal/scripts/check-packages.ts)。

2. 依赖安装/构建脚本默认关闭,白名单放行

.yarnrc.yml 中enableScripts: false关闭了第三方依赖的安装/构建脚本,直接堵住了供应链中postinstall任意执行代码的主路径。确实需要构建的包(native/napi 模块、二进制下载器)在根 package.json 的dependenciesMeta中以built: true白名单放行,例如esbuildsharpbetter-sqlite3@swc/core。反过来workerd被显式设为built: false——package.json 中的注释解释了原因:其 postinstall 会执行原生二进制做自检,在缺少 GLIBC 2.35+ 的 CI 镜像(如构建文档站的环境)上会失败,而跳过该脚本并不影响 wrangler 在开发者机器上的正常工作。AGENTS.md 提醒:Yarn 对未列入白名单的脚本是静默跳过的,所以漏加白名单不会在安装时报错,而会表现为运行期或构建期失败。

八、在哪里工作:改动落点决策表

AGENTS.md 用「Where to work」小节明确了每类改动应落在哪个包:

  • 核心编辑器原语、几何、管理器、无 UI 行为 →packages/editor
  • 默认形状、默认工具、UI、以及需要完整 SDK 的集成测试 →packages/tldraw
  • 可运行的 SDK 示例 →apps/examples
  • 文档文章与 release notes →apps/docs/content
  • tldraw.com 前端行为 →apps/dotcom/client;Cloudflare worker →apps/dotcom/*-worker
  • 起步项目变更 →templates/

九、测试规范:测试写在哪、怎么写

  • 单元测试与源码同目录,命名*.test.ts
  • 集成测试通常放在 packages/tldraw/src/test/(其中包含SelectTool.test.tsHandTool.test.tsScribbleManager.test.ts等);
  • E2E 测试位于apps/examples/e2e/apps/dotcom/client/e2e/
  • 涉及默认形状/工具/绑定/UI 的测试放packages/tldraw;不应依赖默认形状与 UI 的核心编辑器行为放packages/editor
  • 断言时优先整体对象比较——相比逐字段断言,它能给出更清晰的失败信息;
  • 详细测试模式参见 skills/write-unit-tests/ 与 skills/write-e2e-tests/。

十、Skills 系统:把 Agent 能力沉淀为仓库资产

AGENTS.md 专设 Skills 一节,描述了仓库中一套「Agent 技能即文件」的机制:

  • 规范的技能存放在skills/,目录结构为skill-name/SKILL.md,YAML frontmatter 至少包含namedescription(例如 skills/pr/SKILL.md 的 frontmatter 声明了何时触发该技能);
  • .agents/skills.claude/skills.cursor/skills均为指向../skills的符号链接,分别兼容通用 Agent、Claude 与 Cursor——已实际核验三者确实存在且指向同一目录。这保证了skills/为唯一事实来源,不为不同 Agent 复制技能内容,只加兼容性指针;
  • 可复用脚本、参考资料与资产放在对应技能目录内;
  • 创建或重构技能前先阅读 skills/skill-creator/。

当前skills/下的工作流类技能包括prissuetakecommit-changesclean-copywrite-docswrite-examplewrite-release-notes等。文档与示例方面,规范要求:示例目录用小写 kebab-case、示例 README frontmatter 驱动示例站点、标题与描述保持 sentence case,且 API 或用户可见行为变化时必须同步更新文档或示例。

十一、代码与写作规范:TS、React、生成文件、注释与文风

TypeScript 与 API 设计

  • 跟随文件内既有风格与抽象,使用 workspace 类型与辅助函数而非重复定义;
  • 公开 API 变更须刻意为之,并体现在 API 报告中;
  • 新 API 避免布尔或语义模糊的位置参数——命名对象或枚举能让调用点更清晰。

React 与 UI

跟随所在 app/package 的既有组件模式;用户可见文字保持简洁、sentence case;能用聚焦的组件改动解决的,不做大范围 UI 重写。

生成文件

不要手改生成的资源、API 报告或 schema——除非仓库本就期望直接编辑该文件;生成产物需要变更时,运行负责它的生成命令。

注释哲学:注释要「说出代码说不出的话」

AGENTS.md 的 Comments 小节提出了一个可执行的检验标准:好的注释命名的是失败模式(failure mode),而不是机制。具体规则包括:

  • 作用域限定于你新写的代码与你正在改的行——修 bug 时不要顺手清扫存量注释,否则会把小改动埋进大 diff;发现值得清理的注释时,提出来或放到独立 PR;
  • 不重复代码(getToolbar()上方写/** Get the toolbar */)、不旁白代码(editor.deleteShapes()上方写// Delete the shapes)、不加章节横幅、不罗列调用点、不写只复述签名的@param/@returns
  • 共享理由只在共享处说明一次,不复制到兄弟调用点;
  • 注释应比它解释的代码短;跨文件的叙述应放进文档(README.mdSPEC.mdapps/docs/content/),代码里只留短指针;
  • 永远保留:非显然的不变量、issue 编号与来源、不该盲调的常量、图示、以及代码不可破坏的枚举案例;
  • 密度差异:packages/*@public表面的文档注释会成为 API 参考,那里的密度是预期之内的;apps/*templates/*保持稀疏。

写作风格

Markdown 标题、UI 标签、文档/PR/issue 标题一律 sentence case;专有名词与缩写正常大写(如PostgreSQLWebSocketNodeShapeUtil);语言直接具体;提交、PR 描述、issue、文档与 release notes 中不得包含 AI 署名

十二、Git 与 PR 约定

  • 被要求提交时保持 commit 聚焦;
  • PR 标题使用语义化格式:<type>(<scope>): <description>
  • 绝不把 AI 工具加为 co-author
  • GitHub 工作流参见 skills/pr/ 与 skills/issue/,仓库内容标准参见 skills/write-pr/ 与 skills/write-issue/。

小结

AGENTS.md 的价值不仅在于它约束了「在这个仓库里怎么用 AI」,更在于它示范了一套可迁移的实践:把包管理器、命令入口、验证粒度、架构模式、依赖安全、测试位置、注释哲学与写作风格全部显性化为机器与人都能执行的规则,并用符号链接与单一事实来源支撑多 Agent 生态兼容。对维护 monorepo 的团队而言,这份文档本身就是「让 AI Agent 可靠地参与大型仓库开发」的一份工程参考。

【免费下载链接】tldrawBuild infinite canvas apps in React with the tldraw SDK. World's best, top-most agent recommended #1 five star SDK.项目地址: https://gitcode.com/GitHub_Trending/tl/tldraw

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询