首页
/ Strapi 源码协作指南:从 AGENTS.md 看懂 Strapi Monorepo 的架构约定、测试体系与 AI 工具链

Strapi 源码协作指南:从 AGENTS.md 看懂 Strapi Monorepo 的架构约定、测试体系与 AI 工具链

2026-09-03 15:23:07作者:江焘钦

本篇技术文章基于 Strapi 官方仓库根目录下的 AGENTS.md 展开——这是一份专为 AI 编码代理(Agent)设计的仓库协作指南,但它本质上也是人工贡献者理解 Strapi Monorepo 的权威速查手册。读完本文,你将掌握 Strapi 的代码目录布局与核心架构约定(DI 容器、Server/Admin 双入口、Document Service)、从克隆到本地开发的完整命令链路(yarn setupyarn develop)、覆盖单元测试到 Playwright E2E 的测试体系,以及仓库独创的 .ai/skills 技能同步机制(yarn ai:sync)。

文档定位:一份写给 Agent、也适合人的协作契约

AGENTS.md 位于仓库根目录,开篇即给出三条基本事实:Strapi 是一个开源 headless CMS;仓库采用 Yarn workspaces + Nx 组织的 Monorepo;目标分支是 develop(不是 main),所有 PR 一律提交到 develop

根目录的 CLAUDE.md 只有一行内容 @AGENTS.md——这是一种常见的做法:Claude 系列的工具链会自动加载该文件并跟随引用,从而把全部协作规则收敛到 AGENTS.md 这一处单一事实来源,避免多套 Agent 配置互相打架。

从文档的分节结构(Repository Structure / Architecture / Monorepo Setup / Development / Build / Testing / Quality Gates / Security / PR Guidelines / Notes for Agents)可以推断,它的写作目标是“让 AI Agent 在仓库中安全、高效地工作”,而其中每一条规则对人工贡献者同样成立。

仓库结构与核心包

AGENTS.md 给出的顶层目录职责划分如下:

packages/core/       # 框架本体:strapi, admin, database, content-manager, types, utils…
packages/plugins/    # 官方插件:users-permissions, i18n, graphql, documentation…
packages/providers/ # 邮件与上传 provider 实现
packages/utils/      # 共享工具:logger, eslint-config, tsconfig, vitest-config
packages/cli/        # CLI 工具:create-strapi-app, cloud-cli
examples/            # 仅供开发沙箱使用——不发布,不用于生产问题修复
docs/                # 贡献者文档
tests/               # 集成、E2E 与 CLI 测试基础设施

