# 从零构建 Agent 友好项目:Harness 工程实践与文档标准 > 用途:用于新项目初始化和长期治理。它定义“哪些知识需要存在、放在哪里、按什么格式写、如何验证”。 > > 核心结论:OpenSpec 只负责当前行为与行为变更;完整 Harness 还必须让 Agent 能找到事实、运行系统、观察结果、遵守边界、独立验证并持续清理熵。 ## 1. 先澄清:ADR 不是 OpenSpec - OpenSpec 的标准 Artifact 是 `proposal`、增量 `specs`、`design` 和 `tasks`。 - `design.md` 记录**一次 Change** 的实现设计、取舍、迁移和回滚。 - ADR 是业界通用但独立的“长期架构决策记录”,不属于 OpenSpec,也不是新项目必需品。 - 默认不建 `adr/`。只有一个跨 Change、长期生效、存在真实竞争方案且无法从代码理解原因的决策,才考虑单独记录;否则留在对应 Change 的 `design.md`。 ## 2. Harness 的完整范围 OpenAI 的 Harness Engineering 不只是“短 AGENTS.md + docs”。一个完整闭环包含: 1. **仓库可读**:事实进入仓库,并有清晰索引和单一权威位置。 2. **环境可运行**:每个工作区能独立启动、测试和复现。 3. **结果可观察**:Agent 能读取日志、指标、追踪、页面和 DOM,而不是靠猜。 4. **架构可约束**:依赖方向、边界数据解析和关键不变量可机械检查。 5. **任务可判定**:需求被写成可观察、可验证的行为契约。 6. **执行可闭环**:Agent 能复现、修改、验证、比较前后结果并处理反馈。 7. **知识可维护**:链接、Owner、新鲜度和生成来源可检查,过期内容持续清除。 8. **人类掌舵**:人负责目标、优先级和判断点;Agent 负责读取、执行、验证和维护。 因此,Context 收敛不是“少写文档”,而是让默认 Context 很小、按需 Context 有标准、运行反馈足够强。 ## 3. 从最小集合开始 ### 3.1 所有项目 Day 0 必需 ```text AGENTS.md # 短导航与真正的全局硬约束 README.md # 人和 Agent 都可执行的启动入口 ARCHITECTURE.md # 一页系统地图和依赖边界 openspec/ # 当前行为与行为变更 CI / scripts # 格式化、检查、测试、构建命令 ``` ### 3.2 有真实内容时才创建 ```text docs/integrations/ # 存在第三方契约 docs/engineering/ # 存在跨模块、长期工程约束 docs/generated/ # 能由命令稳定再生的参考资料 RELIABILITY.md # 存在队列、重试、容灾、SLO 等系统性要求 SECURITY.md # 存在统一信任边界、敏感数据或威胁模型 FRONTEND.md # 前端规模足以需要统一交互/状态/设计规则 PRODUCT_SENSE.md # 多团队或 Agent 经常误判产品取舍 QUALITY_SCORE.md # 已有明确评分维度和维护机制 ``` 不要预建空目录、空模板或“以后也许有用”的文档。 ### 3.3 如何理解 OpenAI 文章中的示例目录 文章展示的是一套成熟仓库的实际结构,不是要求每个项目照抄。与本指南的映射如下: | 文章中的示例 | 解决的问题 | 本指南的默认选择 | |---|---|---| | `ARCHITECTURE.md` | 系统地图与边界 | Day 0 创建一页版本 | | `docs/design-docs/`、`DESIGN.md` | 跨范围设计知识 | 单次变更放 OpenSpec `design.md`;只有长期跨 Change 设计才另建 | | `docs/exec-plans/{active,completed}`、`PLANS.md` | 长任务持续执行 | 默认用 OpenSpec `tasks.md`;非行为型长期治理才建唯一执行计划 | | `docs/product-specs/` | 当前产品行为 | 使用 `openspec/specs/`,不再复制一套 | | `docs/generated/db-schema.md` | Agent 可检索的生成事实 | 有稳定生成命令时放 `docs/generated/` | | `docs/references/*-llms.txt` | 将仓库外依赖资料变成 Agent 可读输入 | 仅保存任务高频需要且无法稳定在线获取的官方资料;第三方协议归 `docs/integrations/` | | `FRONTEND.md` | 前端统一边界 | 前端复杂度触发后创建 | | `PRODUCT_SENSE.md` | 产品判断原则 | 重复误判触发后创建 | | `QUALITY_SCORE.md` | 领域/架构质量评分 | 有固定评分和治理动作后创建 | | `RELIABILITY.md`、`SECURITY.md` | 跨系统可靠性和安全约束 | 对应风险出现后创建 | 关键不是目录名一致,而是:每类知识有唯一权威位置、Agent 可发现、能被验证、不会和 OpenSpec 重复。 ### 3.4 不重复的事实分工 | 知识 | 权威位置 | 不应放入 | |---|---|---| | 当前可观察业务行为 | `openspec/specs/` | AGENTS、工程规范 | | 拟议行为变化 | `openspec/changes//` | 主 Specs、路线图副本 | | 系统地图和依赖方向 | `ARCHITECTURE.md` | 每个 Change 重复描述 | | 第三方提供的契约 | `docs/integrations/` | 业务 Spec 原文复制 | | 长期工程约束 | `docs/engineering/` + 检查器 | 任务型 Skill | | 实现事实 | 代码、配置、迁移 | 叙述文档副本 | | 可再生参考资料 | `docs/generated/` | 手工维护文档 | | 任务过程 | OpenSpec Change 或唯一执行计划 | 第二套 TODO/状态台账 | | 完成证据 | 测试、CI、运行输出 | 长期“完成总结” | ## 4. 每类文档的统一质量契约 除生成文档外,长期文档至少要让读者回答: ```yaml purpose: 这份文档解决什么问题 scope: 适用与不适用范围 source_of_truth: 哪些事实由本文权威维护,哪些只引用 owner: 负责判断内容是否仍成立的角色或团队 last_verified: 最后通过代码、运行结果或官方来源核验的日期 update_triggers: 哪些变更发生时必须同步检查本文 verification: 用什么命令或证据判断内容仍有效 ``` 这不要求所有文件都使用 YAML;要求这些信息明确可找到。 ### 合格标准 - 写具体规则和可判定结果,不写“注意质量”“合理处理”等口号。 - 关键声明有代码路径、命令、测试、Schema 或官方来源支撑。 - 复制外部内容时标明来源版本和核验时间。 - 一项事实只有一个权威正文,其他位置只链接。 - 每个“必须/禁止”都对应机械检查,或明确说明当前为何只能人工审查。 - 示例只用于消除歧义;示例不得成为第二份规则。 ### 不合格信号 - 没有适用范围、Owner 或更新触发条件。 - 只有目录介绍,没有依赖方向、入口或验证方式。 - 把当前 Bug 写成理想行为,或把未来设计冒充当前事实。 - 从代码能直接搜索得到的列表被手工复制并长期维护。 - 同一个状态、错误码或字段定义在多份文档中各写一遍。 ## 5. AGENTS.md 标准 ### 必填内容 1. 项目一句话目标。 2. Agent 从代码无法自然发现、且几乎所有任务都适用的硬约束。 3. build、test、lint、spec 验证的真实命令。 4. 事实源优先级和按需文档入口。 5. 禁止直接修改的生成物、敏感路径或外部生产边界。 ### 禁止内容 - 完整 DTO、Model、路由或迁移操作步骤。 - 领域状态机、接口字段表和第三方协议正文。 - 已完成任务、历史方案、长 Review 清单。 - Agent 能从代码、包管理器或 `--help` 获取的通用知识。 ### 尺寸与验证 - 80~120 行是目标,150 行是软预算。 - 每一行应对大多数任务有价值。 - CI 检查链接有效;验证命令必须在干净环境可运行。 ```md # 项目 Agent 指南 ## 项目目标 <一句话> ## 全局硬约束 - <规则;对应检查命令或规则文档链接> ## 验证 - Build: `` - Test: `` - Lint: `` - Spec: `openspec validate --all` ## 事实源 - 当前行为:`openspec/specs/` - 系统边界:`ARCHITECTURE.md` - 外部契约:`docs/integrations/` - 工程约束:`docs/engineering/` ``` ## 6. ARCHITECTURE.md 标准 它是系统地图,不是完整设计书。目标是让新 Agent 在几分钟内知道从哪里进入、允许依赖谁、数据如何流动。 ### 必填章节 1. **系统职责与非职责**:系统解决什么,不解决什么。 2. **运行单元**:API、Worker、定时任务、前端、数据库、缓存、外部系统。 3. **领域/模块地图**:模块职责、Owner(如有)和主要入口路径。 4. **依赖方向**:允许和禁止的跨层、跨模块依赖。 5. **关键数据流**:请求、异步事件、回调、读写路径。 6. **信任与事务边界**:外部输入在哪里解析,事务在哪里开始/结束。 7. **验证方法**:结构测试、依赖检查、启动或 smoke 命令。 8. **详细资料索引**:链接 Specs、工程约束和外部契约,不复制正文。 ### 写法标准 ```md ## 模块:订单 - 职责:创建订单并管理支付前后的状态流转 - 入口:`internal/...` - 可依赖:共享错误、支付 Port - 禁止依赖:HTTP Handler、具体支付 SDK - 行为契约:`openspec/specs/orders/spec.md` - 结构验证:`` ``` ### 机械检查 - 用 import/dependency 测试验证禁止依赖。 - 用 smoke 命令验证列出的运行单元确实可启动。 - 用链接检查验证每个引用存在。 - 模块增删、入口迁移或依赖方向改变时触发更新。 ## 7. 外部契约文档标准 外部契约记录“第三方实际要求我们怎样交互”。它不是本系统的产品需求,也不是 SDK 使用教程。 ### 7.1 目录规则 ```text docs/integrations// ├── README.md # 当前接入契约与导航 ├── examples/ # 经脱敏、可复现的请求响应样例(需要时) └── source/ # 无稳定链接的官方原文快照(需要时) ``` 官方内容有稳定 URL 时只保存链接和项目所需摘要;不要复制整站文档。 ### 7.2 README 必填字段 ```md # 接入契约 ## 元数据 - Owner: <角色/团队> - 官方来源: - 官方版本/发布日期: <值或 unknown> - 项目适用环境: - 最后核验: YYYY-MM-DD - 更新触发: SDK升级、官方版本变化、字段/签名/错误码变化 ## 接入范围 - 使用能力:<项目实际使用的 API/事件> - 不使用能力:<容易误用但明确不接入的能力> ## 端点与认证 | 场景 | Method | URL/Topic | 认证 | 超时 | ## 请求契约 | 字段 | 类型 | 必填 | 约束 | 来源章节 | 项目映射 | ## 响应与错误 | 外部状态/错误码 | 含义 | 可重试 | 项目处理 | 告警 | ## 签名与回调 - 签名原文构造:<精确定义> - 验签步骤:<精确定义> - 时间窗/重放保护:<规则> - 回调确认语义:<响应内容和重试条件> ## 可靠性 - 幂等键:<字段与作用域> - 超时:<连接/请求> - 重试:<次数、退避、仅哪些错误> - 限流:<规则> - 对账/补偿:<触发与入口> ## 安全与数据 - 凭证名称及托管位置:<只写名称,不写密钥> - 敏感字段:<日志脱敏规则> - 来源校验:<证书/IP/签名等> ## 验证 - 本地/沙箱命令:`` - 固定输入:`` - 预期结果:`` - 生产人工验收:<只有真实环境才能完成的最小步骤> ``` ### 7.3 质量门禁 - 所有项目使用的字段都能追溯到官方来源或经确认的真实样例。 - 签名、金额单位、时间格式、编码、回调确认内容必须写成精确规则。 - 每种外部错误明确:重试、失败、忽略、人工处理中的一种。 - 重试必须同时定义上限、退避和幂等保护。 - 示例必须脱敏,并可被测试或脚本读取;真实密钥不得进入仓库。 - 至少有一个沙箱/契约测试,或明确记录为何只能人工验收。 ### 7.4 不合格示例 ```md 调用失败时适当重试。 ``` 问题:没有错误范围、次数、退避、幂等和最终失败动作,无法实现或验证。 合格写法: ```md 仅对连接超时和外部错误 E_TEMP 重试;最多 3 次,间隔 1s/2s/4s; 每次复用同一幂等键。三次失败后记录 integration failure 并进入人工对账队列。 ``` ## 8. 工程约束文档标准 工程约束描述“所有相关代码长期必须保持的性质”。DTO、Model、路由、迁移、注释、依赖边界属于此类,而不是 Skill。 ### 8.1 一条约束的标准格式 ```md ### ENG--NNN:<可判定标题> - 状态:active | deprecated - 适用范围:<路径、语言、组件或操作> - 规则:MUST/MUST NOT <单一可判定约束> - 理由:<错误成本或架构原因;不复述规则> - 正例:`<最小示例或现有代码链接>` - 反例:`<最小示例>` - 机械检查:`<测试/Lint/脚本命令>` 或 `暂为人工:<原因>` - 例外:<允许条件、批准者、记录位置;无则写“无”> - Owner:<角色/团队> - 最后验证:YYYY-MM-DD - 更新触发:<框架升级、目录调整、事故等> ``` ### 8.2 规则拆分标准 - 一个 ID 只表达一个义务,避免“正确、安全、高性能地处理”。 - 适用范围必须能映射到路径或组件。 - 正例优先链接仓库内稳定实现,不复制大段代码。 - 反例只展示最容易犯且有实际代价的错误。 - 规则能由机器判断时,文档必须链接检查器;检查器才是执行门禁。 - 例外必须有边界和到期/复审条件,不能写“特殊情况除外”。 ### 8.3 分类 | 分类 | 应记录 | 首选验证 | |---|---|---| | 架构 | 依赖方向、分层、边界解析 | 结构测试、import Lint | | 数据 | 迁移、主键、金额单位、事务 | Schema/Lint/集成测试 | | API | 路由注册、错误形状、兼容性 | OpenAPI diff、契约测试 | | 可靠性 | 幂等、重试、锁、Outbox | 故障注入、集成测试 | | 安全 | 权限、敏感字段、信任边界 | 安全测试、静态检查 | | 代码品味 | 禁止无价值抽象、复杂度上限 | Lint + Review | ### 8.4 合格与不合格示例 不合格: ```md 数据库迁移要谨慎,注意兼容旧数据。 ``` 合格: ```md ### ENG-DB-003:新增非空列必须可在线回填 - 适用范围:`migrations/` - 规则:已有数据表新增非空列时,MUST 先增加可空列或带兼容默认值,完成回填后再收紧约束。 - 理由:直接增加无默认值的非空列会使现有数据迁移失败。 - 机械检查:`` - 例外:仅空表;必须在 Change design 中提供查询证据。 ``` ## 9. OpenSpec 生成提案的标准 用户不需要手工填写长表。AI 生成 Change,但生成器和 Reviewer 必须遵守质量门禁。 ### 9.1 Explore 后才能确定的内容 - 当前行为和证据路径。 - 目标、原因、范围和非目标。 - 角色、资源、前置状态和数据范围。 - 状态、金额、权限、事务、并发、幂等和外部失败边界。 - 已知事实、推断和真正需要人决策的问题。 ### 9.2 Proposal 只回答为什么、做什么、不做什么、影响哪些 Capability。不得塞入实现步骤和通用工程规范。 ### 9.3 Requirement / Scenario ```md ### Requirement: <一个可观察义务> 系统 SHALL <测试者无需阅读实现即可判定的结果>。 #### Scenario: <场景> - **GIVEN** <角色、数据、前置状态> - **WHEN** <一个动作> - **THEN** <可观察结果> - **AND** <副作用或必须保持的不变量> ``` 门禁: - 一个 Requirement 一个主要义务。 - Scenario 有具体前置条件、触发和结果。 - 覆盖主流程以及代价最高的权限、失败、边界或重复场景。 - 不使用“体验良好”“正确处理”“高性能”等不可判定词。 - 不写函数名、表名、ORM、缓存或队列选型。 - Brownfield 的错误现状也按 As-Is 写入;Spec 描述事实不等于认可设计。 ### 9.4 Design 记录本 Change 的架构通道、数据与事务、并发、外部失败、兼容、迁移、发布、回滚和真实取舍。简单且实现显然时保持简短。 ### 9.5 Tasks - 按可独立验证的纵向切片拆分,不按 Model/Service/Handler 水平拆分。 - 每项映射 Requirement/Scenario,并包含最小验证命令和预期结果。 - 适用时同时验证响应、持久化、副作用和失败不变量。 - 实施发现 Artifact 与事实冲突时同步修订,不静默跳过或扩大任务。 ## 10. Generated docs 标准 仅当内容能稳定再生且 Agent 经常需要查询时创建,例如数据库 Schema、OpenAPI 摘要或配置清单。 每份生成文件顶部必须包含: ```md - Source: <代码/Schema 路径> - Command: `<生成命令>` - Generator version: <版本> - Generated at: <时间或来源 commit> ``` CI 重新生成并检查 diff。生成结果没有稳定命令时,它就不是 generated doc,而是会腐烂的手工副本。 ## 11. 唯一执行计划标准 一般功能直接使用 OpenSpec `tasks.md`,不要再建 `docs/exec-plans/`。只有不改变产品行为、跨多天且 OpenSpec 不适配的迁移/治理任务,才使用单独执行计划。 必填内容: - 目标和完成定义。 - 范围、非目标和受保护路径。 - 前置依赖和顺序。 - 可恢复的任务清单,每项含验证。 - 当前进度,只在这一处更新。 - 关键决策与新发现。 - 回滚条件和命令。 - 最终验收命令及预期结果。 Manager、Executor、Auditor 可以分工,但只能共享这一份任务契约;Harness state 和报告只是可丢弃证据。 ## 12. Agent 可操作环境标准 ### 12.1 独立运行 - 每个 worktree/工作区可使用不同端口和隔离的临时数据启动。 - README 提供一条启动命令、一条测试命令和一条重置命令。 - 依赖、种子数据和环境变量有可复制的本地默认值;真实凭证不入库。 ### 12.2 浏览器与 UI 有 UI 时,Agent 应能: - 启动应用并通过浏览器/CDP 操作关键流程。 - 保存失败前后的截图或视频。 - 读取 DOM、Console error 和失败网络请求。 - 用稳定测试定位器,而非脆弱坐标。 ### 12.3 可观测性 本地至少能按 request/correlation ID 串起: - 结构化日志。 - 关键指标。 - 跨进程或异步链路追踪(系统存在此类链路时)。 提供最小查询命令。临时本地可观测栈应可一键启动和销毁,运行数据不作为长期事实源。 ### 12.4 自主验证闭环 ```text 复现问题 → 捕获基线 → 修改 → 运行最小测试 → 启动系统 → 检查日志/指标/页面 → 对比前后 → 完整门禁 → 提交审查 ``` 只有产品取舍、不可逆操作、真实生产权限或相互冲突的事实需要升级给人。 ## 13. Reliability、Security、Product Sense、Quality Score 这些不是所有项目的固定作业。 ### RELIABILITY.md:何时创建 当系统出现 SLO、重试、队列、定时任务、降级、容灾或数据修复策略时创建。最低结构:关键用户旅程、SLO/错误预算、故障模式、超时重试、幂等与补偿、观测和告警、恢复/演练、Owner。 ### SECURITY.md:何时创建 当存在统一信任边界、敏感数据、权限模型或外部暴露面时创建。最低结构:资产和角色、信任边界、认证授权、数据分类、密钥、审计、主要威胁与控制、验证命令、事件入口、Owner。 ### PRODUCT_SENSE.md:何时创建 当多个功能反复需要相同产品判断、Agent 经常做出局部正确但产品错误的选择时创建。最低结构:目标用户、核心任务、优先级原则、明确非目标、取舍示例、正反例。具体行为仍归 OpenSpec。 ### QUALITY_SCORE.md:何时创建 只有团队真的按固定维度定期评分并采取行动时创建。每项必须有定义、证据来源、当前分数、阈值、Owner、改进动作和复评日期;没有维护机制就不要创建。 ## 14. 文档检查与持续清熵 ### 每次变更 - 检查内部链接和引用路径。 - OpenSpec 校验全部通过。 - 生成文档可无差异再生。 - 架构边界检查通过。 - Change 完成后同步/归档 Specs,删除被替代的同义说明。 ### 周期性 doc-gardening Agent 定期生成候选清单,人只处理真正的判断点: - 失效链接、孤儿文件和长期 TBD。 - `last_verified` 过期且影响仍高的文档。 - 与代码、测试或 Specs 冲突的声明。 - 重复规则、重复事实和已被检查器取代的提醒。 - 已完成的临时计划、报告和可丢弃运行证据。 清理优先级:删除 > 合并到权威位置 > 更新 > 新建索引。 ### 黄金原则 把反复出现的 Review 意见和事故教训变成最靠近问题的自动化约束:测试、类型、Lint、Schema、结构检查或运行时保护。不要持续加长 AGENTS.md。 ## 15. Day 0 到稳定期的落地顺序 1. Agent 生成最小可运行仓库、格式化、包管理、CI 和测试骨架。 2. 建立短 `AGENTS.md`、可执行 `README.md` 和一页 `ARCHITECTURE.md`。 3. 初始化 OpenSpec;第一个真实功能走 Explore → Propose → Review → Apply → Verify → Archive。 4. 打通独立工作区启动、日志读取和最小 smoke 测试。 5. 出现真实第三方时按外部契约模板创建资料。 6. 出现重复工程失误时先加检查器,再补对应约束 ID。 7. 只有触发条件成立时增加 Reliability、Security 等专项文档。 8. 持续删除完成报告、重复事实和过期 Context,避免周期性大扫除。 ## 16. 最低验收清单 - [ ] 新 Agent 只读 AGENTS.md 就能找到行为、架构、外部契约和验证入口。 - [ ] README 的启动、测试、重置命令在干净工作区可执行。 - [ ] ARCHITECTURE.md 的依赖方向有检查或明确人工门禁。 - [ ] OpenSpec Requirement/Scenario 可观察、可判定。 - [ ] 外部契约的版本、字段、签名、重试、幂等和验证证据齐全。 - [ ] 每条工程约束有范围、规则、理由、检查、例外和 Owner。 - [ ] Agent 能自行读取错误日志;有 UI 时能读取页面和网络失败。 - [ ] 同一事实没有多个权威正文。 - [ ] 文档链接、生成检查、Spec 校验和测试进入 CI。 - [ ] 临时计划、状态和运行证据不会成为第二事实源。 ## 17. 参考资料 ### 第一方 - [OpenAI Harness Engineering](https://openai.com/index/harness-engineering/) - [OpenSpec Overview](https://openspec.dev/docs/overview) - [OpenSpec Writing Specs](https://openspec.dev/docs/writing-specs) - [OpenSpec Getting Started](https://openspec.dev/docs/getting-started) - [LongHorizon-Harness](https://github.com/AMAP-ML/LongHorizon-Harness) ### 补充实践 - [Augment:How to write good AGENTS.md files](https://www.augmentcode.com/blog/how-to-write-good-agents-dot-md-files) - [BetterClaw:AGENTS.md best practices](https://www.betterclaw.io/blog/agents-md-best-practices) - [What goes in AGENTS.md?](https://ro14nd.de/what-goes-in-agents-md/) - [Domain Expertise Is the New Agentic Coding Moat](https://www.developersdigest.tech/blog/domain-expertise-agentic-coding-moat) - [O’Reilly:How to write a good spec for AI agents](https://www.oreilly.com/radar/how-to-write-a-good-spec-for-ai-agents/)