为 LobeHub Acceptance 编写项目级验收适配层:`.agents/acceptance/PROJECT.md` 设计规范与完整模板
本指南讲解 LobeHub 内置 acceptance(端到端验收)技能中“项目层(project layer)”的设计与落地方法:一个与被测仓库解耦的验收 Agent,如何通过提交在仓库根目录 .agents/acceptance/PROJECT.md 中的适配器,安全、确定地启动服务、登录认证、探测状态并完成证据采集。读完本文你将掌握项目适配器的目录结构、六个固定章节的编写骨架、可直接复制的模板、首次引导(bootstrap)流程、漂移维护规则以及通用层与项目层两份“生活日志”的分工原则。
为什么需要一层“项目适配器”
LobeHub 的 acceptance 技能(版本见 SKILL.md 头部 frontmatter,当前为 0.3.0)是一个与具体项目无关的通用端到端验证工具:由 Builder Agent 负责"编写或发现计划 → 选择验证面(CLI / Web / Electron / Native / iOS)→ 逐条捕获证据 → 发布 round → 自查覆盖率"这条链路。
但"如何启动和停止被测服务、需要哪些端口与服务、认证如何工作、产品暴露哪些界面(surface)、如何一键跳入应用指定状态"——这些每个仓库都不一样,也绝不应该被技能用"猜测"的方式去推断。项目适配器(per-project adapter)正是为解决这一矛盾而生:所有项目特有细节都被收进仓库根目录的 .agents/acceptance/PROJECT.md,技能读取它,但从不猜测项目的命令。
技能自身的职责与仓库的职责因此被切分为两层,这是整个设计的第一原则(见 SKILL.md 的 "Read the project layer first"):
| 层 | 拥有者 | 回答的问题 |
|---|---|---|
项目层(.agents/acceptance/) |
被验证的仓库 | how this repository is run:启动/停止命令、端口、服务、认证、surface、探针 |
| 通用层(acceptance 技能) | LobeHub builtin skill | what a valid round is:计划、证据、报告、round 不可变规则、硬性约束 |
当两者对**“如何运行”有分歧时,项目层获胜;当两者对“什么构成一个有效 round”**有分歧时,本技能(通用层)获胜。运行前两层都必须读取;不得在 PROJECT.md 已回答的启动命令、端口、认证流程上自行发明。若出现分歧,应当在运行过程中直接修复适配器,而不是绕过它。
这段"契约在技能、流程在仓库、双方互不复述"的边界,在 acceptance/index.ts 的实现注释中有更明确的表述:这一拆分取代了原先仓库内置的 agent-testing 技能——契约留在此处,仓库的流程留在彼处。配套测试 index.test.ts 也专门断言了 "routes to the project layer before touching an environment"(触及环境前先路由到项目层),验证技能正文必须包含 .agents/acceptance/、PROCESS.md 与指向本适配器文档的链接。
.agents/acceptance/ 目录结构与入库约定
适配器所在的仓库目录布局如下:
<repo>/.agents/acceptance/ # 提交入库 —— 适配器与项目日志是团队资产
├── PROJECT.md # 适配器:命令、端口、服务、认证、界面
├── PROCESS.md # 可选:项目的运行流程(审批门禁、清理、发布)
├── common-mistakes.md # 项目层生活日志(可写)
├── probe-mock-patterns.md # 项目层生活日志(可写)
├── references/ # 可选:项目自有的 how-to
└── scripts/ # 可选:项目环境 / 探针 / 截图脚本
.agents/acceptance/ 必须提交入库(committed)——适配器与项目生活日志是被团队成员共享、受版本控制的资产;PROJECT.md 还可以引用 .agents/acceptance/scripts/ 或仓库任意位置的脚本。
与适配器相反,每次运行产生的报告产物不入库。原适配器文档称之为报告输出目录 .records/:报告是单次运行的临时产物,被发布到 LobeHub Acceptance 而不是提交。在当前 CLI 实现中,这些产物实际落在自动自我忽略的 .acceptances/ 目录下(见 acceptanceDir.ts):ensureAcceptanceDirIgnored 在 .acceptances/ 内部写入一个内容为 * 的 .gitignore,使整棵产物树(result.json、report.md、证据截图与 GIF 等二进制)永远不进入 git 历史,同时也绝不改写项目自身的根 .gitignore;每次 round 按 YYYYMMDD-HHMMSS-<slug> 在主题分组下分配不可变子目录(acceptanceDir.ts)。该实现注释明确指出:这与"物化技能需提交"是刻意相反的决策——技能是可供评审的团队资产,应提交;产物不是,不应提交(acceptanceDir.ts)。
PROCESS.md:可选的项目自有运行流程
一个会自我验证的仓库,往往不只是需要分享命令——它可能还要求:
- 触碰环境前的审批门禁(approval gate);
- 一套清理纪律(teardown discipline);
- 明确的发布目标;
- 约定的报告目录规范。
这些与命令无关、但决定"这一次运行怎么执行"的约定,放在适配器旁边的 .agents/acceptance/PROCESS.md 中。只要该文件存在,它就拥有运行流程的所有权,而 acceptance 技能只负责提供验收契约(plan、evidence、report、round)。关于"运行方式"两者冲突时以项目层为准;关于"什么是有效 round"则以技能为准。
PROJECT.md 的固定六段式骨架
PROJECT.md 永远按如下顺序包含六个章节。技能会按编号引用章节(PROJECT.md §2、§3……),因此编号顺序必须保持不变:
- Project summary(项目概要) — 产品是什么;与测试相关的仓库布局(哪个包承载服务器、Web 应用、桌面壳、CLI)。
- Environment(环境) — 如何启动/停止开发环境;必需服务(数据库、缓存、队列、对象存储)及各自启动方式;如何检测"已在运行"以免一次运行覆盖用户的服务器;环境与端口如何解析(优先使用项目自身的 env 解析命令,绝不硬编码端口表)。
- Auth(认证) — 测试账号、种子(seeding)命令、以及按界面区分的登录态状态检查(每个界面一条命令回答"我在这个界面是否已登录?")。
- Surfaces(界面) — CLI / Web / Electron 哪些适用;对每个适用的界面给出:启动命令、基础 URL/端口、agent-browser 会话名(Web/Electron)、由哪些探针脚本驱动。
- Project probes & quick navigation(项目探针与快速导航) — 进入应用状态的快捷路径:认证探针、当前路由探针、进行中操作探针,以及
goto <route>快速导航与值得跳转的路由清单。这是项目侧"状态自省助手"的等价物;技能用它取代手写的 store-eval 片段。 - Known constraints(已知约束) — 通用门禁在运行前必须知道的任何事项:某条代码路径的硬性前置服务(例如"Agent 运行需要队列服务处于启动状态")、需要各自独立安装的独立子包、仅支持 macOS 的界面,或任何一次运行必须遵守的仓库特有注意事项。
可直接复制的 PROJECT.md 模板
以下为官方模板全文,可直接作为编写起点(占位符 <...> 需按项目实际替换,不适用的界面章节删除):
# PROJECT.md — acceptance adapter for <project name>
## 1. Project summary
<One paragraph: what the product is. Then the repo layout that matters for testing —
which directory/package is the server, the web app, the desktop shell, the CLI.>
## 2. Environment
- **Start dev server:** `<command>` (base URL: `<url>`, port: `<port>`)
- **Stop dev server:** `<command>` (must stop only what this run started)
- **Required services:** <db / cache / queue / object store — with the start command
for each, or "none">
- **Already-running detection:** `<health-check command>` — how to tell the server is
up before starting another one.
- **Env / port resolution:** `<command or file>` — the source of truth for ports and
URLs. Do NOT hard-code a port table; read it here.
## 3. Auth
- **Test account(s):** <how to obtain — seeded, fixture, or a real login>
- **Seeding command:** `<command>` (or "n/a")
- **Per-surface status check:**
- CLI: `<command>` — signed-in when <...>
- Web: `<command>` — signed-in when <...>
- Electron: `<command>` — signed-in when <...>
## 4. Surfaces
<For each surface that applies. Delete the ones that don't.>
### CLI
- Invocation: `<how the CLI is run — from source or built binary>`
- Auth: <see §3 CLI>
- Standalone install: `<command>` or "covered by root install"
### Web
- Launch: `<dev server command>` (from §2)
- Base URL: `<url>`
- agent-browser session: `<session name>`
### Electron
- Launch: `<start command>` — CDP port `<port>`
- Stop: `<command>`
- Login persistence: <how login survives across runs>
## 5. Project probes & quick navigation
- Auth probe: `<command>` → `{ isSignedIn, userId }`
- Route probe: `<command>` → current route
- Operations probe: `<command>` → running operations
- Quick navigation: `<command> goto <route>`
- Routes worth jumping to: <list>
## 6. Known constraints
- <e.g. "agent runs require the queue service (§2) up, or the run dies before any
real work">
- <e.g. "the desktop and CLI packages are standalone — install inside each">
- <e.g. "OS-capture surfaces are macOS-only">
几个值得注意的实操要点:
- 第 2 节的端口解析强调"读,不要写":端口的唯一事实来源应指向项目自身的 env 解析命令或文件,而不是在适配器里维护一份会漂移的端口表。
- 第 3 节的每界面登录态检查必须是一条可执行命令,输出能明确回答"该界面是否已登录",这是 Web/Electron 每次截图前认证门禁(auth gate)的前提(详见 auth-web.md)。
- 第 5 节的探针(probe)是技能替代自写 store-eval 的标准手段:为认证、当前路由、运行中操作各准备一条命令,并提供
goto <route>快速导航。探针脚本可放在.agents/acceptance/scripts/或仓库任意位置。 - 第 6 节把"通用门禁运行前必须知道的事"显式化:例如 macOS-only 的 OS 捕获面、需要独立安装的桌面/CLI 子包等,防止技能在错误的平台上做无效验证。
首次引导(First-run bootstrap):先建适配器,再跑任何验证
当仓库中不存在 .agents/acceptance/PROJECT.md 时,验收 Agent 必须在做任何其他事情之前先把它构建出来,流程分四步:
- 探索仓库。 阅读能揭示项目如何运行的信号:
package.jsonscripts、README、CI 工作流(.github/workflows/**)、Makefile/Justfile、docker-compose*.yml/compose.yaml、.env.example,以及任何现成的测试/开发文档。记录 dev-server 命令、所需服务、端口、认证方案与存在的界面。 - 按上述骨架起草
PROJECT.md,用探索结果填满每一节。对不确定的值,明确标注为猜测(guess),而不是凭空编造一条命令。 - 提交用户确认。 把草稿展示给用户并请求确认或修正——尤其是启动/停止命令、必需服务与认证路径。不得针对未经确认的适配器启动 dev server 或编写测试步骤。
- 仅在获得批准后写入
.agents/acceptance/PROJECT.md;若该目录不存在则先创建。
一个重要边界:lh acceptance install 只负责把技能文件放到 .agents/skills/acceptance/,它不做任何仓库探索。 适配器草稿需要模型参与,因此正是"第一次验证运行"这个环节完成 PROJECT.md 的引导初始化。
源码侧的 install 语义
lh acceptance install 的实现印证了上述边界(acceptanceRun.ts):
- 它通过服务端
verify.getSkillBundle拉取最新技能包,把SKILL.md与全部 resource 文件写入<cwd>/.agents/skills/acceptance/——这是一个物化产物(materialized artifact),通过重新安装来更新、从不手工编辑,且应当提交(安装过程不会为它写入任何 ignore 条目)。 - 已有文件存在且未传
--force时跳过;acceptance update语义上等价于显式--force强制刷新,并会删除旧 bundle 中已不存在(重命名/拆分后)的陈旧引用文件,防止旧引用继续被发现。 - 安装同时会
linkHarnessSkills建立各 harness 目录(如.claude/skills)指向.agents/skills的相对符号链接(见 skillWiring.ts),并播种.acceptances/.gitignore,使从未运行过的仓库在首次截图时也不会产生未跟踪噪音。 - 只有安装技能文件这一个职责——安装完成后不会触发任何 repo 探索或
PROJECT.md生成。
漂移规则:把适配器当作生活日志维护
把适配器当作一份持续更新的生活日志(living log):当运行中观察到的现实与之背离时(端口迁移、启动命令变化、某个服务变为必需),应当在运行过程中就地修复 PROJECT.md,而不是静默绕开它。这样下一次运行不必重新发现同一处漂移。
这套"运行中修正文档"的纪律与技能正文中 "fix a divergence in the adapter during the run instead of working around it" 的规则一脉相承(SKILL.md):仓库被验证得越多,适配器越准确,后续运行的成本就越低。
两层生活日志(living logs)与单向保密规则
技能同时维护两层 common-mistakes.md 与 probe-mock-patterns.md,但两者的性质完全不同:
| 层 | 文件位置 | 可写性 | 更新方式 |
|---|---|---|---|
| 通用层(generic layer) | 技能源内 references/common-mistakes.md、references/probe-mock-patterns.md(本仓库路径为 references/) |
只读 | 向技能源提交 PR |
| 项目层(project layer) | 仓库内 .agents/acceptance/common-mistakes.md、.agents/acceptance/probe-mock-patterns.md |
可写 | 运行中直接追加记录 |
原因在于:安装在消费者仓库里的通用层副本是从技能源物化而来的,对它的任何就地编辑都会在下次技能更新时丢失,因此必须通过 PR 修改技能源。而项目层是唯一允许一次运行记录项目特有经验教训的地方。运行时 Agent 会读取两层日志,但只写项目层(技能正文要求:Record new project-specific learnings in the project layer only)。技能的两份通用日志在注入方式上也与适配器不同——common-mistakes.md 需在每次标记 pass 前完整阅读其 Checklist;probe-mock-patterns.md 按标题索引只抽取本轮需要的条目(SKILL.md)。
当某条项目层记录被证明与具体产品无关时,可以将其通用化(genericize)——删掉所有项目特有名词——后通过 PR 上提(promote)到上游通用层。
这里有一条单向保密规则(Confidentiality runs one way):任何涉及项目包名、路由、schema、环境变量、服务名或业务逻辑的内容,必须留在项目层;只有把项目名词全部移除后读起来依然成立的规则,才允许被提升到通用层。这保证了通用层技能在任意仓库间流通时,不会携带任何一个具体项目的内部信息。
结语:契约与实现的边界是这套体系的核心
从 .agents/acceptance/PROJECT.md 的六段骨架、PROCESS.md 的运行流程所有权、首次引导的四步流程,到运行时"就地修复而非绕开漂移"的维护纪律,再到两层生活日志的单向保密规则——acceptance 项目适配层的核心思想始终一致:技能负责"什么样的验证是有效的",仓库负责"这个仓库怎么跑",二者各司其职、互不复述,项目细节永远收敛在仓库侧的可写层中。这使同一个验收技能可以被安全地复用到任意仓库,同时让每个仓库的验证行为精确、确定且可被团队评审与版本化。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00