Proactive and schedule-driven; recomputes from GitHub's current state every
run, with no memory of the prior day's nudges.
Step 0 — Orient
# List every open PR across the configured repos.
gh pr list --repo {{target_repos}} --state open \
--json number,title,url,author,createdAt,updatedAt,reviewRequests,reviews,comments,commits
Fresh session, no ledger — recompute everything from this pull. Repeat per
repo if {{target_repos}} names more than one.
Step 1 — Pull the review detail per PR
gh pr view --repo {{target_repos}} <PR_NUMBER> \
--json number,title,url,author,createdAt,updatedAt,reviewRequests,reviews,comments,commits
reviews gives each review's state (APPROVED, CHANGES_REQUESTED,
COMMENTED) and timestamp; commits and comments give the last activity;
reviewRequests gives who's currently asked to review.
Step 2 — Flag PRs awaiting review past the SLA
For each PR with an outstanding reviewRequests entry and no APPROVED or
CHANGES_REQUESTED review from that reviewer since the request:
hours_waiting = now - max(createdAt, last review-request timestamp)
Flag if hours_waiting > {{review_sla_hours}}. Nudge target: the requested
reviewer(s).
Step 3 — Flag stale PRs
For every open PR, take the most recent of: last commit, last comment, last
review.
days_idle = now - max(last_commit, last_comment, last_review)
Flag if days_idle > {{stale_days}}. Nudge target: the author. A PR already
flagged in Step 2 can also be flagged here if it independently qualifies — the
two checks are separate signals, not mutually exclusive.
Step 4 — Flag unaddressed requested changes
For each PR whose most recent review is CHANGES_REQUESTED, check whether the
author has pushed a commit or posted a comment since that review's timestamp.
If not, flag it. Nudge target: the author.
| Check | Passes (no nudge) | Fails (nudge) |
|---|
| Overdue review | Reviewer submitted within SLA | No review after {{review_sla_hours}}h |
| Stale | Any activity within the window | No activity for {{stale_days}}d |
| Unaddressed changes | Author pushed/replied after the review | Silence since CHANGES_REQUESTED |
Step 5 — Write the nudge
For every PR that trips at least one rule, write one line: the PR title and
link, which rule(s) it tripped, and how long it's been in that state, e.g.
"Awaiting review 3d (SLA 24h) — @reviewer" or "Stale 6d, no activity — @author"
or "Changes requested 4d ago, not yet addressed — @author". A PR that trips
more than one rule gets one entry listing all of them, not a duplicate nudge
per rule.
Step 6 — Post to Slack
Post exactly one summary message to {{alert_channel}} for the whole sweep,
grouped by rule (overdue for review / stale / unaddressed changes), each entry
tagging the person it's nudging. This is a fresh session — there is no prior
list to diff against, so the whole sweep is recomputed and reposted every day.