mcpField
S
ship

ship

github.com/rheinmir开发10216 次安装2 周前更新
代码仓库

关于 ship

ship 是发布工作流技能,会按仓库类型检查条件,再推送变更或处理待合并的 PR、MR。它先展示检查清单,并在执行远程操作前等待明确批准。

主要功能

  1. 01按仓库类型检查发布条件
  2. 02支持 push、release、PR、MR 和 merge
  3. 03运行健康检查及适用的远程 UAT
  4. 04准备发布说明或 PR、MR 文本
  5. 05远程操作前等待批准

适用场景

  1. 01推送变更前检查准备情况
  2. 02准备发布或创建 PR、MR
  3. 03合并前测试待处理请求

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/rheinmir/setup --skill ship

安装后在 Claude Code 中输入/ship确认已加载。

详细介绍

技能:ship

围绕远程端完成的工作流。运行条件检查清单,在任何产生副作用的步骤(push/tag/PR/MR/merge)之前停止并等待批准。五种级别——4 种推送(outbound)+ 1 种拉取(inbound):push(完成所有步骤,不打 tag)· release(push + tag vX.Y.Z + 发布说明)· pr(推送分支 + 通过 gh 创建 GitHub Pull Request)· mr(推送分支 + 通过 glab 创建 GitLab Merge Request)· merge(列出待合并的 PR/MR → 拉取分支 → gate+测试 → 测试通过则合并)。

WHAT

目的和上下文
  • 目的: 仅在条件检查清单全部通过后,将更改推送到远程端(push/release/PR/MR),或将待合并的 PR/MR 拉取并合入(merge);任何产生副作用的步骤之前都要停止并等待批准。
  • 触发条件(何时使用):
  • 用户提到“release” / “push” / “ship” / “发布” / “准备 push” / “满足 push 条件了吗” / “创建 PR” / “创建 MR”。
  • 在将代码推送到远程端、切出一个 release,或创建 PR/MR 以供审查后合并之前。
  • 想要审查后合并仓库中已打开的 PR/MR:“拉取 PR 并合并” / “测试通过就合并 PR” / “ship merge”。
  • 非目标: 不自动修复 gate 错误(由 /medic + 修复技能负责),不自动关闭 issue,不自动安装或配置身份验证 gh/glab。
心智模型

先执行 repo_role (framework · module · downstream · foreign) → 正确仓库类型的 gate 表 → ,然后才进入通用流程: 级别 (push · release · pr · mr · merge) → 健康 gate (medic --ci + ci-local) → 远程 UAT(仅具备能力的 release/pr/mr)→ git 干净 → selftest → [版本 + 补丁说明] → 检查清单 → 停止等待批准 → 产生副作用 → [UAT 第 2 阶段]。不同级别的区别在于最后一步,而非检查清单。

