ci-watch
Watch GitHub Actions CI correctly with the gh CLI — block until a run / PR check rollup is TRULY terminal, then trust the exit code.
Skill by nubjs
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/nubjs-ci-watch
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: backend, devops, writing, productivity, ci-cd, version-control
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/ci-watch
What's inside
- Skill name
ci-watch- Description
- Watch GitHub Actions CI correctly with the gh CLI — block until a run / PR check rollup is TRULY terminal, then trust the exit code. Invoke (via the Skill tool) whenever you need to wait on CI after REQUESTING a pull-request run (`gh pr edit <n> --add-label ci` — PR CI is opt-in, so a push starts nothing), after a push to main, or after a tag, and act on the result (merge-on-green, release-on-green, fail-fast on red). Encodes the premature-exit pitfall (raw `gh run watch` / `gh pr checks --watch` exit 0 while the run is still QUEUED with no jobs registered, and exit non-zero on a transient API blip) and the blessed fix: `scripts/ci-watch.ts`, which waits for the target to EXIST, polls authoritative terminal status, fails fast on the first failing check, and exits with a status the orchestrator can trust. Run it as a detached run_in_background task.
- License
- MIT
- Metadata
- internal: true
- Instructions
- 90 lines in SKILL.md · view on GitHub
Agent Skills spec issues
- files: referenced but missing: scripts/ci-watch.ts, scripts/merge-cascade.ts, scripts/lib/ci-rollup.ts
Files (1)
- SKILL.md
SKILL.md (first lines)
# Watching CI with the GitHub CLI
## The pitfall: raw watchers exit early
`gh run watch <id> --exit-status` and `gh pr checks <pr> --watch` are not safe to arm right after a push / tag / PR-open:
- **Premature exit while QUEUED.** With no jobs registered yet, gh sees "nothing in progress" and returns **exit 0** even though the run is still queued.
- **Transient errors read as failure.** A mid-watch `HTTP 401: Bad credentials` (token refresh) or a 5xx exits non-zero, indistinguishable from a real CI failure.
- **No native fix** — `--interval` only tunes the poll cadence.
**Never trust a raw watcher's exit code alone.** Re-verify terminal status with `gh run view <id> --json status,conclusion` (done only when `status == "completed"`) or `gh pr view <pr> --json statusCheckRollup` (done only when every item is terminal). And always fail-fast — act on the first failing check, never wait for all checks to finish.
## The blessed tool: `scripts/ci-watch.ts`
Blocks until the target is truly terminal, then exits with a trustworthy status. Dogfoods nub; runs under plain Node too.
```bash
nub scripts/ci-watch.ts --run <run-id> [--repo o/r] [--timeout <min>]
node scripts/ci-watch.ts --pr <number> [--repo o/r] [--timeout <min>]
```
- `--run <run-id>` — watch a workflow run (polls `gh run view --json status,conclusion,jobs`).
- `--pr <number>` — watch a PR's check rollup (polls `gh pr view --json statusCheckRollup,…`).
- `--repo <owner/repo>` — defaults to the current repo.
- `--timeout <minutes>` — wall-clock cap before giving up as pending (default 45).
- `--required <names>` — comma-separated branch-protection check names to gate on (e.g. `--required "CI gate"`). Success fires the instant every required check is green; a ghost or a non-required check — pending *or* failed — never blocks, matching branch-protection semantics. Prefer it when you know the required check name.
- `--no-progress <minutes>` — how long an unchanged incomplete set (all named checks green, only a ghost left) may sit before exiting 4 STUCK-but-safe (default 8).
What it fixes: **waits for the target to EXIST** (not-found / no-jobs-yet is "keep polling," never "done"); polls authoritative terminal state; **fails fast** on the first FAILURE/CANCELLED/TIMED_OUT/ STARTUP_FAILURE; **never hangs on a ghost**; **tolerates transient** gh/API errors (retried with exponential jittered backoff, 10s → cap 60s, 90s unauthenticated).
### The ghost check — why a strict "all checks terminal" gate hangs
GitHub occasionally registers a check-run that never reports a status: PENDING, nameless, forever. A watcher waiting for *every* rollup item to be terminal blocks indefinitely even though every real check is green. So a nameless / never-terminating non-required check does not block a green verdict: once every named check is green and the incomplete set has been unchanged for `--no-progress` minutes, the watcher exits **4 (STUCK-but-safe)** and the caller `--admin` merges. A *named* pending check is never treated as a ghost, so a real in-flight check is never green-lit early.
### Exit-code contract
| code | meaning |
| ---- | ------- |
| 0 | completed AND all green |
| 1 | a check/job failed (the summary names which + the URL) |
| 2 | required/named checks still NOT green after `--timeout` (genuinely stuck) |
| 3 | usage / target-unresolvable / unrecoverable error |
| 4 | STUCK-but-safe — required/named checks all green, but a ghost check will never terminate; safe to `--admin` merge (the caller decides) |
The final stdout line is a single self-describing summary, e.g. `CI-WATCH run 27972328590: SUCCESS (25 job(s) green)`, `CI-WATCH pr 73: FAILURE — check "Test (ubuntu-latest, node 22.13)" → FAILURE (https://…)`, or `CI-WATCH pr 327: STUCK — required/named checks GREEN (51), 1 non-terminal ghost/non-required check(s): (unnamed); safe to --admin merge`.
### NEVER pipe the watcher — a pipe discards the verdict you gate on
The exit code IS the contract, and a pipeline throws it away: in `ci-watch.ts … | tail -20`, `$?` is **tail's** status, so a **FAILED CI reads as SUCCESS**. The pipe also buffers stdout until the pipeline ends, so the log stays empty while the watcher runs.
```bash
# WRONG — $? is tail's, a red CI looks green, and no interim output
node scripts/ci-watch.ts --pr 604 --repo nubjs/nub | tail -25; echo "exit=$?"
# RIGHT — redirect, then gate on the watcher's OWN status
node scripts/ci-watch.ts --pr 604 --repo nubjs/nub > /tmp/ci604.log 2>&1; rc=$?
tail -15 /tmp/ci604.log; echo "exit=$rc"
```
`main()` warns on stderr when it detects a piped stdout (fd 1 is a FIFO for `| cmd`, not for `> file`), but redirect by default rather than relying on the warning. Bash `${PIPESTATUS[0]}` / zsh `${pipestatus[1]}` recover the real status if a pipe is unavoidable.
**Cross-check the rollup regardless of what the watcher says.** Read `gh pr view <pr> --json statusCheckRollup,mergeStateStatus` directly and act on any FAILURE. A watcher that has produced nothing for a long stretch is a suspect, not a status.
For a merge-queue drain, prefer `scripts/merge-cascade.ts` (it gates positively and merges on green); reach for `ci-watch.ts` when you need to block on one run/PR and branch on the result.
## Who runs the watcher
`run_in_background` behaves the same for the orchestrator and for a sub-agent: a backgrounded Bash command persists across turns and re-invokes **its launcher** on exit. Both patterns below are valid.
**Merge-on-green (the default).** The orchestrator runs the blocking watcher as its own `run_in_background` Bash task:
1. **Enqueue:** append `{"pr":N,"branch":"…","thread":"…","note":"…"}` (optional `"hold":true`) to `.frizz/merge-queue.jsonl`. Enqueue UNHELD only once the PR's FINAL head is pushed AND `gh pr edit <n> --add-label ci` has requested a run against it — a stale head can be green-but-wrong, and an unrequested one never goes green at all, so the queue would hold it until the cascade times out.
2. **Watch:** the orchestrator runs `node scripts/merge-cascade.ts --max-minutes 40` with `run_in_background: true`. It gates positively on the required `CI gate` (present + SUCCESS) + mergeable, merges `--squash --admin`, ff-pulls, dequeues, exits → re-invokes the orchestrator. It shares ci-watch's ghost carve-out (`scripts/lib/ci-rollup.ts`), so a still-running or failed REQUIRED gate always blocks and a red PR is never mis-merged.
3. **Landing agents PUSH-THEN-EXIT** — they push, request CI with `gh pr edit <n> --add-label ci`, and report `pushed <sha>, CI requested, queued`. They never watch.
**Self-contained landing agent** (one agent traces push→merge): push the branch; request the run with `gh pr edit <n> --add-label ci`; launch `node scripts/merge-cascade.ts --max-minutes 40` (or `ci-watch.ts`) for its OWN PR via `run_in_background: true`; end its turn; it is re-invoked when the command exits, reports merged/red, and iterates. **Do not preempt a landing agent's background watch** by checking CI yourself and merging manually mid-trace — that impatience is what breaks the flow.
**Foreground chunk loop (fallback only)** — for an agent that must actively iterate and cannot rest:
```bash
# Bash tool: foreground (NOT run_in_background), timeout: 570000 (9.5 min, under the 600000 cap)
nub scripts/ci-watch.ts --pr <N> --chunk # --chunk caps the watch ~9 min and exits 2 with "RERUN to continue" if still pending
# exit 0 = green → act exit 1 = red → fix + re-push exit 2 = pending → RE-RUN the SAME command exit 3 = error
```
While it exits 2, call it again — each chunk completes within the cap (no kill, no orphan). Blocking in the sub-agent's foreground is fine: it is backgrounded relative to the orchestrator. **A dispatch prompt for a self-gating landing agent must spell this loop out** — a sub-agent won't infer it.
A `CronCreate` heartbeat (every ~4 min, one non-blocking `gh pr view` poll per queued PR) is a FALLBACK only if a background shell ever proves unreliable.From nubjs/nub, MIT.
More from nubjs/nub
- 0.848score
nub-charts
nubjs
Build a performance chart for nubjs.com — the SVG bar figures in blog posts, docs pages and social posts (a runtime augmentation against plain node, an…
SkillAFreshness: A★ 4.4KClaude Code +9 - 0.844score
disk-reduction
nubjs
Reclaim disk on the maintainer's Mac when the volume is full or filling — ENOSPC, "no space left on device", a failed build or agent harness, or a routine…
SkillAFreshness: A★ 4.4KClaude Code +9 - 0.844score
cpu-reduction
nubjs
Diagnose and clear CPU, memory, and disk contention on the maintainer's dev host.
SkillAFreshness: A★ 4.4KClaude Code +9 - 0.843score
pm-perf-tracing
nubjs
Performance-trace Nub package-manager installs using the existing phase timings, structured diagnostics, and sampling-profiler workflow.
SkillAFreshness: A★ 4.4KClaude Code +9 - 0.843score
release
nubjs
Cut a Nub patch release end-to-end in one invocation.
SkillAFreshness: A★ 4.4KClaude Code +9 - 0.843score
probe-platforms
nubjs
Bring a test harness or probe up on a NEW operating system (Windows or Linux), or debug one that fails there.
SkillAFreshness: A★ 4.4KClaude Code +9 - 0.843score
type-declarations
nubjs
Add, audit, or update @nubjs/types declarations for Nub runtime APIs.
SkillAFreshness: A★ 4.4KClaude Code +9 - 0.843score
windows-vm-test
nubjs
Run ad-hoc Nub tests and debugging probes in the maintainer's existing local Windows 11 ARM64 QEMU/HVF VM when its external disk and runbook are present.
SkillAFreshness: A★ 4.4KClaude Code +9 - 0.843score
address-issue
nubjs
End-to-end playbook for working a GitHub issue (or bug-fix PR) on nubjs/nub: triage → acknowledge an external report with an "Investigating" comment →…
SkillAFreshness: A★ 4.4KClaude Code +9 - 0.843score
visual-review
nubjs
Verify UI/layout/styling changes are correct by computing occlusion, clipping, and alignment from the browser's resolved paint order via the chrome-devtools…
SkillAFreshness: A★ 4.4KClaude Code +9 - 0.843score
research-thread
nubjs
Use when the deliverable is a FACT — not code, not a design, not a gap catalog.
SkillAFreshness: A★ 4.4KClaude Code +9 - 0.843score
plan-thread
nubjs
Use when an effort's APPROACH isn't settled yet and needs collaborative design BEFORE implementation — fleshing out how a feature/change should work, weighing…
SkillAFreshness: A★ 4.4KClaude Code +9
Compare and alternatives
Featured in
Signals
- Stars
- 4,417
- Forks
- 70
- Open issues
- 27
- Last commit (this folder)
- Sep 7, 2026 (1 month ago)
- Last release
- Oct 19, 2026 (8 days ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/nubjs/nub
- Website
- nubjs.com
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from nubjs
- 0.848score
nub-charts
nubjs
Build a performance chart for nubjs.com — the SVG bar figures in blog posts, docs pages and social posts (a runtime augmentation against plain node, an…
SkillAFreshness: A★ 4.4KClaude Code +9 - 0.844score
disk-reduction
nubjs
Reclaim disk on the maintainer's Mac when the volume is full or filling — ENOSPC, "no space left on device", a failed build or agent harness, or a routine…
SkillAFreshness: A★ 4.4KClaude Code +9 - 0.844score
cpu-reduction
nubjs
Diagnose and clear CPU, memory, and disk contention on the maintainer's dev host.
SkillAFreshness: A★ 4.4KClaude Code +9 - 0.843score
windows-vm-test
nubjs
Run ad-hoc Nub tests and debugging probes in the maintainer's existing local Windows 11 ARM64 QEMU/HVF VM when its external disk and runbook are present.
SkillAFreshness: A★ 4.4KClaude Code +9 - 0.843score
address-issue
nubjs
End-to-end playbook for working a GitHub issue (or bug-fix PR) on nubjs/nub: triage → acknowledge an external report with an "Investigating" comment →…
SkillAFreshness: A★ 4.4KClaude Code +9 - 0.843score
visual-review
nubjs
Verify UI/layout/styling changes are correct by computing occlusion, clipping, and alignment from the browser's resolved paint order via the chrome-devtools…
SkillAFreshness: A★ 4.4KClaude Code +9
Cite this page
ci-watch skill. Agent Mart. https://agentmart.dev/skills/nubjs-ci-watch (last updated 2026-10-24)