Przejdź do głównej zawartości

Auto-PR workflow — Stop hook który dowozi i wybudza Cię na review

Q16 · Równoległość i automatyzacja Jak powstają Twoje PR-y, gdy praca się kończy?

Odpowiedź na maks: “Stop hook, który automatycznie otwiera PR i wybudza mnie na feedback z review.”

Dlaczego to ważne: Pętla auto-PR + fix review zmienia “kod napisany” w “PR dowieziony” bez ludzkiej księgowości pośrodku.

W 2026 wąskie gardło się przesunęło. Kodowanie wspomagane przez AI podbiło wolumen PR-ów o ok. 29% rok do roku, a hamulec to już nie “pisanie kodu” — to księgowy pierścień wokół kodu: odbicie się od właściwej gałęzi bazowej, push, otwarcie PR-a z sensownym tytułem, czekanie na podsumowanie CodeRabbita, naprawianie uwag z Copilot Code Review, ponowny push, czekanie na CI i wreszcie merge. Solo developer, który pisze feature w 25 minut, łatwo poświęci kolejne 25 minut na ten pierścień. Pomnóż to przez 8–12 PR-ów dziennie i “podatek dowozowy” staje się największym wyciekiem w Twoim tygodniu. Agenci stali się niesamowicie dobrzy w pisaniu patcha; pozostali fatalni w przekazywaniu patcha, dopóki nie powiesz im jak, za każdym razem od nowa. Stop hook zamyka tę lukę. Gdy agent kończy istotną pracę, nie czeka na “teraz zrób PR” — robi stage, commit, push, otwiera PR przez gh pr create, obserwuje komentarze review i wybudza agenta w chwili, gdy pojawia się coś do zrobienia. W połączeniu z gh pr merge --auto --squash --delete-branch pętla zamyka się sama, gdy CI staje na zielono. To różnica między agentem, który produkuje kod, a takim, który produkuje zmergowany kod.

