首页
/ OpenHuman 的 ship-and-babysit 工作流:从本地提交到 PR 全绿的端到端发布流程

OpenHuman 的 ship-and-babysit 工作流:从本地提交到 PR 全绿的端到端发布流程

2026-09-05 19:22:49作者:蔡怀权

本文基于 OpenHuman 仓库中的 Agent 定义文件 .agents/agents/ship-and-babysit.md,完整拆解其“提交 → 推送 → 开 PR → 盯 CI 与 CodeRabbit 反馈”的四阶段端到端发布(ship)流程。该文档是 OpenHuman 团队为编码 Agent(Claude Code / Codex 等)编写的行为规范,定义了 fork 模型下的分支/远端规则、功能级 E2E 覆盖门禁、PR 模板合规要求,以及一个可重复执行的 CI 看护循环。读完本文,你将掌握如何在开源 fork 贡献场景中,用脚本化的 gh + git 命令链把一个功能分支安全地驱动到“CI 全绿 + 评审清零”的状态,并了解 OpenHuman 用 mock 后端支撑 Rust / Playwright 双栈 E2E 的配套机制。

一、流程定位:为什么 OpenHuman 需要 ship-and-babysit

.agents/agents/ 目录下,OpenHuman 定义了三个协作 Agent,各司其职:

Agent 文件 职责 触发场景
ship-and-babysit.md 从本地改动一路负责到 PR 变绿:提交、推送、开 PR、盯 CI 与评审反馈 用户要求“端到端把功能发出去”,而非只实现功能
pr-manager.md 接手一个已有 PR:检出、分流评论、应用所有可执行修改、推送回 PR 分支 用户给出 PR URL/编号,要求处理评论、清理、推进到可合并状态
pr-manager-lite.md 在调用方已准备好工作区(分支已检出、base 已合入、upstream 已设置)时,直接跳到“收评论 → 修 → 推” 本地工作区已由 preem 等 shell 助手预先准备好的场景

ship-and-babysit 的 frontmatter 明确了它的定位:

name: ship-and-babysit
description: Commit local changes, push the branch to the user's fork, open or reuse a PR against tinyhumansai/openhuman:main, then babysit CI and CodeRabbit feedback until the PR is green and clean. Use when the user wants an end-to-end ship flow, not just implementation.
model: inherit

即:它不是“实现功能”的 Agent,而是“把已经写完的东西安全送出去并盯到收工”的流程执行器。该文档的完整流程分为四个 Phase:Commit(提交)→ Push(推送)→ Open PR(开 PR)→ Babysit loop(看护循环),并辅以一组硬性 Guardrails(护栏)。下文逐段展开,并结合仓库中真实存在的脚本与测试目录佐证每一环节的落地方式。

二、仓库事实与 fork 模型:流程的前置约定

文档开列了四条“Repo facts”,它们是后续所有命令的坐标系:

  • Upstream 是 tinyhumansai/openhuman,PR 一律以 main 为基线;
  • 分支推送到 origin(用户自己的 fork)upstream 只用于 fetch,绝不向其推送;
  • PR 通过 --head <fork-owner>:<branch> 指向 tinyhumansai/openhuman:main 创建;
  • PR 描述遵循模板 .github/PULL_REQUEST_TEMPLATE.md
  • 功能类改动在 ship 之前必须有匹配的 E2E 覆盖。

为在整个流程中复用,文档要求在开始时一次性解析出 fork 所属者:

FORK_OWNER=$(git remote get-url origin | sed -E 's#.*://[^/]+(\.git)?$#\1#')

这条命令从 origin 的 remote URL(兼容 owner/repo.gitowner:repo.git 两种写法)中用正则提取出 fork owner 段。安全约束同样前置:如果 origin 解析出来就是 tinyhumansai(即没有 fork、直指上游),Agent 必须停下并要求用户先添加 fork remote——永远不把分支推送到上游仓库。这是典型的 fork 贡献模型防护:upstream fetch-only,origin 可读写,从机制上杜绝误推。

