View on GitHub

cat-github-watcher

cat-github-watcher

cat-github-watcher

PR monitoring tool for GitHub Copilot’s automated implementation phases

Japanese English Ask DeepWiki

* This document is largely AI-generated. It was generated by sending issues to an agent.

Status

| Item | Link | |——|——–| | 📊 GitHub Repository | cat2151/cat-github-watcher |

Overview

This Python tool monitors the phases of GitHub Copilot’s automated implementation PRs, executing appropriate notifications and actions at the right time. It targets user-owned repositories for authenticated GitHub users, leveraging the GraphQL API for efficient PR monitoring.

Features

Architecture

This tool is a modularized Python application adhering 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 detects the following four phases:

  1. phase1 (Draft): PR is in Draft state and has review requests.
  2. phase2 (Addressing review comments): copilot-pull-request-reviewer has posted review comments, and corrections are needed.
  3. phase3 (Awaiting review): copilot-swe-agent has completed corrections and is awaiting human review.
  4. LLM working (Coding agent in progress): None of the above apply (e.g., Copilot is implementing).

Usage

Prerequisites

Setup

  1. Clone this repository:
    git clone https://github.com/cat2151/cat-github-watcher.git
    cd cat-github-watcher
    
  2. Create a configuration file (optional):
    cp config.toml.example config.toml
    
  3. Edit config.toml to configure monitoring interval, execution mode, ntfy.sh notifications, Copilot auto-assignment, and auto-merge (optional):
    # Check interval (e.g., "30s", "1m", "5m", "1h", "1d")
    interval = "1m"
        
    # Maximum number of issues to display from repositories with no 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 (phase of each PR) does not change for this duration,
    # the monitoring interval will switch 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 - prioritizing stability)
    no_change_timeout = "30m"
        
    # Override the mention for the coding agent used in post comments (defaults to @copilot)
    [coding_agent]
    agent_name = "@codex[agent]"
        
    # 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.
    # It returns to the normal monitoring interval when a change is detected.
    # Supported formats: "30s", "1m", "5m", "30m", "1h", "1d"
    # Default: "1h" (1 hour)
    reduced_frequency_interval = "1h"
        
    # Verbose mode - displays detailed configuration information
    # When enabled, all settings are displayed at startup, and per-repository settings are displayed during execution.
    # This helps detect configuration errors.
    # Default: false
    verbose = false
        
    # Color scheme for terminal output
    # Can be set to "monokai" (default) or "classic"
    color_scheme = "monokai"
    
    # Individual color codes can be overridden in the [colors] section (#RRGGBB format / ANSI allowed)
    # If omitted, the palette of the above color_scheme will be used.
    [colors]
    # phase1 = "#E6DB74"
    # phase2 = "#66D9EF"
    # phase3 = "#A6E22E"
    # llm = "#F92672"
    # url = "#79C1FF"
    # url = "\u001b[94m"  # Example ANSI in TOML (ESC=[94m)
        
    # Toggle display of PR author
    # Controls whether to display "Author: <login>" in CLI output
    # Default: false
    display_pr_author = false
        
    # Local repository auto-pull setting (global flag specifically for local repo watcher)
    # Default (false): Detects and displays pullable repositories only (Dry-run)
    # If set to true: Automatically git pull pullable repositories
    # Scans repositories in the parent directory every 5 minutes (executes git fetch)
    # Note: This behavior is independent of PR actions, so this flag is specified at the top level only.
    auto_git_pull = false
        
    # Base directory for local repository scanning (defaults to parent of current directory if omitted)
    # local_repo_watcher_base_dir = ".."
        
    # Execution control flags for PR actions - can only be specified within [[rulesets]] sections
    # Global flags are no longer supported (except for auto_git_pull)
    # To apply settings to all repositories, use 'repositories = ["all"]'
        
    # Example ruleset configuration:
    # [[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 comments
    # enable_execution_phase3_send_ntfy = false  # Set to true to send ntfy notifications
    # enable_execution_phase3_to_merge = false   # Set to true to merge phase3 PRs
        
    # [[rulesets]]
    # name = "Simple: Auto-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>"  # Use an unguessable string as anyone can read/write to it
    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 are in phase3
        
    # Phase3 auto-merge settings (optional)
    # Automatically merges the PR once 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 rulesets per repository.
    # IMPORTANT: If auto-merge is enabled, the comment field must be explicitly set.
    [phase3_merge]
    comment = "The agent has determined that review comments have been addressed. User review is skipped under user's responsibility. Merging PR."  # Comment to post before merging (required when auto-merge is enabled)
    automated = false  # Set to true for automated browser operation to click merge button
    wait_seconds = 10  # Wait time in seconds after browser launch, before clicking button
    debug_dir = "debug_screenshots"  # Destination for debug info if image recognition fails (default: "debug_screenshots")
    notification_enabled = true  # Display a small notification window at specified coordinates during automated button operation
    notification_message = "Opening browser and searching for Merge button..."  # Message for the notification window
    notification_width = 400
    notification_height = 150
    notification_position_x = 100
    notification_position_y = 100
    maximize_on_first_fail = true  # Maximize window and re-search if button not found on first attempt
    
    # Auto-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_ci_failure_old: Assigns the oldest "ci-failure" issue (by issue number, default: false)
    # - assign_deploy_pages_failure_old: Assigns the oldest "deploy-pages-failure" issue (by issue number, default: false)
    # - 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)
    # Priority: ci-failure > deploy-pages-failure > good first issue > old issue
    # 
    # Default behavior (if this section is not defined):
    # - Automatically clicks buttons via browser automation.
    # - Uses image recognition with PyAutoGUI.
    # - Optional OCR fallback if image recognition fails.
    # - wait_seconds = 2
    # 
    # Required: PyAutoGUI installation (pip install pyautogui pillow)
    # Optional: pytesseract installation required for OCR fallback
    # 
    # IMPORTANT: For safety, this feature is disabled by default.
    # You must explicitly enable it by setting assign_ci_failure_old / assign_deploy_pages_failure_old /
    # assign_good_first_old / assign_old in rulesets per repository.
    [assign_to_copilot]
    wait_seconds = 2  # Wait time in seconds after browser launch, before clicking button
    debug_dir = "debug_screenshots"  # Destination for debug info if image recognition fails (default: "debug_screenshots")
    confidence = 0.8  # Image matching confidence 0.0-1.0 (default: 0.8)
    enable_ocr_detection = true  # Enable OCR fallback (default: true)
    notification_enabled = true  # Display a small notification window at specified coordinates during automated button operation
    notification_message = "Opening browser and searching for Copilot assignment button..."  # Message for the notification window
    notification_width = 400
    notification_height = 150
    notification_position_x = 100
    notification_position_y = 100
    maximize_on_first_fail = true  # Maximize window and re-search if button not found on first attempt
    # enable_html_detection = false  # HTML detection fallback (experimental, default: false)
    
  4. Prepare Button Screenshots (Only if using automation):

    If using automation features (automated = true or enabling assign_to_copilot / phase3_merge), PyAutoGUI requires screenshots of the buttons to click.

    Required Screenshots:

    For automated issue assignment (assign_to_copilot feature):

    • assign_to_copilot.png - Screenshot of the “Assign to Copilot” button
    • assign.png - Screenshot of the “Assign” button

    For automated PR merging (phase3_merge feature with automated = true):

    • merge_pull_request.png - Screenshot of the “Merge pull request” button
    • confirm_merge.png - Screenshot of the “Confirm merge” button
    • delete_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 screenshots directory. 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.
    • Adjust the confidence setting for image recognition if needed (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 (entire screen at time of failure): {button_name}_fail_{timestamp}.png
      • Candidate region screenshots (if found): {button_name}_candidate_{timestamp}_{number}.png
      • Failure info JSON: {button_name}_fail_{timestamp}.json
        • Includes button name, timestamp, confidence threshold, screenshot path, template image path.
        • Candidate region information (coordinates, size, confidence).
    • For debugging, up to 3 candidate regions are detected with lower confidence (0.7, 0.6, 0.5).
    • The debug directory can be changed via the debug_dir option (within assign_to_copilot or phase3_merge sections).

    Fallback Mechanisms (if image recognition fails):

    • OCR Detection (enabled by default): Uses pytesseract to detect button text.
      • Directly detects text like “Assign to Copilot” on the screen.
      • Robust against sub-pixel rendering differences.
      • Required: tesseract-ocr installation (system-level).
      • Disable: enable_ocr_detection = false.

    Important Requirements:

    • Your default browser must already be logged into GitHub.
    • Automation uses existing browser sessions (it does not perform new authentication).
    • Ensure the correct GitHub window/tab is focused and visible on screen when buttons are clicked.
    • If multiple GitHub pages are open, the first button found will be clicked.

    Create the screenshots directory:

    mkdir screenshots
    
  5. Install PyAutoGUI (only if using automation):

    For basic image recognition only:

    pip install pyautogui pillow pygetwindow
    

    Including OCR fallback (recommended):

    pip install -r requirements-automation.txt
    

    If using OCR, install tesseract-ocr system-wide:

    • Windows: choco install tesseract
    • macOS: brew install tesseract
    • Linux: apt-get install tesseract-ocr

Execution

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

  1. Startup: The tool starts monitoring user-owned repositories for authenticated GitHub users.
  2. PR Detection: Automatically detects repositories with open PRs.
  3. Phase Determination: Determines the phase of each PR (phase1/2/3, LLM working).
  4. Action Execution:
    • phase1: Dry-run by default (if enable_execution_phase1_to_phase2 = true in rulesets, Draft PRs are changed to Ready status).
    • phase2: Dry-run by default (if enable_execution_phase2_to_phase3 = true in rulesets, a comment is posted asking Copilot to apply changes).
    • phase3: Opens the PR page in the browser.
      • If enable_execution_phase3_send_ntfy = true in rulesets, an ntfy.sh notification is also sent.
      • If enable_execution_phase3_to_merge = true in rulesets, the PR is automatically merged (using global [phase3_merge] settings).
    • LLM working: Waits (if all PRs are in this state, issues from repositories without open PRs are displayed).
  5. Automated Issue Assignment: If all PRs are “LLM working” and there are repositories without open PRs:
    • If assign_ci_failure_old = true in rulesets, the oldest “ci-failure” issue is automatically assigned (by issue number).
    • If assign_deploy_pages_failure_old = true in rulesets, the oldest “deploy-pages-failure” issue is automatically assigned (by issue number).
    • If assign_good_first_old = true in rulesets, the oldest “good first issue” is automatically assigned (by issue number).
    • If assign_old = true in rulesets, the oldest issue is automatically assigned (by issue number, any label).
    • Priority: ci-failure > deploy-pages-failure > good first issue > old issue.
    • Default behavior: Automatically clicks buttons via PyAutoGUI (the [assign_to_copilot] section is not required).
    • Required: PyAutoGUI installation and preparation of button screenshots are necessary.
  6. 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.
    • It reverts to the normal monitoring interval when a change is detected.

Dry-run Mode

By default, the tool operates in Dry-run mode and does not perform actual actions. This allows you to safely verify its operation.

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_ci_failure_old = true              # Auto-assign ci-failure issue
assign_deploy_pages_failure_old = true    # Auto-assign deploy-pages-failure issue
assign_good_first_old = true              # Auto-assign good first issue

To enable automatic pulling of local repositories, set it at the top level (outside of rulesets):

auto_git_pull = true  # Automatically git pull pullable local repositories

Stopping

You can stop monitoring with Ctrl+C.

Important Notes

Testing

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 by GitHub Actions using Gemini’s translation based on README.ja.md.

Big Brother is watching your repositories. Now it’s the cat. 🐱