Unified CI watch + auto-fix loop skill. Polls gh pr checks after /moai sync PR creation, classifies required vs auxiliary failures, attempts safe automated patches (max 3 iterations), and escalates semantic failures to the user. Use for CI loop workflow — NOT for general loop iteration patterns (see moai-workflow-loop).
67
82%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
hns-workflow-ci-loop)Unified CI watch + auto-fix loop. The orchestrator invokes this skill after /moai sync
Phase 4 (gh pr create) returns a PR number. The skill polls required checks, classifies
failures into mechanical vs semantic, attempts safe patches up to 3 iterations, and
escalates semantic failures via AskUserQuestion.
Trigger: /moai sync Phase 4 PR-create returns a PR number, or an existing PR needs
CI monitoring.
Two phases, one skill:
gh pr checks every 30s, classify required vs auxiliary via
.github/required-checks.yml SSoT; exit on green/fail/timeout.One-liner:
MOAI_CIWATCH_GH=gh sh scripts/ci-watch/run.sh <PR_NUMBER> <BRANCH>Exit codes:
0 — all required passed → ready-to-merge AskUserQuestion1 — fatal error → surface remediation2 — required failure → JSON handoff → auto-fix phase3 — 30-min hard timeout → blocker message, return controlHARD invariants:
manager-develop (cycle_type=autofix) subagent MUST NOT call it.--force, -f, --force-with-lease all banned)..env*, credentials, .claude/settings*.json, .github/required-checks.yml,
scripts/ci-watch/run.sh.Polling cadence: 30 seconds minimum (GitHub API rate-limit). Override via
CIWATCH_POLL_INTERVAL env, never below 30 in production. Test mode uses
MOAI_CIWATCH_NO_SLEEP=1 (single-tick exit).
30-minute hard timeout: CIWATCH_TIMEOUT_SECONDS=1800 default. On timeout, exit 3.
Do not auto-restart.
Required vs auxiliary: Required checks live in .github/required-checks.yml
branches.<pattern>.contexts. Auxiliary checks listed under auxiliary: MUST NOT block
ready-to-merge. Hardcoding check names in scripts is prohibited.
State file: .moai/state/ci-watch-active.flag (YAML). Tracks pr_number, started_at,
heartbeat_at, required_checks, abort_requested. Heartbeat staleness > 90s allows
takeover. Abort: moai pr watch --abort.
Background watch standardization: For long-running PRs (5+ min), use
gh pr checks <PR> --watch invoked via run_in_background: true. Sleep + poll loops are
prohibited — they block the orchestrator's main session.
Status report format (stderr, state-change ticks only, no ANSI):
[ci-watch] PR #<N>: required 4/6 pass, 2 pending; advisory 0 failHandoff schema on exit 2 — JSON with stable fields: prNumber, branch,
failedChecks[] (each entry {name, runId, logUrl}), auxiliaryFailCount,
totalRequired. Field stability: name, runId, logUrl are stable contract — do not
rename. Schema source: the CI-watch handoff struct.
Entry condition: ci-watch exit 2 + valid JSON handoff. State file:
.moai/state/ci-autofix-<PR>.json (PR-scoped, 24-hour staleness threshold).
OQ2 cadence matrix (single source of truth for iteration behavior):
"trivial" = whitespace, gofmt/goimports, import-order (matches classify.sh RX_TRIVIAL_*).
Patch commit rule: Every patch = new commit. Format:
fix(ci): auto-fix <classification> failure (iter <N>). After push, re-invoke
scripts/ci-watch/run.sh to restart the watch loop.
Iteration 4+ escalation (mandatory blocking, no silent timeout):
manager-develop (cycle_type=autofix) spawn prompt injects: handoff JSON, classification + sub_class,
failed CI log + PR diff, mode directive (mechanical → propose unified-diff patch;
semantic/unknown → return diagnosis only, no patch). HARD: no AskUserQuestion call from
the subagent — return Markdown only.
Audit log: .moai/logs/ci-autofix/<PR-NNN>-<YYYY-MM-DD>.md. Append-only. Each
iteration records classification, sub_class, action, patch_sha, escalation_reason.
**/.env, **/.env.***/credentials*, **/*_key.json, **/*secret*.claude/settings.json, .claude/settings.local.json.github/required-checks.yml (Wave 1 SSoT, read-only for Wave 2/3)scripts/ci-watch/run.sh (Wave 2 invariant)If the manager-develop (cycle_type=autofix) subagent proposes a patch touching any of these, reject and escalate.
Go helpers: the CI-watch classifier (required-vs-auxiliary), the handoff JSON-schema
struct, the watch state file, and the PR-watch report emitters (EmitReadyToMergeReport,
EmitFailureHandoff). Shell: scripts/ci-watch/run.sh (main
loop, mock via MOAI_CIWATCH_GH); scripts/ci-watch/lib/classify.sh (yq + grep
fallback); scripts/ci-autofix/log-fetch.sh (failure log + PR diff);
scripts/ci-autofix/classify.sh (mechanical vs semantic).
gh CLI compat: requires gh >= 2.50 for the workflow JSON field. On older gh,
classify.sh falls back to name-based heuristics from the required: list.
manager-develop (cycle_type=autofix) — failure diagnosis + patch proposal subagent
manager-git — commit/push of auto-fix patches
.claude/rules/local/ci-watch-protocol.md — HARD watch invocation contract (dev-only; governs scripts/ci-watch/)
.claude/rules/local/ci-autofix-protocol.md — HARD autofix invocation contract (dev-only; governs scripts/ci-autofix/)
Both are the dev-repo twins, not the distributed rules of the same basename. The
distributed .claude/rules/moai/workflow/ci-autofix-protocol.md is deliberately
script-free and governs the manager-develop autofix cycle instead; it does not
describe the scripts this skill runs. ci-watch-protocol.md is not distributed at all.
.github/required-checks.yml — Wave 1 SSoT
required-checks.yml to change classification.manager-develop (cycle_type=autofix) subagent calls AskUserQuestion (HARD: orchestrator-only)git push --force / -f / --force-with-lease anywhere in scriptsrequired-checks.yml modified without moai github init re-runbash scripts/ci-watch/test/run_test.sh passes all shell testsgo test ./internal/ciwatch/... ./internal/cli/pr/... -race passesinternal/ciwatch/ coverage >= 85%FormatStatusUpdate() outputEmitReadyToMergeReport first option carries (Recommended)grep -r 'push -f\|push --force' scripts/ci-autofix/ scripts/ci-watch/ returns no matches.moai/logs/ci-autofix/<PR>-<DATE>.md contains every iteration2213871
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.