きっかけ
GitHub issueに特定のラベルを付けると、セルフホストランナー上でClaude Codeが自動起動し、実装からPR作成までを無人でこなす仕組みをすでに運用しています。ただ、PRができた後の「ブラウザで見た目を確認する」作業だけは人間が手動でやっていました。これを自動化できないか検討した過程のメモです。
まず気づいたこと: 実はほぼ自動化済みだった
最初は「ブラウザ確認の自動化を新規に作る」つもりで検討を始めましたが、実際にリポジトリを調べてみると、以下がすでに一気通貫で動いていました。
- issueにラベル付与 → Claude Codeが実装しPRを作成
- PRに対してCI(Lint/テスト/Playwright E2Eテスト)が自動実行
- 全部通れば自動でsquashマージ
- 落ちればClaude Codeが失敗ログを見て自動で修正コミットをpush(最大3回リトライ)
つまり「PR作成→ブラウザ確認→問題なければマージ」という流れ自体はすでに存在していて、車輪の再発明になりかけました。既存のPlaywright E2Eテストは「あらかじめ書かれた重要フロー」が壊れていないかを見るリグレッションテストなので、Claude Codeが今回新しく実装した機能そのものは、対応するテストが別途書かれるまで検証対象に入りません。ここが本当に足りていない部分でした。
設計のポイント1: 2つのワークフローは別の実行
「PRを作るワークフロー」と「CIが走るワークフロー」は別々のGitHub Actions実行で、起動タイミングもズレています。Claude Code側は「PRを作ったら仕事終わり」で、CI側はGitHubがPR作成イベントを検知してから改めて起動します。
このズレを埋めるために、GitHub Actions同士でデータを直接受け渡す仕組み(artifactのダウンロードなど)を作るのではなく、Claude CodeがPRブランチに影響ページ一覧をJSONファイルとしてコミットしておく方式にしました。CI側は普通にブランチをチェックアウトするだけで、そのファイルを読めます。ワークフロー間の連携を考えると複雑になりがちですが、「同じブランチの同じコミットに載せる」だけで解決するのはシンプルで気に入っています。
設計のポイント2: スコープを絞る
固定スクリプトで全ページをスクリーンショット撮影すると、そのPRと無関係な部分まで毎回チェックすることになり、実行時間(≒コスト)が無駄にかかります。git diffからページを機械的に推測する方法も考えましたが、対応表のメンテナンスが面倒になりそうなので、Claude Codeに実装完了時点で「影響を受けたページ一覧」を出力させる方式にしました。実装した本人(AI)が一番把握しているので、二重の判断ロジックを作らずに済みます。
設計のポイント3: 画像はCloudflare R2に、バケットは分離する
PRコメントに画像を直接表示させたかったので、GitHub Actionsのartifact(zipでダウンロードしないと見られない)ではなく、Cloudflare R2にアップロードして公開URLをの形でコメントに埋め込む方式にしました。R2は転送(egress)無料なのでコスト面でも扱いやすいです。
既存のブログ画像用R2バケットとは別に、スクリーンショット専用のバケットを新設することにしました。理由は「見られたら困るから」ではなく2つです。
- 権限の最小化: このPR作成用のセルフホストランナーはissue本文を元にプロンプトを構成する無人ランナーで、プロンプトインジェクションのリスクを許容する設計になっています。同じR2バケットへの書き込み権限を持たせてしまうと、万が一インジェクションが成功した際に公開中のブログ画像まで上書きされ得ます。バケットを分ければ、渡すトークンを「スクリーンショット用バケットへの書き込みのみ」に絞れます
- ライフサイクルの違い: ブログ画像は恒久的に残す運用ですが、PRスクリーンショットはレビューが終われば不要です。バケットを分ければ、こちら側だけに「30日で自動削除」のようなライフサイクルルールを設定でき、ブログ側の設定に影響しません
余談: このジャンルはすでに確立されている
調べてみると「Visual Regression Testing(視覚回帰テスト)」という名前で確立された分野で、PercyやChromatic、Argos-CIといった商用サービスのほか、まさに今回と同じ構成(Playwright + Cloudflare R2 + PRコメント)を実装したOSSのGitHub Action(netbrain/visual-regression-action)も存在していました。ゼロから発明した部分は少なく、既存パターンに乗っかる形で十分実用になりそうです。
まとめ
- 「ブラウザ確認の自動化」を検討する前に、まず既存のCI/CD構成をきちんと調べる価値がある(思ったより自動化が進んでいることがある)
- PRを作るワークフローとCIワークフローが分かれている場合、データの受け渡しは「ブランチにファイルとしてコミットする」のがシンプル
- スクリーンショットの撮影範囲は、実装した本人(AI)に出力させるのが一番確実
- 無人で動くランナーがクラウドストレージに書き込む設計にする場合、用途ごとにバケット・トークンを分けて権限を最小化しておくと安全
同じような「AIエージェントにPR作成まで任せているが、ブラウザでの目視確認だけ手動で残っている」という状況の方の参考になれば幸いです。