Równoległa praca agentów w zespole na poziomie 3 — izoluj zadania i ogranicz kolejkę
Równoległa praca zespołu na poziomie 3 drabiny autonomii oznacza, że kilka zadań agentów działa jednocześnie bez współdzielenia plików, portów ani danych, pod limitem współbieżności ustalonym dla każdej klasy zadań na podstawie zmierzonej przepustowości review i CI, z imiennym właścicielem każdego merge. Równoległość opłaca się tylko wtedy, gdy zaakceptowany throughput przewyższa szeregowy baseline, a rework nie rośnie.
Twoi inżynierowie już teraz uruchamiają po dwa, trzy agenty. Pull requesty przychodzą szybciej niż kiedykolwiek, a release nie jest ani o krok bliżej: dwa branche przepisały ten sam moduł cennika, testy padły, bo dev server innego agenta zajął port, i nikt nie wie, kto ma rozwiązać konflikt. To jest fan-out bez workflow zespołu, a ta strona jest dla tech leada albo CTO, który musi zamienić go w workflow.
Mechanikę pracy jednego developera na worktrees opisuje Uruchamiaj równoległe agenty w izolowanych worktrees. Arytmetykę po stronie review — Kolejka code review, gdy pull requesty otwierają agenci. Ta strona obejmuje standard zespołu pomiędzy nimi: która praca może iść równolegle, jak izolować stan, kto integruje i jak udowodnić, że to się opłaca.
Co daje zespołowi standard pracy równoległej na poziomie 3
Dział zatytułowany „Co daje zespołowi standard pracy równoległej na poziomie 3”- Tabelę decyzyjną: które klasy zadań idą równolegle, a które szeregowo.
- Szablon karty zadania, którą każde równoległe zadanie ma, zanim agent ruszy.
- Skrypt izolacji, który odmawia startu, gdy klasa zadania jest pełna, a w przeciwnym razie daje każdemu zadaniu własny worktree, branch, porty i nazwę bazy danych.
- Limit współbieżności per klasa zadań i regułę jego zmiany.
- Sprawdzenie nakładania się zmian przed merge oraz właściciela integracji, który na nie reaguje.
- Pięć definicji metryk i dwutygodniowy eksperyment porównujący pracę równoległą z szeregowym baseline.
- Jednostronicową politykę zespołu, którą możesz dziś zacommitować do repozytorium.
Jak CTO Scorecard ocenia równoległą pracę zespołu
Dział zatytułowany „Jak CTO Scorecard ocenia równoległą pracę zespołu”Pytanie 14 w CTO Scorecard brzmi: czy zespół uruchamia równoległe zadania agentów w izolowanych worktrees. Cztery odpowiedzi odpowiadają dowodom poniżej. Pełną liczbę punktów daje tylko ostatnia, a każdy jej element musi być czymś, co możesz pokazać, a nie czymś, co zamierzasz.
| Odpowiedź | Punkty | Co możesz zaobserwować | Następny krok |
|---|---|---|---|
| Nikt | 0 | Jedna sesja agenta na inżyniera, jeden checkout | Pilotaż jednej klasy zadań z dwoma izolowanymi zadaniami |
| Eksperymentują pojedynczy devs | 1 | Prywatne nawyki z worktrees, brak wspólnych konwencji | Ustandaryzuj skrypt izolacji i prefiks branchy |
| Polecane / dofinansowane dla seniorów | 2 | Narzędzia są opłacone, ale nie ma limitu, właściciela ani pomiaru | Ustal limity per klasa i wyznacz właścicieli integracji |
| Workflow zespołu z izolacją stanu, zmierzonym limitem równoległości, właścicielem integracji i limitem kolejki review | 3 | Plik polityki, bramka dispatchu, sprawdzenie nakładania się, cotygodniowe metryki | Trzymaj limit tam, gdzie zaakceptowany throughput jest najwyższy, a nie tam, gdzie liczba PR osiąga szczyt |
Dlaczego więcej agentów może obniżyć zaakceptowany throughput
Dział zatytułowany „Dlaczego więcej agentów może obniżyć zaakceptowany throughput”Generowanie skaluje się z liczbą agentów; review i integracja nie. Raport Faros AI AI Engineering Report 2026: The Acceleration Whiplash (kwiecień 2026; telemetria dostawcy z 22 000 developerów na jego własnej platformie) zmierzył obie strony w tym samym okresie: throughput zadań na developera wzrósł o 33,7%, mediana czasu w review o 441,5%, a liczba incydentów na pull request o 242,7%.
To jest sufit poziomu 3: tempo wyznacza kolejka, a nie agent. Jednostką, którą zarządzasz, jest więc praca zaakceptowana — zmergowana, zielona i niecofnięta — a nie liczba otwartych pull requestów czy działających agentów.
Zdecyduj, która praca może iść równolegle
Dział zatytułowany „Zdecyduj, która praca może iść równolegle”Równoległość jest cechą pracy, nie narzędzia. Dwa zadania mogą działać jednocześnie tylko wtedy, gdy żadne nie zmienia czegoś, co czyta drugie. Klasyfikuj każde zadanie według tej tabeli przed dispatchem i dopisuj własne klasy, gdy się ich nauczysz.
| Klasa zadania | Domyślnie | Dlaczego |
|---|---|---|
Pionowy wycinek funkcji (vertical-slice) we własnym module lub pakiecie | Równolegle | Posiadane ścieżki się nie pokrywają; konflikty są rzadkie i tekstowe |
| Testy lub testy charakteryzujące istniejący kod | Równolegle | Dodaje pliki; wyrocznię przeglądasz raz, a nie per zadanie |
| Izolowana poprawka błędu z czerwonym (niezaliczonym) testem | Równolegle | Mały diff, jasne kryterium akceptacji |
| Zmiana współdzielonej abstrakcji, klasy bazowej lub kontraktu API | Szeregowo | Czyta ją każde równoległe zadanie, więc unieważnia każde z nich |
| Migracja schematu bazy danych | Szeregowo | Migracje są uporządkowane; dwie naraz dają konflikt numeracji albo zerwany łańcuch |
| Aktualizacja zależności lub frameworka | Szeregowo | Dotyka lockfile’ów i konfiguracji builda, które współdzieli każdy branch |
| Przekrojowy rename lub przebieg formatowania | Szeregowo, w pojedynkę | Koliduje ze wszystkim; uruchamiaj go, gdy nic innego nie jest w toku |
Zadanie szeregowe nie jest zakazane. Działa samo na swoim torze, a zadania równoległe, które od niego zależą, czekają na jego merge.
Napisz kartę zadania dla każdego równoległego zadania
Dział zatytułowany „Napisz kartę zadania dla każdego równoległego zadania”Agent, który nie zna swoich granic, dryfuje do plików sąsiada. Karta zadania jest kontraktem: backlog gotowy dla agentów kształtuje issue, a karta dodaje to, czego potrzebuje praca równoległa. Przed dispatchem zacommituj kartę do tasks/<slug>.yaml na domyślnym branchu; skrypty czytają ją stamtąd.
slug: billing-retryclass: vertical-slice # wiersz z tabeli klas zadańaccepted_plan: docs/plans/billing-retry.mdowned_paths: - src/billing/retry/** - tests/billing/retry/**read_only_paths: - src/billing/client.ts # współdzielony kontrakt: wolno czytać, nie wolno edytowaćdepends_on: [] # slugi, które muszą zostać zmergowane wcześniejchecks: - npm run typecheck - npm test -- tests/billing/retrystop_when: - a change outside owned_paths is needed - a check fails three times in a rowintegration_owner: "@ana"Lista stop_when jest równie ważna jak zakres. Agent, który trafia na współdzielony kontrakt, ma się zatrzymać i zgłosić, a nie edytować kontrakt i unieważniać trzy inne branche.
Zastąp PLAN_FILE nazwą pliku planu. Przeglądasz graf i tabelę nakładania się, nie kod: jeśli tabela nakładania się nie jest pusta, partia zadań nie jest gotowa.
Izoluj stan szerzej niż worktree
Dział zatytułowany „Izoluj stan szerzej niż worktree”Git worktree daje każdemu zadaniu własne pliki i branch przy jednej wspólnej bazie obiektów. Nie izoluje portów, baz danych, cache’y, kontenerów ani działającego dev servera. Dwa agenty z osobnymi worktrees i jedną wspólną bazą danych nadal dają dwa zielone przebiegi, które sobie przeczą.
Daj każdemu zadaniu cały zestaw jednym poleceniem, żeby nikt nie składał go ręcznie:
#!/usr/bin/env bash# Użycie: scripts/agent-task.sh SLUG INDEX# Odmawia, gdy klasa zadania osiągnęła limit. W przeciwnym razie tworzy jeden# worktree, jeden branch, jeden blok portów i jeden oznaczony draft PR na zadanie.set -euo pipefailslug="$1"index="$2"[ "$index" -ge 1 ] || { echo "INDEX must be >= 1; 0 is the main checkout's block"; exit 1; }
# Bramka dispatchu: klasa z karty zadania, limit z tasks/caps.txt.class=$(yq -r '.class' "tasks/$slug.yaml")cap=$(awk -v c="$class" '$1 == c { print $2 }' tasks/caps.txt)[ -n "$cap" ] || { echo "no cap for class $class in tasks/caps.txt"; exit 1; }open=$(gh pr list --state open --label "class:$class" --limit 200 --json number --jq length)[ "$open" -lt "$cap" ] || { echo "class $class at cap $cap"; exit 1; }
dir="../$(basename "$PWD")-$slug"git fetch --quiet origingit worktree add --quiet -b "agent/$slug" "$dir" origin/maincat > "$dir/.agent-env" <<ENVAPP_PORT=$((3000 + index * 10))DEBUG_PORT=$((9229 + index * 10))DATABASE_NAME=app_${slug//-/_}ENV
# Zajmij slot: od tej chwili ten draft PR liczy się do limitu.git -C "$dir" commit --quiet --allow-empty -m "Start agent/$slug"git -C "$dir" push --quiet -u origin "agent/$slug"gh pr create --draft --head "agent/$slug" --label "class:$class" \ --title "agent: $slug" --body "Task card: tasks/$slug.yaml"echo "Worktree $dir on agent/$slug"cat "$dir/.agent-env"Limity są w tasks/caps.txt, po jednej klasie i jej limicie w wierszu, na przykład vertical-slice 3 i migration 1, a polityka poniżej wskazuje ten plik, zamiast powtarzać liczby. Raz utwórz etykietę class:<nazwa> dla każdej klasy, na przykład gh label create class:vertical-slice, bo gh pr create --label kończy się błędem dla etykiety, która nie istnieje. Skrypt potrzebuje gh, git i yq v4 (mikefarah/yq; -r działa też z pythonowym yq).
Uruchamiaj go z głównego checkoutu, na przykład scripts/agent-task.sh billing-retry 2. Zaczynaj INDEX od 1: indeks 0 dałby zadaniu domyślne porty głównego checkoutu, czyli dokładnie tę kolizję, której skrypt ma zapobiegać. Cztery szczegóły są celowe. Draft PR otwiera się przy dispatchu, a nie wtedy, gdy agent skończy, więc praca w toku liczy się do limitu i nigdy nie ukrywa się jako branch, którego nikt nie widzi. Prefiks branchy agent/ pozwala każdemu późniejszemu skryptowi znaleźć pracę równoległą. Krok portów równy 10 trzyma narzędzie, które przy zajętym porcie przechodzi na „następny wolny”, w obrębie jego własnego bloku. Dodaj .agent-env do .gitignore i niech skrypty dev go czytają, żeby porty działały bez pamiętania o export. Jeśli domyślny branch nazywa się inaczej, zamień origin/main.
Przy równoczesnym dispatchu bramka jest tylko doradcza: dwie osoby, które uruchomią dispatch w tej samej minucie, obie zobaczą wolny slot, a klasa przekroczy limit. Wyłapią to sprawdzenie nakładania się i przegląd limitów. Jeśli potrzebujesz twardego limitu, uruchamiaj dispatch z jednego workflow w jednej grupie concurrency: w GitHub Actions.
Każde z narzędzi potrafi też samo utworzyć worktree. Izolacja portów i danych nadal jest po twojej stronie we wszystkich trzech.
Sprawdzone z Claude Code 2.1.283 (claude --help):
claude --worktree billing-retry(krótko-w) uruchamia sesję w nowym Git worktree. Dodaj--tmux, żeby otworzyć ten worktree we własnej sesji tmux;--tmuxwymaga--worktree.claude --bguruchamia sesję w tle i wypisuje jej ID;claude agentsotwiera agent view (research preview), który wyświetla sesje w tle i pokazuje, które z nich czekają na odpowiedź.- Wbudowany skill
/batchdzieli jedną dużą zmianę na 5–30 jednostek, każdą we własnym worktree. Traktuj każdą jednostkę jak zadanie: nadaj jej posiadane ścieżki tak, jak zrobiłaby to karta, i licz ją do limitu jej klasy. claude rm <id>usuwa sesję w tle wraz z jej worktree, gdy jest to bezpieczne, co załatwia większość sprzątania.
Sprawdzone z Codex CLI 0.157.1 (codex --help, codex features list):
codex --worktreeuruchamia sesję w nowym zarządzanym Git worktree; wewnątrz sesji to samo robi/worktree. Obsługa worktrees jest domyślnie włączona od 0.156.0, ale sesja korzysta z worktree tylko wtedy, gdy o to poprosisz.codex agentsprzegląda wszystkie sesje agentów na współdzielonym lokalnym demonie app-server.- Aplikację desktopową i sprzątanie opisuje strona Codex worktrees.
Według dokumentacji Cursora sprawdzonej 2026-08-28 (cursor.com był niedostępny przy ponownym sprawdzeniu 2026-09-26):
- Worktrees „let Agent work in isolated Git checkouts”.
- Cloud Agents „run in isolated VMs in the cloud with full development environments”, co izoluje porty i usługi, a nie tylko pliki.
- Zanim ustandaryzujesz jedną z tych opcji, przeczytaj Cursor Cloud Agents i automatyzacje.
Sprzątaj według harmonogramu, a nie wtedy, gdy zapełni się dysk. git worktree list pokazuje każdy checkout; git worktree remove <dir> odmawia, gdy worktree ma niezacommitowane lub nieśledzone pliki, a git branch -d agent/<slug> odmawia, gdy branch nie jest zmergowany. Obie odmowy to zabezpieczenie, którego chcesz: nigdy nie dodawaj --force do skryptu sprzątającego. Potem uruchom git worktree prune, żeby usunąć wpisy katalogów skasowanych ręcznie. Nadzór nad wieloma sesjami naraz opisuje strona wiele agentów jednocześnie.
Ustal limit współbieżności per klasa zadań
Dział zatytułowany „Ustal limit współbieżności per klasa zadań”Limit per inżynier („po trzy agenty”) ignoruje jedyne ograniczenie, które ma znaczenie: jak szybko zespół potrafi weryfikować i integrować. Wyprowadź limit z kolejki.
- Policz limit WIP review. Użyj metody z Kolejki code review: zmierzona przepustowość review pomnożona przez czas w review, który jesteś w stanie zaakceptować. Ta liczba to sufit dla wszystkich otwartych pull requestów agentów łącznie.
- Podziel sufit między klasy zadań. Każdej klasie równoległej daj udział, każdej klasie szeregowej limit równy jeden. Zacznij nisko; eksperyment poniżej powie ci, kiedy podnieść limity.
- Blokuj dispatch, a nie tworzenie pull requestów. Bramką jest
scripts/agent-task.shpowyżej: liczy otwarte pull requesty z etykietąclass:<nazwa>, łącznie z draftami, i odmawia, gdy klasa osiągnęła limit ztasks/caps.txt. Blokada przy tworzeniu pull requesta zostawiłaby gotową pracę agenta na branchu, którego nikt nie widzi. Jeśli agenty startują też z workflow albo harmonogramu, najpierw uruchom tam te same linie bramki. - Sprawdzaj osobno pojemność CI. Jeśli mediana przebiegu CI dla partii dłużej czeka w kolejce, niż trwa, to CI jest ograniczeniem i limit spada, dopóki tak nie jest.
- Przeglądaj limity co dwa tygodnie. Zmieniają się, gdy zmienia się przepustowość. Obniż limit klasy w tym tygodniu, w którym rośnie jej rework, bez czekania na przegląd.
Wyznacz właściciela integracji i kolejność merge
Dział zatytułowany „Wyznacz właściciela integracji i kolejność merge”Konflikty tekstowe to łatwy przypadek — Git je zgłasza. Groźne są konflikty semantyczne: dwa branche, z których każdy przechodzi własne checki, a razem psują build, na przykład jeden zmienia nazwę pola, a drugi dodaje wywołanie starej nazwy. Po to istnieje właściciel integracji.
Właściciel integracji partii ustala kolejność merge na podstawie depends_on z kart zadań, rebase’uje każdy branch na najnowszy domyślny branch przed merge (albo prosi o to agenta) i uruchamia pełny zestaw testów na połączonym wyniku, a nie tylko checki danego zadania. Jeśli twoja platforma oferuje merge queue, używaj jej: testuje każdy pull request razem z tymi zmergowanymi przed nim, czyli dokładnie sprawdza konflikty semantyczne. Właściciel zatwierdza połączony wynik, a nie każdy diff z osobna.
Uruchamiaj sprawdzenie nakładania się przed merge, żeby konflikty wychodziły, póki są jeszcze decyzją, a nie niespodzianką:
#!/usr/bin/env bash# Wypisz każdy plik, który zmienia więcej niż jeden otwarty branch agent/*.set -euo pipefailgit fetch --quiet originfor head in $(gh pr list --state open --limit 200 --json headRefName \ --jq '.[].headRefName' | grep '^agent/'); do git diff --name-only "origin/main...origin/$head" | sed "s|\$| origin/$head|"done | sort | awk '{ n[$1]++; b[$1] = b[$1] " " $2 } END { for (f in n) if (n[f] > 1) print f ":" b[f] }'Pętla czyta otwarte pull requesty, a nie zdalne branche, więc zmergowany branch, którego nikt nie usunął, nie pojawi się jako nakładanie się. Pusty wynik oznacza, że żadne dwa otwarte branche nie dotykają tego samego pliku. Linia taka jak src/billing/client.ts: origin/agent/billing-retry origin/agent/invoice-pdf oznacza, że zadanie złamało swoją kartę; właściciel decyduje, który branch zachowuje zmianę, a który robi rebase.
Zastąp BRANCH_A i BRANCH_B slugami obu zadań. Sprawdzasz listę z kroku 2 i zielony pełny zestaw testów, a nie scalony diff linia po linii.
Udowodnij, że równoległość się opłaca względem szeregowego baseline
Dział zatytułowany „Udowodnij, że równoległość się opłaca względem szeregowego baseline”Zespół, który liczy działające agenty albo otwarte pull requesty, zawsze dojdzie do wniosku, że więcej znaczy lepiej. Mierz to, co dociera na produkcję, i porównuj z tym samym zespołem pracującym nad jednym zadaniem naraz.
| Metryka | Definicja | Źródło |
|---|---|---|
| Zaakceptowany throughput | Zmergowane pull requesty agentów na inżyniera tygodniowo, które przechodzą CI i nie zostały cofnięte ani ponownie otwarte w ciągu 14 dni | gh pr list --state merged plus wyszukiwanie revertów |
| Wskaźnik reworku | Odsetek zmergowanych pull requestów agentów, które w ciągu 14 dni wymagają poprawki | etykieta rework nadawana przez właściciela integracji |
| Wskaźnik konfliktów | Odsetek pull requestów agentów, które przed merge wymagały rozwiązania konfliktu | etykieta conflict albo log sprawdzenia nakładania się |
| Czas w review | Od oznaczenia jako gotowy do review do merge, mediana i 90. percentyl; PR agentów startują jako drafty przy dispatchu | zdarzenie ready_for_review na osi czasu każdego pull requesta; zobacz Kolejkę code review |
| Porzucona praca | Branche lub worktrees agent/ bez commita od siedmiu dni | git for-each-ref --sort=-committerdate refs/remotes/origin/agent/ |
Porównanie przeprowadź jako dwutygodniowy eksperyment na jednej klasie zadań. W pierwszym tygodniu każdy inżynier prowadzi jedno zadanie agenta naraz. W drugim klasa działa z proponowanym limitem. Rodzaj zadań i recenzenci pozostają bez zmian. Podnieś limit tylko wtedy, gdy zaakceptowany throughput na inżyniera wzrósł i wskaźnik reworku, wskaźnik konfliktów oraz czas w review zostały w granicach twoich celów. Jeśli throughput wzrósł, a rework razem z nim, dodatkowy output nie był zaakceptowaną pracą; utrzymaj albo obniż limit.
Zastąp START_DATE pierwszym dniem okna w formacie YYYY-MM-DD, a BASELINE tabelą z pierwszego tygodnia. Rekomendacja to propozycja; limit ustala tech lead.
Przyjmij politykę pracy równoległej zespołu
Dział zatytułowany „Przyjmij politykę pracy równoległej zespołu”Zacommituj politykę obok skryptów, żeby agenty i ludzie czytali te same zasady. Dostosuj liczby do swoich pomiarów; to struktura daje dowody do Q14.
# Polityka równoległej pracy agentów
Właściciel: TECH_LEAD · Przegląd co dwa tygodnie · Ostatnia zmiana: DATE
## Kwalifikacja- Równolegle działają tylko klasy zadań oznaczone w tabeli klas jako Równolegle.- Klasy szeregowe (współdzielony kontrakt, migracja, aktualizacja zależności, zmiana przekrojowa) działają pojedynczo, a zależne zadania czekają na ich merge.- Bez karty zadania nie ma dispatchu: posiadane ścieżki, checki, warunki stopu, właściciel integracji.
## Izolacja- Każde zadanie startuje przez scripts/agent-task.sh: własny worktree, branch agent/<slug>, blok portów, nazwa bazy danych. Żadnego wspólnego dev servera ani bazy.- Sekrety pochodzą z zatwierdzonej lokalnej konfiguracji, nigdy nie są kopiowane od kolegi.
## Limity- Limit WIP review zespołu: N otwartych PR agentów (wyliczony w arkuszu kolejki review).- Limity per klasa są w tasks/caps.txt, po jednej parze „klasa limit” w wierszu; każda klasa szeregowa ma limit 1.- scripts/agent-task.sh jest bramką dispatchu: odrzuca nową pracę, gdy klasa osiągnęła limit, a każdy PR agenta ma etykietę class:<nazwa>.
## Integracja- Każda partia ma właściciela integracji. Ustala kolejność merge, uruchamia pełny zestaw testów na połączonym wyniku i go zatwierdza.- scripts/agent-overlap.sh działa przed każdym merge; każde nakładanie się go blokuje.
## Pomiar i sprzątanie- Co tydzień: zaakceptowany throughput, rework, konflikty, czas w review, porzucona praca.- Worktrees i branche agent/* bezczynne od 7 dni są przeglądane i usuwane bez --force.Zastąp TECH_LEAD, DATE i N własnymi wartościami, a liczby per klasa wpisz do tasks/caps.txt. Pięć sekcji odpowiada jeden do jednego odpowiedzi za pełne punkty w Q14, więc dowodem w scorecardzie jest link do tego pliku.
Co się psuje, gdy zespół uruchamia agenty równolegle
Dział zatytułowany „Co się psuje, gdy zespół uruchamia agenty równolegle”Liczba pull requestów rośnie, a releasów nie przybywa. Niedokończona praca piętrzy się w review, a dashboardy wyglądają zdrowo. Naprawa: wstrzymaj dispatch dla klasy, opróżnij kolejkę poniżej limitu, potem wznów pracę z ostatnim limitem, przy którym zaakceptowany throughput był najwyższy.
Dwa zielone branche razem psują build. Konflikt semantyczny przeszedł checki każdego zadania osobno. Naprawa: cofnij późniejszy merge, dodaj test, który ujawnia konflikt, i wymagaj pełnego zestawu testów na połączonym wyniku — przez właściciela integracji albo merge queue.
Testy przechodzą albo nie, zależnie od tego, kto jeszcze pracuje. Worktrees izolowały pliki, ale nie port, bazę danych ani cache. Naprawa: przenieś każde zadanie na skrypt izolacji, a polecenia dev i testów niech czytają .agent-env zamiast wartości domyślnych.
Agent edytuje współdzielony kontrakt, żeby dokończyć zadanie. read_only_paths z karty były radą, a nie bramką. Naprawa: cofnij zmianę kontraktu, zrób z niej zadanie szeregowe i uruchamiaj w CI sprawdzenie zakresu dla każdego pull requesta z brancha agent/:
#!/usr/bin/env bash# Zakończ błędem, gdy branch agent/<slug> zmienia plik spoza owned_paths swojej karty.# Blokuje domyślnie: brak karty, puste owned_paths albo nieudany diff to błąd.set -euo pipefailslug="${1:-${GITHUB_HEAD_REF:?pass SLUG or run on a pull request}}"slug="${slug#agent/}"head="${2:-HEAD}"card="$(git show "origin/main:tasks/$slug.yaml")" || { echo "no card tasks/$slug.yaml on origin/main"; exit 1; }mapfile -t globs < <(yq -r '.owned_paths[]' <<<"$card")(( ${#globs[@]} > 0 )) || { echo "card has no owned_paths"; exit 1; }changed="$(git diff --name-only "origin/main...$head")" || { echo "cannot diff origin/main...$head"; exit 1; }status=0while read -r file; do [[ -z $file ]] && continue [[ $file == tasks/* ]] && { echo "task card edited: $file"; status=1; continue; } for glob in "${globs[@]}"; do [[ $file == $glob ]] && continue 2; done echo "outside owned_paths: $file"; status=1done <<<"$changed"exit "$status"Skrypt czyta kartę z origin/main, a nie z brancha, i kończy się błędem przy każdej zmianie w tasks/, więc agent nie poszerzy sobie zakresu, edytując własną kartę. Domyślnie też blokuje: brak karty, puste owned_paths albo diff, którego nie da się policzyć, to błąd, a nie zielone światło. Sam skrypt nie jest jednak odporny na manipulację. Przy wyzwalaczu pull_request GitHub uruchamia plik workflow z samego pull requesta, więc branch w tym samym repozytorium może zmienić job tak, żeby pominął krok albo uruchomił własną kopię skryptu, a check i tak będzie zielony. Prawdziwą kontrolą jest review: wpis w CODEOWNERS, który przypisuje .github/, scripts/agent-scope.sh i tasks/ właścicielom integracji, oraz reguła ochrony brancha (albo ruleset) na main, która wymaga review od code ownera i czyni ten check obowiązkowym. Wtedy branch, który dotyka bramki, nie zostanie zmergowany bez osoby, która za nią odpowiada. Na pull_request daj jobowi permissions: contents: read, żadnych sekretów i persist-credentials: false przy checkoucie. Alternatywą jest pull_request_target, który zawsze uruchamia workflow z domyślnego brancha. Taki job działa z tokenem repozytorium bazowego, więc zostaw go przy contents: read, bez sekretów, zrób checkout wyłącznie main z persist-credentials: false i pobierz head pull requesta jako dane, bez checkoutu i bez uruchamiania czegokolwiek z niego:
on: pull_request_target: branches: [main]permissions: contents: readjobs: scope: if: startsWith(github.head_ref, 'agent/') runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 with: ref: main fetch-depth: 0 persist-credentials: false - name: Fetch the pull request head as data env: PR_NUMBER: ${{ github.event.pull_request.number }} GH_TOKEN: ${{ github.token }} run: | auth="$(printf 'x-access-token:%s' "$GH_TOKEN" | base64 -w0)" echo "::add-mask::$auth" git -c http.extraheader="AUTHORIZATION: basic $auth" fetch origin "refs/pull/$PR_NUMBER/head" - run: bash scripts/agent-scope.sh "$GITHUB_HEAD_REF" FETCH_HEADFetch korzysta z refs/pull/<number>/head, który istnieje także dla pull requestów z forków, gdzie nazwy brancha nie ma w origin. Token tylko do odczytu trafia wyłącznie do tego jednego git fetch przez -c http.extraheader i nigdy nie jest zapisywany w .git/config; w publicznym repozytorium nagłówek można pominąć. Do mapfile potrzebny jest bash 4 lub nowszy (runnery CI go mają; na macOS zainstaluj bash przez Homebrew) i yq v4. W dopasowaniu wzorców w bashu * przechodzi przez /, więc src/billing/retry/** obejmuje całe drzewo katalogu. Pobierz historię wystarczającą, żeby diff z trzema kropkami znalazł merge base (w GitHub Actions fetch-depth: 0).
Worktrees i branche się mnożą. Dyski się zapełniają, a nieaktualne branche zaśmiecają każdą listę agent/* i raport bezczynności. Naprawa: co tydzień uruchamiaj raport siedmiodniowej bezczynności, usuwaj zmergowane i porzucone elementy poleceniami bez --force i zapisuj, kto zatwierdził każde usunięcie.
Inżynierowie nadzorują więcej sesji, niż są w stanie śledzić. Review zamienia się w bezrefleksyjne zatwierdzanie. Naprawa: zmniejsz liczbę sesji na inżyniera i rotuj dyżur review, jak opisuje sekcja o zrównoważonym tempie w Kolejce code review.
Dokąd dalej po równoległej pracy zespołu
Dział zatytułowany „Dokąd dalej po równoległej pracy zespołu”Równoległość jest stabilna, gdy limity trzymają się przez miesiąc bez rosnącego reworku. Następny szczebel drabiny to praca, która działa bez człowieka obserwującego sesję — ma to sens dopiero wtedy, gdy bramki z tej strony są na miejscu.