首页
/ Nextcloud Server 的 AI 编码 Agent 协作规范全解:从 AGENTS.md 看贡献政策、Conventional Commits、DCO、SPDX 许可头与 autotest.sh 测试流程

Nextcloud Server 的 AI 编码 Agent 协作规范全解:从 AGENTS.md 看贡献政策、Conventional Commits、DCO、SPDX 许可头与 autotest.sh 测试流程

2026-09-05 19:20:49作者:卓炯娓

本文解读 Nextcloud Server 仓库根目录的 AGENTS.md:它是仓库专门为 AI 编码智能体(Claude Code、GitHub Copilot、Cursor、Windsurf 等)编写的行为契约,文档开头即要求 Agent 在生成任何代码、提交(commit)或拉取请求(PR)之前先完整阅读该文件。全文覆盖四条主线:遵循 Nextcloud 贡献政策(披露、责任归属、沟通、安全、许可、代码质量)、仓库级硬性要求(Conventional Commits、强制单元测试、DCO 签署、SPDX 许可头、漏洞上报渠道)、仓库范围边界(本仓库只收哪些组件的变更),以及可执行的本地测试流程。读完本文,你能把 AI 辅助开发的产出规范地推进到「可被 Nextcloud 维护者接受」的状态,并理解每条规则在仓库源码中的落点。

适用前提:本文以仓库当前实际内容为准,version.php 显示当前主干为 36.0.0 dev;仓库内 PHP 测试栈要求 PHPUnit ≥ 11.5(见 autotest.sh)。

一、贡献政策框架:AI 辅助贡献的四条硬性前提

AGENTS.md 明确所有由 Agent 生成或辅助的贡献必须同时满足两份政策:AI 贡献政策(针对 AI 的专项规则,覆盖披露、作者责任、沟通、安全、许可、代码质量与自主 Agent 行为)与通用贡献指南(测试要求、DCO、许可头、Conventional Commits、翻译)。这两份政策在仓库内的对应锚点是 .github/CONTRIBUTING.md,其中的 “AI-assisted contributions” 小节可视为 AGENTS.md 的人类可读版本,核心条款包括:

  • 披露(Disclosure):在 PR 描述中声明使用了 AI 工具,并在每个受影响的 commit 中添加 Assisted-by: AGENT_NAME:MODEL_VERSION 尾注(trailer)。
  • 责任归属(Accountability):提交者对每一行代码负责——能解释、能辩护、能修改。评审者问起实现原因时,“AI 写的”不是可接受的答案。
  • 沟通(Communication):PR 描述、评审评论、issue 报告必须由贡献者用本人语言撰写;把评审意见丢给 AI 再把输出原样贴回是不可接受的。
  • 质量(Quality):AI 产出必须由人完成质量把关——审查、清理、测试后提交;新功能必须在真实运行的实例上由人测试,而不是交给 Agent。从未被执行过的代码、把调试工作转嫁给维护者的代码一律不接受。
  • 许可(Licensing):确保 AI 生成代码不包含与目标仓库许可不兼容的素材。

AGENTS.md 在此基础上进一步收紧:它规定 Agent 遇到可能违反政策的操作时必须显式告知贡献者,说明哪条规则有风险、应如何替代,而不得“静默继续”(silently proceed)。这使 AGENTS.md 成为一份面向机器执行的、可逐条核验的规则清单,而非仅面向人的原则性声明。

二、Agent 行为清单:必须始终做的事(What the agent must always do)

