使用 goose 定位并修复 GitHub CI 失败:基于 gh CLI 的实战教程
本文以 goose 官方博客中的实战流程为主体,讲解如何借助 GitHub CLI(gh)让 goose 直接从 GitHub 拉取失败的 CI 运行记录与注解(annotations),由模型给出可执行的失败摘要,再自动修改代码并暂存变更供人工审查。读完本篇,你可以掌握"配置 goose 的开发者扩展与 GitHub 能力 → 按 check run ID 获取 CI 失败详情 → 驱动 goose 修复并 stage 变更"这一完整闭环,并将该流程迁移到你自己的 PR 调试工作中。
PR 上的 CI 失败几乎每天都在发生,而传统排查路径是:打开 Checks 页签 → 逐个点开失败任务 → 在冗长日志里找真正的报错 → 定位到本地文件 → 修改 → 重新推送。goose 的价值在于把其中"读日志、找注解"的部分交给 agent:它通过 gh 命令拿到结构化的 check run 数据,总结出问题,并直接在你的工作区里应用修复。
需要先说明适用前提:该流程最初发布于 goose 的 beta 阶段,当时的命令与配置格式(如 profiles.yaml、toolkit 列表)与当前仓库已有所不同。下文会先完整保留原文档的操作骨架,再结合当前仓库源码指出对应的现行实现方式,两者配合阅读即可在实际环境中跑通。
一、准备工作
1. 安装并认证 GitHub CLI(gh)
goose 访问 CI check run 详情依赖本机已安装的 gh。它是 GitHub 官方提供的命令行工具,安装并登录后,后续所有 gh api 请求都会自动携带你的身份凭证:
brew install gh
gh auth login
按照交互式提示完成账号认证即可(macOS 上 brew 之外的发行版也可以用对应包管理器安装 gh)。认证是否成功,可用 gh auth status 快速验证。这一步是整个方案的地基:没有有效的 gh 登录态,goose 执行任何 gh api 命令都会返回 401/403,也就拿不到 check run 注解。
2. 配置 goose
原文档给出的 beta 时代配置,是在 ~/.config/goose 下的 profiles.yaml 中定义一个 profile,并同时启用 developer 与 github 两个 toolkit:
my-profile:
provider: anthropic
processor: claude-3-5-sonnet
accelerator: claude-3-5-sonnet
moderator: truncate
toolkits:
- name: developer
requires: {}
- name: github
requires: {}
然后用该 profile 启动会话:
goose session start --profile my-profile
这里的两个 toolkit 分工明确:
developer:提供 shell 执行与文件编辑等本地开发能力。没有它,goose 既跑不了gh命令,也无法修改和 stage 文件;github:封装对 GitHub 的访问。原文档指出,如果 profile 的 toolkit 没有正确配置,goose 将无法访问gh命令——这也是实际调试中最常见的坑,通常表现为 shell 工具调用gh时报命令未找到或认证失败。
结合当前仓库源码:配置格式如何演进
从源码结构看,当前版本已不再使用独立的 profiles.yaml + toolkit 列表,而是把扩展统一收敛到全局配置(~/.config/goose/config.yaml)的 extensions 键下。解析逻辑位于 extensions.rs:parse_extensions_map 遍历 extensions 下的每个条目,缺省 name 时自动用键名注入(inject_name_if_missing),并过滤掉本地不可用的平台扩展。扩展的具体类型定义在 extension.rs 的 ExtensionConfig 枚举中,支持四种形态:
| 类型 | 用途 | 关键字段 |
|---|---|---|
stdio |
启动本地子进程的 MCP server | cmd、args、envs、env_keys、timeout、cwd |
builtin |
随 goose 捆绑的内置扩展(如 developer) |
name、display_name、timeout |
platform |
运行在 agent 进程内、可直接访问 agent 的平台扩展 | name、available_tools |
streamable_http |
连接远程 MCP 端点 | uri、headers、socket、OAuth client_id 等 |
其中 developer 至今仍是默认扩展,源码中 extensions.rs 定义了 pub const DEFAULT_EXTENSION: &str = "developer";,默认超时 300 秒(DEFAULT_EXTENSION_TIMEOUT)。因此,原文档"启用 developer + github 两个 toolkit"的意图,在今天等价于:确保 extensions 中的 developer(builtin)保持启用,并通过 stdio 或 streamable_http 扩展接入 GitHub 能力。仓库自带的 GitHub 接入指南 github-mcp.md 给出了一个现成的远程扩展配置——以 https://api.githubcopilot.com/mcp/ 为端点、Authorization: Bearer <GITHUB_PAT> 为请求头的 streamable_http 扩展。这类远程扩展的 headers 值支持 $VAR/${VAR} 环境变量替换(见 extension.rs 中 substitute_env_vars 对 header 的处理),便于避免把 token 明文写死在配置里。
两种路线可以对照选择:
- gh CLI 路线(本文主线):goose 用
developer扩展的 shell 能力直接执行gh api,无需额外 token 配置(复用gh已有登录态),适合 CI 调试这类以"读 API 数据"为主的场景; - GitHub MCP 路线:配置一个 GitHub MCP server 扩展,获得结构化的工具调用。仓库的 MCP 回放测试 github-mcp-serverstdio 保存了与 GitHub MCP server 的真实交互回放,可作为了解其工具面(issues、pull requests、repository 等)的参考。
无论哪条路线,认证前提都一样:goose 进程能代表你访问 GitHub。
二、获取 CI 失败详情
一切就绪后,直接向 goose 发起请求,指明 PR 与 check run ID:
Can you tell me about the CI failures on PR #11111 in the organization/repo repository? The check run ID is 123456.
check run ID 的获取方式:在 PR 的 Checks 页签点击某个失败项,ID 会出现在浏览器地址栏的 URL 中。
goose 的工作流是:用 gh CLI 拉取该 check run 的信息并整理成摘要。它会执行的核心命令形如:
gh api -H "Accept: application/vnd.github+json" /repos/<owner>/<repo>/check-runs/<check-run-id>/annotations
这条 gh api 调用的意义在于直接命中 GitHub REST API 的 check run annotations 端点:返回的是带 file、start_line、message、annotation_level 等字段的结构化错误注解,而不是成百上千行的原始构建日志。对模型来说,结构化注解的信噪比远高于日志全文,这正是该流程能"一步到位"给出可读摘要的原因。
原文档给出的 goose 输出示例:
Here are the details for Check Run ID 123456:
**Name**: CI-Build-All
**Status**: completed
**Conclusion**: failure
**Annotations Summary:**
1. **ModuleA Test Failure**
File: `ModuleATests`
Line: 35
Error: Mismatched parameter order in function call.
2. **ModuleB Test Failure**
File: `ModuleBTests`
Line: 64
Error: Unexpected nil value encountered during initialization.
3. **ModuleC Test Failure**
File: `ModuleCTests`
Line: 98
Error: Type mismatch in returned value. Expected 'String', found 'Int'.
这个输出格式体现了两个值得保留的习惯:每条问题都带文件 + 行号 + 具体错误语义,并且按失败模块分组。这样的摘要既是给人看的,也是下一步"让 goose 修"时的输入上下文——后续修复请求可以直接引用这份摘要,而不需要模型二次翻日志。
三、驱动 goose 修复并暂存变更
拿到失败详情后,第二步是让 goose 动手修复。原文档示例请求:
Can you fix these issues and stage the changes so I can review them? Do not add unnecessary code comments.
注意这个提示词里刻意加了"不要加多余的代码注释"这类约束——它把"人工审查"的负担提前压低:goose 的职责被限定为按错误信息应用最小修复 + git add 暂存,而不是直接提交或推送。
goose 的响应示例:
I have fixed the following files and staged them:
- `ModuleATests`: Corrected the order of parameters in the function call.
- `ModuleBTests`: Resolved the unexpected nil value encountered during initialization.
- `ModuleCTests`: Adjusted the type mismatch in the returned value.
You can now review the staged changes.
对应地,goose 此时依赖的正是第一节的 developer 扩展能力:读取/编辑本地文件、执行 shell(包括 git add)。从源码结构看,扩展是否提供某个工具由 ExtensionConfig::is_tool_available 控制(extension.rs),available_tools 为空时放行全部工具,也可以在配置中显式收窄——对 CI 修复这类任务,收窄工具面可以让行为更可预期。
四、人工审查暂存的变更
自动化修复不等于免检。原文档列出的审查要点在实践里依然成立:
- 检查是否混入了无意义的注释(如
// Fix xyz); - 检查是否改动了与失败无关的代码区域;
- 如有问题,先
git reset取消暂存再重新修正,避免把噪音带进提交。
一个稳妥的收尾顺序是:git diff --staged 逐块确认 → 本地重跑对应测试或最小化复现 → 确认无误后提交并推送,让 CI 重新验证。这个"人审最后一环"是整套流程可信度的关键:goose 负责压缩了 90% 的日志阅读与定位时间,但最终 diff 仍由你签字。
五、这套流程的价值与边界
把三个阶段串起来看,goose 在 CI 调试中的收益集中在三点:
- 定位:用
gh api拉取 check run annotations,把原始日志压缩成"文件 + 行号 + 错误"三段式摘要,替代手动翻页找日志; - 修复:基于错误信息直接修改代码并
git add暂存,人只需审查 staged diff; - 可复用:整个流程依赖的只是
gh登录态与 goose 的 shell/文件能力,换仓库、换语言、换 CI 系统(只要失败信息能通过 check run annotations 暴露)都能复用同一套提问方式。
边界同样清楚:该流程假设失败原因能从 annotations 中读到(纯编译/测试类失败基本满足;若 CI 失败源于网络、资源配额等基础设施问题,注解往往只有笼统的 exit status 1,此时仍需要人回看原始日志)。另外,原文档针对的是 beta 版 goose,profiles.yaml/toolkit 写法已如前所述被 extensions 配置取代;命令与交互形式请以你当前安装的版本实际运行为准。仓库中 config-files.md 提供了现行配置文件的完整说明,github-mcp.md 提供了 GitHub 扩展的现成接入参数,可作为落地时的对照参考。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