Pełny punkt na Q16 zdobywasz wyłącznie wtedy, gdy wszystkie pięć poniższych prawdziwych w danym dniu:

  • Agent nie pyta o pozwolenie na dowiezienie. Gdy istotna praca produkuje commity albo zmiany w stagingu, agent pushuje feature branch i otwiera PR automatycznie — żadnych “czy mogę teraz otworzyć PR?” w połowie Twojego dnia. Decyzja żyje w kodzie (hook + reguła workflow), a nie w Twojej pamięci roboczej.
  • Workflow odpala Stop hook. Gdy główna tura agenta się kończy, uruchamia się skrypt Stop hook (zwykle ~/.claude/hooks/auto-pr-watch.sh), decyduje, czy bieżący stan repo wymaga akcji ship, fix, czy żadnej, i albo prowadzi akcję bezpośrednio, albo wybudza agenta wąsko sprecyzowanym promptem.
  • Feedback review wybudza agenta z powrotem. Gdy CodeRabbit, Copilot Code Review, ludzki recenzent albo failujący check GitHub Actions postują nowe komentarze po Twoim ostatnim pushu, hook wykrywa nową aktywność (porównując ID komentarzy i SHA HEAD-a do zapisanej sygnatury) i odpala cykl fix. Agent czyta każdy actionable komentarz, robi poprawkę, commituje i pushuje — potem czeka ograniczony interwał (4 min → 12 min to sprawdzona w boju para) na późne komentarze, zanim ogłosi zakończenie.
  • Auto-merge jest kolejkowany, nie wymuszany. Gdy pętla recheck-u uspokoi się bez nic do zrobienia, agent odpala gh pr merge --squash --delete-branch --auto. Flaga --auto kolejkuje merge do momentu, gdy wymagane checki przejdą — nie nadpisuje branch protection, nie pomija CI ani nie przebija blockera flagą --admin. Jeśli checki failują albo recenzenci żądają zmian, pętla wystawia blocker Tobie, zamiast zgadywać.
  • Pętla kończy się naturalnie. Stan jest śledzony per repo jako sygnatura w stylu (akcja, branch/PR#, head_sha, max_comment_id). Gdy agent zadziałał już na danym stanie, hook nie wybudzi go ponownie dla tego samego stanu — tylko dla realnie nowej aktywności. Pętla kończy się, bo komentarze przestają przychodzić, a nie dlatego, że ktoś dodał timer.

Cokolwiek słabszego — “mam skrypt, który tworzy PR, ale sprawdzam go ręcznie”, albo “mam hook, który otwiera PR, ale nie pilnuje review”, albo “pozwalam agentowi mergować, kiedy mu się chce” — jest mid-tier na Q16.

Claude Code wypuścił system hooków na początku 2026 z 27 zdarzeniami lifecycle; Stop hook odpala się, gdy agent kończy odpowiadanie, i jest naturalnym punktem przekazania dla pracy auto-PR. Hooki to deterministyczne komendy shell wpięte w ~/.claude/settings.json — model ich nie wybiera, harness je egzekwuje. To cały trik: hooki zmieniają “agent powinien pamiętać o otwarciu PR-a” (czego nie zrobi) w “harness otwiera PR, deterministycznie” (co robi). Równolegle GitHub Copilot Code Review i CodeRabbit stały się dwoma dominującymi botami review, a oba postują ustrukturyzowany, czytelny maszynowo feedback, który agent może zjeść. Klocki są wszystkie. Robota to zlepić je razem.

Faza ship odpala się w chwili, gdy główna tura agenta kończy się z niezacommitowaną pracą albo niewypushowanymi commitami. Skrypt hooka rozwiązuje branch domyślny repo (nie hardkoduj main — niektóre repo używają master, preview, develop), tworzy feature branch, jeśli siedzisz na default, commituje stagged pracę conventional message-m i otwiera PR.

Okno terminala
# Rozwiąż branch domyślny — nigdy nie hardkoduj.
default=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name)
current=$(git rev-parse --abbrev-ref HEAD)
# Jeśli jesteśmy na default, odbij się przed pushem.
if [ "$current" = "$default" ]; then
git checkout -b "feat/$(date +%s)-auto"
fi
# Stage i commit (conventional message podniesiony z diffa).
git add -A
git commit -m "feat: <zmiana podsumowana przez agenta>" || true
# Push i otwarcie PR-a. gh domyślnie ustawia --base na bazę repo.
git push -u origin HEAD
gh pr create \
--title "feat: <zmiana podsumowana przez agenta>" \
--body "$(cat <<'EOF'
## Summary
- <bullets podniesione z commit messages>
## Test plan
- [ ] CI przechodzi
- [ ] Manualny smoke
🤖 Generated with Claude Code
EOF
)"

Reguły krytyczne: nie pauzuj na potwierdzenie przed pushem, nie hardkoduj branch bazowego i nie używaj --no-verify, żeby pominąć pre-commit hooki — jeśli hook fail-uje, commit się nie wydarzył, więc napraw problem i zrób nowy commit. Nigdy nie rób --amend po failu hooka (to po cichu nadpisze poprzedni dobry commit).

Faza 2 to część, którą większość ludzi pomija — i powód, dla którego ich wynik Q16 cap-uje się na “mam skrypt otwierający PR-y”. Agent musi wrócić do PR-a po tym, jak boty i ludzie zostawią swoje notatki. Hook zajmuje się obserwacją; agent zajmuje się naprawą.

Dla każdego otwartego PR-a, za który odpowiada Twój hook, pobierz każdą powierzchnię feedbacku:

Okno terminala
# Konwersacja top-level
gh pr view "$PR" --comments
# Inline review comments
gh api "repos/$OWNER/$REPO/pulls/$PR/comments"
# Podsumowania review (CodeRabbit, Copilot, ludzcy recenzenci)
gh api "repos/$OWNER/$REPO/pulls/$PR/reviews"
# Status CI
gh pr checks "$PR"
gh run view "$RUN_ID" --log-failed # dla każdego failującego joba

