gstack /canary 深度解析:基于 browse 守护进程与基线对比的部署后可视化金丝雀监控
2026/9/7 18:35:49 网站建设 项目流程

gstack /canary 深度解析:基于 browse 守护进程与基线对比的部署后可视化金丝雀监控

【免费下载链接】gstackUse Garry Tan's exact Claude Code setup: 23 opinionated tools that serve as CEO, Designer, Eng Manager, Release Manager, Doc Engineer, and QA项目地址: https://gitcode.com/GitHub_Trending/gs/gstack

/canary是 gstack(Garry's Stack)技能库中的Post-Deploy Visual Monitor(部署后可视化金丝雀监控)技能。它以"发布可靠性工程师(Release Reliability Engineer)"的视角,在每次发布后的关键 10 分钟窗口内,驱动 browse 无头浏览器守护进程对线上应用反复进行页面加载、截图、控制台错误与性能采样,并与部署前捕获的基线对比,把"已经发布"与"已验证可用"之间的空档补上。阅读本文后,你将掌握/canary的参数语义、基线建立流程、告警分级与瞬态容错规则、健康报告的产物结构,以及它在源码与测试中的底层实现依据。

该技能的权威定义位于 canary/SKILL.md,由 canary/SKILL.md.tmpl 通过bun run gen:skill-docs(见 package.json 的gen:skill-docs脚本)自动生成。技能核心围绕 browse 守护进程展开,browse 的完整命令语义记录在 browse/SKILL.md 与 browse/sections/command-list.md 中。

/canary解决的问题:CI 通过不等于线上可用

技能开头给出了一个典型的失败叙事:一个部署在 CI 中全绿,却在生产环境崩坏,原因可能是缺失的环境变量、CDN 缓存了过期静态资源、或是数据库迁移在真实数据量下比预期慢得多。这类问题的共性在于:它们在 CI 环境里根本不会被观察到,只有真实流量、真实环境变量、真实 CDN 链路才会触发。

/canary的定位就是"shipped 到 verified 之间的安全网",把发现问题的时间窗口压缩到前 10 分钟,而不是 10 小时。它在 docs/skills.md 的技能目录中被描述为SRE角色:"Post-deploy monitoring loop. Watches for console errors, performance regressions, and page failures using the browse daemon.",并在技能正文中将其明确为"post-deploy monitoring mode"。

与技能调度相关的两个环境要素也值得说明:

  • 技能以斜杠命令方式唤起,用户在输入/canary <url>时即触发本技能,frontmatter 中声明了模型需要拥有 Bash、Read、Write、Glob、AskUserQuestion 工具,版本为 1.0.0,premable 层级为 2。
  • frontmatter 里的triggers(如monitor after deploycanary checkwatch for errors post-deploy)让技能在用户以自然语言而非斜杠命令提出"监控部署""金丝雀检查"等请求时也能被正确路由。

底层引擎:browse 守护进程与技能用到的命令

/canary本身不实现浏览器能力,它全部委托给 browse 守护进程。browse 是 gstack 的常驻无头 Chromium,第一次调用自动启动(约 3 秒),此后单条命令约 100ms,且 cookie、标签页、登录会话等状态在多次调用间保持(详见 browse/SKILL.md)。

在每次调用任何 browse 命令之前,技能执行 SETUP 检查来解析可执行文件路径$B:优先使用仓库内的$_ROOT/.claude/skills/gstack/browse/dist/browse,否则回退到$HOME/.claude/skills/gstack/browse/dist/browse;两者都不可执行则输出NEEDS_SETUP,此时需要先向用户确认执行一次性构建(约 10 秒),再运行cd <SKILL_DIR> && ./setup。若系统缺少bun,脚本会用固定版本 1.3.10 并校验 SHA-256 校验和后安装。

/canary监控循环中反复出现的$B命令及其在命令体系中的实现位置如下:

命令用途依据
goto <url>导航到页面,超时或报错意味着页面加载失败导航类命令见 browse/sections/command-list.md
snapshot -i -a -o <png>输出可访问性树(-i仅交互元素)并同时生成带标注框的截图(-a -osnapshot 标志语义见 browse/sections/command-list.md
console --errors仅过滤输出 console 的错误与警告,是"新控制台错误"告警的数据源在 browse/src/commands.ts 中注册
perf输出页面加载耗时,是性能回归告警的数据源同上
links输出全部链接为 "text → href",用于页面自动发现同上
text输出清洗后的页面文本,作为内容快照同上

browse的许多读取类输出(text、links、console 等)会被包裹在BEGIN/END UNTRUSTED EXTERNAL CONTENT标记中,以防御提示注入。snapshot-D(diff)、-c(compact)、-s <sel>(作用域)、-C(cursor-interactive)等标志可以自由组合,-o仅在同时使用-a时生效,例如$B snapshot -i -a -C -o /tmp/annotated.png

命令形态与参数

/canary支持四种参数形态,覆盖"发布前建档、发布后持续监控、单次体检"三种场景:

  • /canary <url>:对某 URL 做发布后10 分钟(默认时长)的持续监控;
  • /canary <url> --duration 5m:自定义监控时长,允许范围为1 分钟到 30 分钟
  • /canary <url> --baseline:捕获基线截图,必须在部署之前运行
  • /canary <url> --pages /,/dashboard,/settings:显式指定要监控的页面清单,覆盖默认的自动发现;
  • /canary <url> --quick:单次通过式健康检查,不进入持续监控循环。

未指定--pages时,页面列表从应用导航自动发现(见 Phase 3)。默认监控时长为 10 分钟,每次采样间隔为 60 秒。整个技能遵守Read-only原则:只观察与报告,除非用户明确要求介入修复,否则不修改代码。

七阶段工作流

Phase 1:Setup,建立产物目录

技能启动后先在项目内建立报告目录结构:

eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null || echo "SLUG=unknown")" mkdir -p .gstack/canary-reports mkdir -p .gstack/canary-reports/baselines mkdir -p .gstack/canary-reports/screenshots

gstack-slug用于生成当前项目的稳定 slug,失败时回退为unknown。之后解析用户参数:默认时长 10 分钟;默认页面由应用导航自动发现。

在动手监控之前,还需要完成 Step 0 的平台与基准分支探测:通过git remote get-url origin判断托管平台(含github.com为 GitHub、含gitlab为 GitLab),或通过gh auth status/glab auth status兜底,进而用gh pr view或 Git 原生命令(git symbolic-refgit rev-parse --verify origin/main等)确定 PR 目标分支或仓库默认分支,作为后续所有比较与日志记录的上下文。

Phase 2:基线捕获(--baseline模式)

基线是金丝雀的灵魂。若传入--baseline,则在部署前对每个页面(来自--pages或首页)采集四类证据:

$B goto <page-url> $B snapshot -i -a -o ".gstack/canary-reports/baselines/<page-name>.png" $B console --errors $B perf $B text

每个页面需收集:截图路径、console 错误数、来自perf的页面加载时间、文本内容快照。随后写入基线清单.gstack/canary-reports/baseline.json

{ "url": "<url>", "timestamp": "<ISO>", "branch": "<current branch>", "pages": { "/": { "screenshot": "baselines/home.png", "console_errors": 0, "load_time_ms": 450 } } }

完成基线后技能立即STOP并明确告知用户:"Baseline captured. Deploy your changes, then run/canary <url>to monitor.",把部署动作交还给用户,保证基线永远代表"发布前的已知良好状态"。

Phase 3:页面自动发现

未显式给出--pages时,通过以下命令发现导航入口:

$B goto <url> $B links $B snapshot -i

links输出中提取前 5 个站内导航链接,首页总是被包含。随后通过 AskUserQuestion 呈现页面清单,推荐选择 A(主导航目标);用户也可以追加更多页面(B),或只监控首页做快速检查(C)。从 browse/sections/command-list.md 的实现看,links输出为 "text → href" 形态,天然适合提取导航目标。

Phase 4:部署前快照(无基线时的回退参照)

若不存在baseline.json,技能会在部署前先做一次快速参考快照,作为后续回归检测的参照系:

$B goto <page-url> $B snapshot -i -a -o ".gstack/canary-reports/screenshots/pre-<page-name>.png" $B console --errors $B perf

需要说明的是,此回退只是"参照点",强度弱于真正的基线。技能因此特意鼓励在部署前使用--baseline没有基线时,金丝雀退化为健康检查(health check)。

Phase 5:持续监控循环

在指定时长内每 60 秒对每个页面执行一次检查:

$B goto <page-url> $B snapshot -i -a -o ".gstack/canary-reports/screenshots/<page-name>-<check-number>.png" $B console --errors $B perf

每次检查后与基线(或部署前快照)对比,按四档告警分级:

  1. 页面加载失败goto返回错误或超时,触发 CRITICAL;
  2. 新控制台错误:出现基线中不存在的错误,触发 HIGH;
  3. 性能回归:加载时间超过基线的 2 倍,触发 MEDIUM;
  4. 坏链:出现基线中不存在的新 404,触发 LOW。

循环内置两条经验法则,防止误报与报警疲劳:

  • 针对变化告警,而非绝对值(Alert on changes, not absolutes):基线里就有 3 个 console 错误的页面,只要仍然只有 3 个就算正常;多出 1 个新错误才触发告警。性能阈值同样是相对的:2 倍于基线是回归,1.5 倍可能只是正常波动。
  • 不要狼来了(Don't cry wolf):只有连续 2 次及以上检查都持续出现的模式才构成告警,单次网络抖动不告警。

一旦出现 CRITICAL 或 HIGH,立即通过 AskUserQuestion 通知用户,告警卡要求包含时间、页面、类型、具体发现、截图证据路径以及基线与当前值:

CANARY ALERT ════════════ Time: [timestamp, e.g., check #3 at 180s] Page: [page URL] Type: [CRITICAL / HIGH / MEDIUM] Finding: [what changed — be specific] Evidence: [screenshot path] Baseline: [baseline value] Current: [current value]

用户据此在四个动作中决策:立即调查并停止监控(A)、继续监控等待下一次采样以确认是否为瞬态(B)、立刻回滚部署(C)、判为误报继续监控(D)。

Phase 6:健康报告

监控结束(或用户提前终止)后产出总结报告:

CANARY REPORT — [url] ═════════════════════ Duration: [X minutes] Pages: [N pages monitored] Checks: [N total checks performed] Status: [HEALTHY / DEGRADED / BROKEN] Per-Page Results: ───────────────────────────────────────────────────── Page Status Errors Avg Load / HEALTHY 0 450ms /dashboard DEGRADED 2 new 1200ms (was 400ms) /settings HEALTHY 0 380ms Alerts Fired: [N] (X critical, Y high, Z medium) Screenshots: .gstack/canary-reports/screenshots/ VERDICT: [DEPLOY IS HEALTHY / DEPLOY HAS ISSUES — details above]

报告落盘为.gstack/canary-reports/{date}-canary.md与同名前缀的.json两份。同时把结果写入 review dashboard 的 JSONL 日志:

eval "$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null)" mkdir -p ~/.gstack/projects/$SLUG

日志条目为{"skill":"canary","timestamp":"<ISO>","status":"<HEALTHY/DEGRADED/BROKEN>","url":"<url>","duration_min":<N>,"alerts":<N>},按项目 slug 分目录持久化在~/.gstack/projects/下,便于跨发布追踪趋势。

Phase 7:基线滚动更新

部署健康时,技能询问用户是否用本次截图更新基线:

  • A) 用当前截图更新基线(推荐:部署健康,新基线反映当前生产状态);
  • B) 保留旧基线。

选择 A 后,最新截图被复制进 baselines 目录并更新baseline.json。这一机制让基线随健康的发布滚动前进,避免基线老化到与生产严重脱节。

关键规则速查

规则含义
速度优先调用后 30 秒内开始监控,不要过度分析
对变化告警与基线对比,而非与行业标准对比
截图即证据每条告警必须附带截图路径,无例外
瞬态容忍仅对连续 2+ 次检查持续出现的模式告警
基线是王道无基线的金丝雀只是健康检查
阈值为相对值2 倍基线为回归;1.5 倍可能是正常波动
只读原则只观察和报告,不修改代码

与发布链路的配合:/land-and-deploy之后的最后一道闸

/canary在技能体系中的上游是 docs/skills.md 描述的发布链路:/ship创建 PR,/land-and-deploy负责合并、等 CI、执行部署并验证生产健康,/canary则在部署完成后立即接管。docs 中给出的典型会话演进是:运行/setup-deploy一次性检测部署平台(Fly.io、Render、Vercel、Netlify、Heroku、GitHub Actions 或自定义)并写入配置,之后/land-and-deploy一条命令从"已批准"走到"已在生产验证",部署完成后用/canary继续盯防:

You: /canary https://myapp.com Claude: Monitoring 8 pages every 2 minutes... Cycle 1: ✓ All pages healthy. p95: 340ms. 0 console errors. Cycle 2: ✓ All pages healthy. p95: 380ms. 0 console errors. Cycle 3: ⚠ /dashboard — new console error: "TypeError: Cannot read property 'map' of undefined" at dashboard.js:142 Screenshot saved. Alert: 1 new console error after 3 monitoring cycles.

该文档同时建议在风险较高的发布后周期性重复运行/canary,而不仅是部署完成后的一次性检查。

技能工程化侧面:模板生成与可校验的产物契约

从仓库结构可以观察到两个工程化细节,它们解释了为什么/canary的流程可以被反复执行而不漂移:

其一,SKILL.md 由模板生成。canary/SKILL.md 文件头注释明确标注" AUTO-GENERATED from SKILL.md.tmpl do not edit directly ",需要重新生成时执行bun run gen:skill-docs(即 scripts/gen-skill-docs.ts)。对照 canary/SKILL.md.tmpl 可见,发布流程主体(Arguments、Phase 1-7、Important Rules)保存在模板中,而 preamble、browse 环境探测({{BROWSE_SETUP}})、基准分支探测({{BASE_BRANCH_DETECT}})等共享段落以占位符形式注入,保证所有技能共享同一套运行时规范且互不漂移。

其二,工作流的产物契约被端到端测试锁定。test/skill-e2e-deploy.test.ts 中定义了Canary skill E2Ecanary-workflow标签):测试在一个临时 git 仓库中复制canary技能目录,然后以模拟提示驱动模型,要求其在没有 browse 守护进程、没有真实 URL的前提下演示对工作流的理解,即创建.gstack/canary-reports/目录结构、按 Phase 2 的 schema(url、timestamp、branch、pages 下的 screenshot / console_errors / load_time_ms)写出模拟baseline.json、按 Phase 6 的 Health Report 格式(CANARY REPORT 头、duration、pages、status、逐页结果表、verdict)写出模拟报告。测试断言目录存在且产物文件数大于 0。这意味着baseline.json与健康报告的字段结构是可被测试校验的契约,任何对 Phase 2 / Phase 6 输出格式的改动都需要同步更新测试,从而防止技能文档与真实行为脱节。

