关于 ship
面向编码 Agent 的通用交付技能,通过仓库专属 ship profile 提供项目细节。流程涵盖工作项处理、实施、评审、CI 和合并关卡,并支持有人参与与无人值守模式。
主要功能
- 01分阶段交付流程
- 02工作项认领与跟踪
- 03实施与验证关卡
- 04PR 评审和 CI 处理
- 05有人参与与无人值守模式
适用场景
- 01将跟踪中的问题从选取推进至合并
- 02以无人值守模式运行交付流程
- 03在合并关卡重新处理 Pull Request
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ gharib89/ skills --skill ship安装后在 Claude Code 中输入/ship确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
CHANGELOG.mdretired-terms.mdreference/context-discipline.mdevidence-lines.mdimplement.mdisolate.mdmechanics.mdmerge-gate.mdphase-steps.mdpr-body.mdreview-loop.mdrework.mdsmall-lane.mdunattended.mdverify.mdscripts/_lib.shbase-fresh.shci-wait.shcleanup.shcomment-issue.shcomment-pr.shdropped-lines.shfile-issue.shscripts/host/ado.shgithub.shscripts/host/ado.d/prs.shthreads-and-lists.shscripts/host/github.d/issues.shprs.shruns-and-reviews.sh详细介绍
原文在翻译后有更新,译文可能不是最新。
ship
此技能是通用的:它只知道如何交付,不了解仓库的任何信息;所有仓库信息都来自交付配置文件 docs/agents/ship.md。.claude/skills/ship 中的副本是派生副本,在其源仓库 Gharib89/skills 中修改,并通过仓库 CLAUDE.md 中 ### Ship 段落所载的命令刷新。
版本。 加载时,运行环境会剥除此文件的 frontmatter,因此请在运行开始时读取一次版本,使用
sed -n 's/^ version: //p' <base directory>/SKILL.md,然后在运行标题、第一条回复的第一行,以及合并摘要中再次打印 ship <version>,这样每个 PR 都会记录由哪个 ship 产出。
参数和标志
$ARGUMENTS:
<issue>:问题编号(Azure DevOps 工作项 ID);单独使用prepare时不需要。未提供且没有标志时:询问要处理哪个问题。- 用自由文本代替数字:文本本身即为任务规格。不获取问题、不认领、不添加
Closes或反映,也不添加点名这些内容的Done when:子句;对preflight、isolate、open-pr、merge和cleanup,问题参数为none。 --unattended:无人值守运行,详见 reference/unattended.md。没有人在场:遇到阻塞时停止并交还,而不是提问;沙箱克隆即为隔离环境;合并关卡会将摘要作为 PR 评论发布并返回。若没有<issue>,则先运行无人值守流程:prepare、PR 上限检查、选择。--inline [--review]:内联流程;在prepare之前,先阅读 small-lane.md 了解规则。
不带 --unattended 时,运行处于有人值守状态:任何需要人工操作的情况都会停止并提问,等待期间认领仍然有效。每次运行都要在 run-file init 之前执行准备,但无问题流程中的内层运行除外:prepare(该流程中使用 --unattended)。在云沙箱(CLAUDE_CODE_REMOTE=true)中,或使用该标志时,运行 tooling --install,然后运行配置文件的 ## Cloud lane
Bootstrap:;其他情况下不执行任何操作。若某个步骤失败,则停止运行,不进行认领,并附上该步骤的末尾输出:tooling 对应 host-unreachable,bootstrap 对应 bootstrap-failed。
组合使用,不要内联重写
在相应阶段通过 Skill 工具加载 tdd(阶段 2)、writing-for-agents(阶段 4,面向 Agent 的文档)、code-review(阶段 4),以及 find-docs(涉及任何 API 声明时,包括配置文件的 Pinned: 库:implement.md),从各技能本身获取其逻辑,并明确告知任何带有无人值守模式的组合技能,本次运行是无人值守的,因为它们无法通过其他方式得知。第 6 阶段的 Change outline 请阅读 show-me;pr-body.md 说明了原因。
流程
按顺序执行各阶段,让主线程专注于编排和决策。首先,阅读
reference/context-discipline.md:了解委派规则,以及避免长时间运行导致上下文窗口膨胀的手段。然后执行本次运行必须首先执行的操作:在 prepare 之后、阶段 0 之前,运行 run-file init <issue|slug> --from-profile,初始化用于保存十项检查清单的 Run 文件。以下每个阶段都要通过 run-file next、open、close 或 skip 更新状态;只有满足其 Done when: 条件后才能关闭,不能提前关闭。
每个阶段都运行其指定的机制,而不是重新推导该机制封装的内容。所有主机写入操作和所有门控读取操作都必须通过机制执行:任何未由机制执行的操作都属于 Ship 缺陷,必须列入合并摘要的 Ship defects: 行,绝不能手动调用;merge-gate.md 说明了草稿应放置的位置。reference/mechanics.md 完整说明了该规则、允许的信息性读取、各阶段运行的机制及其共同约定,包括 --help。
0 · 隔离。 reference/isolate.md 说明了预检会验证和拒绝什么、会加载哪个配置文件及其原因,以及为何要按这种方式创建工作树。运行 preflight <issue>(无人值守运行时加上 --unattended):每条 reasons 都对应下方停止表中的一行。然后运行 read-issue <issue>,这是第 1 阶段的输入;据此推导分支 <type>(feat、fix、docs 等)和 <slug>。接着运行 isolate <issue> <type> <slug>,并使用配置文件中的 Carry: 文件;无人值守时则运行 isolate ... --in-place。所有编辑、提交和 PR 都要在 isolate 打印出的路径下进行,并且边做边提交,因为 PR 需要真实提交。## Worktree 下的 Bootstrap: 在此处运行一次,即隔离完成后。
完成条件:preflight 返回 ok: true,isolate 打印出路径,并且任何 ## Worktree 下的 Bootstrap: 均已成功运行。
1 · 理解。 如果 read-issue 的结果过于含糊,无法据此制定计划:停止为 ambiguous,不领取任务。否则,先领取,再开展任何工作:运行 manage-issue <issue> take,领取状态保持到合并;之后的停止情况遵循停止表。然后搜索问题引用的每个锚点;如果代码树与其中一项矛盾,就通过 update-issue-body 改写该项(implement.md)。如果某项验收标准需要由任何机制都无法执行的宿主操作,则保持原文不变:无人值守时,它是合并摘要中要列出的未满足验收标准;有人值守时,先按两种情况下都适用的 implement.md 询问。之后才能将成功标准写入 Run 文件,作为后续阶段可检查的验收标准;后续具有权威性的评论优先于正文(规范优先级)。
完成条件:claim: taken,已搜索锚点,Run 文件中已记录验收标准。
2 · 实现。 reference/implement.md 说明了各类别、TDD 覆盖规则、外部声明探查、判断与执行的区分,以及相邻发现的处置方式。将工作归类为 docs / code / infra;说明类别、由此决定的跳过路径、三个通道键是否成立,以及 ## Verification 中适用的验证项(其中的 Applies when: 行属于需要在此处判断的说明文字)。根据配置文件的 Subject constraints:,使用 run-file grade <patch|minor|breaking> 记录公共接口变更的版本等级:open-pr 和 update-pr-title 会拒绝等级低于该变更的标题类型。然后按类别先写测试,再实现;无论类别如何,Tripwires: 和 In-PR requirement: 都必须随本次变更一起落地。
从首次编辑起就维护偏差日志:每当实际情况迫使你偏离问题、简述或计划时,采取保守方案,记录偏离内容及原因,然后继续;这些内容会原样写入合并摘要。如果差异超出单个 PR 的范围,或修复需要进行问题范围之外的重新设计,则以 needs-split 停止,并提出拆分方案。
**完成条件:**适用的测试均通过(按类别先失败后通过);Tripwires: 和 In-PR requirement: 均已落地;已记录 Grade:;小型通道的差异统计已记录且未超上限;到目前为止的每项偏离和相邻发现均已记录在 Run 文件中,并注明处置方式。
3 · 验证。 reference/verify.md 说明了结果用语、Without it: 的处置方式,以及 unexercised 的含义。针对你改动的内容,在问题所报告的环境中运行每项适用验证的 Run: 行:在其他环境中通过不代表问题已修复。运行时间较长的验证交给 verify 临时目录中的低成本层级子 Agent。docs 类和小型通道跳过此阶段。
完成条件:run-file close 3 已为每项验证填写 --result;每项适用验证的结果均为 pass、deferred-to-ci 或 unexercised;任何其他结果均已记录,随后按其指定的停止方式处理。或者,run-file skip 3 已记录跳过原因。
4 · 同步文档,然后自我审查。 先处理文档,这样审查时会将文档编辑视为差异的一部分。仅当公开接口或可观察行为发生变化时才触发文档同步:使配置文件中的 Targets: 保持一致,并将编辑纳入本次更改,或纳入跟踪问题的起草章节。内部重构、恢复文档所述行为的 Bug 修复、仅涉及测试或工具的更改,以及注释更改,都跳过此步骤,并在合并门禁处用一行说明。writing-for-agents 流程有自己的触发条件,即使跳过文档同步也会触发:只要差异涉及配置文件 Agent-facing: 行中列出的目标,就必须在判断层级、writing 临时目录中,对差异中所有面向 Agent 的文件执行该流程。人类可读的文案则走机械检查流程。文档同步的编辑提交后,加载 code-review,然后在同一轮中调度该流程及其两个维度,并结束本阶段;每项都要注明其 Report 文件。小型流程:先调度两个维度,再内联运行该流程。
自我审查,所有流程都必须执行:针对自 origin/HEAD 以来的差异调用 code-review;其 Standards 维度读取配置文件中的 ## Coding standards 路径,其 Spec 维度读取问题说明;每个维度的提示词都要包含各自的临时目录(standards、spec),并说明 Local 门禁将在本次运行的后续阶段执行,因此该维度读取门禁的 JSON,绝不自行运行 check.sh full 或测试套件。必须等到所有 Report 文件都到齐才能进行分诊;如果在停止规则规定的两次修复并重试后仍未收到某个文件,应标记为 red-after-retry: <axis>,绝不可凭记忆写出处置结果。按照 implement.md 中的约束和深度检查,在判断层级对每条发现进行自动分诊,每条发现各写一项处置结果。run-file close 4 会拒绝关闭,除非 Run 文件中已包含该节检查要求的证据行:Reverted-fix:、Dropped:、Near-miss: 和 Probe:,以及 run-file prove 和 run-file probe 生成的 red 行和 Probe: 行。
**完成条件:**每个已触发的报告都有对应的 Report 文件存于磁盘上,且其路径已写入 Run 文件;每条发现都有处置结果;close 4 已接收证据行;文档同步已完成,或已用一行说明跳过原因。
5 · 本地门禁。 *前置条件:*所有适用的验证项状态均为 pass、deferred-to-ci 或 unexercised,或者类别为 docs,并且第 4 阶段的每条发现都有处置结果;否则返回前一阶段。先运行 base-fresh:CI 会测试合并引用,因此即便分支早于某次合并,仍可能通过,但工作树中所有“是否存在?”的判断都是在合并前做出的;若落后:遵循其建议、重新运行,然后继续。确认每个 Carry: 文件仍与主检出中的副本一致;若不一致,则视为 carried file modified,因为 ship 绝不会编辑未跟踪的密钥。然后从工作树中内联运行配置文件 Location: 指定的门禁,并对其 JSON 运行 run-file gate record(小型流程:small-lane.md)。每种流程中的 JSON 都包含 verdict(pass|fail|unavailable)、每项门禁的状态(pass|fail|deferred-to-ci|unavailable),以及 gates.secrets;若输出无法解析或缺少 secrets 键,则视为 unavailable。
fail:进入修复循环。deferred-to-ci:继续,并在合并摘要中列出每项延后到 CI 的门禁。unavailable:停止,标记为 local gate unavailable,不创建 PR。
完成条件:base-fresh 返回 fresh: true,Carry: 文件均一致,且记录的 verdict 为 verdict: pass 并包含 gates.secrets。
6 · 开启 PR。reference/pr-body.md 说明正文包含哪些内容,以及正文的编写与回读方式。使用 open-pr <issue> --title --body-file,且必须非草稿(草稿可能不会触发审核者)。标题:根据问题派生的 Conventional Commit 主题,遵守 Subject constraints:;它会成为发布工具读取的 squash 主题,之后若发现标题有误,则使用 update-pr-title 修正。每次写入未关闭 PR 的标题或正文后,都要执行 read-pr <pr>,并检查其中的 ## 标题是否与正文应包含的标题一致。然后执行 reflect <issue> <pr>。
完成条件:read-pr 显示一个未关闭、非草稿的 PR,且包含正文应有的标题;reflect 已发布。
7 · 审核者。reference/review-loop.md 说明每种触发条件对应的轮次、作为预算的上限、如何读取一轮审核、退出语句和回退方案。尽力而为:每轮针对 ## Reviewers 下的每位审核者,先按其 Trigger: 启动,等待一个 poll-pr --brief 时段,分类处理所有新内容,集中推送修复,然后使用 reply-thread 回复每个讨论串,接着执行该区块的 Resolve:;Cap: 限定轮数,只有文档变更的纯修复差异则结束审核。每轮修复通过其针对性测试节点和仓库的编辑检查级别来证明,即其测试框架在每次编辑后对所改文件运行的检查(check.sh edit <file>...);没有测试框架、因而没有编辑检查级别的仓库,则用本地门禁证明。否则,不会在每轮重新运行本地门禁:最终提交的门禁检查,是在 gate read 显示 current: false 时重新运行合并门禁,且绝不能在 code-review 尚未结束时运行(阶段 5)。对于 Fallback-for: 为 None. 的每位审核者,先处理该审核者,再处理回退审核者;当主要审核者退出状态为 not reviewed 时,分别触发每个回退方案(inline lane 除外)。每位审核者的审核均受上限约束,必须留下审核结果或以 not landed 停止。退出状态:reviewed、not reviewed: <reason> 或 not invoked: <primary> reviewed;not reviewed 时,只要 CI 为绿色,就继续执行合并门禁,并在该处报告。退出时,使用 update-pr-body --section --body-file 写入各轮新增的章节、未达标的 Change outline,最后写入 Review;检查标题是否符合 Grade:,然后执行阶段 6 的回读;达到上限、纯文档变更和未落地的轮次所需的本地审核,按 review-loop.md 中的说明处理。
**完成条件:**每位审核者都有一个退出状态词;poll-pr 返回的每个讨论串都已回复,并按 Resolve: 要求解决;每轮新增的章节都已重写;标题符合 Grade:;达到上限、纯文档变更或未落地的轮次所需的任何本地审核都已处理;close 7 收录了每位审核者的 Round: 和 Stop: 语句;read-pr 显示每位审核者各有一行 ## Review。
**8 · CI。**CI 在 PR 开启时启动,并与阶段 7 并行;ci-wait <pr> 会按照配置文件的 Legs: 等待。ci-wait 和 poll-pr 会等待预期的提交版本(mechanics.md)。遇到 conflict 时,标准错误输出会包含恢复方法。只有在 No-checks legal: 明确允许的情况下,no-checks 才可接受。验证项的 Also proven by CI: 行中列出的红色检查项,表示该验证失败:返回阶段 2。审核者退出后若检查项变红:修复、推送,并在 CI 变绿后继续。遵守 Push policy::推送会消耗 CI 时间和审核额度,因此仅在工作树发生变化时推送。
完成条件:ci-wait 返回 green;每个 missing_legs 条目都被 No-checks legal: 允许,或者 no-checks 在允许时使用。
9 · 合并门禁。 reference/merge-gate.md 规定摘要的格式、merge 的作用、两种拒绝情况以及跟踪器草稿。按该文件撰写摘要。有人值守时:遵循其中的 Merge: 分支,默认等待明确的“merge”指令;或者在 Merge: on-clean-gate 时,或运行处于 inline lane 且 run-file gate clean 返回 clean: true 时进行合并;未满足的条件需要人工明确豁免。获得任一授权后,运行 merge <pr> <issue|none> [--worktree <path>],按跟踪器草稿执行 update-issue-body,处理每份 Ship 缺陷草稿(只有在对方明确要求时才提交),运行 run-file close 9,然后最后运行 cleanup <issue|none>,因为它会删除 Run 文件;如果退出码非零,或 merge 或 cleanup 的 JSON 中出现 false,则重新运行负责该步骤的机制;若没有任何机制可重做某一步,则将其作为 Ship 缺陷写入摘要。无人值守时:通过最终 head 的门禁后,再运行 comment-pr <pr> --body-file 并附上摘要,然后运行 run-file close 9。任一流程结束后即返回。
完成条件: 有人值守时,merge 和每个 update-issue-body 的退出码均为 0 且没有 false;每份 Ship 缺陷草稿均已提交、已用候选方案作答,并包含其 command 或已被拒绝;随后 close 9,再运行 cleanup <issue|none>,其退出码为 0 且没有 false。无人值守时,comment-pr 已发布。
停止条件
合并门禁会像第 9 阶段所述那样停止;无人值守通道则会发布结果并返回。 以下停止条件表具有权威性。 其他所有事项,例如分诊自己的发现、修复、重新运行,都由你自主处理。以下两条护栏适用于此流程:
- 红灯问题要修复或报告。 合并门禁前的任何失败,最多可进行两次修复并重试;第二次后仍为红灯时,记为
red-after-retry: <what>;如果失败信息表明方法有误,则应更早停止。无论哪种情况,都要停止并报告,附上具体证据;如果能轻松找到经过验证可行的替代方案,也一并提供,让报告能迅速得到确认。 - 每个停止条件都有名称,必须原样报告,并按下方要求处理认领。
| 停止条件 | 原因 | 认领处理 |
|---|---|---|
| 配置缺失或无效,主机无法访问 | profile missing、profile invalid: <detail>、host-unreachable | 不认领 |
composes 所需的某项 skill 未按指定版本安装,或其版本指定格式错误 | skill missing: <skill>; run <install line>、skill off pin: <skill> at <ref>, pinned <sha>; run <install line>、skills lock unreadable: skills-lock.json; repair it, then re-run preflight、composes pin invalid: <entry>; want <form> | 不认领 |
| 预检无法执行 | closed、is a pull request、already claimed、existing PR、existing branch、worktree exists、not triaged: run /triage first、ready-for-human: attended only | 不认领 |
| 问题描述过于含糊,无法制定计划 | ambiguous | 不认领 |
| 变更超出一个 PR 的范围,或需要重新设计问题中未列明的内容 | needs-split | 有人值守:询问;无人值守:交还 |
| 调查发现问题定义有误 | mis-specified | 有人值守:询问;无人值守:交还 |
| 缺少验证所需的前置条件 | hand-off(有人值守时等待,认领保持不变)/blocked-verification | 有人值守:保持认领;无人值守:交还 |
本地门禁结果为 unavailable | local gate unavailable: <gates> | 有人值守:询问;无人值守:交还 |
| 随附文件已更改 | carried file modified: <file> | 有人值守:询问;无人值守:交还 |
| 重试后仍为红灯 | red-after-retry: <what> | 有人值守:询问;无人值守:交还 |
| 合并前,分支落后于其基准分支 | stale-base: behind <n> on <base> | 有人值守:等待你合并基准分支;无人值守:交还 |
| PR 在合并门禁处已关闭 | pr-closed: <state> | 有人值守:询问;无人值守:交还 |
--inline 与 --unattended 或自由文本同时使用 | inline refused | 不认领 |
prepare 未通过 Cloud 通道的 Bootstrap: | bootstrap-failed | 不认领 |
未关闭的 PR 数量达到或超过配置文件中的 PR cap: | pr-queue-full | 不认领 |
| 没有问题符合筛选条件 | nothing-ready | 不认领 |
| 主机的阻塞项查询存在但执行失败 | blockers-unavailable | 不认领 |
| 已到达合并门禁 | 无:表示本次运行成功 | 保持认领,直到合并 |
交还操作为 manage-issue <issue> handback "<reason>":取消指派、移除
ready-for-agent、添加 ready-for-human,并评论说明原因;如果该命令以 1 退出,其输出会说明认领最终处于何种状态。有人值守的运行中,应停止并询问;只有在人类要求停止时,才交还给人工队列:绝不能交给 Agent 队列,否则会无限循环。
各通道
除非变更已证明是小型,否则每次运行都按完整通道处理:你必须在阶段 2 断言以下三个条件均成立,并宣布类别。无法确定时,就不算小型。
- 不改变公共接口。 公共接口指配置文件中的
## Public surface;Default.表示导出或发布的 API、CLI 标志和退出代码、配置架构、文件格式及文档说明的行为。 - 无需真实环境即可证明。 单元测试或回归测试能够充分证明这一点,或者类别为
docs且没有可测试的行为;无论哪种情况,配置文件中的## Verification均不适用。 - 范围受限。 不引入新依赖,配置文件中的
Tripwires:均未触发,并且变更差异在 small-lane.md 规定的大小上限内。
允许改变行为:修复缺陷就是一种行为变更。涉及防护条件、允许列表或拒绝规则的变更属于完整通道,--review 下的内联变更除外。对于小型或内联变更,请先阅读 reference/small-lane.md。
模型层级
为每个子代理选择模型时,必须依据 context-discipline.md 中唯一的层级表,并为每个子代理标注其模型和临时目录;两者都不会继承。
工作准则
这些准则适用于每次运行在任何仓库中所做的每项编辑,无论个人的 ~/.claude/CLAUDE.md、~/.claude/rules/ 或个人技能中有何规定:
- 用最简单的形式解决问题。 不要为只使用一次的代码添加臆测的功能、可配置性或抽象;如果变更差异可以缩小到三分之一,就重写。
- 精准修改。 只修改问题所需的内容,每一处变更都必须对应问题或已记录的偏离,并遵循现有风格,不动相邻代码、注释和格式。
- 修复根因,而非症状。 不要打临时补丁、吞掉错误,也不要用
TODO代替修复;如果真正的修复超出范围,请说明并登记后续事项。 - 注释说明原因。 为公共 API 以及不明显的约束、不变量和变通方案添加说明;不要为内部实现写叙述性注释。
- PR 正文始终简洁,并说明原因。 说明改了什么以及为什么改;读者可以通过差异了解如何实现。合并摘要除外:请完整撰写。