Traktuj wszystkie cztery jako w zakresie: ludzcy recenzenci, CodeRabbit (który od kwietnia 2026 spawnuje własnego agenta kodowania przez Autofix na planie Pro), Copilot Code Review (multi-agent architektura, która zbiera pełny kontekst repo przed komentowaniem, daje actionable feedback w ~71% review) i log GitHub Actions. Pomiń potwierdzenia, off-topic chatter i pytania, na które już odpowiedziałeś.

Dla każdego actionable komentarza agent: analizuje prośbę, implementuje fix, commituje z jasnym message-m i pushuje. Nie pauzuj na potwierdzenie. Nie nadpisuj historii squashem — pushuj nowe commity, żeby recenzenci widzieli delty, o które prosili.

Pętla recheck-u to sekretny sos. Późne komentarze to norma — CodeRabbit dodaje follow-up 30–90 sekund po pushu, Copilot Code Review potrafi zająć 2–5 minut, ludzie dryfują przez godziny. Para backoff-u 4 min → 12 min jest sprawdzona w boju: 4 min (240s) mieści się w TTL prompt-cache-a; 12 min pokrywa wolniejsze CI i ludzki follow-up. Jeśli wait wystawi nowe actionable komentarze, wróć i zresetuj backoff. Jeśli oba waity nic nie zwrócą, wyjdź do Fazy 3.

Gdy pętla recheck-u uspokoi się bez actionable komentarzy, sprawdź gotowość merge-a i zakolejkuj go:

Okno terminala
# Są blockery?
gh pr view "$PR" --json statusCheckRollup,reviewDecision,mergeable,mergeStateStatus
# Realne blockery: checki FAILURE/CANCELLED, CHANGES_REQUESTED, CONFLICTING.
# Pending checki to NIE blocker — --auto na nie czeka.
# Sprawdź, które metody merge dopuszcza repo.
gh api "repos/$OWNER/$REPO" --jq '{squash:.allow_squash_merge,merge:.allow_merge_commit,rebase:.allow_rebase_merge}'
# Zakolejkuj merge.
gh pr merge "$PR" --squash --delete-branch --auto

--auto kolejkuje merge do momentu, gdy wymagane checki przejdą. Jeśli repo nie ma włączonego auto-merge i flaga zwróci błąd, opuść --auto i mergeuj tylko wtedy, gdy wszystko jest już zielone. Jeśli --squash nie jest dozwolony, ponów z --merge albo --rebase. Po wylądowaniu merge-a, odtwórz czysty stan lokalny: git checkout "$default" && git pull --ff-only && git branch -d <merged-branch>. Małe -d odmawia usunięcia niezmergowanej pracy, więc jest bezpieczne.

Przy każdym realnym blockerze (failujący CI, konflikty, requested changes), wystaw go. Nigdy nie nadpisuj flagą --admin. Ta jedna linia jest różnicą między automatyzacją, która pomaga, a automatyzacją, która w piątek dowozi zepsuty kod.