写在最后:金丝雀的设计哲学

回看整个/canary设计,核心并不在于"截图"或"看日志"这些单个动作,而在于三组取舍:

  • 对比基线而非绝对标准:生产页面本来就可能有历史遗留的 console 错误或偏慢的加载,绝对阈值只会产生噪音;只有"相对基线的变化"才与"这次部署引入了什么"直接相关。
  • 用截图锁定证据:告警消息不携带抽象描述,而是携带可复查的截图路径,任何告警都能被人工回溯确认。
  • 瞬态与持续的区分:网络抖动在发布后 10 分钟窗口内几乎必然出现,只有跨越两次采样仍然存在的异常才值得打断用户。

如果你的部署流程目前只依赖 CI 绿灯,/canary提供了一种低成本补齐生产验证的手段:部署前一条--baseline建档,发布后一条/canary <url>盯防,即可把"发布后前 10 分钟"从无人区变成可观测、可告警、可回滚决策的受控窗口。技能完整定义见 canary/SKILL.md,browse 命令全量参考见 browse/sections/command-list.md,端到端契约测试见 test/skill-e2e-deploy.test.ts。

【免费下载链接】gstackUse Garry Tan's exact Claude Code setup: 23 opinionated tools that serve as CEO, Designer, Eng Manager, Release Manager, Doc Engineer, and QA项目地址: https://gitcode.com/GitHub_Trending/gs/gstack

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询