OpenClaw 重复 PR/Issue 甄别工作流:gitcrawl 候选发现、prtags 分组与 GitHub 评论同步的完整实现
【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 🦞项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw
OpenClaw 仓库中维护了一套针对重复 PR/Issue 的分诊技能(skill),核心文件为 .agents/skills/tag-duplicate-prs-issues/SKILL.md。该技能定义了"本地历史检索(gitcrawl)→ 实时 GitHub 验证(gh)→ 维护者裁决落库(prtags)→ 评论自动同步"的完整链路。读完本文,你将掌握这套三工具分工的分诊流程、重复判定的证据规则与"单组原则",并能复现其中的全部命令、字段定义和裁决输出格式;同时了解仓库中配套的自动化关闭脚本 scripts/close-duplicate-prs-after-merge.mjs 如何用 hunk 级 diff 重叠来硬性佐证"重复"结论。
1. 技能定位:只判重复,不评质量
该 skill 的 frontmatter 明确了使用场景:
name: tag-duplicate-prs-issues description: Use gitcrawl to search duplicate OpenClaw PRs/issues, group related work in prtags, and sync duplicate state to GitHub.技能文档开宗明义:这是给维护者做分诊和归类用的,不是用来评审 PR 实现质量的("This skill is for maintainer triage and grouping. It is not for reviewing the implementation quality of a PR.")。配套元数据 agents/openai.yaml 中也给出了技能的一句话触发描述:"Find duplicate PRs and issues with gitcrawl, group them in prtags, and let prtags sync the GitHub comment"。
技能的最终目标(Goal)被归纳为五步:
- 收集重复证据(gather duplicate evidence)
- 判定是否为真实重复(decide whether it is a real duplicate)
- 为该重复簇创建或复用一个
prtags分组(create or reuse one prtags group) - 把维护者裁决保存到
prtags(save the maintainer judgment in prtags) - 依赖
prtags的正常分组写入来驱动 GitHub 评论同步(rely on normal prtags group writes to drive GitHub comment sync when that integration is configured)
2. 前置准备:安装 prtags、OAuth 登录与"缺件即停"规则
2.1 配套技能与 CLI 安装
文档要求"在 setup 完成前不要写入任何重复分组或标注",但只读的发现阶段(read-only discovery)可以只依赖gitcrawl和实时gh继续推进。配套技能有两处:
$gitcrawl:本地候选发现的第一入口。仓库中对应的技能定义在 .agents/skills/gitcrawl/SKILL.md,其 metadata 声明gitcrawl是一个 Go 二进制(github.com/openclaw/gitcrawl/cmd/gitcrawl@latest),职责是"GitHub archive: issue/PR search, sync freshness, duplicate clusters, gh-shim PR status"。prtags:来自独立仓库的 CLI,技能文档要求从该仓库最新的 GitHub Release 安装,不要依赖旧的本地构建,除非维护者明确想测试未发布行为:
curl -fsSL https://raw.githubusercontent.com/dutifuldev/prtags/main/scripts/install-prtags.sh | bash -s -- --bin-dir "$HOME/.local/bin"2.2 认证:维护者本人 OAuth 设备流
prtags必须以维护者本人账号通过 OAuth device flow 登录,明确禁止用共享维护者 token 做交互式分诊:
prtags auth login prtags auth status预期结果是prtags在本地保存登录的维护者身份,并以此身份执行所有认证写操作。
2.3 Missing-Setup Rule:不要前置预检,但要"缺件即停"
文档对 setup 的检查策略写得很细,值得单独提炼:
- 不要在工作流一开始做强制 preflight,正常步骤先走,直到真正需要某个工具或账号状态为止;
- 一旦发现
prtags缺失或未登录(发生在写步骤时),立即停止,不得在半写状态(partial write mode)下继续; - 缺失工具时引导用户执行上面的 install 脚本;
prtags auth status显示未登录时引导用户执行prtags auth login; - 只有在缺失的工具或登录状态被修复后才允许恢复工作流。
这条规则的意义在于:分诊是"读多写少"的工作流,把预检推迟到真正写之前,既不影响只读探索,又能保证所有写操作要么完整发生、要么完全不发生。
3. 读路径默认值(Read-Path Default):gitcrawl 优先,gh 兜底
技能对工具角色划定了清晰的边界,这是理解整套流程的骨架:
| 工具 | 角色 | 边界 |
|---|---|---|
gitcrawl | 候选生成 + 历史上下文 | 本地 title/body 搜索、neighbors、clusters、已关闭线程发现;所有候选在被实时 GitHub 确认前都只是线索 |
gh | 实时 GitHub 事实 | 目标状态、正文、评论、review、文件、关联 issue、当前 open/closed/merged 状态;仅当 gitcrawl 陈旧、缺数据或无法表达查询时才用gh search |
prtags | 维护者策管层 | 创建/复用一个重复分组;保存重复状态、置信度、理由、组摘要;作为面向 GitHub 的分组评论的唯一事实来源 |
允许放弃 gitcrawl 改用实时 GitHub 搜索的情形被限定为三种具体理由:目标或候选尚未入库、本地数据对当前决策明显陈旧/不完整、gitcrawl 报错或超时或缺少所需数据。回退到实时搜索时必须注明回退及原因。
gitcrawl 技能文档(.agents/skills/gitcrawl/SKILL.md)还补充了两个关键实践:
- 检查同步新鲜度:
gitcrawl doctor --json; - 铁律:"Do not close/label from similarity alone; require matching intent plus live verification."——不得仅凭相似度就关闭/打标,必须意图匹配 + 实时验证。
还有一条针对写失败的兜底规则:如果后续的prtags目标级写入失败,原因是其自身 mirror 尚未同步到位,则应停止并报告"curation backend 缺少该目标对象",而不是强行走 fallback 写路径。
4. 判定规则:证据清单与单组原则
4.1 什么才算重复
工作规则(Working Rules)给出了三条否定式判据:
- 不能仅因为标题相似就判重;
- 不能仅因为改了相同的文件就判重;
- 重复簇必须基于:相同的用户可见问题 + 相同意图 + 实质重叠的实现或调查上下文。
4.2 证据清单(Evidence Checklist)
宣布重复前,证据必须来自至少两个类别。特别注意:gitcrawl 的 neighbors、搜索命中、cluster 成员身份只算候选生成,本身不构成足够证明。
针对PR,可用的证据维度:
- 相同或几乎相同的问题陈述
- 相同或范围重叠的变更文件
- 相同的修复方向
- 相同子系统和相同失效模式
- 相同的关联 issue 或相同的用户可见症状
针对Issue,可用的证据维度:
- 相同的用户可见问题
- 相同的复现路径或失效模式
- 相同的疑似修复区域
- 相同已关联/已讨论的 PR
- 相同维护者已在把两边引向同一个重复归类
"只有措辞相似"(only have wording similarity)被明确列为不合格证据。
4.3 单组原则(One-Group Rule)
重复分组被定义为互斥的:一个 PR/Issue 同一时间最多属于一个重复组。由此推出四条操作约束:
- 建新组之前,先搜索是否已有表达同一重复故事的组;
- 若目标似乎已属于另一个重复组,先停下解决冲突;
- 不能因为措辞略有不同就为同一目标建第二个组;
- 若两个候选组重叠且无法安全合并裁决,停下并询问维护者。
文档特意强调:"This rule matters more than speed."——宁可慢,也要保持"每个问题一个内聚的重复簇",而不是产生一堆近重复簇。
4.4 好分组 vs 坏分组的形状
一个合格的重复组应该描述底层问题和预期修复方向,不能只因共享某个关键词就归组:
- 好形状:相同的用户可见 bug 或维护者任务、相同子系统/代码面、相同的变更方向、相同的重复处置路径;
- 坏形状(反例):"所有碰过 Slack 的 PR"、"所有提到 retry 的 issue"、"所有 auth 相关条目";
- 组标题应命名真实问题,组描述应概括意图与代码面。
文档给出的三个正面示例:
gateway: startup regression from channel status bootstrapwhatsapp: QR preflight timeout handlingrelease: cross-OS validation handoff gaps
5. 八步工作流:从读取目标到评论同步
Step 1:读取目标(Read The Target)
一律用实时 GitHub 获取目标当前状态。PR 用:
gh pr view <number> --json number,title,state,mergedAt,body,closingIssuesReferences,files,comments,reviews,statusCheckRollupIssue 用:
gh issue view <number> --json number,title,state,body,comments,closedAt需要记录八项信息:目标类型与编号、标题、问题陈述、预期意图、子系统、open/closed/merged 状态、是否已有人文提及疑似重复线程。
Step 2:gitcrawl 广域检索
gitcrawl 是"本地 OpenClaw 历史与聚类源",只有当它缺数据、陈旧或故障时才切换到广域实时搜索。命令按"目标与邻近线程 → 关键短语/子系统检索 → 集群细看 → 候选实时验证"四段展开:
# 目标线程与邻居 gitcrawl threads openclaw/openclaw --numbers <issue-or-pr-number> --include-closed --json gitcrawl neighbors openclaw/openclaw --number <issue-or-pr-number> --limit 20 --json # 关键短语与子系统术语(混合检索) gitcrawl search openclaw/openclaw --query "<key phrase from title or body>" --mode hybrid --limit 20 --json gitcrawl search openclaw/openclaw --query "<subsystem or error phrase>" --mode hybrid --limit 20 --json # 集群细节 gitcrawl cluster-detail openclaw/openclaw --id <cluster-id> --member-limit 20 --body-chars 280 --json对候选 PR 用实时文件数据验证代码重叠:
gh pr view <candidate-pr> --json number,title,state,mergedAt,files,body,comments,reviews对候选 Issue 验证实时状态与评论:
gh issue view <candidate-issue> --json number,title,state,body,comments,closedAtStep 3:实时 GitHub 搜索补盲
在 gitcrawl 之后,仅当满足以下情形才做定向实时搜索:目标太新、本地库没有;评论/review 重要而本地库缺失;确切短语本地没有但 GitHub 理应有。
gh search prs --repo openclaw/openclaw --match title,body --limit 50 -- "<key phrase>" gh search issues --repo openclaw/openclaw --match title,body --limit 50 -- "<key phrase>" gh search issues --repo openclaw/openclaw --match comments --limit 50 -- "<error or maintainer phrase>"Step 4:做出三选一裁决
每个目标必须落到以下三种结果之一:
not_duplicateduplicate_needs_judgmentduplicate_confirmed(仅当证据强到维护者可以安全关闭或重新打标该重复项时才使用)
使用duplicate_needs_judgment的明确情形:问题看似相同但实现目标不同;代码重叠弱;措辞含糊;可能存在两种合理的重复组解释;目标似乎同时交叠两个已存在的重复组。
Step 5:复用或创建一个 prtags 分组
先搜后建。文本搜索 + 相似搜索 + 全量列表三路排查:
prtags search text -R openclaw/openclaw "<problem phrase>" --types group --limit 10 prtags search similar -R openclaw/openclaw "<problem summary>" --types group --limit 10 prtags group list -R openclaw/openclaw prtags group get <group-id> prtags group get <group-id> --include-metadata复用条件:代表同一问题、已含明显相关的成员、加入目标后组仍内聚。不要因为 gitcrawl 把若干 PR/Issue 排在一起就扩大既有分组——加入新成员前必须确认实际实现路径与维护者意图仍然一致。只有当没有任何现成组明显合适时才新建:
prtags group create -R openclaw/openclaw \ --kind mixed \ --title "<problem-centered title>" \ --description "<same intent, subsystem, and duplicate-resolution path>" \ --status open随后挂入目标及已知重复成员:
prtags group add-pr <group-id> <pr-number> prtags group add-issue <group-id> <issue-number>若目标似乎已属于另一个组且无法安全复用,停止,不要创建第二个组。
Step 6:幂等地确保标注字段存在
用field ensure保证技能幂等。目标级(PR 与 Issue 各一套)字段:
prtags field ensure -R openclaw/openclaw --name duplicate_status --scope pull_request --type enum --enum-values not_duplicate,candidate,confirmed --filterable prtags field ensure -R openclaw/openclaw --name duplicate_status --scope issue --type enum --enum-values not_duplicate,candidate,confirmed --filterable prtags field ensure -R openclaw/openclaw --name duplicate_confidence --scope pull_request --type enum --enum-values low,medium,high --filterable prtags field ensure -R openclaw/openclaw --name duplicate_confidence --scope issue --type enum --enum-values low,medium,high --filterable prtags field ensure -R openclaw/openclaw --name duplicate_rationale --scope pull_request --type text --searchable prtags field ensure -R openclaw/openclaw --name duplicate_rationale --scope issue --type text --searchable组级字段:
prtags field ensure -R openclaw/openclaw --name duplicate_confidence --scope group --type enum --enum-values low,medium,high --filterable prtags field ensure -R openclaw/openclaw --name duplicate_rationale --scope group --type text --searchable prtags field ensure -R openclaw/openclaw --name cluster_summary --scope group --type text --searchable注意duplicate_status的三值not_duplicate,candidate,confirmed与 Step 4 的三态裁决形成映射:证据不全时写入candidate并调低置信度。
Step 7:保存维护者裁决
PR 与 Issue 各自写入目标级标注:
prtags annotation pr set -R openclaw/openclaw <pr-number> \ duplicate_status=confirmed \ duplicate_confidence=high \ duplicate_rationale="<same problem, same fix direction, overlapping files and comments>"prtags annotation issue set -R openclaw/openclaw <issue-number> \ duplicate_status=confirmed \ duplicate_confidence=high \ duplicate_rationale="<same user-visible problem and same intended fix path>"组级标注:
prtags annotation group set <group-id> \ duplicate_confidence=high \ cluster_summary="<one-sentence problem summary>" \ duplicate_rationale="<why these items belong in one duplicate cluster>"两条失败处理规则:证据不全时写duplicate_status=candidate并降低置信度;若目标级标注写失败是因为prtags无法解析目标(mirror 未追上),则不要强制 fallback 写,保留已写成功的组状态,报告 curation backend 缺少该目标对象,推迟目标级标注直到prtags追上。
Step 8:让 prtags 同步组评论
这条设计是整个技能最有架构意味的一点:不要指示 Agent 直接创建 GitHub 评论。prtags拥有对外的 GitHub 评论,它是组状态的派生投影(derived projection of group state)。配置了评论同步后,组写入本身就会自动入队派生评论,正常情况不需要手动触发同步。手动同步只作为修复/重试路径:
prtags group sync-comments <group-id> # 查看哪些组仍需关注 prtags group list-comment-sync-targets -R openclaw/openclaw技能应把 GitHub 评论视为"正确的 prtags 组状态的后果",既不应把手工写评论当作常规重复工作流的一部分,也不应把sync-comments当作每次裁决的必经步骤。
输出格式与停止条件
每次裁决后返回一段简短的维护者报告:
Decision: duplicate_confirmed | duplicate_needs_judgment | not_duplicate Target: PR #<n> | Issue #<n> Confidence: high | medium | low Evidence: - ... - ... - ... prtags actions: - reused group <group-id> | created group <group-id> - added members: ... - annotations written: ... - comment sync: automatic if configured | manual repair triggered for <group-id>停止条件(Stop Conditions)要求遇到以下情况时停下升级,而不是硬判:目标似乎属于两个不同重复组;重复归类不清晰;措辞匹配但实现目标不同;两个 PR 因不同原因触碰相同文件;两个 issue 症状相似但疑似不同根因。维护者得到的要么是一个干净的重复裁决,要么是一个明确的 "needs judgment" 结果——"Do not blur the line."
6. 仓库源码佐证:hunk 级证据的自动化落地
技能文档反复强调"代码重叠必须与意图匹配相互印证",仓库中与之形成闭环的自动化实现是 scripts/close-duplicate-prs-after-merge.mjs——一个在 PR 落地(merge)后关闭重叠候选 PR 的脚本。它的证据模型恰好是技能"证据清单"在代码面的精确化:
- 共享 issue 引用:
issueRefsFromPr()从closingIssuesReferences以及标题/正文中的close(s|d)/fix(e|s|d)/resolve(s|d)? #N正则中提取 issue 号,求交集; - hunk 级重叠:
parseUnifiedDiffRanges()解析 unified diff 的@@ -old +new,count @@行,得到每个文件的变更行区间;hasOverlappingHunks()做区间相交判断——这比技能文本中"相同或范围重叠的变更文件"更细一档,直接落到行号区间; - 硬性闸门:
buildDuplicateClosePlan()中,若既无共享 issue 又无重叠 hunk,直接抛错拒绝关闭("Refusing to close ... no shared issue and no overlapping changed hunks"),与技能"不能仅凭标题相似判重"的原则在代码上同构; - 默认 dry-run:
parseArgs()中--apply缺省为 false,未显式传--apply时只打印计划("dry-run only; pass --apply to label/comment/close duplicate PRs"),执行时按"打标 → 评论 → 关闭"三步操作,默认标签集为duplicate、close:duplicate、dedupe:child。
其用法为:
node scripts/close-duplicate-prs-after-merge.mjs --landed-pr <number> --duplicates <numbers> [--repo owner/repo] [--apply]对应的测试 test/scripts/close-duplicate-prs-after-merge.test.ts 用 vitest 覆盖了关键语义:PR 列表解析(逗号/空白/#前缀混排)、unified diff hunk 区间解析,以及两个典型的判重放行用例——"无显式 issue 引用但 hunk 重叠"和"issue 引用相同但 hunk 已漂移",验证了"两类证据任取其一即可、但必须至少有一类"的判定逻辑。这与技能文档 Step 4 的谨慎姿态一致:脚本只在机械可证的重叠下自动关闭,而需要维护者判断的部分(意图是否相同)仍留给 tag-duplicate-prs-issues 工作流与 prtags 裁决。
7. 小结:这套流程可迁移的设计原则
从 SKILL.md 与配套脚本看,OpenClaw 的重复甄别体系沉淀了几条可复用的工程原则:
- 分层事实源:本地缓存(gitcrawl)只做候选生成,实时 API(gh)负责事实核验,策管库(prtags)负责裁决与对外投影,三层各司其职、互不越权;
- 写操作的原子性纪律:缺件即停、mirror 未追上即停、不 fallback 强写,保证外部可见状态不会出现"半套标注";
- 评论即派生物:GitHub 评论不手工撰写,而是组状态的投影,手工同步仅作修复手段——这消除了"评论与标注不一致"这类长期漂移问题;
- 证据可计算化:从"至少两类证据"的自然语言规则,到脚本里共享 issue 交集 + hunk 区间相交的机械判定,重复判定在规则层与代码层保持了同一套证据模型。
适用前提提醒:prtags为独立仓库的 CLI,需从 Release 安装并完成 OAuth 登录;gitcrawl为 Go 二进制(见 .agents/skills/gitcrawl/SKILL.md 的 metadata);所有-R openclaw/openclaw命令假定在 OpenClaw 仓库上下文中运行,gh需已登录且有仓库读写权限。
【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 🦞项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考