首页
/ 让仓库自我维护:goose 如何用 GitHub Actions 把 Issue 变成可合入的 PR

让仓库自我维护:goose 如何用 GitHub Actions 把 Issue 变成可合入的 PR

2026-09-07 20:25:51作者:明树来

本文源文档:documentation/blog/2025-12-28-goose-maintains-goose/index.md

开源项目 goose 是一个开源、可扩展的 AI Agent,它不仅能写代码,还能安装、执行、编辑与测试代码。当 AI Agent 让更多人能轻松参与开源贡献时,维护者面对的问题也随之增多。goose 团队给出了一种自我消化的解法:把 goose 直接嵌入 GitHub Actions,让维护者在 Issue 下评论一条 /goose ...,goose 便会在容器中读取 Issue、探索代码库、运行验证,最终提交一份 draft PR。阅读本文后,你将理解这套"Issue → PR"自动化流水线的完整设计:触发方式、recipe 的分阶段约束、TODO 扩展如何充当外部记忆,以及维护者角色如何从"实现者"转变为"审阅者"。

背景:维护者为什么需要让 AI 处理自己的 backlog

随着 AI Agent 能力增强,越来越多人愿意写代码并贡献开源。这对生态是净收益,却也改变了维护者的日常现实——goose 团队正面对数量增长远超处理速度的 PR 与 Issue。与其抗拒,不如拥抱:

  • 人工排查一个用户反馈通常横跨数小时甚至数天;
  • 低优先级问题常常在 Discord 或 GitHub 评论区滚动消失,用户会以为没人倾听;
  • 即便是修复,也常因"谁有足够上下文并抽出时间写这段代码"而卡住。

开源真正的瓶颈往往不是"能否有人写出这段代码",而是"能否有掌握足够上下文的人抽出时间写这段代码"。goose 团队的答案是把 goose 用在自己的维护工作上,做自己的第一个用户。

事实上,goose 在 1.0 发布前就借助 goose 本身完成了从 Python CLI 到 Rust、Electron 与 MCP-native 架构的迁移。将这种能力延伸到 Issue 分类与变更审查,成为很自然的下一步——于是他们把 goose 直接嵌入了 GitHub Actions 工作流(即上游仓库中公开的 goose-issue-solver.yml 工作流,最初由 Tyler Longwell 构建,将团队手动探索的想法变成任何维护者都能用一条评论触发的机制)。

第一阶段:本地会话中的"单次对话修复"

在 GitHub Action 出现之前,goose 团队已经用本地 goose 加速 Issue 工作流。原文记录了一个真实案例:

  1. 一位用户在 Discord 反馈:某个 Ollama 模型在 chat 模式下抛错,原因不明;
  2. 维护者没有亲自翻代码,而是让 goose 探索代码、定位根因并解释回来;
  3. 随后让 goose 借助 GitHub CLI(gh)打开了一个 Issue;
  4. 同一会话中,goose 表示有 95% 的把握修复该问题。由于改动很小,维护者让 goose 直接打开一个 PR,当天即被合并。

对比传统路径,问题报告的处理是碎片化的:先澄清问题、在 GitHub 搜索相关 Issue、拉最新代码、grep 文件、阅读逻辑、形成假设——要么写成详细 Issue 塞进开发者的 backlog(后来者还需重新切换上下文),要么亲自动手修复(常常耗费更多时间并在 review 阶段反复往返)。而用 goose,整个过程坍缩为一次对话。

但本地工作流仍有局限:问题仍由维护者驱动——需要停下来、开启会话、粘贴 Issue 上下文、引导 goose 修复、跑测试、开 PR。

第二阶段:把整条链路压缩进一条评论

GitHub Action 将上述全部步骤压缩为一条评论。团队成员看到某个 Issue,评论 /goose 后就可以继续做别的事;goose 在容器中启动,读取 Issue,探索代码库,运行验证,然后打开一个 draft PR。维护者回来时面对的是一个"已给出的解决方案",而不是一块空白的编辑器。

原文记录了三个可复现的实例:

案例 现象 触发 结果
时间问题 goose 总是默认使用 2024 年,尽管上下文里已有正确日期(Issue 搁置两天) 维护者凌晨 1:59 评论 /goose solve this minimally 14 分钟后 goose 打开了对应的 PR(#6101)
社区修复 用户反馈 slash commands 不能正确处理可选参数 维护者评论 /goose can you fix this 一小时内出现带修复与 4 个新测试的 draft PR
Ollama 报错 用户报告模型在 chat 模式抛错 本地会话驱动 当天开 PR 并合并

这背后的价值在于可扩展性:手动分类无法规模化,而 backlog 同时混杂着功能请求、复杂 Bug 和快速修复。Action 允许你指向某个 Issue 说"试试这个",而无需押上整个下午——goose 失败只损失几分钟算力,成功则节省数小时。对贡献者而言,响应速度改变一切:即便 PR 不完美、需要调整,贡献者也能看到项目的动能。

Under the Hood:六阶段 recipe 约束 Agent 行为

表面上,触发方式只是类似 /goose fix this 的评论;实际上工作流内部定义了远超一条简单提示的约束。核心机制是一个 recipe(配方),它用阶段(phase)确保 goose 真正完成任务,且不做超出要求的事:

阶段 goose 做什么 为什么重要
Understand 阅读 Issue,把所有需求提取到文件中 迫使 AI 在写代码前先明确"完成"长什么样
Research 用搜索与分析工具探索代码库 防止对陌生代码盲目修改
Plan 决定实现方案 在动手前先拦截架构性错误
Implement 严格按需求做最小改动 "需求里没有的,就不要加"
Verify 运行测试与 linter 在人类看到 PR 前拦截明显失败
Confirm 重读原始 Issue 与需求 防止 AI 宣布胜利却漏掉一半任务

recipe 还授予 goose 对 TODO 扩展的访问权限——这是一个内置工具,充当外部记忆。简单说:phase 告诉 goose 该做什么,TODO 帮 goose 记住自己在做什么。当 goose 在代码库中逐步构建解决方案时,上下文窗口会被填满,早期指令可能被压缩或丢失;TODO 持久存在,让 goose 随时可以核对已完成与未完成项。

从仓库源码可以印证这一机制的设计:

  • TODO 扩展是 goose 内置的 platform extension,实现位于 crates/goose/src/agents/platform_extensions/todo.rs。其官方文档 documentation/docs/mcp/todo-mcp.md 说明:当任务涉及多文件/多组件或范围不确定时,goose 会自动创建内部清单,边工作边读取和更新进度,并在最后核对全部任务是否完成;你也可以随时让 goose "show me the current todo list"。
  • recipe 是 goose 的一等公民能力。配方文件支持 YAML 与 JSON 两种格式,见 crates/goose/src/recipe/mod.rsRECIPE_FILE_EXTENSIONS = &["yaml", "json"]Recipe 结构体(同文件 L42 附近)定义了 title、description、instructions、extensions 等字段。

可落地的 recipe 文件长什么样

本仓库自带一份真实可运行的 recipe,位于 workflow_recipes/release_risk_check/recipe.yaml。它演示了"分段式 instructions + 声明式扩展 + 参数"的组合:

version: 1.0.0
title: "Release Change Risk Check"
description: "Create a report to assess the change in an upcoming release"

instructions: |
  ## Step 1: Generate the heuristic report
  Run the script to collect PR data and do initial risk scoring:
  {{recipe_dir}}/release_risk_report.py --version {{version}} -o /tmp/release_report.md
  ...
  ## Step 2: AI review of MEDIUM and HIGH risk PRs
  ...
  ## Step 3: Generate the final report
  ...

prompt: follow the instructions to generate the final report

parameters:
  - key: "version"
    input_type: string
    requirement: required
    description: "release version"

extensions:
  - type: platform
    name: developer

对照 documentation/docs/guides/recipes/session-recipes.md 中完整的字段参考,recipe 还支持更多配置项:activities(桌面端可点击的示例任务)、settings(goose_provider / goose_model / temperature)、retry(自动重试与成功校验)、response(结构化 JSON 输出)、以及通过 {{ variable_name }} 模板变量 + parameters 声明实现参数化运行。

在 CLI 中使用 recipe 的常用命令包括:

# 在会话内由当前会话生成 recipe
/recipe
/recipe my-custom-recipe.yaml

# 运行本地 recipe
goose run --recipe recipe.yaml
goose run --recipe ./recipes/my-recipe.yaml --interactive
goose run --recipe recipe.yaml --params language=Python

# 校验 recipe 是否完整、参数格式是否正确、引用的扩展是否存在
goose recipe validate recipe.yaml

recipe 既可以存放在本地目录,也可以存放在 GitHub 仓库中统一共享:在 crates/goose-cli/src/recipes/github_recipe.rs 中可以读到完整检索逻辑——配置 GOOSE_RECIPE_GITHUB_REPO(owner/repo)后,goose 会用 gh 克隆配方仓库、用 git archive 抽取对应目录并解析其中的 recipe.yaml/recipe.json(从源码结构看,检索过程还包含了认证检查与临时目录清理等防护逻辑)。这正是 issue-solver 工作流能按 recipe 名调度修复流程的基础设施。

护栏:谁可以触发、能碰哪些文件、谁来做最终裁决

工作流同时强制了几层护栏:

  1. 触发权限:限制谁可以调用 /goose,避免任意用户消耗 CI 算力或滥用 Agent 能力;
  2. 文件作用域:限定 goose 允许触碰的文件范围,防止修复扩散到无关模块;
  3. 人工审阅:要求维护者对每个 PR 进行 review 与 approve,Agent 只提交 draft PR,不直接合并。

在仓库侧的 recipe 执行栈里也能看到配套的安全设计:例如 crates/goose/src/recipe/read_recipe_file_content.rs 中的测试明确覆盖了"拒绝读取符号链接指向的外部文件",防止恶意 recipe 借路径逃逸读取任意位置;read_recipe_file 对超出默认工具响应阈值的超大 recipe 内容也做了放行处理,说明配方内容会被完整注入、而读取路径被严格收敛。这正是把"AI 能碰什么"做成硬约束的工程体现。

为什么"goose 维护 goose"是一件值得坚持的事

用 goose 维护 goose 看起来有些奇妙,但它让团队保持诚实:我们是自己的第一个客户——如果 Agent 在这里产不出可合入的 PR,团队会立刻感受到。

原文点出了这套实践面向的未来:并非 AI 取代维护者,而是维护者可以指向一个问题说"试试这个",然后回到一个具体的提案面前,而非一块空白编辑器。如果这成为常态,开源将以不同的方式规模化。

这套 GitHub Actions 工作流在源项目中是公开的,任何维护者都可以在自己的 CI 流水线中参考该模式。对于本镜像仓库的读者,若要复现类似实践,可以从以上仓库内的 recipe 规范、本地 recipe 示例(workflow_recipes/release_risk_check/recipe.yaml)与 TODO 扩展文档出发,先本地验证"分阶段约束 + 外部记忆 + 最小改动"的写法,再移植到自己的 CI 工作流中。

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

项目优选

收起
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