AGENTS.md 用 “What this agent must always do” 一节列出了 12 条正向义务,这里逐条保留并补充仓库证据:

  1. 添加 Assisted-by 尾注:每个包含 AI 辅助内容的 commit 都要带 Assisted-by: AGENT_NAME:MODEL_VERSION
  2. PR 披露 AI 工具使用:每个 PR 的描述中都要包含 AI 工具使用声明。
  3. 小而聚焦的 PR:一个 PR 只解决一个关注点,不触碰无关文件、不夹带顺手重构。
  4. 依赖必须先核验:建议任何依赖包之前,先对照真实包注册表(registry)验证其存在;禁止使用幻觉出来或未经核验的包名。
  5. 注释只写“代码是什么”,不写“代码怎么来的”。这是 AGENTS.md 中最细致的一段,给出四子条:
    • 注释描述代码做什么——方法签名、行为、以及代码本身无法表达的约束(例如不明显的不变量或 workaround);
    • 绝不添加记录进度、决定或变更的注释(如 “changed X to Y”“as requested”“this fixes ...”“previously this did ...”)——这类信息属于 commit message 或 PR 讨论,写在代码里会迅速过期并产生误导;
    • 不为自明代码做旁白,代码不用注释也能读懂时就直接省略;
    • 注释保持简短,密度与周边代码一致。
  6. 复用现有 helper 与工具函数,而不是把相同逻辑内联重写;修复有缺陷的模式时,要修复变更代码中该模式的每一处出现,而不只是被指出的那一处。
  7. 权限与访问控制检查必须前置:守卫操作之前执行检查,绝不事后补检,也绝不只在 UI 层做检查。
  8. 跨上下文接线用户可见功能:新增或修改面向用户的功能时,要在受影响组件被使用的所有上下文中接通——默认认证视图、公共分享页、以及 Smart Picker 与引用(reference)小部件这类嵌入上下文;发射新事件时,要逐一确认组件的每个消费者都订阅并处理了该事件。
  9. 政策冲突必须显式提醒:贡献者即将或已经执行的某个动作违反 AI 贡献政策或贡献指南时,明确指出并给出替代做法。
  10. PR 体积预警:当一个 PR 逼近数千行变更规模时,应提示拆分;建议在开 PR 之前给出逻辑拆分方案,而不是之后。
  11. 复杂变更先开 ticket 对齐方向:当功能足够复杂——涉及多个子系统、需要架构决策、或正确路径尚不明确——推荐先开 ticket 与贡献者/维护者对齐,避免写出可能被拒或需要推倒重来的 PR。
  12. 新增 PHP 文件后运行 build/autoloaderchecker.sh:该脚本要求 composer ≥ 2.9.2,重新 dump-autoload 生成主自动加载器,并检查主加载器中不应出现的 Bamarni\Composer\Bin 插件(命中时会要求改用 --no-dev 重新生成并提交结果)。

三、Agent 行为清单:永远不能做的事(What the agent must never do)

与正向清单对应,AGENTS.md 列出 6 条绝对禁区,共同主题是“人类保留最终提交权”:

  1. 不得自主对外动作:不得自主开 issue、提交 PR、发表评审评论或发送安全报告——每项贡献都必须由人审查后提交。
  2. 不得添加 Signed-off-by:Developer Certificate of Origin 的认证只能由人类贡献者做出(详见第六节)。
  3. 不得提交未经人工独立核验的安全报告:已验证的漏洞应通过 Nextcloud 的 HackerOne 渠道上报,而不是 GitHub issue。
  4. 不得代写:PR 描述、评审评论、issue 报告必须出自贡献者本人语言。
  5. 不得全自动化解决入门友好类问题:不得全自动解决标记为 good first issue 或类似新手友好标签的 issue。
  6. 不得提交未经贡献者审查清理的代码:死代码、冗余逻辑、过量注释、乱码替换字符(如 U+FFFD)、无关改动,必须在提交前清除。

四、Commit 规范:Conventional Commits 与 Assisted-by 尾注

AGENTS.md 要求所有 commit message 采用 Conventional Commits 格式,完整模板如下(此为 AGENTS.md 原文的完整继承):

<type>(<scope>): <short description>

[optional body]

Assisted-by: AGENT_NAME:MODEL_VERSION

常用 type 包括:featfixrefactortestdocschoreperfbuildci;scope 应与受影响的组件或应用一致,例如 files_sharingcoreencryption。AGENTS.md 给出的完整示例:

feat(files_sharing): allow sharing with contacts

Assisted-by: ClaudeCode:claude-sonnet-4-6

仓库侧可以印证这套约定:.github/CONTRIBUTING.md 的 “Conventional Commits” 小节同样要求该格式并给出同一示例 feat(files_sharing): allow sharing with contacts;从仓库结构看,scope 与目录一一对应(core/apps/files_sharing/apps/encryption/ 等),这使得 commit 历史可以直接映射到源码位置。注意 AGENTS.md 与人类版贡献指南的差异点:人类指南只写 Conventional Commits,AGENTS.md 额外要求尾注区携带 Assisted-by,两者并存不冲突——Signed-off-by(人)与 Assisted-by(Agent)分属不同角色。

五、测试与本地验证:autotest.sh 的真实行为

AGENTS.md 的测试要求共四条:

  • 每段被变更或新增的代码都必须有单元测试覆盖;新逻辑没有测试的 PR 不接受。
  • 在单元测试困难的区域,鼓励在修 bug 的同时做重构以建立可测性。
  • 新功能必须由人类贡献者在真实运行的 Nextcloud 实例上手工测试后才能提交——“给 Agent 一份测试步骤让它跑一遍”不构成替代。
  • 测试命令:NOCOVERAGE=0 ./autotest.sh <db> <path>,其中 db 至少包括 sqlite 与 pgsql。

5.1 从 autotest.sh 源码看该命令做了什么