输入和输出约定
字段是否必需?含义
输入repo_role自动读取python3 harness/scripts/repo_role.py . --json(客户端:~/.claude/harness/harness/scripts/repo_role.py)——.overstack.yaml 中声明的标签;若缺失,则根据证据推断并询问用户一次,然后使用 --set;本次手动指定:ship <级别> --as <role>
输入级别否(默认为 push)push · release · pr · mr · merge——用户描述范围即可,无需记住标志
输入用户批准是,任何产生副作用的步骤之前对 push/tag/release/PR/MR/merge/canary 明确回复“yes”
输出检查清单 + 建议命令是各步骤 gate 的结果、UAT 第 1 阶段或跳过的原因、commit message、最终命令
输出文本视级别而定release → RELEASE-vX.Y.Z.md;pr/mr → PR/MR 正文;push → 仅 commit message;merge → 测试报告 + 决策
输出产生副作用仅在批准后已执行的 push / tag / release / PR / MR / merge
规则与能力
  • RULE-01 (MUST):medic --ci 未通过时不得推送——除非用户明确覆盖;即使覆盖,也必须在补丁说明中写明理由。
  • RULE-02 (MUST):补丁说明不得夸大——如果有未完成的部分,必须列出已知限制。
  • RULE-03 (MUST):**级别只在最后一步不同,清单不变:**所有级别都必须通过健康门禁;仅最终产物不同(tag / release / PR / MR / merge)。用户说“pr”/“mr”时不要创建 tag;用户只说“push”时不要开 PR。
  • RULE-04 (MUST):**medic --ci 通过并不能证明远程路径可用——这属于 /fdk-uat 的职责。**具有新能力的 release/pr/mr 必须先通过 UAT 阶段 1(canary),才能建议执行步骤 7;只有在 diff 确认没有增加任何用户可见能力时才可跳过,并且必须写明理由。真实事故记录:2026-09-17,此前所有推送(包括 6c839d8)都只通过了 medic --ci/ci-local,从未通过真实远程 UAT。
  • RULE-05 (MUST):**merge 级别——测试是合并条件,不是走过场:**合并前必须拉取分支 + 运行 medic --ci + 执行真实测试;如果未通过,绝对不能合并,保留原样交给作者。一对一处理,不要一次盲目合并多个 PR。
  • RULE-06 (MUST):**PR/MR 正文遵循与补丁说明相同的规则:**面向用户表述;如果有未完成的部分,必须列出已知限制。不得包含 SHA/内部函数名。不得自动添加 Closes #N。
  • RULE-07 (MUST):**副作用操作需要用户说“yes”:**push/tag/release/PR/MR 都是难以撤销的对外操作 → 始终先停止并展示命令,等待批准;不得在 commit/PR 正文中添加 AI 署名(遵循 fdk)。
  • RULE-08 (MUST):**不得自行安装/认证 gh/glab:**缺少工具 → 停止并告知用户;不要猜测 host。
  • RULE-10 (MUST):**运行任何门禁前,先确认 repo 类型。**清单第一行始终为 🏷 repo_role=<role> (khai báo | sổ máy | suy luận | ép tay)。来源为 suy luận → 询问用户确认,然后标记(repo_role.py . --set <role>;foreign 则记录到机器登记簿中,不要动他人的 repo)。某种 repo 类型的门禁不适用于其他类型:ci-local/capability-stamp/UAT 只对 framework 有意义;在 module/downstream 中运行属于误判,在 framework 中跳过则会造成漏洞。2026-09-20 的教训:单流程 /ship 让人必须记住,发布 engine repo 的流程截然不同。
  • RULE-11 (MUST):**推送前先读取门禁的 rc。**push/tag 命令必须单独放在读取并打印 rc= 之后的一个步骤中;禁止用 ; 将门禁与 push 串接,或用 | tail 管道吞掉 rc。2026-09-20 当天发生的两起事故:medic 未通过时仍推送了 c83b065,以及 install-test 报告 FAIL 时仍创建了 tag v3.0.1——两者都因命令串接导致。在 framework 中,如果工作树有未提交的陌生文件(例如被其他工具覆盖),请在该 commit 的干净 CHECKOUT 上运行门禁(git worktree add --detach <tmp> HEAD),以免误判 workflow。
  • RULE-12 (MUST):**foreign = 做客于他人的地盘。**仅限 pr/mr 级别,不得直接推送到默认分支;遵循对方的 commit/CI 规则(阅读 CONTRIBUTING,不适用 R15 或 overstack 规则);不得安装,不得写入 .overstack.yaml,不得向 repo 添加我们的任何配置文件。
  • RULE-09 (MUST):组合使用,不要重复造轮子:用 medic 检查健康状况,用 git tag 管理版本,用 gh/glab 创建 PR/MR——此 skill 只负责协调清单。
  • 能力:读取 repo + 运行本地门禁;写入远程(push/tag/PR/MR/merge)只能通过已认证的工具,并且必须先获批准。
失败边界
  • 门禁未通过(medic --ci / ci-local / freshinstall)→ blocked,打印问题所在 + 修复命令,不得 push。
  • UAT 任一阶段 FAIL → failed,停止发布,删除 canary;阶段 2 FAIL → 按照 /fdk-uat 步骤 5 从远程移除 commit。
  • 不确定 diff 是否包含“新能力”或版本级别 → clarify(询问用户),不得自行决定。
  • 缺少 gh/glab 或尚未认证 → blocked,告知用户安装并登录。
  • merge 级别:PR 未通过 → 不得合并该 PR(整批标记为 partial),并说明原因。

HOW

