一个使用 Go 和 Cobra 编写的命令行工具:通过 GitHub REST API 获取当前项目 GitHub 远程仓库中所有未关闭的 Issue,打印列表后调用 pi 编码代理(非交互模式)逐个执行,并在每个 Issue 实现完成后将其关闭。
make build
# 或
go build -trimpath -o bin/git-check ./cmd/git-check保留的 JSON 事件流演示使用与 Issue 执行相同的共享消费器:
make pijson
./bin/pijson "hello"运行时使用进程的当前工作目录,而不是二进制文件所在目录。
命令行参数:--max-times(整数,最多执行的 Issue 数量;0 表示不限制,直到被 Ctrl-C 中断)、--idle-delay(时长,默认 5m;当没有待处理 Issue 时 sleep 该时长后继续轮询,0 表示空闲时直接退出)和 --improve(布尔;开启代码优化阶段,见下文)。
# 执行 3 个 Issue 后退出
./bin/git-check --max-times 3
# 持续执行,使用 Ctrl-C 停止
./bin/git-check
# 没有 Issue 时每 10 分钟轮询一次
./bin/git-check --idle-delay 10m
# 没有 Issue 时进入代码优化阶段:每个空闲轮次调用 pi 改进代码库一次
./bin/git-check --improve启动后循环执行以下步骤:
- 通过 GitHub REST API 获取当前仓库中所有未关闭的 Issue(
created升序,跳过 Pull Request),并打印列表(open issues (N):); - 调用
pi编码代理逐个执行每个 Issue:pi --mode json "Execute this GitHub issue: #N <title> (<url>)\n\n<body>\n\n请使用 team run 实现。",解析其 NDJSON 事件流后,只输出 assistant 的可读 thinking/text 内容; - 每个 Issue 执行完成后,通过 GitHub API 将其状态修改为关闭:
PATCH /repos/{owner}/{name}/issues/{number}(请求体{"state":"closed"}); - 本轮所有 Issue 执行完毕后进入下一轮循环,重新获取仍未关闭的 Issue。同一轮内已执行过的 Issue 会跳过。
Issue 执行路径固定使用 pi --mode json;代码优化阶段是 ADR-0001 定义的独立路径,仅由 ImproveExecutor 使用 pi --print,两条路径不会混用。
当仓库没有未关闭的 Issue(或剩余 Issue 均已在本次运行中执行过)时,默认 sleep 5 分钟(--idle-delay 可调整)后继续轮询,直到达到 --max-times 上限或收到 Ctrl-C;--idle-delay 0 时则直接退出(退出码 0)。
开启 --improve 后,每当一轮循环没有任何待执行 Issue(没有未关闭的 Issue,或剩余 Issue 均已执行过)时,工具先调用 pi 执行一次代码库改进迭代,再进入空闲等待:
[2026-08-21 21:27:33] improving codebase with pi
[2026-08-21 21:27:33] running pi for codebase improvement: /usr/local/bin/pi --print
[2026-08-21 21:27:33] pi exited for codebase improvement: code=0 duration=2m05s
[2026-08-21 21:27:33] codebase improvement iteration finished
[2026-08-21 21:27:33] no open issues remain; sleeping 5m0s before next fetch
改进提示词参考了 Matt Pocock 的 improve skill(扫描代码库寻找"深化"机会:浅模块变深模块、删除测试、优先关注最近频繁改动的热点区域,目标是可测试性与 AI 可导航性)和 Kun Chen 的 gnhf 项目(每次迭代只做一处小的、已提交的、有记录的改动,迭代之间通过笔记文件共享上下文):
- 每个空闲轮次只改进一处,pi 需要补充/更新测试、运行
make fmt/vet/test/lint并提交这一次改动; - 每次改进后,pi 会把本次改动的简短说明追加到
.improve-notes.md(该文件已被 git 忽略,仅作跨迭代记忆),后续迭代可参考它继续; - 改进迭代不计入
--max-times上限;--idle-delay 0配合--improve时,每个空闲轮次改进一次后退出; - 若工作树存在未提交改动(例如上一次改进失败留下的残留),本次改进会跳过并记日志
skipping codebase improvement: working tree is dirty,避免在脏树基础上叠加改动; - 不传
--improve时行为与之前完全一致(仅空闲轮询/退出)。
Issue 查询使用当前目录启动时选定的 GitHub remote,直接调用 GitHub REST API:
GET https://api.github.com/repos/{owner}/{name}/issues?state=open&sort=created&direction=asc&per_page=100
结果按创建时间升序分页扫描,跳过 Pull Request(issues 端点会混入 PR)。关闭 Issue 同样直接调用 GitHub REST API:
PATCH https://api.github.com/repos/{owner}/{name}/issues/{number}
{"state": "closed"}
关闭失败不会中断循环:日志会记录 failed to close issue #N,该 Issue 保持打开;本次运行会避免重复执行,后续重新启动可能再次获取。
需要网络访问 GitHub API。未提供令牌时可以匿名访问(每小时 60 次配额,循环频繁调用建议配置令牌);设置 GITHUB_TOKEN 或 GH_TOKEN 环境变量后使用 Bearer 认证(每小时 5000 次配额)。不需要安装 gh。需要能在 PATH 中找到 pi 可执行文件。
Issue 查询或关闭失败、当前目录不是 Git 仓库、没有 GitHub remote,或找不到 pi 可执行文件时会立即报错退出。认证失败(401)、仓库不存在或无权限(404)、API 配额耗尽(403)会给出对应的明确错误。
错误输出到 stderr,退出码为:0 成功,1 运行时错误,2 参数错误,130 被 Ctrl-C 或 SIGTERM 中断。
系统执行过程的日志(带时间戳)打印到 stderr,包括:git 状态检查、Issue 获取、pi 调用与退出(退出码和耗时)等每个步骤:
[2026-08-21 21:17:20] inspect git status
[2026-08-21 21:17:20] git status: directory=/path/to/repo
[2026-08-21 21:17:21] got issue #1: <title> (<url>)
[2026-08-21 21:17:21] running pi for issue #1: /usr/local/bin/pi --mode json
[2026-08-21 21:17:21] prompt for issue #1: Execute this GitHub issue: #1 <title> (<url>)
<body>
[2026-08-21 21:17:21] pi exited for issue #1: code=0 duration=1m23s
[2026-08-21 21:17:21] closing issue #1
[2026-08-21 21:17:21] issue #1 closed
[2026-08-21 21:27:33] no open issues remain; sleeping 5m0s before next fetch
pi 的 JSON 输出会被解析;只有 assistant 的 thinking/text 内容写入 stdout(同时输出 open issues (N): 待执行列表),原始 JSON、user 消息、工具调用和生命周期事件不会泄漏到 stdout。日志继续写入 stderr,与结果互不干扰。空闲轮询期间按 Ctrl-C 可立即中断;--improve 模式下改进迭代期间同样可用 Ctrl-C 中断。
HTTPS remote 中的用户名和密码不会在检查结果中输出。
make test
make vet
make fmt
make lint
make pijson