阅读 autotest.sh 可以还原整条验证链路,这也是 Agent 执行测试前应理解的环境契约:

  1. 环境前置检查:通过 which 定位 PHP(可用 PHP_EXE 覆盖),优先使用仓库内置的 lib/composer/bin/phpunit,否则回落到系统 phpunit;强制校验 PHPUnit 主版本 > 11 或 ≥ 11.5(autotest.sh#L84-L87),并检查 config/ 目录与 config/config.php 可写(autotest.sh#L89-L92)。
  2. 数据库配置:脚本内定义 DBCONFIGS="sqlite mysql mariadb pgsql oci mysqlmb4"autotest.sh#L15),即 AGENTS.md 所说 “db 是 sqlite 或 pgsql” 只是最小集,脚本实际支持 6 种数据库配置;主存储配置为 localswift(OpenStack 对象存储,会拉起 Swift/Ceph 容器)。
  3. 配置备份与还原:若存在开发用 config/config.php,先备份为 config-autotest-backup.php;用 tests/preseed-config.php 覆盖为测试配置;trap cleanup_config EXIT 保证退出时清理 Docker 容器、恢复原有配置并删除 autotest 生成的临时配置(autotest.sh#L126-L167)。
  4. 数据目录:若存在 /dev/shm 则把数据目录放 tmpfs 上以加速测试,否则落在 $BASEDIR/data-autotest
  5. 触发安装:安装本身通过 occ 完成——occ maintenance:install -vvv --database=... --database-name=oc_autotest --admin-user=admin ...autotest.sh#L357),测试库名固定为 oc_autotest、用户 oc_autotest
  6. 执行测试:进入 tests/ 目录,用 tests/phpunit-autotest.xml 配置运行 phpunit,并带 --fail-on-warning --fail-on-risky --log-junit autotest-results-<db>.xml 等严格开关(autotest.sh#L395-L396);TEST_SELECTION 环境变量还可按 QUICKDBDBNODBPRIMARY-s3 等分组选择测试集。
  7. 路径参数解析:第二个参数 <path> 若不存在于 tests/ 下,则自动补 ../ 前缀再交给 phpunit(autotest.sh#L423-L427),因此 NOCOVERAGE=0 ./autotest.sh sqlite lib/TemplateTest.php 这类用法中,传相对仓库根的路径即可。

关于 NOCOVERAGE 的语义,从源码结构看需要澄清一点:外部存储测试脚本 autotest-external.sh 的判断是 if [ -z "$NOCOVERAGE" ] 时才附加 --coverage-clover/--coverage-html 参数,即变量非空即关闭覆盖率。因此 AGENTS.md 写作 NOCOVERAGE=0 的实际效果是“以不带覆盖率采集的方式跑测试”(更快);若需要覆盖率产物,应留空该变量(或按 autotest.sh 内提示以 COVERAGE=1 启用 clover/html 输出,见 autotest.sh#L388-L393)。

5.2 测试配置入口

PHPUnit 的入口配置是 tests/phpunit-autotest.xml,外部存储后端另用 tests/phpunit-autotest-external.xml;测试启动器 tests/bootstrap.php、前置配置 tests/preseed-config.php 与数据库容器配置(tests/docker/ 下 MariaDB、mysqlmb4 的 cnf)共同构成测试环境。对 Agent 的实操含义:改动 lib/core/apps/<app>/lib/ 后,先按目录定位对应测试文件,再执行 autotest.sh 指定该文件验证,最后由人在活实例上做功能验证。

六、DCO 与 SPDX 许可头:提交前的两道“法律”检查

6.1 开发者源证书(DCO)

Nextcloud 使用 DCO 作为额外保障。仓库内的完整文本见 contribute/developer-certificate-of-origin(DCO 1.1,Copyright (C) 2004, 2006 The Linux Foundation and its contributors):贡献者以提交行为认证其对代码拥有授权许可的权利。

AGENTS.md 对此的两条规则:

  • Signed-off-by 尾注只能由人类贡献者添加,Agent 不得代加:
Signed-off-by: Random J Developer <random@developer.example.org>
  • 配置好 user.nameuser.email 后,人类可用 git commit -s 自动签署;.github/CONTRIBUTING.md 还额外建议了 git 别名写法(git config --global alias.ci 'commit -s',之后 git ci 即签署提交)。

这与第三节的 “never do” 第 2 条互相印证:DCO 是人对代码来源与授权的法律性声明,机器无法承担该责任。

6.2 SPDX 许可头

AGENTS.md 要求每个新文件都带正确的 SPDX 许可头;本仓库默认许可为 AGPL-3.0-or-later,PHP 文件的标准写法即 AGENTS.md 原文示例:

/**
 * SPDX-FileCopyrightText: <year> <name>
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

仓库根目录的 AGENTS.md 自身就是 HTML 注释式 SPDX 头的实例(SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors / SPDX-License-Identifier: AGPL-3.0-or-later)。更完整的分语言格式见 contribute/HowToApplyALicense.md

  • 前端源码.js.ts.css 等)使用 /** ... */ 块注释;
  • .vue 文件使用 <!-- - SPDX-FileCopyrightText: ... - SPDX-License-Identifier: ... --> 注释(仓库根目录 AGENTS.md、apps/*/ 下的 vue 文件均是实例);
  • 后端 .php 使用文档块注释;
  • 修改既有文件时保留原许可头,只追加自己的版权行(多人版权行的 diff 示例见 HowToApplyALicense.md);若文件已有通用头,则把自己加入 AUTHORS.md。

背景事实:Nextcloud 自 2016-06-16 起由 AGPLv3-only 切换到 “AGPLv3 或任何后续版本”,且不要求 CLA,版权属于各贡献者。AGENTS.md 的许可条款还有一条专门针对 AI 的红线:AI 生成代码不得包含与 AGPL-3.0-or-later 不兼容来源的素材。

七、安全规范:漏洞上报渠道与人工复核

AGENTS.md 的安全章节包含三条规则:

  1. 不要为潜在漏洞开 GitHub issue:按安全政策,通过 Nextcloud 的 HackerOne 渠道上报。这一点与 .github/CONTRIBUTING.md 的 “SECURITY” 条款一致——安全类缺陷必须走 HackerOne 而非 bug tracker。
  2. AI 生成的安全报告必须经人类独立验证后才能提交
  3. 人工复核三类高风险面:访问控制逻辑、认证模式、依赖包名——AGENTS.md 明确指出 AI 工具存在“幻觉包名”和复现已知漏洞模式(vulnerable patterns)的已知倾向。

结合第二节 “must always do” 第 7 条可以读出仓库对安全的一贯姿态:访问控制检查必须发生在被守卫操作之前、且必须落在服务端逻辑层而非仅 UI 层;AI 产出中的认证/鉴权代码默认按“不可信”对待,强制人审。

八、仓库范围:这个 repo 到底收哪些代码

AGENTS.md 最后一节划定了本仓库的组件边界,避免 Agent 把变更放到错误的仓库:

  • 属于本仓库:Nextcloud server 核心,以及捆绑应用 files、encryption、external storage(files_external)、sharing(files_sharing/sharing)、deleted files(files_trashbin)、versions(files_versions)、LDAP(user_ldap)、WebDAV(dav)。
  • 不属于本仓库:其余组件的 issue 与变更应提交到 Nextcloud 组织下各自的独立仓库。

这一边界在仓库目录中可以直接验证:apps/ 下确实同时存在上述核心捆绑应用(如 apps/files_sharing/apps/encryption/apps/user_ldap/apps/dav/)与大量独立分发的应用(cloud_federation_apicontactsinteractiondashboardprovisioning_api 等);后者在官方发行中属于独立仓库,修改它们时 Agent 应提示贡献者“此变更不属于本仓库范围”,而不是就地修改。.github/CONTRIBUTING.md 也以相同口径重申了该范围。

九、落地检查清单:从代码生成到提交前的完整闭环

把 AGENTS.md 的全部规则压缩成一条可执行流程,供人类贡献者与 Agent 共同遵循:

  1. 生成阶段:复用既有 helper;注释只描述行为与不变量;访问控制检查前置;用户可见功能在认证视图、公共分享页、Smart Picker/reference 嵌入等全部上下文接线;新依赖先对照注册表核验。
  2. PHP 新增文件:补 SPDX 头(AGPL-3.0-or-later)→ 运行 build/autoloaderchecker.sh 重新生成并提交自动加载器。
  3. 测试阶段:为新/改逻辑补单元测试 → NOCOVERAGE=0 ./autotest.sh sqlite <path>(或 pgsql)本地跑绿 → 人类在真实实例上手工验证新功能。
  4. 提交阶段:Conventional Commits 格式、scope 对应组件 → 添加 Assisted-by: AGENT_NAME:MODEL_VERSION → 人类用 git commit -s 添加 Signed-off-by → 清理死代码、冗余逻辑、乱码字符与无关改动。
  5. PR 阶段:PR 描述由人撰写并披露 AI 工具使用 → 单一关注点、体积过大时先给出拆分方案 → 跨子系统或架构级变更先开 ticket 对齐 → Agent 全程不代开 issue/PR/评审/安全报告。
  6. 安全:疑似漏洞只走 HackerOne 渠道,且经人独立验证。

延伸阅读(仓库内路径)

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