Watch GitHub PR CI checks in the background and notify on completion. Use when: (1) User wants to monitor CI/CD status, (2) User says 'watch CI', 'check CI', 'monitor checks', or 'wait for CI', (3) User wants to know when checks pass or fail. Runs a background gh polling shell loop (NOT a subagent — near-zero token cost), sends macOS notification on completion. Also handles merged PRs by watching the target branch CI.
Watch GitHub PR CI checks in the background and notify on completion. Use when: (1) User wants to monitor CI/CD status, (2) User says 'watch CI', 'check CI', 'monitor checks', or 'wait for CI', (3) User wants to know when checks pass or fail. Runs a background gh polling shell loop (NOT a subagent — near-zero token cost), sends macOS notification on completion. Also handles merged PRs by watching the target branch CI.
Watch CI
Monitor GitHub PR CI checks in the background, notify on completion via macOS system notification.
Also supports watching CI on the merge target branch when a PR is already merged.
The polling itself is a pure shell loop (gh CLI + jq) launched via Bash with run_in_background: true. No subagent is spawned — token cost is paid only at launch and at completion, not on every poll cycle.
On Claude Code on the web ($CLAUDE_CODE_REMOTE=true): follow web/web-mode.md. gh is unavailable, so the gh-based poll scripts won't run — poll CI through the GitHub MCP instead (pull_request_read with get_check_runs, or actions_* / get_job_logs), or the Monitor tool. There is no macOS notifier on web; just report status when checks finish. When this watch is part of a -m merge flow (/pr-complete -c -w, or the Merge Mode of /x-as-pr / /x-wt-teams), follow web-mode.md §8: poll in-turn and block until the checks are terminal — Step 3's "launch a background poll and end the turn" model is terminal-only, because web has no background-task wakeup, so a background watch + turn-end would leave the merge unfired. Stay in the turn until terminal, then let the caller merge in the same run.
Scripts
scripts/notify.sh — macOS notification helper
scripts/poll-pr-checks.sh <pr-number> [max-min] — poll an open PR's checks until terminal, then notify
scripts/poll-runs.sh <branch> <commit-sha> [max-min] — poll workflow runs on a branch+commit until terminal, then notify
All scripts default to a 60-minute cap and a 30-second poll interval.
Workflow
Step 1: Identify the PR
Determine which PR to watch:
# If user provides a PR number or URL, use it directly# Otherwise, detect from current branch
gh pr view --json number,title,url,headRefName,baseRefName,state,mergeCommit --jq '{number,title,url,headRefName,baseRefName,state,mergeCommit}'
If no PR is found for the current branch, inform the user and stop.
Check the PR state:
If state is "OPEN" → proceed to Step 2 (normal PR watch)
If state is "MERGED" → proceed to Step 2b (merged PR: watch target branch CI)
If state is "CLOSED" (not merged) → inform the user the PR was closed without merging and stop
Report to the user: PR number/title, total checks, current status breakdown (passed/pending/failed).
If all checks already passed or failed, skip to Step 4 or Step 5 respectively. Otherwise proceed to Step 3.
Step 2b: Merged PR — Switch to Target Branch CI
When the PR is already merged:
Get the base branch and merge commit SHA from Step 1 output
Inform the user: "PR #123 is already merged into main. Watching CI on main for merge commit abc1234..."
Show initial status:
gh run list --branch <base-branch> --commit <merge-commit-sha> --json databaseId,name,status,conclusion --limit 20
If no runs found with commit SHA, retry without it:
gh run list --branch <base-branch> --json databaseId,name,status,conclusion --limit 10
Proceed to Step 3.
Step 3: Launch Background Poll (CLI-only, no subagent)
Do NOT launch a subagent. Use the Bash tool with run_in_background: true to run the polling shell script. The script polls gh directly, exits when checks reach a terminal state, fires a macOS notification, and prints a final RESULT: line.
After launching, tell the user: "Watching CI in background. You'll be notified when it completes."
When the background task completes you'll be notified automatically. Read its output file to see the RESULT: line, report to the user, and — if FAILED — proceed to Step 5's investigation steps.
Step 4: All Checks Passed (Foreground Fast Path)
If checks already passed at Step 2/2b (no polling needed):
Send notification:
bash $HOME/.claude/skills/watch-ci/scripts/notify.sh success "All CI checks passed! PR #<number>"
gh pr checks <PR_NUMBER> --json name,state,bucket,link --jq '[.[] | select(.bucket == "fail" or .bucket == "cancel")]'
gh run list --branch <branch> --status failure --limit 5 --json databaseId,name,conclusion
gh run view <run-id> --log-failed
Analyze and report. For open PRs: offer to fix. For merged PRs: report only, do NOT auto-fix on the target branch.
Notes
Polling is a pure shell loop run via Bash run_in_background: true — no subagent, no per-cycle token cost. The main conversation only pays at launch and at completion.
System notifications use macOS osascript via notify.sh
The gh CLI must be authenticated and have access to the repository
30-second polling interval balances responsiveness with API rate limits
Default cap 60 minutes; override with the optional [max-min] arg to either script
For merged PRs, watches workflow runs on the target branch filtered by merge commit SHA
The script's stdout (progress lines + final RESULT: line) is captured by the background task — read the output file when you get the completion notification