| description | Monitor a GitHub PR and Jira ticket for new reviewer feedback. Evaluates each comment against the original PR scope and actively flags scope creep. |
|---|---|
| argument-hint | <github-pr-url> [jira-ticket] [interval, e.g. 30m or 1h] |
Watch a GitHub PR and (optionally) a Jira ticket for new reviewer comments and review changes. For every piece of feedback received, assess whether it is in scope, scope creep, or needs clarification — and present a clear, opinionated verdict so the author never has to fight that battle alone.
Before starting, check which of these are available in the session and use them proactively throughout:
- Jira (
mcp__claude_ai_Atlassian__*) — fetch issue details, post comments, create follow-up tickets - Slack (
mcp__claude_ai_Slack__*) — read CI notification channels (e.g.#ios-builds,#android-builds) for build results; post to channels when requested. When sending messages, follow the messaging convention defined in your globalCLAUDE.md. - Bitrise API — trigger builds, poll build status, retrieve build artifacts. Base URL:
https://api.bitrise.io/v0.1. Auth token may be in$SKOOVE_BITRISE_TOKEN,$BITRISE_API_TOKEN, or similar. Always checkenv | grep -i bitrisebefore telling the user you can't trigger a build. - GitHub CLI (
gh) — PR/issue management, branch operations
Parse $ARGUMENTS to extract:
github_pr_url— a full GitHub PR URL, e.g.https://github.com/org/repo/pull/123. Parseowner,repo, andpr_numberfrom it. Never infer the repo from the current working directory — always require the URL so this works across repos.jira_ticket— optional; a Jira key likeLEARN-1961.interval— optional; defaults to30m. AcceptNm,Nh, or plain integers (treated as minutes).
If no URL is provided (or if a bare PR number is given without a repo), stop and print:
Usage: /pr-monitor <github-pr-url> [jira-ticket] [interval]
Example: /pr-monitor https://github.com/org/repo/pull/42 PROJ-123 1h
Establish the scope baseline before starting the loop.
- Fetch the PR using
gh pr view <pr_number> --repo <owner>/<repo> --json title,body,baseRefName,headRefName. - Extract the PR title and body. If the body is empty, use the title only.
- Look for a plan/design doc in the repo to ground the scope. A PR description is often a one-liner; the real intent — phases, explicit non-goals, decision log, what's deferred to follow-ups — usually lives in a plan file on the branch. This context sharpens every scope verdict (especially what is intentionally out of scope), so do it on first run before judging any feedback:
- Search the checked-out branch under
docs/for plan/design docs:git ls-files 'docs/**/*plan*.md' 'docs/**/*.md' | grep -iE 'plan|design|spec|epic|decision'. Also check the PR body for a linked plan path or Confluence/Jira link. - If the PR body or branch name references a Jira key, the linked ticket and its plan doc are the most authoritative scope sources — prefer them over inference.
- If one or more plausible plan docs exist, read the most relevant (match by ticket key / feature name / branch). Extract the stated goals, non-goals / out-of-scope list, phase boundaries, and any "deferred to follow-up" notes. Fold these into the scope statement.
- If none exist, proceed with the PR title/body alone — don't block on it.
- Search the checked-out branch under
- Summarise the PR's intent in 1–3 sentences (the "scope statement"), incorporating the plan doc's goals and explicit non-goals. Store this mentally — every piece of feedback will be judged against it. When a plan doc named a non-goal, treat requests for that work as 🚧 by default and cite the plan.
- Note the current timestamp as
last_checked(ISO 8601).
Print the scope statement to the user before starting the loop so they can correct it if wrong. Name the plan doc you grounded it in (or say none was found), so the user can point you at the right one:
Scope: <your one-liner>
Grounded in: <plan-doc-path or "PR description only — no plan doc found">
Non-goals: <out-of-scope items from the plan, if any>
Watching github.com/<owner>/<repo>#<pr_number> (and JIRA-XXX) every <interval>. Ctrl-C to stop.
Implement the loop body directly here and call ScheduleWakeup at the end of each turn to self-pace at interval. Do not delegate to /loop.
Step 0 — Sync the PR branch FIRST (before evaluating or acting). 🚨 CRITICAL — never skip.
Comments are not the only thing that changes between iterations: the author, reviewers, or co-authors push commits to the PR branch too. The API calls below see new comments but not new code. If you evaluate or implement against a stale local checkout you will duplicate work someone already did and/or create merge conflicts. So, every iteration, before anything else:
- Read the PR head:
gh pr view <pr_number> --repo <owner>/<repo> --json headRefName,headRefOid→head_branch,head_sha. - Compare against what you last saw. If
head_shadiffers from the previous iteration'shead_sha(or your local branch tip), someone pushed commits — surface it to the user ([HH:MM] ⚠️ <branch> moved: <N> new commit(s) by <authors> since last check) and inspect them (gh pr view,git log --oneline <prev_sha>..<head_sha>,git show <sha>). A reviewer who left a comment may have also pushed the fix — re-check before you act on that comment. - If you have a local checkout you will act in (the usual case — you implement ✅ fixes here):
git fetch origin <head_branch>, then integrate before touching anything —git merge --ff-only origin/<head_branch>when you have no local commits, otherwisegit rebase origin/<head_branch>(or stop and tell the user if it won't apply cleanly). Verifygit rev-parse HEAD==head_shabefore implementing any change. If you have no local checkout, you can still detect/inspect new commits via the API but must NOT attempt a local fix without first obtaining a synced checkout onhead_branch. - Store
head_shaas the new baseline for the next iteration's comparison.
Skipping this once is enough to redo a teammate's just-pushed commit — treat it as mandatory.
Step 1 — Fetch new activity
Run in parallel:
gh api "repos/<owner>/<repo>/pulls/<pr_number>/comments" --paginate— inline review comments (each hasid,user.login,body,created_at)gh api "repos/<owner>/<repo>/issues/<pr_number>/comments" --paginate— top-level PR comments (same shape)gh api "repos/<owner>/<repo>/pulls/<pr_number>/reviews" --paginate— review submit eventsgh pr view <pr_number> --repo <owner>/<repo> --json state,author— PR state + author login- If
jira_ticketis set: callmcp__claude_ai_Atlassian__getJiraIssuewithfields: ["comment","status"] - If a Bitrise build was previously triggered: poll its status via
GET https://api.bitrise.io/v0.1/apps/<app_slug>/builds/<build_slug>(auth: Bitrise token from env). On completion, check the relevant CI notification Slack channel (search for#ios-builds,#android-builds, or similar) for the new artifact hash/tag, then update the downstream dependency reference (e.g.dependencies.txt) automatically.
Store each comment's id and user.login — you will need them for threaded replies.
Filter to items created after last_checked. If nothing is new, print:
[HH:MM] No new activity.
and reschedule.
Step 2 — Evaluate each new item
For each new comment or review, apply the scope filter below and assign one of four verdicts:
| Verdict | Meaning |
|---|---|
| ✅ Actionable | In scope, clear, implementable. Should be addressed. |
| 🔍 Clarification needed | Possibly valid but too vague to act on without a question. |
| 🚧 Scope creep | Asks for work outside the PR's stated goal. Resist. |
| 💬 Acknowledged | Opinion / nit / praise with no required action. |
Scope filter — questions to ask for each comment:
- Does the requested change relate to code that this PR already touches, or to a new area? — If new area → lean 🚧.
- Does the request add new behaviour, new APIs, or new requirements not mentioned in the PR description or linked Jira ticket? — If yes → 🚧 unless trivial (one line).
- Could this comment be addressed in a follow-up ticket without blocking merge? — If yes and the change is non-trivial → 🚧.
- Is the feedback specific enough to implement without a design discussion? — If no → 🔍.
- Is the comment a general observation, style preference, or compliment with no clear ask? — 💬.
Anti-scope-creep heuristics (flag these proactively):
- "While you're at it, could you also…" → almost always 🚧
- Requesting a full refactor of unchanged code → 🚧
- Adding tests for code not touched by this PR → 🚧 (unless the PR is a test PR)
- Architecture / design suggestions that require consensus → 🔍 first, 🚧 if the author didn't invite them
- Changing behaviour beyond what the PR description describes → 🚧
Step 3 — Act on each new item
Process items in verdict order: ✅ first, then 🔍, then 🚧/💬.
Posting comments — rules that apply to every verdict:
- Thread replies: For inline review comments, reply in-thread using
gh api "repos/<owner>/<repo>/pulls/<pr_number>/comments" --method POST --field body="..." --field in_reply_to=<comment_id>. For top-level issue comments, post togh api "repos/<owner>/<repo>/issues/<pr_number>/comments" --method POST --field body="..."(GitHub has no threading for these). - @-mention: Open the comment with
@<commenter-login>so the reply is directed at them. - Always link code you reference. Whenever you name a file, function, class, or specific lines, make it a clickable GitHub permalink — never a bare path or "line 34". Optimize for the reader: they should reach the exact code in one click without hunting.
- Format:
[\RouteServiceProvider.php:34-51`](https://github.com///blob//#L34-L51). Use a line range (#L34-L51) when pointing at a block, a single anchor (#L34`) for one line. - Pin to a commit SHA, not a branch. Branch links (
/blob/develop/…) drift as the file changes and silently point at the wrong lines later. Get the SHA the lines actually live at —git rev-parse HEADfor your just-pushed code, or the comment'soriginal_commit_idwhen replying about the diff. (On GitHub you'd pressyto canonicalise a URL; do the equivalent by hand.) - When you cite a commit (e.g. "Fixed in
8ec0e77"), link it too:[\8ec0e77`](https://github.com///commit/8ec0e77)`. - Verify the path and line numbers against the file at that SHA before posting — a confidently-wrong line link is its own small credibility hit.
- Format:
- Attribution: Close every comment with a blank line followed by
_— [Claude Code](https://claude.ai/code), acting on behalf of @<pr-author>_. This makes it unambiguous that an AI agent posted this, not the author. - For Jira comments, append
_(Posted by Claude Code on behalf of <author-email>)_at the end.
✅ Actionable — three-step response:
-
Acknowledge immediately by posting a comment on the PR (following the rules above) or Jira (via
mcp__claude_ai_Atlassian__addCommentToJiraIssue):"@<commenter> On it — fixing now.
— Claude Code, acting on behalf of @<pr-author>"
-
Implement the fix. First re-confirm you are on the latest head (Step 0 —
git fetch+ verifygit rev-parse HEAD== the PRheadRefOid); if commits arrived since you read the comment, re-check whether the fix is still needed — a collaborator may have already pushed it. Then make the code change and commit it. If the fix is ambiguous, state your interpretation in the commit message and proceed. Only pause if the change requires a design decision the author must make — in that case, say so in the acknowledgment comment and propose the two options. If the fix requires a new CI/Bitrise build, trigger it via the API (checkenv | grep -i bitrisefirst — never ask the user to do this manually if a token is available). -
Post a follow-up comment (in the same thread) once the commit is pushed:
"@<commenter> Fixed in
<short-sha>: [one sentence describing what changed].— Claude Code, acting on behalf of @<pr-author>"
🔍 Clarification needed — answer it, don't defer it:
Do not draft a question for the author to post later. Instead:
- Read the relevant code to find the answer.
- Post the answer directly as a threaded PR/Jira comment, following the posting rules above.
- If the question implies a legitimate concern (e.g. "Is this thread-safe?"), treat it as ✅ and fix the underlying issue; the answer in the comment should reference the fix.
Verify before you assert — never bluff in the author's voice. Every comment is posted on the author's behalf, so a confident-but-wrong claim damages their credibility, not yours. Before stating anything as fact:
- Cite ground truth with a link — never assert from memory. Every factual or implementation claim must trace to something you checked this session and can link to inline: a file/config you read (repo permalink), or, for how a header/library/framework/protocol behaves, its authoritative source — the upstream source code or the official documentation / RFC. Training-data recall is not a source; quoting framework behaviour from memory ("X-Real-IP is set by Nginx to the client IP") is exactly how the earlier
x-real-ipmistake happened. If you're inferring rather than verifying, say so ("I believe… but haven't confirmed"). - Infrastructure/runtime behaviour usually can't be verified from the repo — Nginx/LB/proxy headers, what's set in prod, DNS, env-specific config. When a point turns on this and you have no citable source, do not assert it: surface it to the author (via AskUserQuestion or a flagged note) instead. This is the one exception to "answer it, don't defer it."
- "It already works elsewhere, so it must be correct" is not proof. Existing code can be quietly relying on a fallback, dead code, or broken-but-harmless. Trace why it works before citing it as precedent.
- When a reviewer pushes back on a claim the bot made, re-examine honestly — do not double down. Re-derive from the code. If the reviewer is right, concede plainly ("You're right, my earlier reply was wrong"), correct it, and fix the code. Reviewers are often domain experts on their own infra; weight that heavily.
🚧 Scope creep — decline politely and immediately:
Post a threaded comment (following the posting rules above):
"@<commenter> Thanks for the suggestion — I'll track this as a follow-up ticket to keep this PR focused on [scope statement].
— Claude Code, acting on behalf of @<pr-author>"
Do not implement anything. Do not say "we could look at this later in the PR."
💬 Acknowledged — no reply needed unless the comment is a direct question, in which case treat as 🔍.
Print a local summary to the terminal after processing all items:
─────────────────────────────────────────
[HH:MM] 3 new items processed
✅ Fixed: "toggle label color off-state" → abc1234
🔍 Answered: "why resolveThemeColor not TypedValue?" → commented
🚧 Declined: "refactor BarsSceneView while you're at it"
─────────────────────────────────────────
Step 4 — Update last_checked to now.
Step 5 — Reschedule using ScheduleWakeup with delaySeconds derived from interval (convert minutes to seconds). Pass the original /pr-monitor $ARGUMENTS as the prompt so the loop resumes with full context on next fire.
Omit the ScheduleWakeup call when:
- The PR is merged or closed (
gh pr view <pr_number> --repo <owner>/<repo>showsstate: MERGEDorCLOSED) - The Jira ticket moves to Done / Closed status
- The user types
/cancel-pr-monitor(not yet implemented — they can just close the session or cancel the cron job shown at startup)
When stopping, print:
github.com/<owner>/<repo>#<pr_number> is <MERGED/CLOSED>. Monitor stopped.
- Be direct and opinionated about scope — "this is scope creep" beats "this might potentially be considered outside scope". But be humble about facts: confidence on scope judgements, never on unverified technical claims (see "Verify before you assert" above). A wrong fact posted in the author's voice is worse than no comment.
- Default to protecting the author from gold-plating and reviewer overreach.
- Never suggest implementing a 🚧 item in the current PR — always suggest a follow-up ticket.
- Keep output compact. Skip items with verdict 💬 unless the user hasn't seen any output yet this session.
/pr-monitor https://github.com/Learnfield-GmbH/skoove-trainer/pull/53 LEARN-1961 1h
/pr-monitor https://github.com/Learnfield-GmbH/skoove-serverless-api/pull/12 30m
/pr-monitor https://github.com/Learnfield-GmbH/wynton-ios/pull/7