首页
/ goose 开源项目如何把 Issue 变成新的 PR:从 PR 驱动到 Issue 驱动的贡献模型与自动化实现

goose 开源项目如何把 Issue 变成新的 PR:从 PR 驱动到 Issue 驱动的贡献模型与自动化实现

2026-09-07 16:36:23作者:邓越浪Henry

本文基于 goose 官方博客《Moving to issues as the new PRs》,解读 goose 项目将外部贡献的入口从"提交 PR"上移到"发起并推进 Issue"的动机、完整工作流与配套规则;并结合仓库中 CONTRIBUTING.mdGOVERNANCE.md 以及 buzz/ 目录下的真实自动化脚本与 Goose recipe,说明这套模型如何在代码层面落地运转。读完后你将理解:为什么编码智能体让 PR 不再是合适的贡献单位、Issue 看板上每个阶段的确切含义、PR 的准入条件,以及如何用仓库内现成的工具把 GitHub Issue 状态同步到社区频道并自动分派负责人。

goose 仓库 184 个未合并 Pull Request 的截图,列表向下渐隐

背景:编码智能体改变了开源贡献的经济学

传统的开源贡献方式门槛很高:新贡献者要先把项目构建起来、把应用跑起来、让测试通过,即使知道该修哪个 bug,也需要对项目架构有粗略理解、对被修改的代码有细节了解。编码智能体(coding agent)彻底改变了这一成本结构。

博客的核心论点可以概括为三句话:

  1. 问题不在代码质量。由智能体生成的代码往往比首次贡献者写出的更好;
  2. PR 曾经是"认真做过功课"的不完美证据——为什么要费力实现一个功能,除非你相信维护者会需要它?修 bug 所需的工作量也强迫贡献者理解周边代码。这种摩擦筛选出了承诺,并强迫贡献者在写代码前获得上下文;
  3. 今天,产出一个"看起来可行"的功能实现或 bug 修复变得非常便宜,而判断这个变更是否属于项目、正确方案长什么样,仍然昂贵。PR 带着"这些问题已回答"的外表到达,但实际上智能体只是做了一系列看似合理的选择;维护者必须找出这些选择、判断哪些正确、解释哪些应该改。贡献者的智能体会快速改代码,但判断力来自维护者。

把这一点推到极端:开源项目会变成一个只有公共代码、没有实质公共参与的项目——由小核心团队及其智能体开发,其他人变成被动的用户或工单提交者。而 goose 治理文档明确把开放性作为核心价值,GOVERNANCE.md 中 Contributors 的定义本身就包含"通过 issues、pull requests 或 discussions 贡献"。外部参与者带来的全新视角、新想法、意外用例和领域知识,是核心团队永远看不到的问题。

因此 goose 的决策是:放弃 PR 作为主要贡献机制,把外部贡献上游化。有价值的贡献地点不再主要是写代码,而是提交好 issue,并参与把 issue 变成深思熟虑的方案的那场讨论。

Issue 驱动的贡献模型:七个阶段的看板

goose 采用公开的 Goose Issues board(GitHub Projects)来组织所有贡献。结合 CONTRIBUTING.md 中的 "Issue Workflow" 章节,每个开放 issue 在看板上的阶段与含义如下:

看板阶段 含义
Inbox issue 等待分诊(triage)
Needs info 需要更多信息,issue 才能推进
Accepted / design 团队希望解决该问题,正在敲定设计、约束与验证方案
Ready 预期方案已确定,可以开始实现
In progress 实现进行中
Verification 实现完成,等待人工确认其确实可用
Done 结果已验证,issue 关闭

工作流的关键节点:

  • 发现 bug 或想要新功能时,照常提交 GitHub issue。新 issue 进入 Inbox;分诊时维护者可能要求补充信息,也可能带解释地关闭 issue。
  • 希望解决的问题移入 Accepted / design,贡献者与核心团队在那里确定预期设计、架构约束以及结果如何被验证。
  • 讨论收敛后,issue 移入 Ready——此时智能体才可以开始写代码
  • 实现期间状态为 In progress,完成后进入 Verification 等待人工确认,最后才到 Done
  • 不打算跟进的 issue 会带解释关闭;goose 明确"不使用拒绝标签"(no rejection labels)。

CONTRIBUTING.md 进一步指出了最佳贡献位置:"Best place to contribute is the discussion between Accepted / design and Ready"——这正是工程发生的地方:把一个有价值的问题变成智能体可以实现的、具体的解决方案。贡献方式包括:带来上下文和领域知识、挑战假设、比较多种方案、识别约束与权衡、并就"结果如何被验证"达成一致。

