watch command
Watch a PR's CI to completion — diagnose on red, notify and offer the merge on green. Never auto-merges.
/ca:watch$ca-watch/ca-watchAvailability is read from each shipped host catalog. Preview-only commands are marked on the page.
What it does
Section titled “What it does”Watches a pull request’s CI checks to completion without polling by hand. The wait is a real
server-side block (gh pr checks <PR> --watch), so it costs nothing while checks run — arbiter is
re-invoked exactly once, when that process exits, not on a timer. On red, it retrieves the failing
job’s logs and acts at a configured depth: propose names the likely cause and proposes a fix
without touching any tracked file (the fix itself routes through /ca:fix or /ca:feature);
branch additionally opens an unmergeable spike/fix-* branch carrying the proposed change for
review, leaving the default branch untouched. On green, it notifies and presents the merge command
as an offer — it never runs gh pr merge itself.
CODEARBITER_BABYSIT (default off) governs whether /ca:pr auto-attaches a watcher to the PR it
opens; /ca:watch <PR> itself works ad-hoc regardless of that flag.
/ca:watch <PR number | url | branch>Defaults to the current branch’s PR when the argument names none of those.
Example
Section titled “Example”> /ca:watch 231
watching PR #231 checks... (gh pr checks 231 --watch)[blocks server-side until every check finishes]
All checks passed.Ready to merge: gh pr merge 231 --squash --delete-branchRun it? (this command will not run it for you)When to reach for it
Section titled “When to reach for it”Open the PR first with /ca:pr; apply a fix for a diagnosed red with /ca:fix or /ca:feature;
review a diff without watching CI with /ca:review.
| Gate | When | Effect |
|---|---|---|
| no auto-merge | CI turns green | notifies and offers the ready-to-run merge command; never runs it itself |
| default-branch merge | the offered merge targets the default branch | routes through the merge-to-default hard gate — the offer cannot bypass it |
Related
Section titled “Related”Compatibility
Section titled “Compatibility”This compatibility route remains available for existing workflows. Use pr --watch for new work.
Source
Section titled “Source”Source — plugins/ca/commands/watch.md (v2.18.2)
---description: Watch a PR's CI to completion — diagnose on red, notify and offer the merge on green. Never auto-merges.argument-hint: "<PR number | url | branch>"---
# /ca:watch — PR CI babysitter
<!-- catalog-compatibility-notice:start -->> Compatibility route. Prefer `/ca:pr --watch` for new usage. This installed route remains> functional under the command-route compatibility policy at ${CLAUDE_PLUGIN_ROOT}/includes/command-compatibility.md;> continue with the unchanged watcher workflow below.<!-- catalog-compatibility-notice:end -->
Watch a pull request's checks to completion without babysitting them by hand. Thewait happens server-side, so it costs nothing while CI runs; arbiter wakes once, onthe verdict — diagnoses a red, or offers you the merge on a green. Arbiter neverpulls the merge trigger.
## Precondition
Requires the GitHub CLI authenticated (`gh auth status`). If `gh` is absent orunauthenticated, report the precondition failure naming `gh` and STOP — do not starta phantom watcher.
## Flow
1. **Resolve the PR** from `$ARGUMENTS` (number, URL, or branch; default to the current branch's PR).2. **Watch to completion** — run the watch as a **detached background task** built on the server-side block: ``` gh pr checks <PR> --watch ``` This blocks until every check finishes and then exits non-zero on failure. It is NOT a polling loop — there is no interval-based wake-up. Arbiter is re-invoked once when the watch process exits.3. **On red** — retrieve the failing job's logs (`gh run view --log-failed` / `gh pr checks`) and act at the configured depth. Resolve that depth with the canonical resolver rather than reading the env var by hand (so the accepted values can't drift). Resolve the interpreter once by presence — `PY=python3; { command -v python3 >/dev/null 2>&1 && python3 --version >/dev/null 2>&1; } || PY=python` — never `python3 X || python X`, which reruns X on any nonzero exit (#577): ``` "$PY" "${CLAUDE_PLUGIN_ROOT}/hooks/babysit.py" --root "${CLAUDE_PROJECT_DIR}" ``` It prints one JSON line; act at its `on_red` value (`CODEARBITER_BABYSIT_ONRED`, default `propose`): - **`propose`** — name the likely cause and propose a concrete fix. Do NOT edit any tracked file; applying the fix routes through `/ca:fix` or `/ca:feature`. - **`branch`** — additionally open a `spike/fix-*` branch carrying the proposed change for review. That branch is a spike: it can never PR or merge. The default branch is left untouched.4. **On green** — notify the user and present a merge **offer** (the `gh pr merge` command, ready to run). The watcher itself NEVER merges. If the PR targets the default branch, the merge routes through the merge-to-default hard gate — the offer cannot bypass it.
## On/off
A global flag, `CODEARBITER_BABYSIT` (default **off**, mirrors `CODEARBITER_PRUNE`),governs auto-attachment: when on, `/ca:pr` auto-attaches a watcher to the PR itopens. `/ca:watch <PR>` works ad-hoc regardless of the flag. The flag is never set onthe user's behalf — enabling it is the user's explicit choice. Both the command andthe flag are dormant in a repo without `arbiter: enabled`.
## When NOT to use
- Open the PR first → `/ca:pr`.- Apply a fix for a diagnosed red → `/ca:fix` (or `/ca:feature`).- Review a diff without watching CI → `/ca:review`.
## Hard gate
- MUST NOT auto-merge. Green → notify + offer only; the watcher never invokes `gh pr merge`.- A merge into the default branch MUST route through the merge-to-default hard gate — the green offer cannot and does not bypass it.- MUST NOT implement a polling loop that re-invokes the model on a timer — the watch is the server-side `gh pr checks --watch` block.- MUST surface a missing/unauthenticated `gh` as a precondition failure, not a silent no-op.- At depth `propose` MUST NOT edit any tracked file; at depth `branch` the proposed change lands only on an unmergeable `spike/fix-*` branch.