关于 flowchad-runner
flowchad-runner 是用于验证 FlowChad 浏览器流程的技能,适用于合并前、部署后及定期运行。它逐个执行流程、采集视觉证据,并将结果写入 GitHub 和本地报告。
主要功能
- 01按顺序执行浏览器流程
- 02逐步采集截图和视频证据
- 03遇到 CAPTCHA 时交由 Navvi
- 04上传证据并向 GitHub 报告
- 05生成本地报告和结果状态
适用场景
- 01验证 PR 修改影响的流程
- 02部署后运行生产环境检查
- 03定期执行关键流程冒烟测试
- 04在配置 CAPTCHA 行为后本地排查流程
MCP 相关
该技能在浏览器流程执行期间,将 Navvi 用作处理 CAPTCHA 的 MCP 工具。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ fellowship-dev/ dogfooded-skills --skill flowchad-runner安装后在 Claude Code 中输入/flowchad-runner确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
CONTEXT.mdreferences/interactive-contract.mdscripts/test_validate_contract.pyvalidate_contract.pystages/01-preflight/CONTEXT.mdstages/02-load-flows/CONTEXT.mdstages/03-walk-flows/CONTEXT.mdstages/04-upload-evidence/CONTEXT.mdstages/05-report/CONTEXT.md详细介绍
flowchad-runner
使用 Playwright/Navvi 验证指定的 FlowChad 工作流,捕获每个步骤的屏幕截图和视频证据,遇到 CAPTCHA 时自动切换到 Navvi,尽力上传证据,然后将结果发布到 GitHub 并写入本地报告。每个阶段都由具有独立上下文的专用子 Agent 执行。这里的 ICM 重点是清晰的阶段契约 + 可恢复性,而不是并行处理:工作流不能并发运行,因为它们共享浏览器、会话和角色状态,并会相互冲突。阶段 03 会在顺序循环中逐个运行工作流。
适用场景
- 对影响已声明工作流的 PR 进行明确的合并前验证
- 部署后进行生产环境验证
- 每周或按计划执行关键生产环境冒烟测试
- 已明确配置本地 CAPTCHA 行为时,手动进行本地诊断
不适用场景
- 仅涉及文档、Dependabot 或不受影响的 PR:返回
N/A,且不创建预览 - 将仅静态分析描述为交互式认证
- 全局启用 Provider 自动预览;预览必须按需明确启动
参数
| Param | 必填 | 默认值 | 备注 |
|---|---|---|---|
flow-name | 是 | — | 工作流名称,或以下选择器之一:affected / all |
repo | 是 | — | 目标 org/repo |
pr-number | 否 | (无) | 如果已设置,则向此 PR 发布结果评论 |
trigger | 否 | manual | pr | merge | cron | manual — 用于驱动 URL 解析和部署等待 |
从 $ARGUMENTS 按位置解析:$1=flow-name $2=repo $3=pr-number $4=trigger。
当 cron/manual 调用没有 PR 编号时,使用字面值 none。
选择器不是工作流名称。 仅当 $1 既不是 affected 也不是 all 时,它才是工作流名称:
flow-name | 解析为 |
|---|---|
affected | affects glob 与 PR 已更改文件匹配的工作流——生产环境用法,每个 flowchad-on-double-checked 分发任务都会使用 |
all | smoke.flows,若无则使用 smoke.critical,再无则使用 .flowchad/flows/ 中的文件 |
| (某个名称) | 与受影响集合取交集后的该工作流 |
(任意值,trigger=cron) | smoke.critical |
绝不能将 affected 或 all 解析为 .flowchad/flows/<selector>.yml。将字面字符串 affected 与实际工作流名称取交集会得到空集合,并导致真正影响某个工作流的 PR 被错误地返回 N/A。
结果约定
| 状态 | 含义 |
|---|---|
PASSED | 必需步骤已通过,并提供了真实的浏览器证据 |
FAILED | 浏览器证据表明产品或工作流存在缺陷 |
BLOCKED | 必需的目标、部署、浏览器、角色或凭据不可用 |
N/A | PR 仅涉及文档、Dependabot,或不影响任何已声明的工作流 |
交互式工作流绝不能仅凭 curl、静态 HTML 或 bundle 检查判定通过。创建或升级 .flowchad/config.yml 和工作流定义时,请阅读 references/interactive-contract.md。
功能
5 阶段 ICM 流程(全部按顺序执行——没有并行阶段):
| 阶段 | 模式 | 描述 |
|---|---|---|
| 01-preflight | 子 Agent | 验证契约,解析流程选择器,解析目标/选择性预览,等待部署完成,检查捕获主机/角色 |
| 02-load-flows | 子 Agent | 读取 .flowchad/config.yml,验证每个流程文件是否存在,加载流程 YAML,解析证据后端 |
| 03-walk-flows | 子 Agent | 生成一个工作 devbox(操作端没有浏览器),然后进行顺序循环:逐个处理每个流程——连接浏览器、运行步骤、逐步截图、判断预期结果、CAPTCHA→Navvi、记录对话 |
| 04-upload-evidence | 子 Agent | 上传带有 evidence_class: visual 的截图/GIF(永久 URL),记录每个文件的成功/失败情况,在有请求对话时附上一份未分类的副本,并停止工作进程 |
| 05-report | 内联 | 汇总结果,嵌入每一步的截图 URL,发布判定 PR 评论(以机器可读的 `` 标记开头)+ 应用仍具决定作用的 chad-approves/chad-rejects 标签;在有请求 Slack 线程时向其中发布判定结果;失败时创建问题;写入本地报告;发出结果标记 |
浏览器实际运行的位置
Dockerfile.operator 不会安装浏览器系统库;.devcontainer/Dockerfile(仓库 devbox/工作进程镜像)会准确安装 Chromium 所需的库。因此,Playwright 捕获会在阶段 03 启动的工作 devbox 上运行,而 Navvi——绑定到操作端会话的 MCP 工具——则在操作端轮次中运行。在操作端轮次中尝试 chromium.launch() 会失败,并报错 "missing system shared libraries … no sudo/apt-get available",从而产生不含截图的 BLOCKED 判定。负责分发的自动化上下文已经说明 "Use qa worker."
携带 flowchad-runner 的操作端 pylot.qa 和 booster-pack.qa 都携带 pylot-cli(注入的基线工具,因此每个操作端都具备)和 evidence-upload,这些已涵盖操作端所需的一切。它们不需要安装 playwright 或 visual-evidence:浏览器要求属于工作进程镜像,而非操作端。
交接位置
所有交接内容都位于解析后的仓库工作区($WORKDIR,见工作区解析)中:
$WORKDIR/.procedure-output/flowchad-runner/{stage}/handoff.md
阶段 01 会写入已解析的运行上下文(URL、角色、流程列表)。每个子 Agent 阶段只会收到其 CONTEXT.md 列为输入的交接路径——绝不会收到编排器历史记录。
执行
严格按顺序逐个运行各阶段。此流程中不会并行启动 Task。每个子 Agent 阶段恰好启动一个 Task,并等待其完成后再启动下一阶段。
工作区解析(务必首先执行)
契约、流程、交接文件和报告都位于目标仓库的检出目录中。任务运行所在的工作区不包含该检出目录——切勿假设当前目录就是仓库。执行任何其他操作之前,请先以确定性方式解析该目录:
SKILL_DIR="$HOME/.claude/skills/flowchad-runner"
[ -d "$SKILL_DIR" ] || SKILL_DIR="$(pwd)/.claude/skills/flowchad-runner"
if [ -f .flowchad/config.yml ]; then
# Already inside a checkout (local/manual runs)
WORKDIR="$(pwd)"
else
REPO_NAME="${REPO##*/}"
REPO_DIR="/tmp/flowchad-${REPO_NAME}"
if [ ! -d "$REPO_DIR/.git" ]; then
# Plain https URL — inline credentials would bypass git-credential-pylot
git clone "https://github.com/${REPO}.git" "$REPO_DIR" 2>/dev/null \
|| gh repo clone "$REPO" "$REPO_DIR"
fi
cd "$REPO_DIR"
git fetch origin --prune
if [ "$TRIGGER" = pr ] && [ -n "$PR_NUMBER" ] && [ "$PR_NUMBER" != none ]; then
# Validate the PR's OWN contract — flows/config may change in the PR itself
git fetch origin "pull/${PR_NUMBER}/head:flowchad-pr-${PR_NUMBER}" --force
git checkout -f "flowchad-pr-${PR_NUMBER}"
else
DEFAULT_BRANCH=$(gh repo view "$REPO" --json defaultBranchRef -q .defaultBranchRef.name)
git checkout -f "$DEFAULT_BRANCH"
git reset --hard "origin/${DEFAULT_BRANCH}"
fi
WORKDIR="$REPO_DIR"
fi
[ -f "$WORKDIR/.flowchad/config.yml" ] || {
echo "[flowchad] blocked: $REPO has no .flowchad/config.yml at the resolved ref"
exit 0
}
如果因缺少配置而退出,请将以下解析后的标记作为助手的最后一行完整内容输出(不要从 Bash 输出,也不要放在代码围栏中),然后停止:
[pylot:$PYLOT_OUTCOME_NONCE] outcome="flowchad blocked: $REPO has no .flowchad/config.yml at the resolved ref" status=blocked
之后的每条命令(验证器、阶段交接、报告)都必须通过 cd "$WORKDIR" 运行。
由于子 Agent Task 不会继承编排器的 cd,阶段提示词必须包含绝对路径:将下方模板中的 $WORKDIR 和 $SKILL_DIR 替换为其字面值——绝不能传递 .claude/... 或 .procedure-output/... 这样的相对路径。
阶段 01 → 04(顺序执行的子 Agent)
每个阶段都启动一个 Task。Task 提示词必须独立完整:
- 仅包含该阶段的输入交接路径
- 包含该阶段的 CONTEXT.md 路径
- 不要传入编排器历史记录或先前的推理
Task 提示词模板:
You are running stage {NN}-{name} of the flowchad-runner procedure.
Workspace: cd {WORKDIR} before any step (absolute path — all relative paths resolve there).
Read your stage instructions:
{SKILL_DIR}/stages/{NN}-{name}/CONTEXT.md
Your inputs:
{list each input handoff path this stage needs — absolute, under {WORKDIR}}
Write your output to:
{WORKDIR}/.procedure-output/flowchad-runner/{NN}-{name}/handoff.md
Execute all steps in CONTEXT.md. Write handoff.md before exiting.
{WORKDIR} 和 {SKILL_DIR} 是在 Workspace resolution 中解析出的绝对路径。
当前阶段完成前,不要启动下一阶段。如果阶段 01 无法解析出 TARGET_URL,或阶段 01 的 deploy-wait 失败,或阶段 02 发现流程文件缺失,则输出对应的结果标记并停止(这些阶段也会自行创建 GitHub issues)。
阶段 01 开始前,从 $WORKDIR 确定性地验证已检入的契约:
cd "$WORKDIR"
mkdir -p .procedure-output/flowchad-runner
MODE="$TRIGGER"
[ "$MODE" = merge ] && MODE=production
[ "$MODE" = pr ] && MODE=preview
[ "$MODE" = manual ] && MODE=local
python3 "$SKILL_DIR/scripts/validate_contract.py" \
--mode "$MODE" --repo "$REPO" --format json \
> .procedure-output/flowchad-runner/contract.json
任何验证器错误都会阻止 production、preview 和 cron certification。对于这些模式,不要静默回退到旧版 .url、模板标识或 localhost。
阶段 05(内联执行)
在编排器中自行运行阶段 05。阅读 CONTEXT.md:
.claude/skills/flowchad-runner/stages/05-report/CONTEXT.md
汇总先前的交接信息、发布 PR 评论/创建失败 issues、写入本地报告文件,并由编排器输出 [pylot] outcome=... 标记(绝不能由子 Agent 输出)。
阶段交接链
01-preflight ─► 02-load-flows ─► 03-walk-flows ─► 04-upload-evidence ─► 05-report (inline)
(URL, (validated (SPAWN WORKER, (permanent URLs (PR comment
persona, flow YAML, sequential per step, upload WITH the
capture_host, evidence per-flow walk, accounting, screenshots,
FLOWS_TO_RUN) backend) results+transcript) STOP WORKER) issues, marker)
工作器 devbox 跨越阶段 03→04:阶段 03 启动它并让它保持运行,以便阶段 04 上传其文件系统上的证据;阶段 04 将其停止。如果阶段 04 没有停止它,阶段 05 会将其作为后备措施停止。
退出路径
- 成功:阶段 05 输出
[pylot:$PYLOT_OUTCOME_NONCE] outcome="flowchad {flow} on {repo}: all flows passed" status=success - 失败:阶段 05 输出
[pylot:$PYLOT_OUTCOME_NONCE] outcome="flowchad {flow} on {repo}: {N} flow(s) failed" status=failed(阶段 05 已创建失败 issues) - 阻止:阶段 01(契约无效/没有 URL/部署失败/没有浏览器)或阶段 02
(流程缺失)输出
[pylot:$PYLOT_OUTCOME_NONCE] outcome="flowchad blocked: {reason}" status=blocked,然后停止整个链。 - 不适用:阶段 01 检测到 PR 不受影响、仅涉及文档或由 Dependabot 创建,并在不部署的情况下输出
[pylot:$PYLOT_OUTCOME_NONCE] outcome="flowchad N/A: no affected interactive flow" status=success。
硬性规则
- 所有阶段都必须按顺序运行——每次只能运行一个 Task,等待其完成后再运行下一个。 整个流程中任何地方都不得并行分发任务。
- 在阶段 03 中逐个遍历流程——绝不能为每个流程各运行一个子 Agent。流程共享浏览器/会话/角色状态,并行运行会导致冲突。
- 阶段 05 必须内联运行——
[pylot] outcome=...标记必须由编排器生成,不能由子 Agent 生成。 - 绝不能将完整的编排器上下文传入子 Agent 的 Task 提示词——仅传入输入。
- 每个阶段都必须先写入 handoff.md,下一阶段才能读取。
- 不得跳过任何阶段——即使阶段的操作是“无需处理”,也必须执行(例如,后端为
none的证据上传仍须写入 handoff)。 - 步骤出错属于发现项,不是崩溃——阶段 03 在步骤出错后仍须继续收集证据;只判定流程级别的通过/失败。
- **不使用 Quest,不使用外部仪表板。**报告 = 本地报告文件 + GitHub;另外,仅当任务的
dispatched_by_conv已设置时,才向发起流程请求的线程发送一条slack-post。由自动化分发的运行只发布到 GitHub,不发布到其他地方。 - **交互式 PASS 必须有浏览器证据。**静态/curl 诊断可以支持
FAILED或BLOCKED结果,但绝不能支持PASSED。 - **生产环境关键控制绝不可设为可选或跳过。**缺少 CAPTCHA/Navvi 能力时,结果必须为
BLOCKED,不能判定为通过,也不能在生产环境中跳过。 - **选择性创建 Preview。**绝不启用提供商自动创建 Preview;仅当不存在 staging 目标,且存在明确分发、与任务相关的 PR 时,最多按需创建一个 Preview。
- **Cron 使用
smoke.critical。**失败时创建或更新去重后的 issue,并附上浏览器证据;公开 skill 不负责调度器。 - **绝不能在操作员回合中启动浏览器。**操作员镜像没有浏览器库。Playwright 捕获任务交由 worker devbox 执行;Navvi 保持在操作员侧运行。缺少捕获主机时,结果必须为
BLOCKED,不能以静态探测判定通过。 - **每个上传的资源都必须包含
evidence_class: visual。**未分类的能力 URL 会在 30 天后返回 410,因此未分类的回执就是带有到期日的回执。发布已分类资源还必须设置override_policy: true。 - **判定结果必须附带回执。**截图 URL 必须按步骤嵌入 PR 评论。没有图片的流程遍历判定只是陈述,不是证据。
- **上传失败时必须尽力交付,并且必须如实披露。**上传失败绝不会阻止运行,也绝不能被隐去——阶段 04 统计失败次数,阶段 05 输出失败信息。不作说明就无法区分“没有截图需求”和“截图上传失败”。
参考文件
CONTEXT.md— 架构概览stages/NN-name/CONTEXT.md— 各阶段的输入、任务和输出约定references/interactive-contract.md— 目标配置以及 CAPTCHA/i18n 示例scripts/validate_contract.py— 确定性环境/流程约定验证器