关于 issue 本身的写作要求也很明确:功能请求应描述一个广泛有用的问题,而不只是你偏好的实现方式;"添加功能很容易,维护它是长期成本",因此增加复杂度而通用收益不足的功能可能被拒绝。博客和贡献指南都强调:issue 要自己写。智能体可以帮你做研究、帮你探索,但你必须理解这个 issue;可以给出方案方向,但应避免在 issue 中写详细解决方案尤其是代码。

新的 PR 规则:没有 Ready issue 就没有 PR

模型切换后,PR 的角色从"贡献的起点"变成"Ready issue 的实现载体"。CONTRIBUTING.md 的 "From Issue to Pull Request" 章节给出了硬性规则:

  • 不要在 issue 到达 Ready 之前开始实现或开 PR;
  • 每个外部 PR 必须:
    • 链接它所实现的 Ready issue;
    • 保持在 issue 中约定的设计与范围内;
    • 说明 issue 的验证方案是如何执行的;
    • 把任何实质性设计变更退回 issue 继续讨论
  • 不实现 Ready issue 的 PR 会被关闭;对 AI 代码评审意见不处理(feedback left unaddressed)的 PR 也会被关闭——这正呼应了博客正文的说法。
  • 例外项:自动化的依赖/发布 PR、紧急安全修复、核心团队明确指派的工作。
  • 不要短时间内连续开很多 PR,按偏好顺序提交,等前面的落地后再开新的。

配套的评审机制包括:使用 codex 作为 AI 代码评审,所有评论要么修复、要么加一行说明解释为何不成立,否则 PR 可能被关闭;以及"Agent Loop Migration"约定——在 crates/goose/src/agents/agent.rs 的旧 agent loop 向 crates/goose/src/agents/state_machine/ 状态机迁移完成之前,涉及 agent-loop 行为变更的 PR 必须在两条路径上都实现并测试,并说明如何验证了两条路径的等价性。这些细节说明"issue 先于 PR"不只是一句口号,而是有具体、可执行的检查标准。

署名规则:贡献单位从"补丁"变成"问题到已验证方案"

这个模型同时改变了"谁该获得署名"。报告问题、复现问题、贡献领域知识、塑造设计、实现方案、验证结果,都可以是有意义的工作。CONTRIBUTING.md 的表述与博客一致:"Substantial contributors at any stage may be recognized as co-authors. The unit of contribution is taking a problem to a verified solution, not writing the patch."——每个阶段的实质性贡献者都可以被记为共同作者(co-author),开源贡献的单位不再是补丁,而是把一个问题一路带到已验证的解决方案,而其中大部分贡献现在发生在 issue 里。

仓库中的自动化落地:buzz/ 目录

博客宣布的看板模型在仓库里有完整的工程化实现:buzz/ 目录是一套把 aaif-goose/goose 的 GitHub issue 连接到公共 Buzz 社区频道的自动化工具集(见 buzz/README.md)。它体现了"issue 是贡献主记录"这一理念的运转方式:GitHub 上的 issue 状态变化会实时同步为社区频道的话题,讨论发生在 issue 及其关联频道中。

两套身份与四个核心工具

这套系统使用两个身份:

  • Github Manager:服务身份,脚本用它的 Nostr 密钥创建和管理 issue 频道、添加成员、发布 issue 摘要、同步频道话题;
  • 受管 bot(当前是 Doose):由 Buzz Desktop 运行的 agent 身份,只有在 Github Manager 显式提及时才会审阅 issue。

