| name | monitor-ci |
|---|---|
| description | Use when waiting for CI checks to complete on a PR, polling for new review comments after a push, or monitoring GitHub Actions status. Triggers on "wait for CI", "check bugbot", "monitor PR", "poll for comments", "wait for checks". |
Poll a GitHub PR for new review comments and check completion. Reports as soon as new threads appear or all checks finish — distinguishing between passed and failed checks.
Invoke with: /monitor-ci <owner/repo> <pr-number>
If owner/repo is omitted, infer from the current git remote. If pr-number is omitted, infer from the current branch.
Run a background Bash command that polls every 30 seconds:
- Snapshot the current review thread count and commit SHA
- Every 30s, check for new unresolved review threads
- Also check if all CI checks on the HEAD commit have completed
- Exit and notify as soon as either:
- New review threads are detected
- All checks complete with no new threads
Run this as a background Bash command so the user can keep working:
# Resolve owner/repo and PR number
REPO="<owner/repo>"
PR=<number>
HEAD_SHA=$(gh pr view $PR --repo "$REPO" --json headRefOid --jq '.headRefOid')
# Snapshot current state
INITIAL_THREADS=$(gh api graphql -f query="
{
repository(owner: \"${REPO%%/*}\", name: \"${REPO##*/}\") {
pullRequest(number: $PR) {
reviewThreads(first: 100) { totalCount }
}
}
}" --jq '.data.repository.pullRequest.reviewThreads.totalCount')
echo "Monitoring PR #$PR ($REPO) | commit: ${HEAD_SHA:0:7} | threads: $INITIAL_THREADS"
while true; do
sleep 30
# Check for new threads
NEW_THREADS=$(gh api graphql -f query="
{
repository(owner: \"${REPO%%/*}\", name: \"${REPO##*/}\") {
pullRequest(number: $PR) {
reviewThreads(first: 100) { totalCount }
}
}
}" --jq '.data.repository.pullRequest.reviewThreads.totalCount' 2>/dev/null)
if [ -n "$NEW_THREADS" ] && [ "$NEW_THREADS" != "$INITIAL_THREADS" ]; then
DIFF=$((NEW_THREADS - INITIAL_THREADS))
echo "NEW COMMENTS: $DIFF new thread(s) (was $INITIAL_THREADS, now $NEW_THREADS)"
break
fi
# Check if all checks completed — use gh pr checks which handles encoding safely
CHECK_STATUS=$(gh pr checks $PR --repo "$REPO" --json name,state,bucket 2>/dev/null)
if [ -z "$CHECK_STATUS" ]; then
continue
fi
TOTAL=$(echo "$CHECK_STATUS" | jq 'length')
PENDING=$(echo "$CHECK_STATUS" | jq '[.[] | select(.bucket == "pending")] | length')
if [ "$TOTAL" -gt 0 ] && [ "$PENDING" = "0" ]; then
FAILED=$(echo "$CHECK_STATUS" | jq -r '[.[] | select(.bucket == "fail")] | .[] | " FAILED: \(.name)"')
FAILED_COUNT=$(echo "$CHECK_STATUS" | jq '[.[] | select(.bucket == "fail")] | length')
PASSED_COUNT=$(echo "$CHECK_STATUS" | jq '[.[] | select(.bucket == "pass")] | length')
# Check for new threads one final time
FINAL_THREADS=$(gh api graphql -f query="
{
repository(owner: \"${REPO%%/*}\", name: \"${REPO##*/}\") {
pullRequest(number: $PR) {
reviewThreads(first: 100) { totalCount }
}
}
}" --jq '.data.repository.pullRequest.reviewThreads.totalCount' 2>/dev/null)
NEW_THREAD_MSG=""
if [ "$FINAL_THREADS" != "$INITIAL_THREADS" ]; then
DIFF=$((FINAL_THREADS - INITIAL_THREADS))
NEW_THREAD_MSG=" | $DIFF new comment thread(s)"
fi
if [ "$FAILED_COUNT" -gt 0 ]; then
echo "CHECKS FAILED: $FAILED_COUNT failed, $PASSED_COUNT passed out of $TOTAL${NEW_THREAD_MSG}"
echo "$FAILED"
echo ""
# Fetch logs for failed GitHub Actions runs
FAILED_RUNS=$(gh run list --repo "$REPO" --commit "$HEAD_SHA" --status failure --json databaseId,name --jq '.[] | "\(.databaseId)\t\(.name)"' 2>/dev/null)
if [ -n "$FAILED_RUNS" ]; then
echo "$FAILED_RUNS" | while IFS=$'\t' read -r RUN_ID RUN_NAME; do
echo "--- Failed: $RUN_NAME (run $RUN_ID) ---"
gh run view "$RUN_ID" --repo "$REPO" --log-failed 2>/dev/null | tail -80
echo ""
done
fi
break
elif [ -n "$NEW_THREAD_MSG" ]; then
echo "NEW COMMENTS: ${NEW_THREAD_MSG# | } (all $TOTAL checks passed)"
break
else
echo "ALL CLEAR: $TOTAL/$TOTAL checks passed, no new comments."
break
fi
fi
doneWhen the monitor reports back:
- CHECKS FAILED: Fetch the failed check logs, diagnose the failures, and report them to the user. If fixable, fix, commit, push, then re-invoke
/monitor-ci. - NEW COMMENTS: Fetch and display unresolved threads, fix issues, commit, push, then re-invoke
/monitor-ci - ALL CLEAR: CI is green with no new review findings. Inform the user.
gh api graphql -f query='
{
repository(owner: "OWNER", name: "REPO") {
pullRequest(number: PR) {
reviewThreads(first: 30) {
nodes {
id
isResolved
comments(first: 1) {
nodes { body }
}
}
}
}
}
}' --jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)]
| .[] | "\(.id)\n\(.comments.nodes[0].body | split("<!-- DESCRIPTION START -->") | .[1] // "" | split("<!-- DESCRIPTION END -->") | .[0] // .comments.nodes[0].body[0:200])\n==="'gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: "THREAD_ID"}) { thread { isResolved } } }'