Free SKILL.md scraped from GitHub. Clone the repo or copy the file directly into your Claude Code skills directory.
npx versuz@latest install seb155-atlas-plugin-dist-atlas-dev-addon-skills-ci-feedback-loopgit clone https://github.com/seb155/atlas-plugin.gitcp atlas-plugin/SKILL.MD ~/.claude/skills/seb155-atlas-plugin-dist-atlas-dev-addon-skills-ci-feedback-loop/SKILL.md---
name: ci-feedback-loop
description: "Post-push CI monitoring until terminal state. This skill should be used after every git push, when the user asks to 'check CI', '/a-ci', 'wait for CI', or whenever LAW-WORKFLOW-001 requires verification before further work."
mode: [coding, engineering]
effort: low
superpowers_pattern: [iron_law, red_flags, hard_gate]
see_also: [ci-management, finishing-branch, verification]
thinking_mode: adaptive
version: 6.1.0
tier: [core, dev, admin]
category: quality
emoji: "🔄"
triggers: ["check CI", "wait for CI", "pipeline status", "post-push verify", "CI green?"]
---
<HARD-GATE>
NO SECOND PUSH TO THE SAME BRANCH WITHOUT CI VERIFY.
After git push, poll pipeline until terminal state (success/failure/error).
If red: triage + fix + re-push + re-verify. NEVER push through red CI silently.
Signature: sha256:LAW-WORKFLOW-001 (db7f6890b4e49ec020980a354a420ea142965d2725e48ef6227bab12adacc188)
</HARD-GATE>
**Iron Law**: `LAW-WORKFLOW-001` (no-push-without-ci-verify). Override requires HITL AskUserQuestion with "CI is red — push anyway? reason: ___".
<red-flags>
| Thought | Reality |
|---|---|
| "Tests passed locally, CI will be fine" | Different environment, different data, different concurrency. Local green ≠ CI green. Wait for the pipeline. |
| "I'll check CI tomorrow" | Tomorrow's you is dealing with a cascade of 8 broken commits. Now-you has 1 commit to triage. |
| "The pipeline usually takes 10 min, let me start the next thing" | Yes, AFTER green. Before green = context-switch penalty when CI red interrupts Phase 2 mid-sentence. |
| "Only l1-structural failed, unrelated to my change" | Prove it. Run the test locally. If truly unrelated, document + file issue. Don't guess. |
| "Push through red CI just this once" | "Just once" compounds. 27 red pushes in a row is the 2026-04-23 incident lesson. |
</red-flags>
# CI Feedback Loop
## Purpose
After every `git push`, poll the CI pipeline to terminal state BEFORE moving to the
next work item. Enforces LAW-WORKFLOW-001. Catches regressions in the shortest
possible feedback loop.
## The Loop (strict sequence)
```
1. git push → CI triggers
2. Fetch pipeline ID for current branch → via Woodpecker API
3. Poll every 20-30s until terminal state → running → success | failure | error
4a. If SUCCESS → OK to continue next work
4b. If FAILURE → triage + fix + re-push + goto 1
```
## Commands (Woodpecker + Forgejo)
```bash
source ~/.env # loads WP_TOKEN
# Get latest pipeline on current branch
BRANCH=$(git rev-parse --abbrev-ref HEAD)
PIPELINE_ID=$(curl -s -H "Authorization: Bearer ${WP_TOKEN}" \
"https://ci.axoiq.com/api/repos/2/pipelines?branch=${BRANCH}&limit=1" \
| python3 -c "import json,sys; d=json.load(sys.stdin); print(d[0]['number'])")
# Poll status
STATUS=$(curl -s -H "Authorization: Bearer ${WP_TOKEN}" \
"https://ci.axoiq.com/api/repos/2/pipelines/${PIPELINE_ID}" \
| python3 -c "import json,sys; print(json.load(sys.stdin).get('status'))")
# Terminal states: success | failure | error | killed | declined | blocked
```
For the Monitor tool (automated polling with notifications):
```bash
Monitor(
command="source ~/.env; last=''; while true; do \
pl=$(curl -s -H 'Authorization: Bearer ${WP_TOKEN}' \
'https://ci.axoiq.com/api/repos/2/pipelines?branch=BRANCH&limit=1'); \
num=$(echo \"$pl\" | python3 -c \"import json,sys;d=json.load(sys.stdin);p=d[0] if isinstance(d,list) and d else None;print(p.get('number','?') if p else '?')\"); \
st=$(echo \"$pl\" | python3 -c \"import json,sys;d=json.load(sys.stdin);p=d[0] if isinstance(d,list) and d else None;print(p.get('status','?') if p else '?')\"); \
if [[ \"$st\" != \"$last\" ]]; then echo \"[$(date +%H:%M:%S)] #${num}: ${st}\"; last=\"$st\"; fi; \
case \"$st\" in success|failure|error|killed) echo \"[TERMINAL] #${num} => ${st}\"; break;; esac; \
sleep 20; \
done",
timeout_ms=900000
)
```
## Failure Triage Checklist
On failure:
1. Identify failing step: `/api/repos/2/pipelines/{id}` → workflows[].children[] with state=failure
2. Fetch logs via web UI or `claude --print "pull log for step X"` (API returns HTML not JSON)
3. Reproduce locally before guessing: run the exact step's command
4. Fix root cause (not workaround)
5. Re-push → re-enter the loop
## When NOT to use this skill
- Dry-run / local-only work (no push happened)
- CI disabled for this branch (documented in CI yaml)
- Explicit HITL override with recorded reason in decision-log
## Integration with .claude/ci-audit.jsonl
This skill reads/writes `.claude/ci-audit.jsonl` (via `hooks/ci-audit-log`). Each
push gets one entry; this skill updates `resolved_at` + `failed_tests` on terminal.
## Native Watch Integration (SOTA 2026)
### Tool selection (decision tree)
```
Repo forge?
├─ GitHub → gh run watch --exit-status
├─ GitLab → glab ci status --wait
└─ Forgejo/WP → Monitor tool OR atlas ci watch <N>
```
### GitHub
```bash
gh run watch --exit-status # blocks, exits non-zero on failure
gh pr checks --watch # watch PR checks live
```
### GitLab
```bash
glab ci status --wait # blocks, exits non-zero on failure
```
### Forgejo + Woodpecker — Monitor tool (preferred, reactive)
Full Monitor invocation using `hooks/lib/watch-filter.sh` grep (Plummer doctrine):
```bash
Monitor(
description="CI terminal state: Woodpecker pipeline on ${BRANCH}",
command="""
source ~/.env 2>/dev/null
BRANCH=$(git rev-parse --abbrev-ref HEAD); REPO_ID=${WP_REPO_ID:-2}; last=''
while true; do
r=$(curl -sf -H "Authorization: Bearer ${WP_TOKEN}" \
"${WP_URL:-https://ci.axoiq.com}/api/repos/${REPO_ID}/pipelines?branch=${BRANCH}&limit=1")
n=$(echo "$r" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d[0]['number'] if d else '?')")
s=$(echo "$r" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d[0]['status'] if d else 'unknown')")
[[ "$s" != "$last" ]] && echo "[$(date +%H:%M:%S)] #${n} => ${s}" && last="$s"
case "$s" in
success) echo "[TERMINAL:GREEN] #${n}"; break ;;
failure|error|killed|declined|blocked) echo "[TERMINAL:RED] #${n} => ${s}"; break ;;
esac; sleep 20
done
""",
timeout_ms=900000
)
```
The `watch-filter.sh` grep (success+failure both required — Plummer SOTA):
```bash
grep --line-buffered -E \
'success|succeeded|passed|green|failure|failed|error|cancelled|timeout|Traceback|Killed|OOM|FAILED|assert'
```
### Cache-warm during long watch
For watches > 5 minutes, compact context before Monitor to stay in cache window:
- 5-min TTL cache; 8-min build = 3 cache misses without compaction
- `/compact --keep` before Monitor invocation if context budget > 60%
### Full cookbook
See `references/watch-commands.md` — all 3 forges, decision tree, AXOIQ Woodpecker
API endpoint catalog, environment vars, terminal state table.
## Auto-Archeology Handoff
When CI reaches failure terminal state, handoff to `ci-archaeology`:
```bash
# On TERMINAL:FAILURE → invoke ci-archaeology skill
if [[ "$terminal_status" =~ ^(failure|error|killed)$ ]]; then
# ci-archaeology: fetch failing step + decode logs + classify root cause + propose fix
# 1. Get failing step: GET /api/repos/{id}/pipelines/{N} → workflows[].children[state=failure]
# 2. Decode log: GET /api/repos/{id}/pipelines/{N}/logs/{step_id} (base64 data field)
# 3. Classify: ruff|mypy|test|deploy|network
# 4. Fix + re-push + re-enter loop
echo "[AUTO-HANDOFF] → ci-archaeology skill"
fi
```
If ci-archaeology fails twice: escalate to `ci-recovery` agent (Opus-level reasoning).
If ci-recovery fails: HITL gate via AskUserQuestion.
## See also
- `ci-management` — broader CI admin (restart, cancel, secrets, health dashboard)
- `finishing-branch` — completes branch → implies final CI verify
- `verification` — code-level verification before push
- `ci-archaeology` — failure triage after red pipeline
- `ci-recovery` — deep recovery when ci-archaeology insufficient
- `ship-all` — Phase 4.2 calls this skill for post-deploy CI wait
- `references/watch-commands.md` — full cookbook (gh, glab, Woodpecker, Monitor)
- `LAW-WORKFLOW-001` in `iron-laws.yaml`
- `LAW-CI-VERIFY-001` — iron law: never merge without verified CI green