Przejdź do głównej zawartości

Automatyzacja pipeline’ów z AI oznacza, że agent kodujący, taki jak Claude Code, Codex czy Cursor, edytuje samą konfigurację CI: joby świadome zmian, które pomijają nietknięte serwisy, triage oddzielający niestabilne testy od prawdziwych regresji oraz naprawy zepsutych workflowów. Pipeline pozostaje wiarygodny tylko wtedy, gdy lintery, zawsze uruchamiany check zbiorczy i code ownerzy weryfikują każdą zmianę agenta.

Twoje monorepo uruchamia każdy job przy każdym pushu. Jednolinijkowa zmiana w README czeka na pełny build sześciu serwisów, te same trzy specy end-to-end padają w części przebiegów i przechodzą po ponownym uruchomieniu, a cały zespół nauczył się klikać Re-run failed jobs bez czytania logu. Chcesz, żeby agent to naprawił, ale CI jest bramką, która chroni main. Agent, który po cichu osłabi tę bramkę, sprawia, że każdy późniejszy zielony check kłamie.

Ta strona jest dla developerów, którzy odpowiadają za CI repozytorium, i dla tech leadów, którzy decydują, które checki są wymagane. Dotyczy agenta, który edytuje pipeline. Uruchamianie agenta jako kroku w pipelinie opisuje strona agenci headless w CI, a wypuszczanie scalonej zmiany na produkcję — progressive delivery dla zmian pisanych przez agentów.

  • ci.yml świadomy zmian, zbudowany na dorny/paths-filter, z minimalnymi uprawnieniami, akcjami przypiętymi do commita i jednym checkiem zbiorczym, który oznaczasz jako wymagany.
  • Pętlę triage niestabilnych testów: log nieudanego przebiegu trafia do agenta, a każdy werdykt „niestabilny” potwierdzasz ponownym uruchomieniem speca, zanim cokolwiek trafi do kwarantanny.
  • Job lintujący workflowy (actionlint i zizmor), który sprawdza każdą zmianę agenta w .github/ bez czytania YAML-a linia po linii.
  • Trzy prompty do skopiowania, polecenia dla Claude Code, Codeksa i Cursora oraz tryby awarii, w których zielony pipeline staje się fałszywym sygnałem.

Agent szybko pisze wiarygodnie wyglądający YAML. Ryzykiem nie jest błąd składni, bo CI zgłasza go od razu. Ryzykiem jest pipeline, który się uruchamia, świeci na zielono i już nie sprawdza tego, co sprawdzał wcześniej: filtr, który pomija job z testami, retry, który ukrywa regresję, albo uprawnienie, które poszerza token. Wytyczne DORA dotyczące wdrażania AI przypisują tę samą rolę kontroli wersji: „As AI increases the volume and velocity of code generation, version control becomes your critical safety net” (blog Google Cloud, Nathen Harvey i Allison Park, 2025-12-10). CI to ta część siatki bezpieczeństwa, która działa przy każdej zmianie.

Dlatego każdy workflow na tej stronie ma tę samą kolejność:

  1. Najpierw kontrakt. Powiedz agentowi, których checków nie wolno pominąć (sprawdzanie typów, lint, testy każdego zmienionego pakietu) i który job jest wymaganym checkiem statusu.
  2. Pozwól agentowi edytować. Użyj promptu do danego zadania, na prawdziwym układzie katalogów.
  3. Zweryfikuj mechanicznie. Job lintujący, check zbiorczy i jeden celowy testowy push dowodzą poprawności zmiany. Czytasz wynik weryfikacji, a nie każdą linię YAML-a.
  4. Zatwierdź przez własność. Wpis w CODEOWNERS dla /.github/ kieruje każdą zmianę pipeline’u do osoby odpowiedzialnej za bramkę.

Buduj tylko to, co się zmieniło, z dorny/paths-filter

Dział zatytułowany „Buduj tylko to, co się zmieniło, z dorny/paths-filter”

W monorepo największa oszczędność w CI zwykle bierze się z nieuruchamiania jobów, których wejścia się nie zmieniły. dorny/paths-filter porównuje diff ze wzorcami ścieżek i wystawia jedno wyjście na filtr, które kolejne joby czytają w warunkach if:. Przy pull_request pobiera listę zmienionych plików przez API GitHuba, więc job potrzebuje pull-requests: read. Przy push używa gita, więc potrzebuje checkoutu.

Agent powinien wygenerować plik o takim kształcie, wyprowadzony z twoich prawdziwych workspace’ów, a nie skopiowany:

.github/workflows/ci.yml
name: CI
on:
pull_request:
push:
branches: [main]
permissions: {}
jobs:
changes:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
outputs:
api: ${{ steps.filter.outputs.api }}
web: ${{ steps.filter.outputs.web }}
workflows: ${{ steps.filter.outputs.workflows }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4.0.3
id: filter
with:
filters: |
api:
- 'services/api/**'
- 'packages/shared/**'
- 'package-lock.json'
- '.github/workflows/**'
web:
- 'services/web/**'
- 'packages/shared/**'
- 'package-lock.json'
- '.github/workflows/**'
workflows:
- '.github/**'
test-api:
needs: changes
if: ${{ needs.changes.outputs.api == 'true' }}
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- run: npm ci && npm test --workspace=services/api
# test-web: the same shape, gated on needs.changes.outputs.web
required:
if: ${{ always() }}
needs: [changes, test-api]
runs-on: ubuntu-latest
steps:
- name: Fail if any needed job failed or was cancelled
if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
run: exit 1

Cztery szczegóły tego pliku agenci najczęściej psują, więc nazwij je w prompcie:

  • Współdzielone wejścia są w każdym filtrze. packages/shared/**, lockfile i katalog workflowów przebudowują każdego konsumenta. Zmiana w samym CI uruchamia więc raz cały zestaw testów.
  • Porównanie jest jawne. Wyjścia filtra to napisy 'true' i 'false', więc warunek porównuje z == 'true'.
  • Wymaganym checkiem jest jeden job zbiorczy. Dokumentacja GitHuba mówi, że pominięty job zgłasza status „Success” i nie blokuje scalenia, nawet jeśli jest wymaganym checkiem. W ochronie gałęzi oznacz jako wymagany tylko required. Uruchamia się przy każdym zdarzeniu i pada, gdy którykolwiek z potrzebnych mu jobów zawiódł albo został anulowany.
  • Akcje są przypięte do commita. Komentarz zachowuje czytelną wersję. zizmor, używany w jobie lintującym poniżej, od wersji 1.20.0 domyślnie wymaga przypięcia wszystkich akcji do hasha.

Sposób pracy różni się między narzędziami. Cursor edytuje plik w edytorze i pokazuje diff. Claude Code i Codex mogą działać headless z terminala i zlintować wynik w tej samej sesji.

Uruchom w trybie print z katalogu głównego repozytorium, z lokalnie zainstalowanym actionlint (brew install actionlint). acceptEdits pozwala agentowi zapisywać pliki bez pytania, a allowlista pozwala mu uruchomić actionlint na własnym wyniku:

Okno terminala
claude -p "$(cat prompts/change-aware-ci.md)" \
--permission-mode acceptEdits \
--allowedTools "Bash(actionlint *)"

Zapisz prompt poniżej jako prompts/change-aware-ci.md, żeby zespół uruchamiał tę samą instrukcję po dodaniu serwisu. Żeby używać go w sesjach interaktywnych, zrób z niego skill projektu w .claude/skills/.

Zweryfikuj wynik bez czytania każdej linii. Tabela na końcu promptu to twierdzenie agenta o zachowaniu pipeline’u. Sprawdź je na pull requeście: wypchnij jeden commit, który zmienia tylko README.md, i sprawdź stany jobów poleceniem gh pr checks. test-api powinien być pominięty, required powinien przejść, a commit w packages/shared/ powinien uruchomić wszystkie joby testowe. Jeśli którykolwiek wiersz tabeli nie zgadza się z tym, co zrobiło CI, filtr jest błędny, niezależnie od tego, jak wygląda YAML.

Test, który w części przebiegów pada, a w części przechodzi, jest albo niestabilny, albo jest prawdziwym sporadycznym błędem, na przykład wyścigiem w kodzie produktu. Globalne retry traktują oba przypadki tak samo, a to ukrywa ten drugi. Zadaniem agenta jest sklasyfikować każdą awarię, a twoim — potwierdzić każdy werdykt „niestabilny” ponownym uruchomieniem, zanim cokolwiek trafi do kwarantanny.

Najpierw przekaż agentowi log nieudanego przebiegu. GitHub CLI wypisuje tylko nieudane kroki przebiegu:

Okno terminala
RUN_ID=$(gh run list --workflow ci.yml --status failure --limit 1 \
--json databaseId --jq '.[0].databaseId')
gh run view "$RUN_ID" --log-failed > failed.log

Z podłączonym serwerem GitHub MCP agent może pobrać ten sam log sam, gdy wskażesz przebieg. W sesji interaktywnej oszczędza to kopiowanie. W skrypcie prostszy jest potok z gh, który nie wymaga tokena w konfiguracji agenta.

Przekaż log przez potok i ogranicz agenta do czytania plików oraz uruchamiania test runnera, żeby klasyfikacja nie zamieniła się w edycję. --permission-mode dontAsk utrzymuje to u każdego dostawcy, bo -p startuje w trybie auto u zewnętrznych dostawców lub z wyłączoną telemetrią (od v2.1.285):

Okno terminala
claude -p "$(cat prompts/flaky-triage.md)" \
--permission-mode dontAsk \
--allowedTools "Read,Grep,Bash(npx playwright test *)" < failed.log

Zapisz ten prompt jako prompts/flaky-triage.md.

Kwarantannę wprowadź jako osobną zmianę, przeglądaną jak każda inna zmiana wyroczni testowej. Trzymaj testy w kwarantannie na liście z datą i właścicielem. Kwarantanna bez właściciela nigdy się nie kończy.

Pliki workflowów mają dwie klasy defektów, których testy nie wyłapią: wyrażenia, które nie ewaluują się tak, jak zakładał autor, oraz problemy bezpieczeństwa, takie jak template injection, zbyt szerokie tokeny czy nieprzypięte akcje. Pokrywają je dwa analizatory statyczne. actionlint sprawdza typy w składni i wyrażeniach workflowów. zizmor audytuje workflowy pod kątem bezpieczeństwa. Oba działają w kilka sekund, więc uruchamiaj je przy każdej zmianie w .github/, z warunkiem na filtr workflows z pierwszej sekcji. Dodaj ten job do ci.yml i dopisz go do listy needs joba required:

lint-workflows:
needs: changes
if: ${{ needs.changes.outputs.workflows == 'true' }}
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: actionlint
run: |
bash <(curl -sSfL https://raw.githubusercontent.com/rhysd/actionlint/v1.7.12/scripts/download-actionlint.bash) 1.7.12
./actionlint -color
- name: zizmor
run: pipx run --spec zizmor==1.30.1 zizmor --offline --format=github .github/workflows/

Ten job działa na pull_request z tokenem tylko do odczytu i nie wykonuje żadnego kodu z gałęzi kontrybutora, a jedynie uruchamia dwa przypięte lintery na plikach workflowów, więc jest bezpieczny dla pull requestów z forków. Pilnuj, żeby tak zostało: agent poproszony o „przyspieszenie checków” potrafi przełączyć workflow na pull_request_target, który działa z sekretami repozytorium bazowego. Zasady uruchamiania agenta obok sekretów opisuje strona agenci headless w CI.

Jedna linia celowo łamie regułę przypinania po hashu z tego samego joba: skrypt pobierający actionlint jest ściągany po tagu wydania, a instalowaną binarkę ustala argument wersji 1.7.12. Traktuj to jako zaakceptowany wyjątek albo, jeśli Twoja polityka nie dopuszcza żadnych wyjątków, trzymaj kopię skryptu w repozytorium.

Potem ustal własność. Jedna linia w .github/CODEOWNERS i włączone Require review from Code Owners w ochronie gałęzi kierują każdą zmianę pipeline’u do osób odpowiedzialnych za bramkę:

/.github/ @your-org/platform

Code owner nie czyta YAML-a linia po linii. Czyta trzy rzeczy: wynik joba lintującego, tabelę agenta „które joby się uruchamiają” zestawioną z tym, co pokazało gh pr checks, oraz diff listy needs joba required, która nie może się skurczyć bez uzasadnienia w opisie pull requesta.

Wklej ten prompt do sesji interaktywnej na gałęzi pull requesta albo zapisz go jako prompts/pipeline-review.md, żeby każdy recenzent przechodził tę samą listę kontrolną.

Trzymaj wdrożenie poza zasięgiem agenta i poza pull requestami. Uruchamiaj job wdrożeniowy tylko na push do chronionej gałęzi domyślnej, za środowiskiem GitHuba z własnymi sekretami i wymaganymi recenzentami. Agent może napisać i zmieniać ten job jak każdy inny plik workflowu, pod tym samym jobem lintującym i tymi samymi code ownerami, ale żadna sesja agenta nie powinna mieć poświadczeń wdrożeniowych.

To, co dzieje się po starcie joba wdrożeniowego, to progressive delivery: canary, feature flagi i automatyczny rollback na sygnał z poziomu usługi. Ta strona opisuje kontrolery rolloutu i budżet zasięgu awarii dla każdej klasy ryzyka. Joby wdrożeniowe dla konkretnych narzędzi znajdziesz na stronach konfiguracja pipeline’u z Claude Code, Codex w CI/CD z GitHub Action i pipeline’y CI/CD z Cursorem.

Edycja pipeline’u wymaga rozumowania obejmującego wiele plików, bo filtr jest poprawny tylko względem grafu pakietów. Zacznij od domyślnego modelu narzędzia i podnieś effort, zanim zmienisz model. Na 2026-10-12 oznacza to Claude Opus 5.5 w Claude Code od v2.1.280 (na obu kanałach wydań; effort podnosisz przez /effort) i GPT-6.1 Sol w Codeksie (domyślny od CLI 0.159.1). Cursor nie wskazuje jednego modelu domyślnego (strona o modelach i cenach, sprawdzone 2026-10-12), więc sprawdź wybór modelu we własnej instalacji Cursora. Ceny i pełną ofertę modeli znajdziesz w przeglądzie modeli.