工作流
步骤类型输入操作输出/退出失败/下一步
W00确定性reporepo_role.py . --json → 位于 🏷 repo_role=…;来源为 inferred 时询问用户 + --set;从「按 repo_role 划分的流程」表中选择 gate 列role + gate 表role 无效 → blocked
W01确定性repo健康检查 medic --ci,然后运行 python3 fdk/tools/ci-local.py(包含 freshinstall 探测)rc 0报错 → blocked
W02效果diff、级别UAT /fdk-uat 阶段 1 — 仅适用于具备新能力的 release/pr/mr(B02)PASS 或跳过原因FAIL → failed
W03确定性worktreeGit 干净:git status --short,不存在未跟踪的临时文件干净不干净 → 清理后重复 W03
W04确定性diff对涉及的引擎进行自测/快速检查rc 0报错 → blocked
W05判断最新 tag版本 vX.Y.(Z+1) — 仅适用于 release(B01)建议的 tag不确定级别 → clarify
W06判断git log、scratch-log如实撰写 Patch note / PR-MR 正文;如有未完成部分,必须注明 Known-limitations文本—
W07确定性W01–W06 的结果显示检查清单 + 建议命令,停下等待批准"yes"未获批准 → cancelled
W08效果批准按级别执行;如果已运行 W02,则紧接着运行 UAT 阶段 2副作用 + 回执阶段 2 FAIL → 撤销 commit

各步骤的详细说明(W01–W08 的权威来源):

描述范围,而不是记住标志:"push"(仅推送)· "release"(推送 + tag + notes)· "pr"(推送分支 + GitHub Pull Request)· "mr"(推送分支 + GitLab Merge Request)· "merge"(汇总传入的 PR/MR → 测试 → 合并)。默认 = push。

push/release/pr/mr 级别(推送出去)运行以下步骤 1-8。merge 级别(汇总进来)在步骤 8 走单独的分支(参见「merge 级别」)。