Hook musi pamiętać, co już zrobił, albo będzie się odpalać na każdym Stop evencie i albo zaspamuje PR, albo — gorzej — wprowadzi agenta w nieskończoną pętlę. Wzorzec, który działa, to per-repo plik sygnatury w ~/.claude/auto-pr-state/<repo-hash>.json zawierający tuplę (akcja, branch/PR#, head_sha, max_comment_id). Hook liczy bieżącą sygnaturę, porównuje z zapisaną i:

  • Jeśli sygnatura się nie zmieniła, nie rób nic — agent już obsłużył ten stan.
  • Jeśli tylko max_comment_id poszło w górę, wybudź agenta promptem fix.
  • Jeśli head_sha poszło w górę albo PR jest nowy, to świeży stan — zapisz go i zdecyduj, czy budzić.

Żeby zresetować jedno repo: rm ~/.claude/auto-pr-state/<hash>.json. Żeby wyczyścić wszystko: rm ~/.claude/auto-pr-state/*.json. Żeby opt-outować globalnie: zakomentuj hook w ~/.claude/settings.json.

Minimalny działający wpis w ~/.claude/settings.json:

{
"hooks": {
"Stop": [
{
"matcher": "*",
"hooks": [
{ "type": "command", "command": "~/.claude/hooks/auto-pr-watch.sh" }
]
}
]
}
}

Sam auto-pr-watch.sh jest krótki: czyta stan repo, liczy sygnaturę, decyduje między ship, fix albo noop i używa asyncRewake (albo odpowiednika z Twojego harnessa), żeby wybudzić agenta wąsko sprecyzowanym promptem typu “Faza 2 fix: PR #421 ma 3 nowe komentarze CodeRabbita, proszę je zaadresować.” Hook nigdy nie robi roboty — tylko powiadamia. Logika workflow zostaje w promptcie agenta, gdzie ma być.

  1. Sprawdź, że gh jest zainstalowany i zalogowany. Odpal gh auth status. Jeśli nic nie raportuje, odpal gh auth login i wybierz protokół SSH albo HTTPS pasujący do Twoich istniejących git remote-ów. Stop hook jest bez tego bezużyteczny.

  2. Wybierz trigger states, które Twój hook będzie rozpoznawał. Minimum to ship (niezacommitowana praca albo niewypushowane commity na non-default branchu) i fix (otwarty PR dla bieżącego brancha ma komentarze nowsze niż zapisana sygnatura). Opcjonalnie: merge (Faza 3 gotowa) i noop (nic do zrobienia).

  3. Napisz ~/.claude/hooks/auto-pr-watch.sh. Zrób go wykonywalnym (chmod +x). Powinien liczyć bieżącą sygnaturę repo, czytać ~/.claude/auto-pr-state/<hash>.json, decydować akcję, zapisywać nową sygnaturę i albo prowadzić gh bezpośrednio (dla całkowicie mechanicznych kroków), albo wołać API “wybudź agenta” Twojego harnessa z wąskim promptem.

  4. Wepnij Stop hook w ~/.claude/settings.json. Użyj snippetu JSON pokazanego wyżej. Zrestartuj sesję Claude Code, żeby nowa konfiguracja hook-a się załadowała.

  5. Dodaj projektową regułę workflow. W CLAUDE.md (albo odpowiedniku Twojego projektu) udokumentuj kontrakt Fazy 1/2/3 wprost: gdy praca się kończy, pushuj i otwieraj PR bez pytania; gdy przychodzi feedback review, naprawiaj i pushuj bez pytania; gdy pętla recheck-u się uspokoi, kolejkuj auto-merge. Hook tylko powiadamia; agent musi wiedzieć, co robić po powiadomieniu.

  6. Przetestuj na PR-ze do wyrzucenia. Wybierz drobną zmianę (poprawka literówki, tweak komentarza), pozwól agentowi skończyć i obserwuj, jak hook prowadzi Fazę 1. Sam dodaj komentarz do PR-a, poczekaj i obserwuj, jak odpala Faza 2. Zaaprobuj PR, obserwuj, jak Faza 3 kolejkuje merge.

  7. Wyreguluj backoff do tempa review Twojego zespołu. 4 min → 12 min to rozsądny default. Jeśli pracujesz z planem CodeRabbit Pro postującym branche Autofix, możesz chcieć trzeci wait 25-minutowy, żeby złapać commit Autofix-a. Jeśli jesteś solo, trzymaj ciasno.

  8. Dodaj frazę opt-out. Wybierz zdanie typu “nie rób z tego PR-a” albo “to eksploracja” — gdy je powiesz, agent pomija Fazę 1 całkowicie. To zawór bezpieczeństwa dla spike-ów, prototypów i pracy na zepsutym stanie.

  • Push prosto na branch domyślny. Najdroższy pojedynczy błąd. Zawsze rozwiązuj default-a przez gh repo view --json defaultBranchRef --jq .defaultBranchRef.name i odbij się od niego, jeśli na nim siedzisz. Jeśli commity już wyciekły na default-a, zresetuj go do originu przed pushem — nigdy nie force-pushuj brancha domyślnego.
  • --no-verify, żeby ominąć pre-commit hooki. Jeśli hook fail-uje, commit się nie wydarzył. Pomijanie hooka po cichu dowozi zepsuty kod. Napraw przyczynę i zrób nowy commit. Ta sama reguła dla --no-gpg-sign i innych flag w stylu “spraw, żeby błąd zniknął” — badaj, nie omijaj.
  • Force-push na main / master / preview. Nigdy. Nawet z --auto-merge. Jeśli widzisz, że Twój hook sięga po git push -f przeciwko default-owi, zabij hooka, zanim wyląduje. Force-push do własnego feature brancha jest OK; force-push na shared branch to sposób na utratę cudzej pracy.
  • --amend po failującym pre-commit hook-u. Commit się nie wydarzył, więc --amend modyfikuje poprzedni commit — zwykle niszcząc wcześniejszą pracę. Po failu hooka zawsze rób nowy commit.
  • --admin-override przy gh pr merge. To omija branch protection. Nigdy nie jest właściwym ruchem z automatycznego hooka. Jeśli checki fail-ują albo recenzenci żądają zmian, pętla musi wystawić blocker Tobie i się zatrzymać.
  • Zapomnienie o deduplikacji przez plik sygnatury. Bez sygnatury Stop hook odpala się na każdej turze i albo zaspamuje PR duplikatami fixów, albo zakleszcza agenta w nieskończonej pętli “Faza 2 znowu”. Sygnatura jest tym, co kończy pętlę.
  • Traktowanie każdego komentarza jako actionable. Potwierdzenia (“LGTM!”), pytania, na które już odpowiedziałeś, i off-topic chatter nie powinny odpalać cyklu fix. Filtruj komentarze, które wprost proszą o zmiany albo raportują blockery.
  • Brak frazy opt-out. Spike-i, prototypy i exploracyjne branche nie chcą PR-a. Jeśli nie umiesz powiedzieć “pomiń Fazę 1”, hook będzie z Tobą walczył na pracy do wyrzucenia.
  • Masz skrypt Stop hook-a w ~/.claude/hooks/auto-pr-watch.sh (albo odpowiedniku Twojego harnessa) i jest on wpięty w ~/.claude/settings.json.
  • Gdy agent kończy istotną pracę na feature branchu, PR pojawia się na GitHubie bez tego, byś ręcznie odpalał gh pr create.
  • Stop hook rozwiązuje branch domyślny dynamicznie — możesz przenieść go z main na preview i workflow nadal działa.
  • Gdy CodeRabbit, Copilot Code Review, ludzki recenzent albo failujący check GitHub Actions postują nowe komentarze, agent wybudza się i adresuje je w ciągu ~5 minut — bez konieczności, byś re-pejstował komentarze.
  • Po uspokojeniu się pętli recheck-u bez actionable komentarzy, gh pr merge --squash --delete-branch --auto jest kolejkowany automatycznie.
  • Masz per-repo plik sygnatury w ~/.claude/auto-pr-state/ i hook nie odpala się ponownie na tym samym stanie dwa razy.
  • Masz frazę opt-out (“nie rób z tego PR-a”) i ona faktycznie pomija Fazę 1.
  • Nigdy nie widziałeś, by hook sięgał po --no-verify, --admin albo git push -f na shared brancha. Jeśli widziałeś, zabiłeś hooka, zanim wylądował.