cat-github-watcher
GitHub Copilotによる自動実装フェーズのPR監視ツール
※このドキュメントは大部分がAI生成です。issueをagentに投げて生成させました。
状況
- ドッグフーディング中です。
- 大きなバグを一通り取りました。
- 破壊的変更が頻繁にあります。
- 備忘
- 当初はGitHub Actionsで実装を試みましたが、PR監視という目的には適さないことが判明したため、Python版に移行しました。
- Python版は、認証済みGitHubユーザーのユーザー所有リポジトリを監視し、PRのフェーズに応じた通知やアクションを実行します。
Quick Links
| 項目 | リンク | |——|——–| | 📊 GitHub Repository | cat2151/cat-github-watcher |
概要
GitHub Copilotが自動実装を行うPRのフェーズを監視し、適切なタイミングで通知やアクションを実行するPythonツールです。 認証済みGitHubユーザーのユーザー所有リポジトリを対象に、GraphQL APIを利用して効率的にPRを監視します。
特徴
- 全リポジトリ自動監視: 認証済みGitHubユーザーのユーザー所有リポジトリのPRを自動監視
- GraphQL API活用: 効率的なデータ取得で高速監視を実現
- フェーズ検知: PRの状態(phase1: Draft状態、phase2: レビュー指摘対応中、phase3: レビュー待ち、LLM working: コーディングエージェント作業中)を自動判定
- Dry-runモード: デフォルトでは監視のみ行い、実際のアクション(コメント投稿、PR Ready化、通知送信)は実行しない。明示的に有効化することで安全に運用可能
- 自動コメント投稿: フェーズに応じて適切なコメントを自動投稿(要:設定ファイルで有効化)
- マルチエージェント対応: PR作成者が
openai-code-agentなど*-codex-coding-agent系なら@codex[agent]、anthropic-code-agentなど*-claude-coding-agent系なら@claude[agent]を自動メンションし、これらに該当しない場合は@copilotにフォールバック([coding_agent].agent_nameで上書き可能、未設定時は@copilot) - Draft PR自動Ready化: phase2でのレビュー指摘対応のため、Draft PRを自動的にReady状態に変更(要:設定ファイルで有効化)
- モバイル通知: ntfy.shを利用してphase3(レビュー待ち)を検知したらモバイル端末に通知(要:設定ファイルで有効化)
- 個別のPRがphase3になったときに通知
- すべてのPRがphase3になったときにも通知(メッセージはtomlで設定可能)
- issue一覧表示: 全PRが「LLM working」の場合、オープンPRのないリポジトリのissue上位N件を表示(デフォルト: 10件、
issue_display_limitで変更可能) - 自己更新: 起動時に必ず更新チェックを実行し、更新があれば自動pullして再起動する。さらに
enable_auto_update = trueを設定すると、監視ループ中も1分ごとに更新チェックを継続する(デフォルト無効) - ローカルリポジトリpull検知: デフォルトで親ディレクトリにある自分のリポジトリのpull可能状態を表示(Dry-run)。
auto_git_pull = trueを設定すると自動pullする(cat-repo-auditor参考実装) - 省電力モード: 状態変化がない場合、API使用量を削減するため監視間隔を自動的に延長(
no_change_timeoutとreduced_frequency_intervalで設定可能) - Verboseモード: 起動時と実行中に詳細な設定情報を表示し、設定ミスの検出を支援(
verboseで有効化)
アーキテクチャ
このツールは、単一責任の原則(SRP)に従ってモジュール化されたPythonアプリケーションです。
ディレクトリ構成
cat-github-watcher/
├── cat-github-watcher.py # エントリーポイント
├── src/
│ └── gh_pr_phase_monitor/
│ ├── colors.py # ANSI カラーコードと色付け
│ ├── config.py # 設定の読み込みと解析
│ ├── github_client.py # GitHub API 連携
│ ├── phase_detector.py # PRフェーズ判定ロジック
│ ├── comment_manager.py # コメント投稿と確認
│ ├── pr_actions.py # PRアクション(Ready化、ブラウザ起動)
│ └── main.py # メイン実行ループ
└── tests/ # テストファイル
フェーズ判定ロジック
ツールは以下の4つのフェーズを判定します:
- phase1 (Draft状態): PRがDraft状態で、レビューリクエストがある場合
- phase2 (レビュー指摘対応中): copilot-pull-request-reviewerがレビューコメントを投稿し、修正が必要な場合
- phase3 (レビュー待ち): copilot-swe-agentが修正を完了し、人間のレビュー待ちの場合
- LLM working (コーディングエージェント作業中): 上記のいずれにも該当しない場合(Copilotが実装中など)
使い方
前提条件
- Python 3.11 以上がインストールされている
- GitHub CLI (
gh) がインストールされ、認証済みであるgh auth login
セットアップ
- このリポジトリをクローン:
git clone https://github.com/cat2151/cat-github-watcher.git cd cat-github-watcher - 設定ファイルを作成(オプション):
cp config.toml.example config.toml config.tomlを編集して、監視間隔や実行モード、ntfy.sh通知、Copilot自動割り当て、自動マージを設定(オプション):# チェック間隔("30s", "1m", "5m", "1h", "1d"など) interval = "1m" # PRのないリポジトリから表示するissue数の上限 # デフォルトは10ですが、任意の正の数(例: 5, 15, 20)に変更可能 issue_display_limit = 10 # 状態変更なしのタイムアウト時間 # 全PRの状態(各PRのフェーズ)がこの時間変化しない場合、 # 監視間隔が省電力モード(下記のreduced_frequency_interval)に切り替わります # 空文字列 "" を設定すると無効化されます # サポートされる形式: "30s", "1m", "5m", "30m", "1h", "1d" # デフォルト: "30m" (30分 - 安定性優先) no_change_timeout = "30m" # 投稿コメントで使うコーディングエージェントのメンションを上書き(省略時は@copilot) [coding_agent] agent_name = "@codex[agent]" # 省電力モード時の監視間隔 # no_change_timeout期間で状態変化が検知されない場合、 # 監視間隔がこの間隔に切り替わりAPI使用量を削減します # 変化が検知されると、通常の監視間隔に戻ります # サポートされる形式: "30s", "1m", "5m", "30m", "1h", "1d" # デフォルト: "1h" (1時間) reduced_frequency_interval = "1h" # Verboseモード - 詳細な設定情報を表示 # 有効にすると、起動時に全設定を表示し、実行中にリポジトリ毎の設定も表示します # 設定ミスの検出に役立ちます # デフォルト: false verbose = false # ターミナル出力のカラースキーム # monokai(デフォルト)または classic を指定可能 color_scheme = "monokai" # [colors] セクションで個別にカラーコードを上書き可能(#RRGGBB形式/ANSI可) # 省略時は上記color_schemeのパレットを使用 [colors] # phase1 = "#E6DB74" # phase2 = "#66D9EF" # phase3 = "#A6E22E" # llm = "#F92672" # url = "#79C1FF" # url = "\u001b[94m" # TOMLで書けるANSI例(ESC=[94m) # PR作者の表示切り替え # CLI出力で "Author: <login>" を表示するかどうかを制御します # デフォルト: false display_pr_author = false # ローカルリポジトリの自動pull設定(ローカルリポジトリウォッチャー専用のグローバルフラグ) # デフォルト(false): pullableなリポジトリを検知して表示のみ(Dry-run) # true に設定すると: pullableなリポジトリを自動でgit pullする # 5分ごとに親ディレクトリのリポジトリをスキャン(git fetch実行) # ※ PRアクションとは独立した挙動のため、このフラグのみトップレベルで指定します auto_git_pull = false # ローカルリポジトリのスキャン対象ディレクトリ(省略時はカレントディレクトリの親) # local_repo_watcher_base_dir = ".." # PRアクション用の実行制御フラグ - [[rulesets]]セクション内でのみ指定可能 # グローバルフラグはサポートされなくなりました(auto_git_pull を除く) # 全リポジトリに設定を適用するには 'repositories = ["all"]' を使用してください # ルールセット設定例: # [[rulesets]] # name = "全リポジトリのデフォルト - dry-runモード" # repositories = ["all"] # "all" は全リポジトリにマッチします # enable_execution_phase1_to_phase2 = false # trueにするとdraft PRをready化 # enable_execution_phase2_to_phase3 = false # trueにするとphase2コメント投稿 # enable_execution_phase3_send_ntfy = false # trueにするとntfy通知送信 # enable_execution_phase3_to_merge = false # trueにするとphase3 PRをマージ # [[rulesets]] # name = "シンプル: good first issueをCopilotに自動割り当て" # repositories = ["my-repo"] # assign_good_first_old = true # これだけでOK! [assign_to_copilot]セクションは不要です # # デフォルト動作: ブラウザでissueを開いて手動割り当て # ntfy.sh通知設定(オプション) # 通知にはPRを開くためのクリック可能なアクションボタンが含まれます [ntfy] enabled = false # trueにすると通知を有効化 topic = "<ここにntfy.shのトピック名を書く>" # 誰でも読み書きできるので、推測されない文字列にしてください message = "PR is ready for review: {url}" # メッセージテンプレート priority = 4 # 通知の優先度(1=最低、3=デフォルト、4=高、5=最高) all_phase3_message = "All PRs are now in phase3 (ready for review)" # すべてのPRがphase3になったときのメッセージ # Phase3自動マージ設定(オプション) # PRがphase3(レビュー待ち)に達したら自動的にマージします # マージ前に、以下で定義したコメントがPRに投稿されます # マージ成功後、自動的にfeature branchが削除されます # 重要: 安全のため、この機能はデフォルトで無効です # リポジトリごとにrulesetsで enable_execution_phase3_to_merge = true を指定して明示的に有効化する必要があります # 重要:自動マージが有効な場合、commentフィールドを明示的に設定する必要があります [phase3_merge] comment = "agentによって、レビュー指摘対応が完了したと判断します。userの責任のもと、userレビューは省略します。PRをMergeします。" # マージ前に投稿するコメント(自動マージ有効時は必須) automated = false # trueにするとブラウザ自動操縦でマージボタンをクリック wait_seconds = 10 # ブラウザ起動後、ボタンクリック前の待機時間(秒) debug_dir = "debug_screenshots" # 画像認識失敗時のデバッグ情報保存先(デフォルト: "debug_screenshots") notification_enabled = true # ボタン自動操作中に指定座標で小さな通知ウィンドウを表示 notification_message = "ブラウザを開いてMergeボタンを探索中..." # 通知ウィンドウのメッセージ notification_width = 400 notification_height = 150 notification_position_x = 100 notification_position_y = 100 maximize_on_first_fail = true # 1回目にボタンが見つからない場合にウィンドウを最大化して再探索する # issueをCopilotに自動割り当て(完全にオプション!このセクション全体がオプションです) # # シンプルな使い方: rulesetsで assign_good_first_old = true とするだけ(上記の例を参照) # このセクションは、デフォルト動作をカスタマイズしたい場合のみ定義してください。 # # 割り当て動作はrulesetのフラグで制御します: # - assign_ci_failure_old: 最も古い"ci-failure" issueを割り当て(issue番号順、デフォルト: false) # - assign_deploy_pages_failure_old: 最も古い"deploy-pages-failure" issueを割り当て(issue番号順、デフォルト: false) # - assign_good_first_old: 最も古い"good first issue"を割り当て(issue番号順、デフォルト: false) # - assign_old: 最も古いissueを割り当て(issue番号順、ラベル不問、デフォルト: false) # 優先度: ci-failure > deploy-pages-failure > good first issue > old issue # # デフォルト動作(このセクションが定義されていない場合): # - ブラウザ自動操縦で自動的にボタンをクリック # - PyAutoGUIを使用した画像認識 # - 画像認識が失敗した場合、OCRフォールバック(オプション) # - wait_seconds = 2 # # 必須: PyAutoGUIのインストールが必要(pip install pyautogui pillow) # オプション: OCRフォールバックにはpytesseractのインストールが必要 # # 重要: 安全のため、この機能はデフォルトで無効です # リポジトリごとにrulesetsで assign_ci_failure_old / assign_deploy_pages_failure_old / # assign_good_first_old / assign_old を指定して明示的に有効化する必要があります [assign_to_copilot] wait_seconds = 2 # ブラウザ起動後、ボタンクリック前の待機時間(秒) debug_dir = "debug_screenshots" # 画像認識失敗時のデバッグ情報保存先(デフォルト: "debug_screenshots") confidence = 0.8 # 画像マッチングの信頼度 0.0-1.0(デフォルト: 0.8) enable_ocr_detection = true # OCRフォールバックを有効化(デフォルト: true) notification_enabled = true # ボタン自動操作中に指定座標で小さな通知ウィンドウを表示 notification_message = "ブラウザを開いてCopilot割り当てボタンを探索中..." # 通知ウィンドウのメッセージ notification_width = 400 notification_height = 150 notification_position_x = 100 notification_position_y = 100 maximize_on_first_fail = true # 1回目にボタンが見つからない場合にウィンドウを最大化して再探索する # enable_html_detection = false # HTML検出フォールバック(実験的、デフォルト: false)-
ボタンスクリーンショットの準備(自動化を使用する場合のみ):
自動化機能(
automated = trueまたはassign_to_copilot/phase3_mergeの有効化)を使用する場合、 PyAutoGUIがクリックするボタンのスクリーンショットが必要です。必要なスクリーンショット:
issueの自動割り当て用(
assign_to_copilot機能):assign_to_copilot.png- “Assign to Copilot” ボタンのスクリーンショットassign.png- “Assign” ボタンのスクリーンショット
PRの自動マージ用(
phase3_merge機能でautomated = trueの場合):merge_pull_request.png- “Merge pull request” ボタンのスクリーンショットconfirm_merge.png- “Confirm merge” ボタンのスクリーンショットdelete_branch.png- “Delete branch” ボタンのスクリーンショット(オプション)
スクリーンショットの撮り方:
a. GitHubのissueまたはPRをブラウザで開く b. 自動化したいボタンを見つける c. ボタンだけのスクリーンショットを撮る(画面全体ではなく) d. PNG形式で
screenshotsディレクトリに保存する e. 上記の正確なファイル名を使用するヒント:
- スクリーンショットはボタンのみを含め、小さな余白を含める
- OSのスクリーンショットツールを使用する(Windows: Snipping Tool、Mac: Cmd+Shift+4)
- ボタンがはっきり見え、隠れていないことを確認
- ボタンの見た目が変わる場合(テーマ変更など)、スクリーンショットを更新する必要があります
- 画像認識の信頼度を調整する場合は
confidence設定を使用(DPI scalingやテーマによる)
デバッグ情報の自動保存:
- 画像認識が失敗した場合、自動的にデバッグ情報が保存されます
- 保存先:
debug_screenshots/ディレクトリ(デフォルト) - 保存内容:
- スクリーンショット(失敗時の画面全体):
{button_name}_fail_{timestamp}.png - 候補領域のスクリーンショット(見つかった場合):
{button_name}_candidate_{timestamp}_{number}.png - 失敗情報JSON:
{button_name}_fail_{timestamp}.json- ボタン名、タイムスタンプ、信頼度閾値、スクリーンショットパス、テンプレート画像パス
- 候補領域の情報(座標、サイズ、信頼度)
- スクリーンショット(失敗時の画面全体):
- デバッグ時は低い信頼度(0.7, 0.6, 0.5)で最大3つの候補領域を検出
- デバッグディレクトリは設定で変更可能:
debug_dirオプション(assign_to_copilotまたはphase3_mergeセクション内)
フォールバック方式(画像認識が失敗した場合):
- OCR検出(デフォルト有効): pytesseractを使用してボタンのテキストを検出
- 「Assign to Copilot」などのテキストを画面上から直接検出
- サブピクセルレンダリングの違いに対して頑健
- 必須: tesseract-ocrのインストール(システムレベル)
- 無効化:
enable_ocr_detection = false
重要な要件:
- デフォルトブラウザでGitHubに既にログイン済みである必要があります
- 自動化は既存のブラウザセッションを使用します(新しい認証は行いません)
- ボタンクリック時に正しいGitHubウィンドウ/タブがフォーカスされ、画面に表示されていることを確認してください
- 複数のGitHubページが開いている場合、最初に見つかったボタンがクリックされます
スクリーンショットディレクトリの作成:
mkdir screenshots -
PyAutoGUIをインストール(自動化を使用する場合のみ):
基本的な画像認識のみ:
pip install pyautogui pillow pygetwindowOCRフォールバックも含む(推奨):
pip install -r requirements-automation.txtOCRを使用する場合は、システムにtesseract-ocrをインストール:
- Windows:
choco install tesseract - macOS:
brew install tesseract - Linux:
apt-get install tesseract-ocr
- Windows:
実行
ツールを起動して監視を開始:
python3 cat-github-watcher.py [config.toml]
または、Pythonモジュールとして直接実行:
python3 -m src.gh_pr_phase_monitor.main [config.toml]
動作の流れ
- 起動: ツールを起動すると、認証済みGitHubユーザーのユーザー所有リポジトリの監視を開始
- PR検知: オープンPRを持つリポジトリを自動検出
- フェーズ判定: 各PRのフェーズを判定(phase1/2/3、LLM working)
- アクション実行:
- phase1: デフォルトはDry-run(rulesetsで
enable_execution_phase1_to_phase2 = trueとするとDraft PRをReady状態に変更) - phase2: デフォルトはDry-run(rulesetsで
enable_execution_phase2_to_phase3 = trueとするとCopilotに変更適用を依頼するコメントを投稿) - phase3: ブラウザでPRページを開く
- rulesetsで
enable_execution_phase3_send_ntfy = trueとするとntfy.sh通知も送信 - rulesetsで
enable_execution_phase3_to_merge = trueとするとPRを自動マージ(グローバル[phase3_merge]設定を使用)
- rulesetsで
- LLM working: 待機(全PRがこの状態の場合、オープンPRのないリポジトリのissueを表示)
- phase1: デフォルトはDry-run(rulesetsで
- Issue自動割り当て: 全PRが「LLM working」かつオープンPRのないリポジトリがある場合:
- rulesetsで
assign_ci_failure_old = trueとすると最も古い”ci-failure” issueを自動割り当て(issue番号順) - rulesetsで
assign_deploy_pages_failure_old = trueとすると最も古い”deploy-pages-failure” issueを自動割り当て(issue番号順) - rulesetsで
assign_good_first_old = trueとすると最も古い”good first issue”を自動割り当て(issue番号順) - rulesetsで
assign_old = trueとすると最も古いissueを自動割り当て(issue番号順、ラベル不問) - 優先度: ci-failure > deploy-pages-failure > good first issue > old issue
- デフォルト動作: PyAutoGUIで自動的にボタンをクリック(
[assign_to_copilot]セクションは不要) - 必須: PyAutoGUIのインストールとボタンスクリーンショットの準備が必要
- rulesetsで
- 繰り返し: 設定された間隔で監視を継続
- 状態変化がない状態が
no_change_timeoutで設定された時間だけ続いた場合、自動的に省電力モード(reduced_frequency_interval)に切り替わりAPI使用量を削減 - 変化が検知されると通常の監視間隔に戻る
- 状態変化がない状態が
Dry-runモード
デフォルトでは、ツールはDry-runモードで動作し、実際のアクションは実行しません。これにより、安全に動作を確認できます。
- Phase1(Draft → Ready化):
[DRY-RUN] Would mark PR as ready for reviewと表示されるが、実際には何もしない - Phase2(コメント投稿):
[DRY-RUN] Would post comment for phase2と表示されるが、実際には何もしない - Phase3(ntfy通知):
[DRY-RUN] Would send ntfy notificationと表示されるが、実際には何もしない - Phase3(マージ):
[DRY-RUN] Would merge PRと表示されるが、実際には何もしない - ローカルリポジトリ: pullable状態のリポジトリを
[PULLABLE]と表示し[DRY-RUN] Would pull <repo>と表示されるが、実際には何もしない
実際のアクションを有効にするには、config.tomlの[[rulesets]]セクションで以下のフラグをtrueに設定します:
[[rulesets]]
name = "特定のリポジトリで自動化を有効化"
repositories = ["test-repo"] # または ["all"] で全リポジトリ
enable_execution_phase1_to_phase2 = true # Draft PRをReady化
enable_execution_phase2_to_phase3 = true # Phase2コメント投稿
enable_execution_phase3_send_ntfy = true # ntfy通知送信
enable_execution_phase3_to_merge = true # Phase3 PRをマージ
assign_ci_failure_old = true # ci-failure issueを自動割り当て
assign_deploy_pages_failure_old = true # deploy-pages-failure issueを自動割り当て
assign_good_first_old = true # good first issueを自動割り当て
ローカルリポジトリの自動pullを有効にするには、トップレベルで設定します(rulesets外):
auto_git_pull = true # pullable なローカルリポジトリを自動でgit pullする
停止
Ctrl+C で監視を停止できます。
注意事項
- GitHub CLI (
gh) がインストールされ、認証済みである必要があります - GitHub Copilot (特に copilot-pull-request-reviewer と copilot-swe-agent) との連携を前提としています
- 認証済みユーザーのユーザー所有リポジトリのみが監視対象になります。ツールをシンプルかつ集中させるため、Organizationリポジトリは含まれません(YAGNI原則)
- GraphQL APIを使用するため、APIレート制限に注意してください
- ntfy.sh通知を使用する場合は、事前にntfy.shでトピックを設定してください
テスト
プロジェクトにはpytestを使用したテストスイートが含まれています:
pytest tests/
ライセンス
MIT License - 詳細はLICENSEファイルを参照してください
※英語版README.mdは、README.ja.mdを元にGeminiの翻訳でGitHub Actionsにより自動生成しています
Big Brother is watching your repositories. Now it’s the cat. 🐱