三、Phase 1 — Commit:只提交相关内容,不绕过 hook

提交阶段有四步纪律:

  1. 检查 git status、已暂存与未暂存的 diff,以及近期提交信息(用于对齐提交风格);
  2. 如果没有任何改动、且分支已推送、且已有 PR,直接跳到 Phase 4——这是看护循环可以独立复用的关键设计,意味着该文档既可以驱动“从零到绿”,也可以接管“只差盯 CI”的半成品状态;
  3. 如有本地改动,只暂存相关文件,并使用 Conventional Commits 前缀:feat:fix:refactor:chore:docs:test:
  4. 对自己的改动不得绕过 commit hooks(不得用 --no-verify)。

pr-manager.md 相比,ship-and-babysit 的提交纪律更严格:后者在 rebase 解决冲突后允许 --force-with-lease,而本文档对 hook 的态度是“自己的改动必须过 hook”,唯一例外出现在 Phase 2 的 pre-push 场景(后述),且要求把例外显式记录进 PR 描述。

四、Feature E2E 规则:ship 前的覆盖门禁

这是文档中最具工程含金量的一段——它把“什么改动需要什么测试”固化成了可执行的判定规则:

  • Rust 侧:涉及 core、domain、persistence、CLI、JSON-RPC 的功能改动,需要在 tests/*_e2e.rs 中有 Rust E2E 覆盖;新增或变更的 RPC 面通常应落在 tests/json_rpc_e2e.rs
  • 前端侧:用户流程需要 Playwright E2E 覆盖,落在 app/test/e2e/specs/*.spec.ts。仓库中该目录实际包含大量 spec(如 chat-tool-call-flow.spec.tsauth-access-control.spec.tscard-payment-flow.spec.ts 等),与该规则的目录约定一致。
  • mock 贯穿全程:E2E 必须通过 scripts/mock-api-server.mjsscripts/mock-api/*app/test/e2e/mock-server.ts 把后端调用打满 mock,禁止在 E2E 中触碰真实后端或第三方 API
  • 优先使用聚焦命令,避免全量跑:
pnpm test:rust:e2e -- --suite <suite>
pnpm --filter openhuman-app test:e2e:web:build
bash app/scripts/e2e-web-session.sh test/e2e/specs/<spec>.spec.ts
  • 单元测试仍然有价值(针对窄逻辑),但不能替代新功能的 E2E 覆盖。

这几条规则在仓库中都有真实实现支撑,可以直接验证:

  1. pnpm test:rust:e2e 在根 package.json 中定义为 bash scripts/test-rust-e2e.sh。脚本 scripts/test-rust-e2e.sh 的实际行为与文档完全对应:它先在固定端口(默认 MOCK_API_PORT=18505)启动 node scripts/mock-api-server.mjs,轮询 __admin/health 直至就绪,然后串行执行 tests/*_e2e.rs 中列出的全部 suite;支持 --suite <name> 多次过滤(对应文档里的“聚焦命令”),-- 之后的参数转发给 cargo test(例如 -- --ignored 可启用带 #[ignore] 的用例)。脚本还显式设置 BACKEND_URL / VITE_BACKEND_URL 指向 mock 地址,并把 RUST_MIN_STACK 提到 16 MiB 以承载 agent-harness E2E 的深 future 栈——细节与“mock 打满、不碰真实服务”的规则一一对应。该脚本同时被 .github/workflows/e2e.ymlrust-e2e-linux job 调用,保证本地命令与 CI 行为同源。
  2. pnpm --filter openhuman-app test:e2e:web:buildapp/package.json 中映射到 bash ./scripts/e2e-web-build.sh,是 Playwright web 端 E2E 的构建入口。
  3. bash app/scripts/e2e-web-session.sh test/e2e/specs/<spec>.spec.ts 对应的 app/scripts/e2e-web-session.sh 会拉起三件套:mock 后端(默认端口 18473)、openhuman-core(端口 17788,/rpc 端点)和 web 服务(端口 4173),并用临时 OPENHUMAN_WORKSPACE 隔离状态——这正是文档要求的“整条调用链走 mock”的具象化。

从源码结构看,这套规则的意图是:Rust 核心与 Tauri 前端各有独立 E2E 通道,但共享同一个 mock 后端(scripts/mock-api-server.mjs),使本地、Docker、CI 三处跑的是同一条链路,从而让“Feature E2E rule”不只是一句口号,而是有脚本、端口、健康检查兜底的可验证门禁。

五、Phase 2 — Push:先确认不在 main 上

推送阶段三步:

  1. 确认当前分支不是 main
  2. 推送到 origin,若缺少 upstream tracking 则加 -u
  3. 对 pre-push hook 失败做了区分处理:
    • 若 hook 失败源于无关的既有破损(pre-existing breakage),允许 git push --no-verify,但必须在 PR 描述中显式记录这一例外;
    • 若 hook 失败源于自己的改动,必须修复后重新推送。

这个“区分归因、例外留痕”的做法,比一刀切地禁止或允许 --no-verify 更贴近真实 fork 贡献场景:上游仓库的 hook 失败不应阻塞一个与本地改动无关的 PR,但任何绕过都必须进入 PR 叙事,供维护者审计。

六、Phase 3 — Open PR:查重 + 模板合规

开 PR 阶段的命令与要求:

  1. 验证 upstream 确实指向 tinyhumansai/openhuman
  2. 先查该分支是否已有 PR,避免重复开 PR:
gh pr list --repo tinyhumansai/openhuman --head <fork-owner>:<branch> --state open --json number,url
  1. 若不存在 PR,先检查 git log main..HEADgit diff main...HEAD,再撰写标题与描述,且描述必须严格遵循 .github/PULL_REQUEST_TEMPLATE.md。其中 checklist 的每一项都必须勾选;不适用项要写成 - [x] N/A: <reason> 的形式,这样 scripts/check-pr-checklist.mjs(由根 package.jsonpr:checklist 脚本暴露)才能通过。

这一点与真实模板内容吻合:.github/PULL_REQUEST_TEMPLATE.md 的 “Submission Checklist” 明确要求“If a section does not apply to this change, mark the item as N/A with a one-line reason. Do not delete items.”,清单条目覆盖测试新增(happy path + 至少一个 failure/edge case)、变更行 diff 覆盖率 ≥ 80%(由 pnpm test:coveragepnpm test:rust 本地预演,门禁在 .github/workflows/ci-lite.yml)、docs/TEST-COVERAGE-MATRIX.md 的功能 ID 矩阵更新、无新增外部网络依赖(mock 策略)、以及 ## Related 中用 Closes #NNN 关闭关联 issue 等。模板还专门设有一段 “AI Authored PR Metadata”——要求 AI 发起的 PR 记录 Linear issue、分支、commit SHA、验证命令(pnpm --filter openhuman-app format:checkpnpm typecheck、聚焦测试、Rust/Tauri fmt/check)以及被阻断的验证命令与影响面。这与 ship-and-babysit 文档本身作为 Agent 规范的身份形成闭环:Agent 开的 PR,描述结构由模板强约束,且要能解释自己跑了哪些验证

  1. main 为基线创建 PR;
  2. 记录 PR 编号与 URL,供后续看护循环使用。

七、Phase 4 — Babysit loop:看护循环

这是文档同名“babysit”的核心:一个明确终止条件的循环,重复执行直到 PR 变“clean”:

  1. 查 CI
gh pr checks <PR#> --repo tinyhumansai/openhuman --json name,state,link,description
  1. 修 Actions 失败:若是 Actions 支撑的 check 失败,用 gh run view <run-id> --log-failed --repo tinyhumansai/openhuman 拉取失败日志,修复、提交、再推送;
  2. 查 CodeRabbit 反馈:同时拉取 PR 行内评论与 issue 评论:
gh api repos/tinyhumansai/openhuman/pulls/<PR#>/comments --paginate
gh api repos/tinyhumansai/openhuman/issues/<PR#>/comments --paginate
  1. 逐条处置建议:正确且在范围内的建议直接采纳;错误或超范围的建议,先在讨论串里回复一个简短的驳回理由,再处理;
  2. 通过 GitHub GraphQL API 关闭已解决的评审线程(resolve review thread);
  3. 退出条件(三个同时满足):必需 check 全部成功、没有未解决的 CodeRabbit 线程、没有新的 CodeRabbit issue 评论在要求改动。

循环的退出条件被写成合取式(AND),这避免了“CI 绿了但评审没清”或“评审清了但 CI 还在跑”就提前收工的常见 Agent 失败模式。

八、Guardrails:四条不可逾越的护栏

文档末尾列出的护栏值得单独强调,它们定义了该流程的“权力边界”:

  • 绝不推送到 upstream——上游仓库对贡献者永远是 fetch-only;
  • 绝不 force-push main
  • 绝不未处理就 resolve 评审线程——要么修掉问题,要么回复有理有据的驳回理由;
  • 不合并 PR。流程在“CI 全绿 + 评审干净”处停止,合并权保留给维护者。

最后一条尤其关键:它把 ship-and-babysit 定义为“推进到可合并”而非“替人合并”,与 pr-manager.md 中“finish the PR, not produce a triage report”(必须动手修,而不是只输出分流报告)的哲学互补——前者负责把 PR 做完,后者(连同 Guardrails)确保它停在维护者决策的边界之前。

九、配套机制速查

把文档中出现的关键命令/文件与仓库实体对照,读者可以按路径自行深入:

文档中的要素 仓库中的对应实现
pnpm test:rust:e2e -- --suite <suite> package.jsontest:rust:e2escripts/test-rust-e2e.sh(mock 后端 + tests/*_e2e.rs 串行执行,--suite 可多次过滤)
Rust E2E 覆盖落点 tests/*_e2e.rs tests/json_rpc_e2e.rs 等,与脚本内 ALL_E2E_SUITES 列表一致
前端 E2E 落点 app/test/e2e/specs/*.spec.ts app/test/e2e/specs/ 下大量 Playwright spec(chat-*auth-*agent-* 等)
mock 后端 scripts/mock-api-server.mjsscripts/mock-api/app/test/e2e/mock-server.ts
web 端 E2E 会话脚本 app/scripts/e2e-web-session.sh(mock + core + web 三进程拉起,端口隔离)
PR 模板 .github/PULL_REQUEST_TEMPLATE.md(checklist / diff 覆盖率 ≥ 80% / AI Authored PR Metadata)
checklist 校验 pnpm pr:checklistscripts/check-pr-checklist.mjs
同族 Agent pr-manager.mdpr-manager-lite.md

十、小结:一份可移植的 Agent 发布规范

ship-and-babysit 的技术价值不在于任何单条命令,而在于它把“fork 贡献 + AI Agent 值守”这一真实协作场景中的每一个风险点都转化成了显式规则:fork owner 一次性解析且永不推上游、提交只圈相关文件、hook 例外的双归因处理、开 PR 前查重、checklist 的 N/A: <reason> 合规写法、CI 与 CodeRabbit 双通道轮询、线程必须先处置再 resolve、以及“到绿为止但不合并”的权限边界。

从仓库结构看,这套规范并非孤立文本:--suite 过滤、mock 健康检查、e2e-web-session.sh 的三进程编排、pr:checklist 脚本都已经在仓库中实现并被 CI 复用。对维护多语言(Rust + React/Tauri)单仓的团队而言,把这类“发布纪律”沉淀为 Agent 定义文件(.agents/agents/ 下三个 md 文件互为印证),并让规范中的每条命令都能在仓库里找到同名脚本承接,是保证 AI 参与贡献时行为可预期、可审计的关键做法。

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