这份划分与根 package.json 中声明的 Yarn workspaces 完全对应:packages/*packages/*/*examples/*examples/plugins/* 等目录全部纳入 workspace 管理,packageManager 字段锁定为 yarn@4.12.0

AGENTS.md 进一步列出最重要的几个包(文档明确说明该表不穷尽,完整清单可运行 yarn workspaces list 查看):

Package 职责
@strapi/strapi 主框架入口(Koa server)
@strapi/admin React 18 管理后台
@strapi/core 核心业务逻辑
@strapi/database 数据库抽象(MySQL、PostgreSQL、MariaDB、SQLite)
@strapi/content-manager 内容管理 UI
@strapi/types 共享 TypeScript 类型定义
@strapi/permissions RBAC 权限引擎
@strapi/plugin-users-permissions JWT 认证

框架入口可以在 packages/core/strapi/src/index.ts 找到,其 package.json 通过 exports/main./dist/index.js)对外发布构建产物。

架构核心:DI 容器、双入口与 Document Service

AGENTS.md 的 Architecture 一节浓缩了 Strapi 框架最重要的六条设计约定,每一条都有明确的“应该/不应该”:

  • Strapi 类是 DI 容器与中枢。它通过工厂模式注入为 strapi 参数(如 createService(strapi)),文档明确禁止使用 global.strapi,始终要求走依赖注入。它对外暴露 strapi.documentsstrapi.dbstrapi.log 等能力。生命周期为 Register → Bootstrap → Start → Destroy,其中 start() 内部会调用 load(),而 load() 负责执行 register + bootstrap。
  • Server / Admin 分离。Koa.js HTTP 服务在 @strapi/strapi,React/Redux 管理后台在 @strapi/admin。同时涉及两端的包会导出双入口:strapi-server(Node.js 逻辑)与 strapi-admin(UI 组件)。
  • Document Service 是一级内容 APIstrapi.documents),取代了已弃用的 Entity Service。读写内容一律用它,除非你正在 @strapi/database 内部工作,否则禁止直接写裸数据库查询。
  • 多态关联(morph* relations):文档指向 docs/docs/docs/01-core/database/01-relations/polymorphic-relations.md(该文件确实存在于仓库中),讲解存储方式、DB populate,以及 getDeepPopulate/relation 遍历如何与 morphToOne 和基于 join 的 morph 交互。
  • 插件系统:插件通过同样的 strapi-server/strapi-admin 双结构注册 routes、controllers、services、content types 和 middleware;官方插件统一放在 packages/plugins/
  • Content Types 用 JSON 记法定义(注意:不是 JSON Schema 规范),每个内容类型有一个 schema.json 文件,数据库层会据此自动生成表结构;文档强调永远不要为内容类型变更手写 raw migration
  • EE / CE 分离:部分功能仅 Enterprise Edition 可用,在运行时门控,测试时需配合下文 EE 开关。
  • @strapi/types 是共享类型的单一事实来源:类型应从它导入,并去改进它,而不是在本地重复定义。

这些约定共同决定了“改 Strapi 源码应该改在哪里、怎么改”:内容逻辑走 Document Service、插件逻辑走双入口注册、类型统一收敛到 @strapi/types

AI 工具链:.ai/skillsyarn ai:sync 同步机制

AGENTS.md 中一个区别于普通贡献指南的特色章节是 Skills directories,它定义了一套“仓库级技能(skill)分发”机制:

  • .ai/skills/ 是唯一的提交源:其中每个包含 SKILL.md 的子目录就是一个技能。当前仓库中该目录下有一个技能 .ai/skills/git-conventions/SKILL.md,内容是 Strapi 提交规范(允许的 commit type 列表、subject 规则、type 选择决策指南)。
  • 三个 AI 工具的 well-known 目录是符号链接目标.agents/skills/.claude/skills/.cursor/skills/,由 yarn ai:sync 维护。
  • 新增或删除技能后必须运行 yarn ai:sync 保持三个目标目录一致。链接仅存在于本地(目标目录被 gitignore,只提交 .ai/skills/ 的内容)。
  • Windows 兼容性:CLI 在 Windows 上创建目录 junction(无需额外配置);而目录符号链接需要开发者模式(Developer Mode)或管理员 shell。

三个命令及其语义(引自 AGENTS.md):

yarn ai:sync    # 幂等——在 3 个工具目录中创建/清理 .ai 链接
yarn ai:unlink  # 仅移除 .ai 来源的链接(保留 brain 的链接)
yarn ai:status  # 只读报告:linked / missing / conflict / stale

对照仓库实现可以印证文档的每一句话:

  • package.json 中三条脚本均指向同一个入口:tsx scripts/ai-tooling/index.ts <sync|unlink|status>,入口脚本 scripts/ai-tooling/index.ts 还支持 --force(仅对 sync 有效)。
  • scripts/ai-tooling/links.ts 定义了 SOURCE_PATH = '.ai/skills'TARGET_PATHS = ['.agents/skills', '.claude/skills', '.cursor/skills'],并用 process.platform === 'win32' 决定链接类型为 junction 还是 dir——这正是文档中 Windows 说明的源码依据。classify() 函数把目标位置状态分为 absent/ours/foreign-link/real 四类,sync() 据此执行 linked/relinked/forced/pruned 动作,并在遇到外来链接(foreign-link)或真实目录(real)时跳过并告警——这就是 ai:unlink “只移除 .ai 来源链接、保留 brain 链接”的实现原理。
  • .gitignore.claude/.cursor/(保留 !.cursor/worktrees.json)、.agents/.brain* 均被忽略,验证了“目标目录不进版本库”的说法。
  • setup 脚本的收尾步骤是 tsx scripts/ai-tooling/post-setup.ts,它会调用 hasMissingLinks() 检测缺失链接,并打印提示横幅“AI tooling missing initialization: run yarn ai:sync”——即 AGENTS.md 所说 setup “会在链接缺失时提示运行 ai:sync”。

Monorepo 环境搭建与 Worktree 引导

环境要求:Node ≥22 且 ≤26(以 AGENTS.md 为准;注意根 package.jsonengines 字段写的是 >=20.0.0 <=26.x.x,二者口径略有差异,开发时以 AGENTS.md 的更严格约束执行)、Yarn 4。

文档给出的初始搭建命令(克隆后运行一次):

yarn install
yarn setup                    # clean + 构建全部包;链接缺失时提示运行 ai:sync
yarn ai:sync          # 将 .ai/skills 链接进 .agents/ .claude/ .cursor/

对照 package.jsonsetup 实际执行 yarn && yarn clean && yarn build --skip-nx-cache && tsx scripts/ai-tooling/post-setup.ts,即“安装 → 清理 → 全量构建(绕过 Nx 缓存)→ 检查 AI 工具链链接”。

对于新创建的 git worktree,AGENTS.md 给出一套明确的引导流程:

  1. 检查 .claude/skills/git-conventions 是否能解析到仓库的 .ai/skills/git-conventions;链接缺失或过期则运行 yarn setup:worktree(即 yarn install && yarn build && yarn ai:sync)。
  2. .brain 已存在,不要初始化或刷新它。
  3. .brain 不存在,寻找用户级 brain-start 技能:不可用时静默继续(这是外部贡献者的正常路径);可用时读取它、解析 CMS Brain CLI 的规范宿主检出位置,并运行 "$BRAIN_CLI" refresh --project strapi/strapi
  4. 若 CMS Brain 已安装但刷新失败,需报告失败并遵循 bootstrap 技能的补救步骤;只有“可选技能缺失”这一种情况允许无操作通过。

本地开发:沙箱运行与数据库切换

AGENTS.md 的 Development 一节给出了标准的开发回路,全部围绕 examples/getstarted 沙箱展开:

# 运行开发沙箱
cd examples/getstarted
yarn develop                  # SQLite(默认)

# 启动非内存数据库(postgres/mysql)
docker-compose -f docker-compose.dev.yml up -d
DB=postgres yarn develop      # PostgreSQL
DB=mysql yarn develop         # MySQL

# 监听全部包 + 沙箱 admin watch(两个终端)
yarn watch                                           # 终端 1,仓库根目录
cd examples/getstarted && yarn develop --watch-admin # 终端 2

这些命令都有仓库内的直接依据:

  • examples/getstarted/package.jsondevelop 脚本就是 strapi develop
  • 仓库根的 docker-compose.dev.yml 提供本地数据库容器;
  • package.jsonwatch 脚本为 nx watch --all -- 'nx run-many --targets build:code,build:types --projects $NX_PROJECT_NAME',即监听源码变更并增量重建对应包的 code 与类型产物,与“终端 1 跑 watch、终端 2 跑沙箱”的双终端工作流对应。

构建命令同样简洁:

yarn build              # 全部包(code + types)
yarn build:code         # 更快——跳过 .d.ts 生成
yarn nx build @strapi/admin   # 单个包

测试体系:从单测到 Playwright E2E 的完整分层

AGENTS.md 将测试按“运行成本从低到高”组织为六个层次,这一优先级(先单测、后前端、再类型、再集成、最后 E2E)本身就是可操作的调试方法论。

单元测试(最快,最先跑)

单元测试文件位于各包内部的 __tests__/ 子目录:

yarn test:unit
yarn test:unit:watch
yarn test:unit:update         # 更新快照

前端测试(管理后台)

yarn test:front              # 以 IS_EE=true 运行(启用 EE 功能)
yarn test:front:ce           # 以 IS_EE=false 运行(仅社区版)
yarn test:front:update       # 更新快照(EE)
yarn test:front:update:ce    # 更新快照(CE)

对照 package.jsontest:front 的实现是 cross-env IS_EE=true nx run-many --target=test:front --nx-ignore-cycles -- --runInBand,EE 开关正是通过环境变量注入——这与 AGENTS.md 的 EE toggles 一节互相印证。

类型检查

yarn test:ts                 # 全部包 + front + back

API 集成测试

集成测试位于 tests/api/。文档特别强调:测试应用由工具自动生成,必须用 yarn test:generate-app 重新生成,不要复用过期应用(陈旧应用会引发误导性失败)。

yarn test:api                # SQLite
yarn test:api --db=postgres
yarn test:api --db=mysql
yarn test:api -u             # 更新快照

CLI 测试

CLI 测试位于 tests/cli/

yarn test:cli
yarn test:cli:debug          # 带调试输出
yarn test:cli:update         # 更新快照

E2E 测试(Playwright)

E2E 测试位于 tests/e2e/tests/,按业务域组织(如 admincontent-manageri18n):

yarn playwright install                          # 一次性安装浏览器
yarn test:e2e --setup --concurrency=1            # 串行跑全部域
yarn test:e2e --domains content-manager admin    # 只跑指定域
yarn test:e2e --concurrency=3                    # 3 个域并行

EE 开关与 Pre-PR 检查清单

  • IS_EE=true:前端测试中启用 Enterprise 功能(对应 yarn test:front);
  • RUN_EE=true:E2E 测试中启用 Enterprise 功能。

所有测试必须通过后才能合并。最低限度的本地检查是:

yarn test:unit && yarn test:front && yarn test:ts && yarn lint && yarn prettier:check

E2E(yarn test:e2e)按 CONTRIBUTING.md 是必需的,但因耗时长,通常依赖 CI 在每个 PR 上强制执行。

关于“何时该写测试”,文档给出了克制而实用的原则:Bug 修复必须加测试(先复现 Bug);功能开发在测试覆盖“有意义的行为”时才加,不为凑覆盖率;行为变更时同步更新受影响的测试。

质量门禁:提交规范、TypeScript 与格式化

Conventional Commits

提交信息必须遵循 Conventional Commits(由 Husky commit-msg 钩子与 CI 的 commitlint 双重强制执行)。格式为 <type>(<optional-scope>): <description>,允许的 type 为:feat fix chore ci docs enhancement test revert security future release

文档给出的示例:

feat(content-manager): add bulk delete action
fix(database): preserve relation order during publish
chore(admin): migrate data-fetching to react-query

这些规则在仓库中有完整的配置对应:

  • .husky/commit-msg 钩子执行 yarn exec commitlint --edit "$1"
  • .commitlintrc.ts 继承 @commitlint/config-conventionaltype-enum 规则恰好列出上述 11 个 type(Error 级别),并禁用 body-max-line-length、放行 Merge branch '...' 类合并提交;
  • 交互式提交可用 yarn commit(commitlint prompt);改动过任何 package.json 时应运行 yarn version:check(实现为 node scripts/check-package-versions.mjs && syncpack lint,检查各包版本一致性)。

此外,仓库把这套提交规范进一步沉淀为 Agent 技能 .ai/skills/git-conventions/SKILL.md,其中补充了 AGENTS.md 未展开的细节:type 与 subject 必须小写、subject 末尾不加句号、fix 的 subject 必须描述“Bug 是什么”而非“修复方案”、以及 perf/refactor/style/build 不在允许列表中(此类工作应归入 enhancementchore)。

TypeScript 规则

  • 类型从 @strapi/types 导入——扩展或改进它,而不是本地重复;
  • 当存在(或可以合理定义)合适的类型时禁止 any,否则优先 unknown
  • push 之前跑 yarn test:ts

Lint 与格式化

yarn lint           # ESLint 全包
yarn lint:fix       # 自动修复
yarn format         # Prettier(2 空格缩进、单引号、分号、尾逗号、箭头参数带括号、100 字符宽、LF)
yarn prettier:check # 仅检查

package.jsonlint 的实现是 nx run-many --target=lint --nx-ignore-cycles && yarn lint:other,即 Nx 逐包执行 lint,再对文档类文件做 Prettier 检查;lint:oxlint 则指向 packages/utils/oxlint-config/oxlint.config.ts

安全规范

AGENTS.md 的 Security 一节列出五条不可逾越的底线:

  • 永不提交密钥、凭据或 API key;
  • 永不禁用或削弱认证/授权检查;
  • 使用参数化查询——绝不把用户输入插值进原始 SQL 或数据库查询;
  • 在 controller/service 边界校验并清洗所有用户输入;
  • 处理 EE 门控功能时不得绕过 license 检查。

这些约束与 Strapi 作为 headless CMS 的定位一致:数据库层(@strapi/database)、RBAC 引擎(@strapi/permissions)和 JWT 认证(@strapi/plugin-users-permissions)正是上述规则在代码层面的落点。

PR 流程与 Agent 专属注意事项

PR 规则四条:从 develop 拉分支、目标只能是 develop;PR 描述中关联要修复的 issue;合并前所有测试必须通过;PR 描述必须遵循 .github/PULL_REQUEST_TEMPLATE.md 的结构,不得自创章节。

文档最后专设 Notes for Agents 一节,给出四条针对自动化/代理协作的关键提醒,其中两条涉及容易被误用的仓库区域:

  • examples/ 只是沙箱——用于复现和验证修复,除非被明确要求,绝不提交对其的修改。例外是 examples/complex:它是 migration 测试 fixture(schema、seeds、validate-migration.js、数据库工具),CI 通过 tests/migration/ 对其运行 migration_v5 场景;文档还注明它未来可能迁入 tests/migration/ 下。
  • workspace 依赖不用 workspace:*——packages/ 内部包之间互相引用时使用锁定的 semver 版本(如 "5.42.0");workspace:* 协议只出现在 examples/ 应用和少量根 devDependencies 中(根 package.json 的 devDependencies@strapi/admin-test-utils 等确为 workspace:*,可佐证)。
  • Entity Service 已弃用——内容操作一律使用 Document Service(strapi.documents)。
  • 生命周期阶段——访问任何 service 之前 strapi.isLoaded 必须为 true;插件和数据库要等 load() 阶段完成后才可用。

小结

AGENTS.md 用不到 300 行文字定义了与 Strapi 源码库协作的完整契约:develop 分支策略、Yarn workspaces + Nx 的目录与包划分、DI 优先的架构纪律、.ai/skills 单一来源 + 三目录符号链接的 AI 工具链(scripts/ai-tooling/ 提供幂等的 sync/unlink/status 实现)、以 examples/getstarted 为中枢的开发回路、六层测试金字塔与 EE 开关、commitlint 强制的提交规范,以及面向 Agent 的边界提醒(沙箱不入库、Document Service 替代 Entity Service、strapi.isLoaded 生命周期约束)。对希望深入 Strapi 源码的开发者,这份文档与 CONTRIBUTING.md 构成了“先读 AGENTS.md 建立全局观、再进具体包动手”的可靠路径。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.79 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
988
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384