关于 ci-sentinel
ci-sentinel 是配合 Claude 使用的技能和定时工作流,用于分类单个仓库中开放 PR 的失败检查。它只发布诊断评论,不推送修复,并通过每日令牌预算和 SHA 去重控制运行。
主要功能
- 01每日扫描失败的 PR
- 02通过 /ci-debug 分类故障
- 03发布诊断评论但不修复
- 04按 SHA 防止重复评论
- 05设置每日令牌预算和单个 PR 超时
适用场景
- 01检查仓库开放 PR 中的失败项
- 02新提交后添加 CI 诊断评论
- 03安装或检查 sentinel 工作流
- 04查看账本中的近期分类
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ yonatangross/ orchestkit --skill ci-sentinel安装后在 Claude Code 中输入/ci-sentinel确认已加载。
详细介绍
ci-sentinel — 每日自主 CI 分类器
直接回应 275 次会话的洞察审计(2026-05-16):一个月内有 14 次 ci-debugging 会话和 7 次 fix-ci-failures 会话,其中大多数都在重复执行你已在 /ci-debug 中编码的同一套 10 种模式分类。此技能可让分类器自主运行。
它的功能
⏰ daily cron (08:17 UTC)
│
▼
📥 gh pr list → PRs with FAILURE checks (yours, max 10)
│
▼
🤖 for each PR (skipping those already commented at this SHA):
claude -p → run /ci-debug → capture verdict markdown
│
▼
💬 post collapsed PR comment with marker so future runs dedupe
│
▼
📜 append { ts, pr, sha, tokens } to .sentinel/ledger.jsonl
│
▼
💰 if daily token spend > ORK_SENTINEL_DAILY_TOKEN_BUDGET → pause
它不会做什么(v1)
- 绝不会推送修复。 即使是 100% 确信的 lockfile 漂移匹配,v1 也只会在 PR 评论中提出建议。自动推送是 v2 才会考虑的问题,前提是连续一个季度没有误报。
- 不会发送告警。 新颖的失败会在评论中标记为
🆕;你可以在常规状态检查时发现它们,而不会遭遇通知轰炸。 - 不会分析已关闭或已合并的 PR。
- 不会探索安装它的仓库以外的范围。 这是有意按仓库设计的。组织范围的扫描是另一种模式,这正是
/status的用途。 - 不会根据不可信文本采取行动。 CI 日志和 PR 标题及正文都是不可信输入,可能包含提示注入。根据
Read("${CLAUDE_PLUGIN_ROOT}/shared/rules/untrusted-input-quarantine.md"),分类器只读这些内容,并将失败类别提取为结构化事实;“提出而不应用”的设计(不自动推送)本身就能让执行方远离原始字节;隔离规则则明确了这一点,而确定性信号(退出代码、测试输出)会绕过读取器,直接作为事实依据。
为什么可以无人值守地运行
| 风险 | 缓解措施 |
|---|---|
| Token 成本失控 | 设定 ORK_SENTINEL_DAILY_TOKEN_BUDGET=1000000 上限,并由工作流的第一步强制执行。每天重置。 |
| 对同一 SHA 重复发表评论 | 每条评论都带有标记 ``;工作流会在发表评论前扫描现有评论。 |
| 错误分类导致刷屏 | “提出而不应用”意味着最坏的结果也只是评论变多,但内容看起来仍准确。你可以将它们折叠;但错误的自动修复无法撤销合并。 |
| 卡住的 PR 不断被重新分类 | 对 SHA 采用幂等处理——只有推送新提交时才会重新运行。 |
| Sentinel 本身导致 CI 出问题 | 在 ubuntu-latest 上运行,不由 pull_request 或 push 触发。不会阻塞任何其他工作流。 |
在新仓库中安装
- 将 OrchestKit 仓库中的
.github/workflows/ci-sentinel.yml复制到目标仓库(此技能附带该文件)。 - 使用
claude setup-token创建 Max 方案 OAuth Token,然后将其添加为CLAUDE_CODE_OAUTH_TOKEN密钥:gh secret set CLAUDE_CODE_OAUTH_TOKEN -R <owner>/<repo>。工作流会直接从作业级 env 读取此值;不再使用ANTHROPIC_API_KEY,仅设置该变量会导致运行失败:当CLAUDE_CODE_OAUTH_TOKEN未设置或已过期时,工作流的身份验证探针会直接报错。 - (可选)调整工作流中的
ORK_SENTINEL_DAILY_TOKEN_BUDGETenv。 - 设置
inputs.dry_run = true,手动触发运行以验证配置。 - 确认试运行没有发表评论,且作业摘要显示正常后,即可交由每日 cron 接管。
当探针报告 401 时,按相同方式轮换 Token:运行 claude setup-token,然后重新运行 gh secret set。
在本地作为后台会话运行
如果你通过 claude --bg 在本地运行 Sentinel,而不是使用工作流:
固定会话(CC 2.1.147+): 在
claude agents中按Ctrl+T固定会话。固定的后台会话在空闲时仍会保持运行(两次运行之间不会被静默清理),会就地重启以应用 CC 更新,而不是直接退出;在内存压力下,也只有在非固定会话之后才会被清理。
恢复会话(CC 2.1.144+): 通过
claude --bg启动的会话现在会显示在/resume中,并标记为bg——可以直接通过/resume恢复崩溃的 Sentinel,而无需进入 Agent 视图。
配置
此工作流有意通过文件内的环境变量进行配置(而非工作流输入),这样派生仓库可以保持自包含:
| 变量 | 默认值 | 含义 |
|---|---|---|
ORK_SENTINEL_DAILY_TOKEN_BUDGET | 1000000 | 每日硬性上限。不按小时执行;按 UTC 日历日计算。由于移除了 --bare(见下文“为什么不使用 --bare”),上限从 500k 提高到了 1M。 |
ORK_SENTINEL_PER_PR_TIMEOUT_S | 300 | 每次 PR 调用 claude -p 的墙钟时间上限。 |
max_prs(workflow_dispatch 输入) | 10 | 单次扫描中分析的 PR 数量上限。 |
dry_run(workflow_dispatch 输入) | false | 跳过评论发布(用于规范验证)。 |
为什么不使用 --bare(2026-05-18 的发现)
最初的设计基于 claude -p --bare(CC 2.1.81+),以尽可能减少插件和钩子的加载,并将每个 PR 的用量稳定在约 4k token。首次实际运行发现,--bare 不会使用 ANTHROPIC_API_KEY 环境变量、--settings.apiKey 或 --settings.apiKeyHelper 进行身份验证——每次调用都会返回 "Not logged in · Please run /login"。我们使用多种设置形式在本地复现了这一问题。
因此移除了 --bare;每个 PR 的成本从约 4k 增至约 10k token(加载插件和钩子),而 --no-session-persistence 可部分抵消这一增长(避免写入磁盘)。每日预算从 500k 提高到 1M,以应对这一变化。(预算上调早于 2026-07 切换为每日 cron 和 Max 计划 OAuth 身份验证;按当前频率,上限完全是预留余量,见下文“成本模型”。)
如果/当 CC 修复 --bare 的身份验证问题后,只需修改一行,工作流即可恢复为 bare 模式。
分发信封(CC 2.1.142+ 标志 — M146-6 / #1849)
每次 claude -p 调用都会锁定分发信封,因此无论运行器继承了什么设置,每个 PR 的成本都能保持可预测:
| 标志 | 值 | 原因 |
|---|---|---|
--permission-mode | acceptEdits | 无头模式下“使用工具而不提示”。/ci-debug 需要 Bash(gh pr checks、gh api ...logs)来读取失败信息。原先的值是 dontAsk,但它会静默拒绝需要权限的工具,导致每次分析结果都是空的(M146-7、#1862 Bug C)。此处绝不可使用 bypassPermissions。 |
--max-turns | 4 | 限制对话轮数。扫描、分类、报告——完成。 |
--output-format | json | 预算熔断器需要 usage.total_tokens。 |
--no-session-persistence | (标志) | 不将会话状态写入磁盘;哨兵运行是临时的。 |
⚠️
acceptEdits具备编辑能力。权限模式并不是让哨兵只提议、不应用的保障。 请准确区分各项控制的作用:
- 真正的结构性控制是在
ci-sentinel.yml顶层设置permissions: contents: read。 该作业使用的GITHUB_TOKEN根本无法写入仓库内容,因此无论模型尝试什么,GitHub API 都会拒绝git push、分支更新或gh pr merge。这是强制措施,而非约定。这也解释了为什么模型对运行器检出内容所做的本地编辑无处生效:不是因为运行器是临时的,而是因为无法推送这些更改。- 模型仍然可以写入,而且这些写入会持久保留。 作业设置了
GH_TOKEN,并授予pull-requests: write和issues: write权限,提示词还要求模型使用ghCLI。因此,使用acceptEdits的模型可以发布、编辑或删除评论,编辑 PR/issue 的标题和正文,添加标签,以及关闭或重新打开 PR 和 issue。作业结束后,这些操作都不会撤销。请将 GitHub 对话状态视为可写入的影响范围。- 提示词措辞只是约定,不是控制措施。 分发提示词是
Run /ci-debug on PR N ... Use only the gh CLI. Output the report markdown only,而/ci-debug的规范要求只提出建议,绝不应用。这能避免模型破坏性地使用其写入权限范围,但没有强制保障;CI 日志和 PR 正文也都是不可信输入。后果:保留
contents: read。将其扩大为contents: write(或添加 git 写入步骤并授予相应权限)才是真正会将其变为自动修复 Bot 的改动,而且提示词措辞将降为唯一控制措施。将pull-requests/issues权限收紧为read会缩小剩余影响范围,但代价是哨兵赖以存在的判定评论无法发布。此处绝不可使用bypassPermissions。
这些值在工作流中是硬编码的。如果你需要为 Fork 覆盖设置(例如想使用不同的 permission-mode),请直接编辑 .github/workflows/ci-sentinel.yml——有意不将其作为 workflow_dispatch 输入公开,以防一次性的手动运行意外导致成本激增。
评论格式
每条判定评论都如下所示:
<details><summary>🛰️ <b>CI Sentinel verdict</b> (sha abc123def)</summary>
## CI Debug: <repo> · #<n>
**Failing job:** ...
**Classification:** Pattern #N — <name>
**Reference:** memory <file.md>
**Proposed fix:** ...
</details>
默认折叠——除非点击,否则不会产生收件箱噪声。始终包含 SHA,以便你判断判定是否仍然有效。
变更日志(推迟至 v1.1)
洞察审计的最高优先级设计要求提供一个 CI_PLAYBOOK.md,由哨兵在每次人工驱动的新型失败修复后更新。v1 不会写入 playbook——它只会向 .sentinel/ledger.jsonl 追加分类行。playbook 位于 /ci-debug 的 SKILL.md 中,v1 阶段由人工维护。
v1.1 发布后,日志流程如下:
- 修复 PR 合并后,哨兵会将该 PR 的标题与现有模式进行差异检查。
- 如果发现新模式,它会创建一个后续 issue,建议将此模式添加到
/ci-debugSKILL.md。 - 人工在 PR 中批准该模式;哨兵会在下一轮扫描时采用它。
成本模型(粗略估算)
每次 PR 分析:约 8-12k 个令牌(完整加载 CC——包括插件和钩子——因为已移除 --bare,详见上文「为何不使用 --bare」)。
每天运行一次扫描,平均有 3 个失败 PR:约 30k 个令牌/天。最糟糕的一天触及 max_prs=10 上限时,为约 120k 个令牌。
每日预算为 1M 个令牌,典型日约有 30 倍余量,触及上限时约有 8 倍余量。按此频率,额度上限是用于防止失控循环(例如重试循环卡住)的保护措施,而不是你在正常情况下会接近的支出上限。
美元成本:该工作流使用 Max 方案 OAuth 令牌进行身份验证,因此一次扫描消耗的是方案额度,而非按量计费的额度,不会产生额外的账单项目。如果你将分支切换回按量计费的 ANTHROPIC_API_KEY,按每天约 30k 个令牌、约 $15/MTok(Sonnet 输入/输出混合计价)计算,每个仓库每月约 $12-15。无论哪种方式,与每月 21 次、每次 10-20 分钟的手动 CI 调试相比,成本都能立即收回。
本节中的旧数据(「约 30k 个令牌/小时」「约 720k/天」)来自最初的每小时 cron。2026-07,工作流在迁移到 OAuth 的同时改为每天运行一次(
cron: "17 8 * * *"),因为每小时扫描会消耗同一份交互式 Max 方案额度。
相关技能
- 上游——
/ci-debug负责分类(sentinel 是触发器)。 - 可组合使用——
swarm-migrate(sentinel 完成诊断后,你可以跨仓库修复并启动 swarm)、/status(sentinel 不能替代全组织扫描)。 - 反模式——在你自己的会话中使用
/loop /ci-debug是手动替代方案;部署 sentinel 后,就可以不再手动执行。
何时调用此技能(而非 cron)
ci-sentinel install——将工作流复制到新仓库并检查密钥。ci-sentinel status——读取.sentinel/ledger.jsonl并汇总过去 24 小时的情况。ci-sentinel enable/disable——切换工作流的on.schedule区块。
每天的 cron 运行本身不会调用此技能——工作流会直接调用针对 /ci-debug 的 claude -p(无头模式——不是 --bare;由于上文「为何不使用 --bare」中记录的身份验证失败,已移除该选项)。此技能用于围绕 sentinel 执行人工管理操作。
CC 2.1.183 强化了「提出但不应用」机制:计划任务和 webhook 触发器的投递现在会被归类为任务通知,而非键盘输入,因此在自动模式下,投递内容不再能批准待处理操作或设置会话标题。如果你在运行中的自动模式会话里执行 sentinel(而非通过无头
-pcron 运行),触发的重跑将无法再自动批准修复提示词。这从运行框架层面堵住了触发器投递路径。它不会改变无头 cron 路径:该路径中,强制执行的控制措施是permissions: contents: read(无法推送或合并),而模型仍持有pull-requests: write+issues: write权限,只能依靠提示词措辞来遵守「提出但不应用」原则。详见上文的 dispatch-envelope 说明。
此设计为何胜出(一段话)
你已在 /ci-debug 中编码了 10 种 CI 故障模式,历史记录中也有 632 次 ScheduleWakeup 调用——你信任异步处理,也信任引用记忆条目的模式匹配分类。CI sentinel 是组合,而非发明:GitHub Actions cron 会触发针对每个仍未关闭且 CI 状态为红色的 PR 的无头 /ci-debug,发布折叠后的判断结果,并遵守「提出但不应用」原则。最坏的情况是评论太多。最好的情况是每月省下 21 次反复进行的 CI 排查。开发耗时:数小时。回本时间:立即。