Skip to content
Automation
Skill

/pr-watch

Event-driven GitHub PR watching. Use when the owner wants to be kept on top of pull requests: re-review a person's PRs whenever they change, follow up on any PR the owner has already reviewed, react when a review is requested from the owner, or note merges, closes and submitted

From plugin
sutando
40179 skills18 hooks

Claude Code

$ npx -y skills add sonichi/sutando --skill pr-watch --agent claude-code

SKILL.md

pr-watch.SKILL.md
name: pr-watch
description: "Event-driven GitHub PR watching. Use when the owner wants to be kept on top of pull requests: re-review a person's PRs whenever they change, follow up on any PR the owner has already reviewed, react when a review is requested from the owner, or note merges, closes and submitted or dismissed reviews, without polling and without a Monitor that expires after 30 minutes. A Claude Code mod runs `gh webhook forward` for each watched repo and turns each relevant event into a new turn of this session. Optionally keeps an HTML tracker page of the watched PRs in a configured Room Commons room."
user-invocable: true

pr-watch

Watches GitHub pull requests by event, not by polling. A Claude Code mod (a plugin of function hooks) starts `pr_watch.py run` when the session starts; the runner keeps one `gh webhook forward` per watched repo and prints one line per relevant event. Nothing polls GitHub, and nothing expires the way a `Monitor` does at 30 minutes.

How an event reaches the session depends on whether a turn is running:

  • **Idle:** the mod submits the event as a new prompt (`$.prompt.submit`), which starts a turn.
  • **Turn running:** a submitted prompt would only wait for the turn to end, so the mod holds the

event and attaches it to the next tool result of the main loop (the tool call's `context`, which the model reads right after that tool's output). Events still held when the turn ends are submitted together as one prompt. Subagents' tool calls never carry them.

When to use it

  • "Re-review Alice's PRs whenever she pushes", "tell me when Bob's PR merges".
  • "Ping me when someone requests my review on acme/widgets."
  • "Keep an eye on every PR I've reviewed there, whoever wrote it."
  • Any standing PR watch that should survive past one Monitor window.

Not for one-off checks of a single PR: read it with `gh pr view` instead.

Events forwarded

Per watched repo (`config.json`), filtered by `pr_watch.py`:

| Event | Forwarded when | Line | |---|---|---| | `pull_request` `opened`, `synchronize`, `reopened`, `ready_for_review`, `closed` | the PR author is a watched `--author` (`*` = anyone) | `PR_EVENT o/r#N <action> author=… head=<sha8> merged=true\|false reason=author` | | `pull_request` `synchronize`, `reopened`, `ready_for_review`, `closed` | the watch has `--reviewed` and one of the `--me` logins has submitted a review on the PR, whoever wrote it | `PR_EVENT o/r#N <action> author=… head=<sha8> merged=… reason=reviewed` | | `pull_request` `review_requested` | the requested reviewer is one of the `--me` logins, on any PR in the repo | `PR_EVENT o/r#N review_requested reviewer=… author=… head=…` | | `pull_request_review` `submitted` | on a watched author's PR, by someone other than the `--me` logins (the owner's own review echoing back is dropped, though it still marks the PR reviewed) | `PR_EVENT o/r#N review_submitted by=… state=approved\|changes_requested\|commented author=… head=…` | | `pull_request_review` `dismissed` | the dismissed review is by one of the `--me` logins, on any PR in the repo | `PR_EVENT o/r#N review_dismissed reviewer=… author=… head=…` |

An event matching both the author rule and the reviewed rule yields one line, `reason=author`. The webhook payload does not list a PR's reviewers, so the reviewed rule asks `GET repos/{repo}/pulls/{n}/reviews` (see Costs). When that call fails or times out (10 s), the event is forwarded anyway with `reason=reviewed reviewed=unknown`, never dropped.

Only logins, numbers, states and short shas reach the prompt; titles and bodies never do, so a PR's text cannot steer the session. The agent reads the PR itself when it acts. (The runner does store each PR's title in `tracker.json` for the tracker page's About column; see Tracker.)

Requirements

  • `gh`, signed in, with **admin** on every watched repo (creating a webhook needs it).
  • The `cli/gh-webhook` extension. Installing it is a download, so **ask the owner first**, then

`gh extension install cli/gh-webhook`. Without it the runner prints a `PR_WATCH_NOTE` and exits.

  • `python3` (standard library only).

Setup

S=skills/pr-watch/scripts/pr_watch.py
python3 $S add --repo acme/widgets --author alice --author bob --me owner-login
python3 $S add --repo acme/gadgets --me owner-login --reviewed   # every PR owner-login reviewed
python3 $S install-mod --mods-dir "<the session's mods folder>"

`install-mod` writes the mod into `<mods-dir>/pr-watch/` and copies the runner (and `manifest.json`, for its settings) to `<workspace>/state/pr-watch/`, so the forwarder keeps working when the engine checkout changes branch or updates. Re-run it after updating this skill.

Loading the mod is the owner's one step: **enable hot reload of the mods folder in the session's terminal** (one click), or start the session with `claude --plugin-dir <mods-dir>/pr-watch`. Never enable it for them.

Other commands:

python3 $S list                    # the watch config
python3 $S remove --repo acme/widgets
python3 $S status                  # runner, forwarders, recorded hook ids
python3 $S cleanup                 # delete the hook ids this skill recorded (refused while a runner is active; --force)
python3 $S tracker-kind --kind html-<id> --room '!room:server'   # the page a session publish wrote to

`add` and `remove` signal a running runner (SIGHUP), which starts or stops that repo's forwarder without a reload.

Configuration

The watches live in `<workspace>/state/pr-watch/config.json`, written by `add` and `remove`:

{
  "watches": [{"repo": "acme/widgets", "authors": ["alice"], "me": ["owner-login"], "reviewed": true}],
  "settings": {"PR_WATCH_TRACKER_ROOM": "!room:server"}
}

`reviewed` (set by `add --reviewed`) needs at least one `me` login other than `*`.

The skill's settings are declared, with their defaults, in the `config` block of `manifest.json` (see `skills/MANIFEST.md`, "Config-only manifests"):

| Key | D

Read more
@sonichi
Ships withsutando

My AI Stand — Realtime by Day, Rewriting Itself by Night. Summon my AI superpower. Voice, vision, screen, meetings, calls when I'm engaged. Learns my patterns, ships its own code when I'm not. Runs across my Macs, interacts with people & their Stands.

Stars on GitHub

Momentum

stars in total
401
Star history of sonichi/sutando on GitHub, a chart by star-history.com

Other skills on sutando.

More skills from other plugins.

agent-builder
Skill

agent-builder

Load immediately after an Agent intent, before the first agent_builder_* call. Governs how you create, configure, test, and…

n8n1d209k
@n8n-io@n8n-ioInstall Skill

Questions about pr-watch.

Which coding agents can use pr-watch?
pr-watch installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.