关于 watch-github
watch-github 是一项技能,在 Claude Code 会话中轮询 GitHub 上的 PR 和分支动态。它发送评论、评审、CI 结果、提交头变更、标签、冲突、合并及关闭事件摘要,并支持指定工作流作为门禁。
主要功能
- 01监视 PR 和分支头
- 02报告评论与评审动态
- 03按指定工作流判断 CI
- 04跟踪提交头、标签、冲突和合并
- 05按动态调整轮询间隔
适用场景
- 01推送更改后监视 CI
- 02跟进开放 PR 的评审和评论
- 03合并后监视主线分支
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ vivswan/ skills --skill watch-github安装后在 Claude Code 中输入/watch-github确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
LICENSE.mdREADME.md.codex-plugin/plugin.jsonagents/openai.yamlscripts/github-events.mtsscripts/github/check-suites.mtsgh.mtspr-activity.mtsrepository.mtsscripts/targets/branch.mtsci.mtspr.mts详细介绍
监控 GitHub
每个 Claude Code 会话启动一个守护进程作为后台任务,轮询该会话关注的拉取请求和分支最新提交。会话只需订阅一次,然后继续工作。评论、评审、CI 结果、头部变更、标签变更、与基准分支的冲突、合并和关闭都会作为消息发送到会话中,每次轮询一条消息;同时也会作为日志行写入,供其他 Agent 读取。
守护进程属于 /session-events 技能,与本技能安装在一起;本技能是它的 GitHub 数据源。该页面规定消息封装格式、运行时目录和文件、文件接收器以及两小时上限。本页面规定轮询内容和事件含义。
运行条件:一个 Claude Code 会话、一个用户、由该会话启动一次的守护进程,以及通过已认证的 gh 访问 GitHub。
示例
一次推送已完成,PR 处于打开状态。每个会话启动一次守护进程作为后台任务,然后用一行命令订阅该 PR 及其门禁工作流:
bun "<skill-dir>/scripts/github-events.mts" daemon # once per session, as a BACKGROUND task
bun "<skill-dir>/scripts/github-events.mts" watch owner/repo#12 --expect-workflow checks
会话继续工作。几分钟后,门禁检查完成,以下消息会自动出现在对话中:
<cross-session-message from="uds:/run/user/1000/session-events/4242.github-events.sock" from-name="github-events" from-mode="bypass">
PR owner/repo#12: CI green on 1a2b3c4d5e6f: 3 workflows
https://github.com/owner/repo/pull/12/checks
automated notice from github-events; no reply needed
</cross-session-message>
无需花费一个轮次询问“还没有变化吗”。守护进程是会话自身的子进程:其消息会立即到达,封装中的名称为 github-events;会话结束时,它也会自行退出。
适用场景
- 刚在启用了 CI 的分支上运行
git push,或刚打开 PR:监控该 PR。 - 等待 PR 更新:等待评审、回复、合并,或确认“CI 是否通过?”
- PR 刚合并,或直接推送已进入主线:每个会话监控一次主线分支
owner/repo:main;此后该分支的每个最新提交都会接受检查。
目标
bun "<skill-dir>/scripts/github-events.mts" watch owner/repo#12 --expect-workflow checks --expect-workflow lint
bun "<skill-dir>/scripts/github-events.mts" watch owner/repo:main --expect-workflow checks
| 目标 | 事件 | 结束条件 |
|---|---|---|
owner/repo#n,一个拉取请求 | 评论、评审、ci、head、标签、冲突、已合并、已关闭、异常 | 合并或关闭时 |
owner/repo:branch,一个分支最新提交 | ci、head、异常 | 永不结束;每次推送到该分支都会产生一个新的 head |
Issue 和安全警报是此数据源未来支持的目标形式,不会成为新的命令或技能。
--expect-workflow <name> 可重复使用,用于指定门禁:即 .github/workflows/ 下工作流文件的 name:,该工作流负责检查目标。单次调用中的标志构成完整的门禁集合。对同一目标重复执行 watch 会替换门禁和游标:重新检查其 CI,并从此刻重新建立活动基线。
如果没有守护进程,watch 会以状态码 3 退出并打印准确的启动命令。首次发现 PR 时,不会上报 PR 上已有的评论、评审或标签;只有此后新增的内容才会成为事件。PR 的 CI 结果、已合并或已关闭状态,以及已有的冲突,都会立即进行判定。
事件
每条消息包含一次轮询的事件,每个事件都有一个 URL,结尾一行是 automated notice from github-events; no reply needed。永远不要回复这类消息。每段文本都是结构化信息:谁、在哪里、数量、状态以及 SHA。消息中不会包含评论、审查或构建日志的内容;请通过 URL 查看。
| 类型 | 行中的内容 | 操作 |
|---|---|---|
comment | PR owner/repo#12: 2 new comments by octocat at src/x.ts:41, src/y.ts:7,后面是最新评论的 URL | 打开 URL,并按一轮审查来处理 |
review | PR owner/repo#12: review by octocat (CHANGES_REQUESTED), 3 comments,后面是该审查的 URL | 按照 /pr-landing-discipline 技能进行同样的处理 |
ci | PR owner/repo#12: CI green on 1a2b3c4d5e6f: 3 workflows,后面是检查页面;如果某个未列出的工作流失败,则会附上 ; other checks red: claude-review;或者 PR owner/repo#12: CI red on 1a2b3c4d5e6f: checks / check / Run tests,后面是失败运行的 URL | 绿色:继续;红色:运行 gh run view <id> --log-failed 查看摘要,修复后推送,下一条结果会自动送达 |
head | PR owner/repo#12: head moved to 1a2b3c4d5e6f; last commit by octocat(这是提交的作者,不是推送者),每次更新都会发送,包括你自己的推送 | 如果 head 不是你推送的:操作分支前先拉取 |
label | PR owner/repo#12: label added: merge-when-green;同一次轮询中有多个标签时:PR owner/repo#12: labels added: approved, merge-when-green;PR owner/repo#12: label removed: needs-rebase;如果同一次轮询中既添加又移除标签,则在同一行中用 ; 分隔;后面是该 PR 的 URL | 标签名称提到你或某个门禁时:采取行动;其他标签仅供参考 |
conflict | PR owner/repo#12: conflicts with main; rebase needed;在你完成变基后,或合并测试自行恢复正常后,会发送 PR owner/repo#12: conflicts resolved;后面是该 PR 的 URL | 变基到基准分支并推送;如果推送后冲突依然存在,这条消息会再次出现 |
merged | PR owner/repo#12: merged into main | 停止跟进;主分支的 CI 由目标分支负责 |
closed | PR owner/repo#12: closed without merging | 停止跟进 |
trouble | PR owner/repo#12 is not readable; unwatch it or check access;PR owner/repo#12: CI settled on 1a2b3c4d5e6f with no run of checks; check the workflow name(或 no checks on 1a2b3c4d5e6f after 2 polls, so no run of checks);PR owner/repo#12: 3 reads failed; read the daemon log;或连续三次轮询失败后 /session-events 技能发出的消息 | 工具故障,不代表流水线失败或通过;参见下方的注意事项 |
| 忙碌 | 不是一种类型:如果某次轮询中有事件、待处理的汇总结果,或 head 仍在评估中,则间隔保持为 60 s;每次无事发生的轮询都会将等待时间加倍,依次为 120 s、240 s,最后为 300 s | 无需操作 |
目标为分支的消息则以 branch owner/repo:main: 开头。评论行会统计所有作者的评论,包括当前会话自己的登录名:如果某位所有者使用同一登录名,就无法将其与 Agent 区分开;其决定也绝不会被当作回声丢弃。审查中的行内评论只会在审查行中统计,不会再次作为评论统计。
当前登录用户撰写的审查在提交之前不会触发事件;提交后会以相同 ID 产生一个事件。有两种情况不会提示或表现异常:如果草稿提交时,较新的活动已使其超出读取窗口(十条审查,或线程中的三条回复),就无法找到;如果删除操作将较早的评论重新纳入窗口,则该评论会被报告一次。
任一方推送后,GitHub 都会重新计算合并测试,并在此期间返回 UNKNOWN。测试结果确定之前不会有任何通知。
CI 规则
- 绿色表示每个指定门禁的最新一次运行均已通过(跳过也算通过);如果未指定门禁,则 PR 的汇总结果为
SUCCESS。指定门禁时,门禁之外失败的运行会列在; other checks red:之后;之后变红的旁观检查会触发新的ci事件,因为/pr-landing-discipline技能会将所有检查都计入绿色状态。 - 红色表示任一指定门禁的最新一次运行失败或已取消,且之后没有更新的运行;如果未指定门禁,则汇总结果为
FAILURE或ERROR。红色状态行会列出每个套件中最多 50 个失败作业,分别注明工作流、作业和第一个失败步骤;没有运行记录的门禁会列在; no run of之后。 - 门禁没有运行记录时,如果汇总结果仍在等待,则该门禁处于待处理状态;如果汇总结果已确定但仍没有该门禁的运行记录,则触发一次
trouble事件。如果某个提交上完全没有检查,则轮询两次后也会触发一次trouble事件:这可能是门禁名称拼写错误,或工作流未在此引用上触发。 - 没有检查且没有门禁表示没有 CI,而不是待处理:不会输出任何内容,提交会保持空闲,直到出现汇总结果。必须确保某项运行被登记时,请使用
--expect-workflow指定门禁。 - 单位是工作流。 对同一个 SHA 重新触发会累积多个运行;只判断每个工作流最新的一次运行,较早的已取消运行会被取代。
- 给出判定后,有变动时会重新判断该提交:有门禁的提交每次轮询都会重新判断(门禁重新运行不一定会改变汇总结果),没有门禁的提交则在汇总结果变化时重新判断。判定相同则保持静默;判定不同则触发新的
ci事件。新提交会从零开始判断。
轮询预算
GitHub 将 GraphQL 的请求限制单独计入一个配额,而 Actions REST 端点(gh run list、gh run watch、gh run view)则计入另一个配额;并行运行的 watcher 会长时间占用后者,超过一次运行所需的时间。守护进程只读取 GraphQL:有活动时每分钟一次;按照 /session-events 技能的渐进安排,在没有活动时每五分钟一次。
每次轮询对每个仓库消耗一个请求:包含每个被监控 PR 的条目、每个被监控分支的最新提交,以及每个仍在判断或带有指定门禁的提交的检查套件,并在一个查询中使用别名(每个仓库每 30 个 PR 额外消耗一个请求)。除此之外:
- 每个条目有变动的 PR 读取一次详细信息(评论、评审、讨论串),分页读取到上次已查看的活动为止
- 检查套件超过 100 个的提交分页读取一次
- 每个红色判定读取一次,列出每个套件中最多 50 个失败作业及其步骤
在稳定状态下,没有任何变动时,每个仓库每五分钟只消耗一个请求。消息之间切勿运行 gh run watch、生成 watcher 子代理,或手动读取 PR:本会话的唯一轮询器是守护进程。
如果某个工作流的运行共用同一个 concurrency 组键,较新的推送会取消较早提交的待运行任务,因此只有最新提交会得到判定;再次推送前请等待判定结果。
Commands
usage: github-events.mts <command> [options]
daemon [--interval <s>] [--mode bypass|prompting] [--id <name> [--pid <pid>]]
watch <target> [the source's flags] [--id <name>]
unwatch <target> | --all [--id <name>]
wait [--since <id>] [--timeout <s>] [--id <name>]
poll | status | stop [--id <name>]
the daemon serves the Claude Code session named by CLAUDE_CODE_MESSAGING_SOCKET and exits with it;
--id <name> names a file-sink daemon for a non-Claude agent instead, --pid <pid> ends it with that process;
--mode is the session's permission mode, carried in the envelope: bypass (the default) or prompting;
--interval is 60 s by default, 1 to 86400
targets: <owner/repo>#<n> for a pull request, <owner/repo>:<branch> for a branch tip
--expect-workflow <name> names a workflow whose run must appear on the head before CI reads green; repeatable
the session-events skill must be installed beside this one; without it every command exits 2 naming the install: npx skills add Vivswan/skills -g --skill session-events
files: <dir>/<pid>-<start>.github-events.{state.json,events.jsonl,log} and <dir>/<pid>.github-events.sock for a session; <id>.github-events.* for a file sink;
<dir> is $SESSION_EVENTS_DIR, else $XDG_RUNTIME_DIR/session-events, else $CLAUDE_CODE_TMPDIR/session-events-<uid>, else <os tmpdir>/session-events-<uid>, else /tmp/session-events-<uid>
prints: one message per poll with alerts, wrapped in <cross-session-message from="uds:<socket>" from-name="github-events" from-mode="<mode>"> and ending "automated notice from github-events; no reply needed";
wait prints the new events as JSON lines, then cursor: <id>
exits: 0 ok (stop with no daemon running, and a second daemon start, are ok too); 2 usage, a state file that is not JSON, or no runtime directory;
3 no daemon answers for this session: stderr names the socket and the background command that starts one; 4 wait only: the timeout passed with no newer line
| 退出码 | 含义 |
|---|---|
| 0 | 正常;没有守护进程运行时执行 stop 也正常,第二次启动 daemon 也正常 |
| 2 | 用法错误(未设置 CLAUDE_CODE_MESSAGING_SOCKET 且没有 --id、目标未使用任一种形式、门名称为空)、没有运行时目录,或此技能旁未安装 /session-events 技能:install it beside this skill: npx skills add Vivswan/skills -g --skill session-events |
| 3 | 没有守护进程响应此会话:stderr 会列出套接字和用于启动守护进程的准确后台命令 |
| 4 | 仅适用于 wait:等待超时,期间没有更新的行 |
默认情况下,--interval 为 60 s。文件接收端(--id)、wait 及其游标,以及运行时文件均属于 /session-events 技能;此来源的日志行为 {"id":17,"at":"2026-10-12T14:03:20Z","repo":"owner/repo","pr":12,"sha":"1a2b...","kind":"ci","text":"...","url":"..."},如果目标是分支,则该行用 branch 替代 pr。
在一组协作 Agent 中,负责协调的会话将守护进程作为自己的后台任务运行,--mode 与会话模式一致,并监视这一组中的 PR;构建者不会在那里运行 watch。负责协调的会话要让构建者处理某条评审意见时,会通过一条消息转发该行。
常见问题
| 现象 | 含义 | 处理方法 |
|---|---|---|
watch 以状态码 3 退出,并列出套接字和命令 | 此会话没有守护进程 | 将打印出的命令作为后台任务运行,然后再次运行 watch |
| 守护进程运行约两小时后自行停止,但会话仍在运行 | 执行环境对后台任务的时长设有限制;对应行由 /session-events 技能的页面负责 | 使用相同命令重新启动;已保存的目标会继续监视 |
连续三次轮询失败后出现 trouble 事件 | gh、网络或 GitHub 连续三次拒绝轮询;首先检查 gh auth status | 修复守护进程日志中指出的问题;令牌过期时需要执行 stop 并重新启动,因为守护进程继承了会话的令牌 |
出现 trouble 事件:CI 已稳定,但没有任何门的运行记录 | 指定的工作流从未在该提交上注册运行记录 | 对照 .github/workflows/*.yml 检查名称,然后使用正确的门集合再次运行 watch;绝不要将汇总结果视为通过 |
出现 trouble 事件:无法读取 | PR 或分支返回 null:已删除、已重命名或无权访问 | 执行 unwatch,或修复访问权限 |
出现 trouble 事件:3 次读取失败 | 轮询仓库读取一直有响应,但此目标的详细信息或分页套件连续三次读取失败 | 查看守护进程日志;每次轮询都会重试该目标,成功后计数器会重置 |
| 仅列出工作流名称的红色行 | 读取失败作业时出错;判定结果仍然有效 | 对运行 URL 中的 id 执行 gh run view <id> --log-failed |
缺少 gh | daemon 从第一次轮询起就会失败 | 安装并验证 GitHub CLI;在此之前,报告推送时附上 PR URL,绝不要悄悄跳过监视 |
使用 Agent 工具启动的本地子 Agent 与所属会话共享收件箱套接字和 pid,因此在其中运行 watch 会订阅该会话的守护进程,事件也会发送到该会话。来自 agent teams 的队友是拥有独立套接字的单独进程,并运行自己的守护进程。