flowchad-runner について
flowchad-runnerは、マージ前、デプロイ後、定期実行でFlowChadのブラウザフローを検証するスキルです。フローを順に実行して視覚的な証跡を収集し、GitHubとローカルレポートに結果を記録します。
主な機能
- 01ブラウザフローの逐次実行
- 02各ステップのスクリーンショットと動画
- 03CAPTCHA発生時のNavviへの切り替え
- 04証跡のアップロードとGitHubへの報告
- 05ローカルレポートと結果ステータス
活用シーン
- 01プルリクエストの変更対象フローを検証
- 02デプロイ後の本番環境チェック
- 03重要フローの定期スモークテスト
- 04CAPTCHA動作を設定した環境でのローカル診断
MCP 対応
このスキルは、ブラウザフローの実行中にCAPTCHAを処理するMCPツールとしてNavviを使用します。
インストール
コマンドをコピーしてターミナルで実行します。
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 に投稿してローカルレポートを作成します。各ステージは、コンテキストを分離した専用サブエージェントとして実行されます。ここでの ICM の利点は、並列化ではなく、明確なステージ契約と再開可能性です。フローはブラウザー、セッション、ペルソナの状態を共有して競合するため、同時には実行できません。ステージ 03 では、フローを逐次ループで1 つずつ実行します。
使用する場面
- 宣言済みフローに影響する PR のマージ前に、明示的に検証する場合
- デプロイ後に本番環境を検証する場合
- 重要な本番スモークテストを週次またはスケジュール実行する場合
- ローカルの CAPTCHA 動作が明示的に設定されている場合に、手動でローカル診断を行う場合
使用しない場面
- ドキュメントのみ、Dependabot、または影響のない PR の場合:プレビューを作成せずに
N/Aを返します - インタラクティブ認定として提示される静的解析のみの場合
- プロバイダー全体でのプレビューの自動有効化:プレビューは明示的にオンデマンドで実行します
引数
| パラメーター | 必須 | デフォルト | 備考 |
|---|---|---|---|
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。
PR 番号のない cron/manual 呼び出しでは、文字列 none を使用してください。
セレクターはフロー名ではありません。 $1 が affected と all のどちらでもない場合に限り、フロー名として扱います。
flow-name | 解決先 |
|---|---|
affected | PR の変更ファイルに affects グロブが一致するフロー — 本番環境で使用する形式であり、すべての 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、またはバンドルの調査だけで合格することはありません。.flowchad/config.yml やフロー定義を作成または更新する場合は、references/interactive-contract.md を参照してください。
機能
5 段階の ICM 手順です(すべて順次実行し、並列の段階はありません)。
| Stage | Mode | Description |
|---|---|---|
| 01-preflight | subagent | コントラクトを検証し、フローセレクターを解決し、ターゲット/選択的プレビューを解決し、デプロイ完了を待機し、キャプチャーホスト/ペルソナを確認します |
| 02-load-flows | subagent | .flowchad/config.yml を読み取り、各フローファイルの存在を検証し、フロー YAML を読み込み、エビデンスバックエンドを解決します |
| 03-walk-flows | subagent | ワーカー devbox を起動(オペレーターにはブラウザーがありません)。続いて順次ループを実行します。各フローを 1 つずつ処理し、ブラウザーに接続して、ステップを実行し、各ステップのスクリーンショットを撮り、期待値を判定し、CAPTCHA は Navvi に渡し、トランスクリプトを記録します |
| 04-upload-evidence | subagent | evidence_class: visual を指定してスクリーンショット/GIF をアップロードし(永続 URL)、ファイルごとの成功/失敗を記録し、該当する場合は依頼元の会話に分類なしのコピーを添付して、ワーカーを停止します |
| 05-report | inline | 結果を集計し、各ステップのスクリーンショット URL を埋め込み、判定の PR コメントを投稿します(機械可読の `` マーカーで始まります)。さらに、引き続き有効な chad-approves/chad-rejects ラベルを適用し、該当する場合は依頼元の Slack スレッドに判定を投稿し、失敗時には Issue を作成して、ローカルレポートを書き込み、結果マーカーを出力します |
ブラウザーが実際に実行される場所
Dockerfile.operator はブラウザーのシステムライブラリをインストールしません。一方、.devcontainer/Dockerfile(リポジトリの devbox/ワーカーイメージ)は Chromium が必要とするものだけをインストールします。そのため、Playwright によるキャプチャーは、ステージ 03 が起動するワーカー devbox 上で実行され、オペレーターセッションにバインドされた MCP ツールの Navvi はオペレーターのターン内で実行されます。オペレーターのターン内で 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、ペルソナ、フローリスト)を書き込みます。各サブエージェントのステージに渡されるのは、その CONTEXT.md が入力として指定するハンドオフパスのみであり、オーケストレーターの履歴は渡されません。
実行
ステージは厳密に順次、1 つずつ実行してください。この手順では Task を並列起動しません。サブエージェントのステージごとに Task をちょうど 1 つ起動し、次のステージに進む前に完了を待ちます。
ワークスペースの解決(必ず最初に実行)
コントラクト、フロー、ハンドオフ、レポートはすべて、ターゲットリポジトリのチェックアウト内にあります。ミッションはそのチェックアウトを含まないワークスペースで実行されます。現在のディレクトリがリポジトリだと決して仮定せず、ほかの処理より先に確実な方法で解決してください。
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" を使って実行します。サブエージェントの Task はオーケストレーターの cd を引き継がないため、ステージのプロンプトには絶対パスを含める必要があります。以下のテンプレートでは、$WORKDIR と $SKILL_DIR の値をそのまま置き換えてください。.claude/... や .procedure-output/... の相対パス形式は決して渡さないでください。
Stages 01 → 04(順次サブエージェント)
各ステージで、Task を1つ起動します。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 のデプロイ待機が失敗した場合、あるいはステージ 02 でフローファイルが見つからない場合は、対応する結果マーカーを出力して停止してください(これらのステージでは GitHub の Issue も作成されます)。
ステージ 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
バリデーターのエラーがある場合、本番、プレビュー、cron の認定はできません。これらのモードでは、レガシーの .url、テンプレート ID、または localhost に暗黙的にフォールバックしないでください。
Stage 05(インライン)
ステージ 05 は、オーケストレーター内で自分で実行します。CONTEXT.md を読みます。
.claude/skills/flowchad-runner/stages/05-report/CONTEXT.md
前のハンドオフを集約し、PR コメントの投稿/失敗 Issue の作成、ローカルレポートファイルの書き込みを行い、[pylot] outcome=... マーカーをオーケストレーターから出力します(サブエージェントから出力してはいけません)。
ステージのハンドオフチェーン
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を出力します (失敗の Issue はステージ 05 で既に作成されています) - ブロック:ステージ 01(契約が無効/URL なし/デプロイ失敗/ブラウザーなし)またはステージ 02(フローが見つからない)が
[pylot:$PYLOT_OUTCOME_NONCE] outcome="flowchad blocked: {reason}" status=blockedを出力し、チェーンを停止します。 - 該当なし:ステージ 01 が影響を受けない PR/ドキュメントのみの PR/Dependabot の PR を検出し、デプロイせずに
[pylot:$PYLOT_OUTCOME_NONCE] outcome="flowchad N/A: no affected interactive flow" status=successを出力します。
厳守事項
- すべてのステージは順番に実行します — 一度に実行する Task は必ず 1 つだけとし、次へ進む前に完了を待ちます。 この手順では並列に処理を分岐することは一切ありません。
- ステージ 03 内ではフローを 1 つずつ実行します — フローごとにサブエージェントを割り当ててはいけません。フロー間でブラウザー/セッション/ペルソナの状態を共有しており、並行実行すると競合するためです。
- ステージ 05 はインラインで実行します —
[pylot] outcome=...マーカーはオーケストレーターが出力しなければなりません。サブエージェントから出力してはいけません。 - オーケストレーターのコンテキスト全体をサブエージェントの Task プロンプトに渡してはいけません — 入力のみを渡します。
- 各ステージは、次のステージが読み込む前に handoff.md を書き込みます。
- ステージを省略してはいけません — アクションが「実行することなし」であっても、すべてのステージを実行します(例:バックエンドが
noneのエビデンスアップロードでも handoff を書き込みます)。 - ステップの失敗はクラッシュではなく、検出事項です — ステージ 03 はステップエラー後もエビデンスの収集を続けます。判定するのはフローレベルの合否のみです。
- Quest および外部ダッシュボードは使用しません。 報告先はローカルのレポートファイルと GitHub です。さらに、ミッションの
dispatched_by_convが設定されている場合に限り、依頼元のスレッドにslack-postを 1 回だけ投稿します。自動化によってディスパッチされた実行では、GitHub 以外には投稿しません。 - インタラクティブテストの PASS にはブラウザーエビデンスが必要です。 静的診断や curl による診断は、
FAILEDまたはBLOCKEDの判定を裏付けることはできますが、PASSEDの判定には使用できません。 - 本番環境で重要な制御は、任意扱いにもスキップにもできません。 CAPTCHA/Navvi の機能が不足している場合は、PASS や本番環境でのスキップではなく
BLOCKEDとします。 - プレビューの作成対象は限定します。 プロバイダーの自動プレビューは有効にしないでください。ステージング環境がなく、明示的にディスパッチされた関連 PR がある場合に限り、オンデマンドのプレビューを最大 1 つ作成します。
- Cron では
smoke.criticalを使用します。 失敗した場合は、ブラウザーエビデンスを添えて、重複を排除した Issue を作成または更新します。公開スキルはスケジューラーを管理しません。 - オペレーターのターンでブラウザーを起動してはいけません。 オペレーターのイメージにはブラウザーライブラリがありません。Playwright によるキャプチャはワーカーの devbox で行い、Navvi はオペレーター側で実行します。キャプチャホストがない場合は、静的プローブで PASS とせず
BLOCKEDとします。 - アップロードするすべてのアセットには
evidence_class: visualを付けます。 クラス指定のない capability 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— 環境/フロー仕様の決定論的な検証ツール