步骤 1、3-4 适用于所有级别。步骤 2(UAT)仅适用于 release/pr/mr。步骤 5(version tag)仅适用于 release。步骤 6 将「撰写内容」改为:release → RELEASE-vX.Y.Z.md;pr/mr → PR/MR 正文(采用同样的用户视角语气,并遵循同样的 Known-limitations 规则)。push 不需要文本,只需 commit msg。merge 级别不撰写说明(只报告测试结果,以及合并/不合并的决定)。

  1. 健康门禁 — medic --ci(或 python3 fdk/tools/medic.py --ci)。FAIL → 停止,打印缺口 + 修复命令;红灯时不要推送。Warn(已知欠债)→ 可以通过,但必须在补丁说明中列出。
    • 然后运行 python3 fdk/tools/ci-local.py(框架仓库)——在本地运行 GitHub 所有工作流中每个 run: 步骤的完整内容(L4)。medic 是 L2;CI 中还有门禁(search-index、skill-provenance、retrieval-eval……)——080926 已经踩过坑:medic 通过并推送后,CI 有 2 个 job 失败。失败 → 不要推送。
    • 包含 freshinstall 探测(E2E):通过 working-tree 将 overstack 用 curl 安装到隔离的空项目中(mktemp 位于仓库外)→ 断言 3 个支柱 + harness 能触发 + orchestration-ready。失败 = 新用户安装路径损坏 → 不要推送。完整版本 curl-github + acceptance live:bash harness/scripts/fresh-install-smoke.sh --remote。
  2. **UAT 门禁 — /fdk-uat(仅限 release/pr/mr 级别,不适用于普通 push):**步骤 1 中的 medic --ci/ci-local 只通过 file:// working-tree 安装——证明“本机代码正常”,不能证明“陌生用户通过 curl 从 remote 下载后能运行”(GH#77 这一类问题:“文档承诺了,但用户没拿到”,2026-09-17 对 push 6c839d8 的实际测量显示完全没有经过 UAT)。
    • 包含新能力的 diff(新 skill / 能触发的新 rule / 新 engine-tool)→ 必须至少运行阶段 1(canary:推送临时分支,从该分支的 raw 进行 curl 安装,检查新能力是否可用),然后才能进入步骤 7。阶段 2(main-URL smoke,等待 CDN)在步骤 8 用户批准真实 merge/tag 后立即运行——不是提议时运行。
    • 纯 bugfix/内部重构的 diff,不增加用户可见能力 → 跳过此步骤,并在步骤 7 的 checklist 中明确写明原因(“没有新能力 — skip UAT”)。
    • 不确定 diff 是否算“新能力” → 询问用户,不要自行决定跳过。
    • 推送 canary 是真实副作用(将临时分支推送到 remote)→ 运行前先停止并询问用户,遵循此 skill 的副作用规则。任何阶段失败 → 停止发布,报告具体错误 + 删除 canary(不能“留待以后处理”)。
  3. Git 干净:git status --short;确保临时垃圾(scratchpad/…)已加入 .gitignore,如果误追踪则运行 git rm -r --cached。检查没有混入机密/临时文件。
  4. 对涉及的 engine 运行自测/快速检查(例如 council.py selftest、与 diff 相关的测试)。
  5. 版本:git tag --sort=-v:refname | head -1 → 最近的 tag vX.Y.Z → 建议 vX.Y.(Z+1)(patch);如果 diff 值得提升,则建议 minor/major——不确定级别时询问用户。
  6. **如实撰写补丁说明(采用面向用户的发布说明语气——类似 Claude Code):**编写 RELEASE-vX.Y.Z.md。
    • **格式:**标题 Version X.Y.Z:,然后使用扁平项目符号列表,每个要点一行。
    • **语气:**以动词开头,描述用户可见的变化,不要罗列 commit/内部实现。Fixed <症状> — <现在的表现> · Added <能力> — <用途> · Removed/Changed …。从读者(“你/你的”)的角度撰写,不写 SHA;除非用户直接输入,否则不写函数名。
    • **按动词隐式分组:**先写 Added/Changed,再写 Fixed(类似 Claude 发布说明)。列表较短时不需要分组标题。
    • **来源:**阅读 git log <tag-cũ>..HEAD + 本次会话的 scratch-log → 将技术性 commit 翻译成用户能理解的表述(可根据感知价值将一个 commit 合并或拆分为多个要点,不必一一对应)。
    • **已知局限(如有未完成部分则必须写明——优于 Claude 的地方):**明确说明尚未实现的提案草案、部分覆盖、medic 已知警告等。“正在处理/已知”。保持沉默 = 夸大其词(council 2026-07-03 的教训)。
  7. 向用户展示 checklist + 建议命令(commit 消息、push、tag/PR/MR、UAT 阶段 1 结果或跳过原因)。停止并等待批准。
  8. 用户批准后:按级别执行。未得到“yes”前,不要自行执行有副作用的步骤。如果步骤 2 已运行 UAT 阶段 1(PASS)→ merge/tag/push 完成后,立即运行 UAT 阶段 2(main-URL smoke,等待 sentinel CDN),然后再告知用户“完成”;失败 → 按 /fdk-uat 步骤 5 从 remote 撤销 commit。
    • **push:**commit + git push。
    • **release:**commit + push + git tag vX.Y.Z + 创建 release(notes = 补丁说明)。
    • **pr(GitHub):**commit + git push -u origin <nhánh> + gh pr create --base <base> --head <nhánh> --title "…" --body-file <PR-body>。Base 默认为仓库主分支(例如 orca),不确定时询问。
    • **mr(GitLab):**commit + git push -u origin <nhánh> + glab mr create --source-branch <nhánh> --target-branch <base> --title "…" --description "…"(或 -F <file>)。
    • 根据 remote 选择工具:git remote get-url origin 包含 github.com→gh,包含 gitlab→glab。ship pr/ship mr 明确指定工具;如果工具未安装/未认证(gh auth status / glab auth status),则停止并告知用户安装+登录(不要自行处理)。
    • 不要自行在 PR/MR body 中添加 Closes #N/Fixes #N,除非用户明确要求——让用户保留手动关闭 issue 的控制权。
