flowchad-runner
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chineseflowchad-runner
flowchad-runner
Verify named FlowChad flows with Playwright/Navvi, capture per-step screenshot + video
evidence, auto-switch to Navvi on CAPTCHA, upload evidence (best-effort), then post results
to GitHub and write a local report. Each stage runs as a focused subagent with isolated
context. The ICM win here is clean stage contracts + resumability, NOT parallelism:
flows CANNOT run concurrently because they share browser, session, and persona state and
would collide. Stage 03 walks flows one at a time in a sequential loop.
使用Playwright/Navvi验证指定的FlowChad流程,捕获每一步的截图+视频证据,遇到CAPTCHA时自动切换至Navvi,尽最大努力上传证据,随后将结果发布至GitHub并生成本地报告。每个阶段作为独立上下文的聚焦子Agent运行。此处的核心优势是清晰的阶段契约+可恢复性,而非并行性:流程无法并发运行,因为它们共享浏览器、会话和用户身份状态,会产生冲突。阶段03会按顺序逐个遍历流程。
When to Use
适用场景
- Explicit pre-merge verification for a PR that affects declared flows
- Production verification after deployment
- Weekly or scheduled critical production smoke runs
- Manual local diagnosis when local CAPTCHA behavior is explicitly configured
- 对影响已声明流程的PR进行明确的合并前验证
- 部署完成后的生产环境验证
- 每周或定期执行的关键生产环境冒烟测试
- 明确配置本地CAPTCHA行为后的手动本地诊断
When Not to Use
不适用场景
- Docs-only, Dependabot, or unaffected PRs: return without creating a preview
N/A - Static-only analysis presented as interactive certification
- Global provider auto-preview enablement; previews are explicit and on-demand
- 仅文档变更、Dependabot PR或未影响已声明流程的PR:返回,无需创建预览环境
N/A - 以交互式认证形式呈现的纯静态分析
- 全局提供商自动预览启用;预览需明确触发且按需创建
Arguments
参数
| Param | Required | Default | Notes |
|---|---|---|---|
| yes | — | Flow name, or |
| yes | — | Target |
| no | (none) | If set, post results comment to this PR |
| no | | |
Parse positionally from : .
Use the literal when a cron/manual invocation has no PR number.
$ARGUMENTS$1=flow-name $2=repo $3=pr-number $4=triggernone| Param | Required | Default | Notes |
|---|---|---|---|
| yes | — | Flow name, or |
| yes | — | Target |
| no | (none) | If set, post results comment to this PR |
| no | | |
Parse positionally from : .
Use the literal when a cron/manual invocation has no PR number.
$ARGUMENTS$1=flow-name $2=repo $3=pr-number $4=triggernoneResult Contract
结果契约
| State | Meaning |
|---|---|
| Required steps passed with real browser evidence |
| Browser evidence demonstrated a product or flow defect |
| A required target, deploy, browser, persona, or credential was unavailable |
| PR is docs-only, Dependabot, or does not affect a declared flow |
Interactive flows can never pass from curl, static HTML, or bundle inspection. Read
references/interactive-contract.md when creating or
upgrading and flow definitions.
.flowchad/config.yml| State | Meaning |
|---|---|
| Required steps passed with real browser evidence |
| Browser evidence demonstrated a product or flow defect |
| A required target, deploy, browser, persona, or credential was unavailable |
| PR is docs-only, Dependabot, or does not affect a declared flow |
交互式流程无法通过curl、静态HTML或包检查来判定通过。创建或升级和流程定义时,请阅读references/interactive-contract.md。
.flowchad/config.ymlWhat it does
功能说明
5-stage ICM procedure (all sequential — no parallel stages):
| Stage | Mode | Description |
|---|---|---|
| 01-preflight | subagent | Validate contract, select affected flow, resolve target/selective preview, deploy-wait, browser/persona check |
| 02-load-flows | subagent | Read |
| 03-walk-flows | subagent | Sequential loop: for each flow one-at-a-time — connect browser, run steps, per-step screenshot, expect-judgement, CAPTCHA→Navvi, transcript |
| 04-upload-evidence | subagent | Best-effort: push screenshots/GIFs to evidence backend, collect URLs |
| 05-report | inline | Aggregate results, post PR comment, create issues on failure, write local report, emit outcome marker |
5-stage ICM procedure (all sequential — no parallel stages):
| Stage | Mode | Description |
|---|---|---|
| 01-preflight | subagent | Validate contract, select affected flow, resolve target/selective preview, deploy-wait, browser/persona check |
| 02-load-flows | subagent | Read |
| 03-walk-flows | subagent | Sequential loop: for each flow one-at-a-time — connect browser, run steps, per-step screenshot, expect-judgement, CAPTCHA→Navvi, transcript |
| 04-upload-evidence | subagent | Best-effort: push screenshots/GIFs to evidence backend, collect URLs |
| 05-report | inline | Aggregate results, post PR comment, create issues on failure, write local report, emit outcome marker |
Handoff locations
交接位置
All handoffs live in the resolved repo workspace (, see Workspace resolution):
$WORKDIRtext
$WORKDIR/.procedure-output/flowchad-runner/{stage}/handoff.mdStage 01 writes the resolved run context (URL, persona, flow list). Each subagent stage
receives ONLY the handoff paths its CONTEXT.md lists as inputs — never orchestrator history.
All handoffs live in the resolved repo workspace (, see Workspace resolution):
$WORKDIRtext
$WORKDIR/.procedure-output/flowchad-runner/{stage}/handoff.mdStage 01 writes the resolved run context (URL, persona, flow list). Each subagent stage
receives ONLY the handoff paths its CONTEXT.md lists as inputs — never orchestrator history.
Execution
执行方式
Run stages strictly sequentially, one after another. There are NO parallel Task launches
in this procedure. Spawn exactly one Task per subagent stage and await it before the next.
Run stages strictly sequentially, one after another. There are NO parallel Task launches
in this procedure. Spawn exactly one Task per subagent stage and await it before the next.
Workspace resolution (ALWAYS run this first)
Workspace resolution (ALWAYS run this first)
The contract, flows, handoffs, and reports all live inside a checkout of the target repo.
Missions run in a workspace that does NOT contain that checkout — never assume the current
directory is the repo. Resolve it deterministically before anything else:
bash
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 "[pylot] outcome=\"flowchad blocked: $REPO has no .flowchad/config.yml at the resolved ref\" status=blocked"
exit 0
}Every subsequent command (validator, stage handoffs, reports) runs with .
Because subagent Tasks do NOT inherit the orchestrator's , stage prompts must carry
ABSOLUTE paths: substitute the literal values of and into the
template below — never pass or relative forms.
cd "$WORKDIR"cd$WORKDIR$SKILL_DIR.claude/....procedure-output/...The contract, flows, handoffs, and reports all live inside a checkout of the target repo.
Missions run in a workspace that does NOT contain that checkout — never assume the current
directory is the repo. Resolve it deterministically before anything else:
bash
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 "[pylot] outcome=\"flowchad blocked: $REPO has no .flowchad/config.yml at the resolved ref\" status=blocked"
exit 0
}Every subsequent command (validator, stage handoffs, reports) runs with .
Because subagent Tasks do NOT inherit the orchestrator's , stage prompts must carry
ABSOLUTE paths: substitute the literal values of and into the
template below — never pass or relative forms.
cd "$WORKDIR"cd$WORKDIR$SKILL_DIR.claude/....procedure-output/...Stages 01 → 04 (sequential subagents)
Stages 01 → 04 (sequential subagents)
For each stage, spawn one Task. The Task prompt must be self-contained:
- Include only the stage's input handoff paths
- Include the path to the stage's CONTEXT.md
- Do NOT pass orchestrator history or prior reasoning
Task prompt template:
text
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}Do not start the next stage until the current one completes. If stage 01 cannot resolve a
TARGET_URL, or stage 01's deploy-wait fails, or stage 02 finds the flow file missing, emit
the matching outcome marker and stop (those stages also create GitHub issues themselves).
Before stage 01, verify the checked-in contract deterministically (from ):
$WORKDIRbash
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.jsonAny validator error blocks production, preview, and cron certification. Do not silently fall
back to legacy , template identity, or localhost for those modes.
.urlFor each stage, spawn one Task. The Task prompt must be self-contained:
- Include only the stage's input handoff paths
- Include the path to the stage's CONTEXT.md
- Do NOT pass orchestrator history or prior reasoning
Task prompt template:
text
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}Do not start the next stage until the current one completes. If stage 01 cannot resolve a
TARGET_URL, or stage 01's deploy-wait fails, or stage 02 finds the flow file missing, emit
the matching outcome marker and stop (those stages also create GitHub issues themselves).
Before stage 01, verify the checked-in contract deterministically (from ):
$WORKDIRbash
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.jsonAny validator error blocks production, preview, and cron certification. Do not silently fall
back to legacy , template identity, or localhost for those modes.
.urlStage 05 (inline)
Stage 05 (inline)
Run stage 05 yourself in the orchestrator. Read CONTEXT.md:
text
.claude/skills/flowchad-runner/stages/05-report/CONTEXT.mdAggregate the prior handoffs, post the PR comment / create failure issues, write the local
report file, and emit the marker from the orchestrator (never a subagent).
[pylot] outcome=...Run stage 05 yourself in the orchestrator. Read CONTEXT.md:
text
.claude/skills/flowchad-runner/stages/05-report/CONTEXT.mdAggregate the prior handoffs, post the PR comment / create failure issues, write the local
report file, and emit the marker from the orchestrator (never a subagent).
[pylot] outcome=...Stage handoff chain
阶段交接链
text
01-preflight ─► 02-load-flows ─► 03-walk-flows ─► 04-upload-evidence ─► 05-report (inline)
(URL, (validated (sequential (evidence URLs, (PR comment,
persona, flow YAML) per-flow walk, best-effort) issues, local
FLOWS_TO_RUN) results+transcript) report, marker)text
01-preflight ─► 02-load-flows ─► 03-walk-flows ─► 04-upload-evidence ─► 05-report (inline)
(URL, (validated (sequential (evidence URLs, (PR comment,
persona, flow YAML) per-flow walk, best-effort) issues, local
FLOWS_TO_RUN) results+transcript) report, marker)Exit paths
退出路径
- Success: stage 05 emits
[pylot] outcome="flowchad {flow} on {repo}: all flows passed" status=success - Failure: stage 05 emits (failure issues already created in stage 05)
[pylot] outcome="flowchad {flow} on {repo}: {N} flow(s) failed" status=failed - Blocked: stage 01 (invalid contract / no URL / deploy failed / no browser) or stage 02
(flow missing) emits
and the chain stops.
[pylot] outcome="flowchad blocked: {reason}" status=blocked - N/A: stage 01 detects an unaffected/docs-only/Dependabot PR and emits
without a deploy.
[pylot] outcome="flowchad N/A: no affected interactive flow" status=success
- Success: stage 05 emits
[pylot] outcome="flowchad {flow} on {repo}: all flows passed" status=success - Failure: stage 05 emits (failure issues already created in stage 05)
[pylot] outcome="flowchad {flow} on {repo}: {N} flow(s) failed" status=failed - Blocked: stage 01 (invalid contract / no URL / deploy failed / no browser) or stage 02
(flow missing) emits
and the chain stops.
[pylot] outcome="flowchad blocked: {reason}" status=blocked - N/A: stage 01 detects an unaffected/docs-only/Dependabot PR and emits
without a deploy.
[pylot] outcome="flowchad N/A: no affected interactive flow" status=success
Hard Rules
硬性规则
- All stages run SEQUENTIALLY — exactly one Task at a time, awaited before the next. There is NO parallel fan-out anywhere in this procedure.
- Flows are walked ONE AT A TIME inside stage 03 — never one subagent per flow. Flows share browser/session/persona state and would collide if run concurrently.
- Stage 05 runs inline — the marker MUST come from the orchestrator, never a subagent.
[pylot] outcome=... - Never pass full orchestrator context into subagent Task prompts — inputs only.
- Each stage writes handoff.md before the next stage reads it.
- Do not skip stages — every stage executes even if its action is "nothing to do"
(e.g. evidence upload with backend still writes a handoff).
none - A broken step is a finding, not a crash — stage 03 continues collecting evidence after a step error; only flow-level pass/fail is judged.
- NO Quest, no external dashboards. Reporting = the local report file + GitHub only.
- Interactive PASS requires browser evidence. Static/curl diagnostics can support a
or
FAILEDresult, neverBLOCKED.PASSED - Production-critical controls are never optional or skipped. Missing CAPTCHA/Navvi
capability is , not a pass and not a production skip.
BLOCKED - Preview creation is selective. Never enable provider auto-previews; create at most one on-demand preview for an explicitly dispatched relevant PR when no staging target exists.
- Cron uses . Failures create or update a deduplicated issue with browser evidence; the public skill does not own the scheduler.
smoke.critical
- All stages run SEQUENTIALLY — exactly one Task at a time, awaited before the next. There is NO parallel fan-out anywhere in this procedure.
- Flows are walked ONE AT A TIME inside stage 03 — never one subagent per flow. Flows share browser/session/persona state and would collide if run concurrently.
- Stage 05 runs inline — the marker MUST come from the orchestrator, never a subagent.
[pylot] outcome=... - Never pass full orchestrator context into subagent Task prompts — inputs only.
- Each stage writes handoff.md before the next stage reads it.
- Do not skip stages — every stage executes even if its action is "nothing to do"
(e.g. evidence upload with backend still writes a handoff).
none - A broken step is a finding, not a crash — stage 03 continues collecting evidence after a step error; only flow-level pass/fail is judged.
- NO Quest, no external dashboards. Reporting = the local report file + GitHub only.
- Interactive PASS requires browser evidence. Static/curl diagnostics can support a
or
FAILEDresult, neverBLOCKED.PASSED - Production-critical controls are never optional or skipped. Missing CAPTCHA/Navvi
capability is , not a pass and not a production skip.
BLOCKED - Preview creation is selective. Never enable provider auto-previews; create at most one on-demand preview for an explicitly dispatched relevant PR when no staging target exists.
- Cron uses . Failures create or update a deduplicated issue with browser evidence; the public skill does not own the scheduler.
smoke.critical
Reference files
参考文件
- — architecture overview
CONTEXT.md - — per-stage inputs, task, output contract
stages/NN-name/CONTEXT.md - — target configuration and CAPTCHA/i18n examples
references/interactive-contract.md - — deterministic environment/flow contract validator
scripts/validate_contract.py
- —— 架构概述
CONTEXT.md - —— 各阶段的输入、任务、输出契约
stages/NN-name/CONTEXT.md - —— 目标配置和CAPTCHA/i18n示例
references/interactive-contract.md - —— 确定性环境/流程契约验证器
scripts/validate_contract.py