cat-github-watcher
PR monitoring tool for the automated implementation phase by GitHub Copilot
Note: This document is largely AI-generated. It was generated by submitting an issue to an agent.
Status
- Currently dogfooding.
- Major bugs have been addressed.
- Frequent breaking changes are expected.
- Memo
- Initially, implementation was attempted with GitHub Actions, but it was found unsuitable for PR monitoring, so it was migrated to a Python version.
- The Python version monitors user-owned repositories of authenticated GitHub users and performs notifications and actions according to the PR phase.
Quick Links
| Item | Link | |——|——–| | 📊 GitHub Repository | cat2151/cat-github-watcher |
Overview
This is a Python tool that monitors the phases of Pull Requests where GitHub Copilot performs automated implementation, executing appropriate notifications and actions at the right time. It efficiently monitors PRs using the GraphQL API, targeting user-owned repositories of authenticated GitHub users.
Features
- Automated Monitoring of All Repositories: Automatically monitors PRs in user-owned repositories of authenticated GitHub users.
- GraphQL API Utilization: Achieves fast monitoring with efficient data retrieval.
- Phase Detection: Automatically determines PR status (phase1: Draft state, phase2: Addressing review comments, phase3: Awaiting review, LLM working: Coding agent in progress).
- Dry-run Mode: By default, it only monitors and does not execute actual actions (posting comments, making PRs Ready, sending notifications). Can be safely operated by explicitly enabling it.
- Automated Comment Posting: Automatically posts appropriate comments based on the phase (requires enablement in the configuration file).
- Automated Draft PR Ready-up: Automatically changes Draft PRs to Ready status for addressing review comments in phase2 (requires enablement in the configuration file).
- Mobile Notifications: Uses ntfy.sh to send notifications to mobile devices when phase3 (awaiting review) is detected (requires enablement in the configuration file).
- Notifies when an individual PR enters phase3.
- Also notifies when all PRs enter phase3 (message configurable in toml).
- Issue List Display: If all PRs are “LLM working”, displays the top N issues for repositories with no open PRs (default: 10, configurable with
issue_display_limit). - Power-saving Mode: Automatically extends the monitoring interval to reduce API usage when there’s no state change (configurable with
no_change_timeoutandreduced_frequency_interval). - Verbose Mode: Displays detailed configuration information on startup and during execution to help detect misconfigurations (enabled with
verbose).
Architecture
This tool is a Python application modularized according to the Single Responsibility Principle (SRP).
Directory Structure
cat-github-watcher/
├── cat-github-watcher.py # Entry point
├── src/
│ └── gh_pr_phase_monitor/
│ ├── colors.py # ANSI color codes and coloring
│ ├── config.py # Configuration loading and parsing
│ ├── github_client.py # GitHub API integration
│ ├── phase_detector.py # PR phase detection logic
│ ├── comment_manager.py # Comment posting and verification
│ ├── pr_actions.py # PR actions (Ready-up, browser launch)
│ └── main.py # Main execution loop
└── tests/ # Test files
Phase Detection Logic
The tool identifies the following four phases:
- phase1 (Draft state): When the PR is in Draft state and has review requests.
- phase2 (Addressing review comments): When copilot-pull-request-reviewer has posted review comments and corrections are needed.
- phase3 (Awaiting review): When copilot-swe-agent has completed corrections and is awaiting human review.
- LLM working (Coding agent in progress): When none of the above apply (e.g., Copilot is implementing).
Usage
Prerequisites
- Python 3.x is installed.
- GitHub CLI (
gh) is installed and authenticated.gh auth login
Setup
- Clone this repository:
git clone https://github.com/cat2151/cat-github-watcher.git cd cat-github-watcher - Create a configuration file (optional):
cp config.toml.example config.toml - Edit
config.tomlto configure monitoring intervals, execution modes, ntfy.sh notifications, Copilot auto-assignment, and auto-merging (optional):# Check interval (e.g., "30s", "1m", "5m", "1h", "1d") interval = "1m" # Upper limit on the number of issues to display from repositories without PRs # Default is 10, but can be changed to any positive number (e.g., 5, 15, 20) issue_display_limit = 10 # Timeout duration for no state change # If the state of all PRs (each PR's phase) does not change for this duration, # the monitoring interval switches to power-saving mode (reduced_frequency_interval below). # Set to an empty string "" to disable. # Supported formats: "30s", "1m", "5m", "30m", "1h", "1d" # Default: "30m" (30 minutes - stability priority) no_change_timeout = "30m" # Monitoring interval in power-saving mode # If no state change is detected during the no_change_timeout period, # the monitoring interval switches to this interval to reduce API usage. # When a change is detected, it returns to the regular monitoring interval. # Supported formats: "30s", "1m", "5m", "30m", "1h", "1d" # Default: "1h" (1 hour) reduced_frequency_interval = "1h" # Verbose mode - display detailed configuration information # If enabled, all settings are displayed on startup, and per-repository settings are also displayed during execution. # Useful for detecting configuration errors. # Default: false verbose = false # Execution control flags - only configurable within the [[rulesets]] section # Global flags are no longer supported # To apply settings to all repositories, use 'repositories = ["all"]' # Ruleset configuration example: # [[rulesets]] # name = "Default for all repositories - dry-run mode" # repositories = ["all"] # "all" matches all repositories # enable_execution_phase1_to_phase2 = false # set to true to make draft PRs ready # enable_execution_phase2_to_phase3 = false # set to true to post phase2 comment # enable_execution_phase3_send_ntfy = false # set to true to send ntfy notification # enable_execution_phase3_to_merge = false # set to true to merge phase3 PR # [[rulesets]] # name = "Simple: automatically assign good first issues to Copilot" # repositories = ["my-repo"] # assign_good_first_old = true # This is enough! The [assign_to_copilot] section is not needed. # # Default behavior: open issue in browser for manual assignment. # ntfy.sh notification settings (optional) # Notifications include a clickable action button to open the PR. [ntfy] enabled = false # set to true to enable notifications topic = "<Enter your ntfy.sh topic name here>" # This topic can be read/written by anyone, so please use an unguessable string. message = "PR is ready for review: {url}" # Message template priority = 4 # Notification priority (1=lowest, 3=default, 4=high, 5=highest) all_phase3_message = "All PRs are now in phase3 (ready for review)" # Message when all PRs enter phase3 # Phase3 Auto-merge settings (optional) # Automatically merges the PR when it reaches phase3 (awaiting review). # Before merging, the comment defined below will be posted to the PR. # After successful merge, the feature branch will be automatically deleted. # IMPORTANT: For safety, this feature is disabled by default. # You must explicitly enable it by setting enable_execution_phase3_to_merge = true in the rulesets for each repository. # IMPORTANT: If auto-merge is enabled, the comment field must be explicitly configured. [phase3_merge] comment = "The agent determines that review comments have been addressed. Under the user's responsibility, user review will be omitted. Merging the PR." # Comment to post before merging (required when auto-merge is enabled) automated = false # set to true to click merge button via browser automation wait_seconds = 10 # Wait time in seconds after browser launch, before clicking the button debug_dir = "debug_screenshots" # Directory to save debug information on image recognition failure (default: "debug_screenshots") # Automatically assign issues to Copilot (completely optional! This entire section is optional) # # Simple usage: just set assign_good_first_old = true in rulesets (see example above) # Define this section only if you want to customize the default behavior. # # Assignment behavior is controlled by ruleset flags: # - assign_good_first_old: Assigns the oldest "good first issue" (by issue number, default: false) # - assign_old: Assigns the oldest issue (by issue number, any label, default: false) # If both are true, "good first issue" is prioritized. # # Default behavior (if this section is not defined): # - Automatically clicks buttons via browser automation # - Uses PyAutoGUI # - wait_seconds = 10 # # REQUIRED: PyAutoGUI installation is required (pip install pyautogui pillow) # # IMPORTANT: For safety, this feature is disabled by default. # You must explicitly enable it by specifying assign_good_first_old or assign_old in the rulesets for each repository. [assign_to_copilot] wait_seconds = 10 # Wait time in seconds after browser launch, before clicking the button debug_dir = "debug_screenshots" # Directory to save debug information on image recognition failure (default: "debug_screenshots") -
Prepare Button Screenshots (only if using automation):
If you use automation features (
automated = trueor enablingassign_to_copilot/phase3_merge), screenshots of the buttons PyAutoGUI needs to click are required.Required Screenshots:
For automated issue assignment (
assign_to_copilotfeature):assign_to_copilot.png- Screenshot of the “Assign to Copilot” buttonassign.png- Screenshot of the “Assign” button
For automated PR merging (if
automated = trueforphase3_mergefeature):merge_pull_request.png- Screenshot of the “Merge pull request” buttonconfirm_merge.png- Screenshot of the “Confirm merge” buttondelete_branch.png- Screenshot of the “Delete branch” button (optional)
How to Take Screenshots:
a. Open a GitHub issue or PR in your browser. b. Find the button you want to automate. c. Take a screenshot of only the button (not the entire screen). d. Save it as a PNG file in the
screenshotsdirectory. e. Use the exact filenames listed above.Tips:
- Screenshots should include only the button, with a small margin.
- Use your OS’s screenshot tool (Windows: Snipping Tool, Mac: Cmd+Shift+4).
- Ensure the button is clearly visible and not obscured.
- If the button’s appearance changes (e.g., due to theme changes), you’ll need to update the screenshots.
- Use the
confidencesetting to adjust image recognition reliability (due to DPI scaling or themes).
Automated Debug Information Saving:
- If image recognition fails, debug information is automatically saved.
- Save location:
debug_screenshots/directory (default). - Contents saved:
- Screenshot (full screen at time of failure):
{button_name}_fail_{timestamp}.png - Failure information JSON:
{button_name}_fail_{timestamp}.json- Button name, timestamp, confidence threshold, screenshot path, template image path.
- Screenshot (full screen at time of failure):
- The debug directory can be changed in the settings:
debug_diroption (within theassign_to_copilotorphase3_mergesections).
Important Requirements:
- You must already be logged in to GitHub in your default browser.
- Automation uses existing browser sessions (it does not perform new authentication).
- Ensure the correct GitHub window/tab is focused and visible on screen when a button is clicked.
- If multiple GitHub pages are open, the first found button will be clicked.
Create Screenshot Directory:
mkdir screenshots -
Install PyAutoGUI (only if using automation):
pip install -r requirements-automation.txtまたは
pip install pyautogui pillow
Run
Start the tool to begin monitoring:
python3 cat-github-watcher.py [config.toml]
Or, run directly as a Python module:
python3 -m src.gh_pr_phase_monitor.main [config.toml]
Workflow
- Start: When the tool is launched, it begins monitoring user-owned repositories of the authenticated GitHub user.
- PR Detection: Automatically detects repositories with open PRs.
- Phase Determination: Determines the phase of each PR (phase1/2/3, LLM working).
- Action Execution:
- phase1: Default is Dry-run (if
enable_execution_phase1_to_phase2 = truein rulesets, Draft PR is changed to Ready state). - phase2: Default is Dry-run (if
enable_execution_phase2_to_phase3 = truein rulesets, posts a comment asking Copilot to apply changes). - phase3: Opens the PR page in the browser.
- If
enable_execution_phase3_send_ntfy = truein rulesets, also sends an ntfy.sh notification. - If
enable_execution_phase3_to_merge = truein rulesets, automatically merges the PR (using global[phase3_merge]settings).
- If
- LLM working: Waits (if all PRs are in this state, displays issues from repositories with no open PRs).
- phase1: Default is Dry-run (if
- Automated Issue Assignment: If all PRs are “LLM working” and there are repositories with no open PRs:
- If
assign_good_first_old = truein rulesets, automatically assigns the oldest “good first issue” (by issue number). - If
assign_old = truein rulesets, automatically assigns the oldest issue (by issue number, any label). - If both are true, “good first issue” is prioritized.
- Default behavior: Automatically clicks buttons with PyAutoGUI (the
[assign_to_copilot]section is not needed). - Required: PyAutoGUI installation and button screenshot preparation are necessary.
- If
- Repeat: Continues monitoring at the configured interval.
- If no state change occurs for the duration set by
no_change_timeout, it automatically switches to power-saving mode (reduced_frequency_interval) to reduce API usage. - When a change is detected, it returns to the normal monitoring interval.
- If no state change occurs for the duration set by
Dry-run Mode
By default, the tool operates in Dry-run Mode and does not execute actual actions, allowing you to safely verify its operation.
- Phase1 (Draft → Ready-up): Displays
[DRY-RUN] Would mark PR as ready for reviewbut does nothing. - Phase2 (Comment Posting): Displays
[DRY-RUN] Would post comment for phase2but does nothing. - Phase3 (ntfy Notification): Displays
[DRY-RUN] Would send ntfy notificationbut does nothing. - Phase3 (Merge): Displays
[DRY-RUN] Would merge PRbut does nothing.
To enable actual actions, set the following flags to true in the [[rulesets]] section of config.toml.
[[rulesets]]
name = "Enable automation for specific repository"
repositories = ["test-repo"] # or ["all"] for all repositories
enable_execution_phase1_to_phase2 = true # Make Draft PR ready
enable_execution_phase2_to_phase3 = true # Post Phase2 comment
enable_execution_phase3_send_ntfy = true # Send ntfy notification
enable_execution_phase3_to_merge = true # Merge Phase3 PR
assign_good_first_old = true # Auto-assign good first issue
Stopping
You can stop monitoring with Ctrl+C.
Caveats
- GitHub CLI (
gh) must be installed and authenticated. - Assumes integration with GitHub Copilot (specifically copilot-pull-request-reviewer and copilot-swe-agent).
- Only user-owned repositories of the authenticated user are monitored. Organization repositories are not included to keep the tool simple and focused (YAGNI principle).
- Since the GraphQL API is used, be mindful of API rate limits.
- If using ntfy.sh notifications, please configure a topic on ntfy.sh in advance.
Tests
The project includes a test suite using pytest:
pytest tests/
License
MIT License - See the LICENSE file for details.
Note: The English README.md is automatically generated from README.ja.md by GitHub Actions using Gemini’s translation.
Big Brother is watching your repositories. Now it’s the cat. 🐱