按 repo_role 执行的流程(W00 选择一列;上方 W01–W08 描述 framework 列)
步骤framework(Rheinmir/setup)module(orca-graph、uiux-asset…)downstream(有 .llmwiki/ 的项目)foreign(他人的 repo)
Gatemedic --ci → ci-local(如果工作树中有陌生文件,则在干净的 checkout 上运行)先 commit → 执行它自己的 test + eval + install-test(逐项读取 rc;install-test 会从 HEAD 克隆,因此未 commit 就等于尚未测试)项目 test + llmwiki-validate + medic(downstream 模式)git 干净 + 他们的 test/CI
远程 UATdiff 包含新能力时(B02)push 后从远程进行安装 smoke test(将模块的 install.sh 安装到临时 HOME)不需要不需要
Version当下发到客户端的内容发生变化时(hook、shim、installer、全局 tool),运行 capability-stamp.py --update — 即使表面 sha 没有变化也必须 bump,否则已是当前版本的机器不会 refreshbump VERSION + 代码中的常量 + CHANGELOG按项目规定按他们的规定
最后一步push(· 根据级别打 tag/创建 PR)push → 等待 CI 通过 → tag + release → 在 framework 中重新 pin(.overstack.yaml 中的 upstream_pin:如果 SKILL 有变更则复制 → sync-skills.py → 将 commit/version 写入 fdk/skills.provenance.json → 发布 framework)push / pr仅 pr / mr
禁止installer 写入此 repo(自行拒绝,rc 3)ci-local、capability-stamp推送 framework 文件、UAT、stamp安装、写入 overstack 配置、违反他们规定的 AI attribution
分支
ID类型条件行为跳过 / 失败汇合
B01conditional_required级别 = releaseW05 version + tag vX.Y.Z + release notes其他级别 → 跳过W06
B02conditional_required级别 ∈ {release, pr, mr} 且 diff 包含新能力W07 前进行 UAT 阶段 1,W08 后进行阶段 2bugfix/内部重构 → 跳过,并在 checklist 中记录原因;不确定 → clarifyW03
B03user_optional级别 = merge单独执行 GOM VỀ 循环(见下文),跳过 W02、W05–W06PR 未通过 → 不合并该 PR总结报告
merge 级别(GOM VỀ — 审核后合并收到的 PR/MR)

不写 note/tag。跳过步骤 2、5-6,改为逐个请求测试的循环:

  1. 根据 remote 选择工具(如上):github.com→gh,gitlab→glab。尚未 auth → 停止并告知用户。
  2. 列出 repo 中打开的 PR/MR:
    • GitHub:gh pr list --json number,title,headRefName,mergeable,isDraft
    • GitLab:glab mr list(如果版本支持,也可以使用 --output json)。 向用户显示列表;如果用户指定了具体编号,则筛选;否则询问是全部处理还是选择处理。
  3. 逐个处理每个 PR/MR,不要盲目批量合并: a. 将分支拉到干净的本地环境:GitHub gh pr checkout <n>;GitLab git fetch origin merge-requests/<n>/head:mr-<n> && git checkout mr-<n>(或 glab mr checkout <n>)。 b. 在该分支上运行 GATE + TEST:medic --ci + 与 PR diff 相关的 selftest/test。这是合并条件 — 未运行前不得合并。 c. 通过 → 提议 merge 命令,停止并等待批准,然后合并:GitHub gh pr merge <n> --squash(或根据 repo 使用 --merge/--rebase);GitLab glab mr merge <n>。未通过 → 不得合并;报告未通过项,并保留 PR 原样以便作者修复。 d. 合并后:返回原分支(git checkout <nhánh-cũ>),清理临时分支。
  4. 总结报告: 对每个 PR/MR,说明已合并 / 因未通过而跳过(附原因)/ 因用户要求而跳过。
验证与停止条件

是否继续取决于工具的 rc(medic、ci-local、fdk-uat、test),而非模型的自我判断。所有副作用均在 W07 停止并等待 “yes”;merge 级别则逐个 PR 停止并等待批准。网络错误时不要自动重试 push/tag — 告知用户。

示例
  • 正向(模块): 在仓库 orca-graph 中输入 “ship release” → W00 打印 🏷 repo_role=module (声明) → 提交 → pytest tests 返回码为 0 → evals/run.py 返回码为 0 → tests/install-test.sh 返回码为 0 → 更新 VERSION → 停止并等待审核 → 推送 → CI 全绿 → 创建标签并发布 → 提醒按照 upstream_pin 在 Rheinmir/setup 中重新固定版本。
  • 边界情况(外部仓库): 在一个没有标记、没有标签的仓库中 → W00 打印 🏷 repo_role=foreign (推断:没有 fdk/wiki,也没有 .harness-stamp) → 请用户确认 → 仅建议 ship pr,阅读对方的 CONTRIBUTING,不写入任何 overstack 文件。
  • 正向: 修改文档后输入 “ship push” → W01 通过,B02 跳过(没有新增能力,记录原因),W03–W04 通过 → 检查清单 + git push → 用户回复 “yes” → 推送。
  • 边界情况/失败: “ship pr” 包含新技能,但 ci-local 有 1 个任务失败 → 阻止于 W01,打印失败任务和修复命令,不推送分支,也不创建 PR。
  • 边界情况: “ship merge” 有 2 个 PR,PR #2 测试失败 → 审核后合并 #1,跳过 #2 并说明原因(部分完成)。

评论

支持 Markdown