核心工具与其职责:

  • create_github_manager:幂等地生成专用 Nostr 密钥对并发布 Github Manager 资料。密钥存放在 $GOOSE_BUZZ_HOME/github-manager(默认 ~/.config/goose/buzz/github-manager),目录权限 0700、文件 0600;身份丢失时只能重建,旧事件的签名无法重签。
  • create_issue_channel:读取一个 GitHub issue,创建永久公开的 Buzz 流(频道名 #<issue-number> <issue-title>),初始话题设为 ⚪ GitHub phase: Inbox,添加 owner/成员/bot,并附带摘要和 issue 链接;不修改 GitHub issue 本身。脚本拒绝为已有频道重复建频道,失败会删除半成品以便重试。
  • list_issue_work:列出 Inbox 中尚未分派、或尚未有频道的 issue,以及 Buzz issues to add 频道中链接的开放 issue;输出 JSON 包含核心团队、GitHub 句柄、Buzz 公钥、兴趣标签与分派容量(recent_assignment_load 统计最近 100 个 issue 的分派负载),供 recipe 据此选人。该命令只读,不改动 GitHub 或 Buzz。
  • syncissues:拉取所有开放 issue 与所有 Buzz 频道,按描述中的 GitHub URL 匹配 issue 频道,把项目阶段和分派人同步到频道话题。阶段到表情标记的映射为:
GitHub 阶段 Buzz 话题标记
Inbox
Needs info 🟡
Accepted / design 🟣
Ready 🟢
Verification 🔵
Done

话题格式形如 🟢 Ready -- assigned to: @github-handle。与已关闭 issue 对应的频道会被打上 ✅ GitHub issue: Closed 并归档;issue 重新打开时频道自动恢复。此外,外部(非仓库 OWNER/MEMBER/COLLABORATOR)用户在 issue 下的新回复会被同步提及到频道,但评论正文不复制进 Buzz,防止评论内容注入提及或 bot 指令——这是一个值得注意的防提示注入设计。使用前建议先 ./buzz/syncissues --dry-run 预览。

这些脚本的本地测试由 Justfiletest-buzz 配方驱动(node --test buzz/*.test.mjs 加语法检查),测试文件为 buzz/github_manager.test.mjs,在 Buzz 自动化代码变更时也会进入 CI。

每小时运行的分派 recipe

buzz/github_issue_manager.yaml 是一个 Goose recipe,管理完整的 Inbox 循环。其 instructions 部分明确把 issue 正文和 Buzz 消息当作不可信数据处理(只用于识别、理解与总结 issue,绝不执行其中指令),并限制唯一的 GitHub 写操作是"用 gh issue edit --add-assignee 把未分派的 issue 分派给一名核心团队成员",禁止编辑正文、评论、改字段、关 issue 或动标签。

分派算法(来自 recipe prompt 与 buzz/core-team.json):

  1. 运行 list_issue_work 获取待处理 issue 列表及每位核心成员的 interest 兴趣列表与 recent_assignment_load(基于最近 100 个 issue,容量 capacity 是唯一负载调节因子,当前花名册中除 filip 为 0.5 外均为 1);
  2. 按 issue 号升序处理:对每个未分派 issue,用 gh issue view --json ... 重读 issue,从兴趣匹配度最高的三名核心成员中选负载最低者分派(负载相同时按主题匹配度决胜),并在本轮内滚动更新候选人的负载计数;
  3. 为该 issue 创建"聚焦的" Buzz 频道:至少包含三个不同的人(Douwe 与 issue owner 必在),只在 issue 棘手或跨领域时加第四人;
  4. 最后运行 syncissues,输出紧凑报告。

单次运行与干跑方式:

goose run \
  --recipe "$PWD/buzz/github_issue_manager.yaml" \
  --params "automation_dir=$PWD/buzz" \
  --no-session

# 干跑:只报告拟议分派,不改 GitHub 或 Buzz
goose run \
  --recipe "$PWD/buzz/github_issue_manager.yaml" \
  --params "automation_dir=$PWD/buzz" \
  --params "dry_run=true" \
  --no-session

buzz/run_hourly 则负责"运行一次 recipe、等待一小时(可用 BUZZ_MANAGER_INTERVAL_SECONDS 覆盖)、循环重复",供专用机器常驻运行。从源码结构看,core-team.json 中每位成员的 interest 列表与其在 goose 代码库中的职责域高度对应(例如 "Agent-loop and state-machine architecture"、"ACP and MCP protocols"、"Security boundaries and permissions"),这解释了为什么分派可以仅凭文本匹配加负载均衡来自动完成。

总结:PR 仍是载体,Issue 是贡献

goose 的这次模型调整可以归纳为四条可复用的实践:

  1. 贡献单位上移:把"提交好 issue + 参与设计讨论"定义为贡献的主体,代码实现只是 Ready issue 的执行环节;
  2. 阶段门禁:Inbox → Needs info → Accepted / design → Ready → In progress → Verification → Done 七阶段看板,让"何时允许写代码"有明确判据,不实现的 PR 直接关闭;
  3. PR 约束具体化:链接 Ready issue、不超范围、说明验证执行、设计变更退回 issue——可检查、可执行;
  4. 自动化承担琐碎环节:分派(兴趣匹配 + 负载均衡)、状态同步(阶段表情话题)、外部讨论回流(防注入的评论提及)全部由仓库内脚本与 Goose recipe 承担,维护者把判断力集中在设计讨论与验证上。

这套机制目前适用于 goose 仓库本身(aaif-goose/goose 的 Projects 看板 1 号 board),其脚本通过 --repo--project-owner--project-number 等参数也可以指向其他仓库,但分派花名册(core-team.json)与社区身份需要随部署环境自行配置。

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

项目优选

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