首页
/ OpenClaw 重复 PR/Issue 甄别工作流:gitcrawl 候选发现、prtags 分组与 GitHub 评论同步的完整实现

OpenClaw 重复 PR/Issue 甄别工作流:gitcrawl 候选发现、prtags 分组与 GitHub 评论同步的完整实现

2026-09-05 09:57:21作者:庞队千Virginia

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)被归纳为五步:

  1. 收集重复证据(gather duplicate evidence)
  2. 判定是否为真实重复(decide whether it is a real duplicate)
  3. 为该重复簇创建或复用一个 prtags 分组(create or reuse one prtags group)
  4. 把维护者裁决保存到 prtags(save the maintainer judgment in prtags)
  5. 依赖 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 同一时间最多属于一个重复组。由此推出四条操作约束:

  1. 建新组之前,先搜索是否已有表达同一重复故事的组;
  2. 若目标似乎已属于另一个重复组,先停下解决冲突;
  3. 不能因为措辞略有不同就为同一目标建第二个组;
  4. 若两个候选组重叠且无法安全合并裁决,停下并询问维护者。

文档特意强调:"This rule matters more than speed."——宁可慢,也要保持"每个问题一个内聚的重复簇",而不是产生一堆近重复簇。

4.4 好分组 vs 坏分组的形状

一个合格的重复组应该描述底层问题和预期修复方向,不能只因共享某个关键词就归组:

  • 好形状:相同的用户可见 bug 或维护者任务、相同子系统/代码面、相同的变更方向、相同的重复处置路径;
  • 坏形状(反例):"所有碰过 Slack 的 PR"、"所有提到 retry 的 issue"、"所有 auth 相关条目";
  • 组标题应命名真实问题,组描述应概括意图与代码面。

文档给出的三个正面示例:

  • gateway: startup regression from channel status bootstrap
  • whatsapp: QR preflight timeout handling
  • release: 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,statusCheckRollup

Issue 用:

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,closedAt

Step 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_duplicate
  • duplicate_needs_judgment
  • duplicate_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-runparseArgs()--apply 缺省为 false,未显式传 --apply 时只打印计划("dry-run only; pass --apply to label/comment/close duplicate PRs"),执行时按"打标 → 评论 → 关闭"三步操作,默认标签集为 duplicateclose:duplicatededupe: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 的重复甄别体系沉淀了几条可复用的工程原则:

  1. 分层事实源:本地缓存(gitcrawl)只做候选生成,实时 API(gh)负责事实核验,策管库(prtags)负责裁决与对外投影,三层各司其职、互不越权;
  2. 写操作的原子性纪律:缺件即停、mirror 未追上即停、不 fallback 强写,保证外部可见状态不会出现"半套标注";
  3. 评论即派生物:GitHub 评论不手工撰写,而是组状态的投影,手工同步仅作修复手段——这消除了"评论与标注不一致"这类长期漂移问题;
  4. 证据可计算化:从"至少两类证据"的自然语言规则,到脚本里共享 issue 交集 + hunk 区间相交的机械判定,重复判定在规则层与代码层保持了同一套证据模型。

适用前提提醒:prtags 为独立仓库的 CLI,需从 Release 安装并完成 OAuth 登录;gitcrawl 为 Go 二进制(见 .agents/skills/gitcrawl/SKILL.md 的 metadata);所有 -R openclaw/openclaw 命令假定在 OpenClaw 仓库上下文中运行,gh 需已登录且有仓库读写权限。

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

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.79 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
988
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384