---
title: "Jak działa /monolynx:sprint-run: dyspozytor, który przerabia sprint sesjami w tle"
description: "Jak skill sprint-run przerabia sprint sesjami w tle: werdykty, blokery, sesje czekające na człowieka. I dlaczego zalecamy pętlę /loop 15m."
url: "https://monolynx.com/blog/jak-dziala-monolynx-sprint-run"
lang: "pl"
author: "Zespół Monolynx"
published: "2026-10-08T07:51:13.122422+00:00"
modified: "2026-10-09T10:35:16.585568+00:00"
last_verified: "2026-10-08"
tags: ["plugin", "claude-code", "agenci-ai", "scrum", "sprint"]
translations: []
reading_time_minutes: 9
word_count: 1782
---

> [!TLDR]
> - `/monolynx:sprint-run` to dyspozytor sprintu: jeden tick czyta stan sprintu i sesji w tle, startuje brakujące sesje i zbiera zakończone.
> - Każdy ticket dostaje własną sesję [/monolynx:work](https://monolynx.com/blog/jak-dziala-monolynx-work) we własnym worktree. Dyspozytor sam nigdy nie dotyka kodu.
> - Tickety z niezamkniętym blokerem i z etykietą `needs-local` nie startują, a sesje czekające na człowieka trafiają do raportu z gotową komendą.
> - Zalecamy uruchomienie w pętli: `/loop 15m /monolynx:sprint-run`. Tick jest idempotentny, więc nie zdubluje sesji ani komentarzy.

## Po co dyspozytor, skoro ticket można uruchomić ręcznie?

Jeden ticket uruchamia się jedną komendą. Sprint z dziesięcioma ticketami to już pilnowanie: który jest wolny, który czeka na merge innego, która sesja skończyła, a która stanęła na pytaniu. Dyspozytor przejmuje to pilnowanie i nic poza nim.

Skill sprint-run jest celowo cienki. Nie czyta kodu, nie edytuje plików, nie commituje. Jego praca to start sesji roboczych i księgowość wokół nich.


**Wywołanie sprint-run**

```console
# zalecane: pętla co 15 minut
/loop 15m /monolynx:sprint-run

# jeden tick ręcznie
/monolynx:sprint-run

# jeden tick z trzema równoległymi sesjami
/monolynx:sprint-run 3
```



**Statystyki**

- **1** - sesja w tle i jeden worktree na ticket
- **5** - werdyktów, które skrypt liczy dla każdego ticketu
- **1** - automatyczne wznowienie padniętej sesji, potem decyduje człowiek
- **0** - edycji kodu wykonanych przez samego dyspozytora


> Nigdy nie pracujesz nad ticketem sam. Widzisz coś do naprawienia w kodzie - to materiał na ticket, nie na Twoją turę.
> -- skill sprint-run, ważne zasady

## Dlaczego zalecamy pętlę co 15 minut?

Jedno uruchomienie skilla to jeden tick. Sesja startuje w jednym ticku, a jej wynik zbiera dopiero któryś z następnych, bo dyspozytor po starcie nie czeka i nie zagląda do logu. Pętla jest więc częścią projektu, tylko trzymaną poza skillem.

```text title="Zalecane wywołanie"
/loop 15m /monolynx:sprint-run
```

Piętnaście minut pasuje do tempa, w jakim zmienia się stan sprintu. Praca nad ticketem trwa znacznie dłużej niż jeden interwał, więc częstsze ticki widziałyby głównie to samo: sesje nadal pracują. Rzadsze zostawiałyby wolny slot pusty po zakończonej sesji i odkładały raport o sesji, która czeka na człowieka.

> [!TIP]
> Tick jest idempotentny. Stan wynika z tego, jakie sesje faktycznie żyją i jaki status ma ticket, a nie z pamięci poprzedniego przebiegu. Dwa ticki pod rząd nie zdublują sesji ani komentarza.


**Porównanie**

| Sposób | Komenda | Kiedy |
| --- | --- | --- |
| Pętla w sesji | `/loop 15m /monolynx:sprint-run` | praca przy komputerze, podgląd raportów na bieżąco |
| Skrypt w tmux | `sprint_run.sh --slots 2` | serwer, sesja ma przeżyć rozłączenie |
| Cron | `sprint_run.sh --once` co 15 minut | cron sam jest pętlą, jeden tick na wywołanie |


Dyspozytor dobrze pracuje w parze z drugą pętlą. Sesje robocze kończą się merge requestem, a te przeprowadza do brancha docelowego [mr-queue, kolejka merge uruchamiana co 10 minut](https://monolynx.com/blog/jak-dziala-monolynx-mr-queue). Po merge blokera następny tick dyspozytora sam startuje ticket, który na niego czekał.

## Co dzieje się w jednym ticku?


**Kroki**

1. **Kontrola wstępna** Skrypt sprawdza klienta, repozytorium, slug projektu i flagi autonomii. Bez kompletu tick nie startuje żadnej sesji.
2. **Stan sprintu** Skill pobiera aktywny sprint i jego tickety.
3. **Stan sesji** Skrypt zestawia tickety z żywymi sesjami w tle i z ogonami ich logów, po czym liczy werdykt dla każdego ticketu.
4. **Zbiór** Zakończone sesje dostają komentarz i są sprzątane, padnięte dostają jedno wznowienie, czekające trafiają do raportu.
5. **Dispatch** Wolne sloty obsadzają tickety w kolejności priorytetu, z pominięciem zablokowanych.
6. **Raport i linia statusu** Tabela ticketów, sekcja "Czekają na człowieka" i jedna zamrożona linia dla pętli.



**Jeden tick dyspozytora sprintu**

Tick zaczyna od sprawdzenia środowiska, potem czyta sprint i sesje w tle. Skrypt przypisuje każdemu ticketowi werdykt. Zakończone sesje są sprzątane, padnięte wznawiane raz, czekające raportowane, a wolne tickety bez blokerów dostają nowe sesje work w osobnych worktree. Tick kończy się raportem i linią statusu.

```mermaid
flowchart TD
  A["Kontrola wstępna"] --> B[Aktywny sprint i tickety]
  B --> C[Sesje w tle i ogony logów]
  C --> D{Werdykt ticketu}
  D -->|done| E[Komentarz i sprzątnięcie sesji]
  D -->|needs_human| F[Ogon logu do komentarza, jedno wznowienie]
  D -->|waiting| G[Raport: czeka na człowieka]
  D -->|running| H[Bez zmian]
  D -->|free| I{Bloker albo needs-local?}
  I -->|tak| J[Pominięty, zostaje w kolejce]
  I -->|nie| K[Start sesji work w worktree]
  E --> L[Raport i linia statusu]
  F --> L
  G --> L
  H --> L
  J --> L
  K --> L
```


## Jakie werdykty liczy skrypt?

Werdykt daje skrypt z listy sesji, statusów ticketów i ogonów logów. Model nie ocenia stanu sesji z prozy.


**Porównanie**

| Werdykt | Co oznacza | Co robi tick |
| --- | --- | --- |
| `free` | brak sesji, ticket do zrobienia | kandydat do startu |
| `running` | sesja żyje i pracuje | nic, zajmuje slot |
| `waiting` | sesja żyje, ale nie posuwa pracy | nic nie rusza, raportuje |
| `done` | ticket w statusie `in_review` albo `done`; dla dyspozytora praca sesji jest skończona | komentarz i sprzątnięcie sesji |
| `needs_human` | sesja padła bez domknięcia ticketu | ogon logu do komentarza, jedno wznowienie |


> [!NOTE]
> Nieznany stan sesji skrypt traktuje jak sesję żywą. Fałszywe "żyje" opóźnia pracę o jeden tick, a fałszywe "padła" uruchomiłoby wznowienie i drugą sesję do tego samego ticketu.

### Skąd dyspozytor wie, że sesja czeka na człowieka?


**Sygnały, które dają werdykt waiting**

| Sygnał | Co dokładnie |
| --- | --- |
| Prompt o zgodę | sesja stoi na pytaniu klienta o uprawnienie |
| Marker STOP | linia `SPRINT-RUN STOP: powód` w ostatniej odpowiedzi sesji |
| Pytanie | ostatnia odpowiedź kończy się pytajnikiem |
| Numerowane opcje | co najmniej dwie opcje i fraza decyzji, na przykład "wybierz" |
| Fraza oczekiwania | odpowiedź kończy się zdaniem zaczynającym się od "Czekam" |
| Zastój | ogon logu niezmieniony przez kolejne ticki, domyślnie dwa |

Odpowiedź człowieka w sesji zdejmuje `waiting`: sygnały liczą się tylko z tego, co sesja napisała po ostatnim wejściu użytkownika.


> [!WARNING]
> Zastój nie zawsze znaczy "utknęła". Sesja, która długo czeka na pipeline albo pełny przebieg testów, wygląda dla skryptu tak samo. Dlatego dyspozytor nie rusza sesji `waiting`: nie wznawia jej, nie kasuje i nie odpowiada za człowieka. Podaje powód i komendę `claude attach`, a ocena należy do człowieka.

Sesja `waiting` nie zajmuje slotu, więc jedno pytanie nie blokuje połowy przepustowości na całą noc. Ma za to własny limit: gdy czeka zbyt wiele sesji naraz (domyślnie dwie), tick przestaje startować nowe, zamiast mnożyć worktree czekające na odpowiedź.

## Które tickety startują, a które czekają?

Kandydatami są tylko tickety z werdyktem `free`. Kolejność jest deterministyczna: priorytet malejąco, a przy równym priorytecie rosnąco po kluczu. Dwa ticki pod rząd wybierają to samo.


**Porównanie**

| Sytuacja ticketu | Zachowanie | Dlaczego |
| --- | --- | --- |
| Bloker w statusie innym niż done | nie startuje, zostaje w kolejce | review to nie merge: sesja wciągnęłaby cudzy, niezmergowany branch |
| Etykieta `needs-local` | nie startuje w tle | wymaga lokalnego środowiska albo decyzji człowieka |
| Ticket z migracją bazy | startuje solo, gdy nic nie biegnie | dwie równoległe migracje rozjeżdżają łańcuch rewizji |
| Brak przeszkód | sesja w tle, komentarz z identyfikatorem | zwykła ścieżka |


Pominięty ticket nie dostaje komentarza, bo pominięcie powtarza się w każdym ticku. Ślad jest w raporcie, z powodem w rodzaju "czeka na merge MON-166". Po zamknięciu blokera następny tick startuje ticket bez niczyjej interwencji.

> [!IMPORTANT]
> Jakość sprintu w tle zależy od jakości ticketów. Sesja bez człowieka nie dopyta o szczegóły, więc opłaca się przygotować backlog skillem [ticket-create, który zamienia pomysł w ticket z kontraktem](https://monolynx.com/blog/jak-dziala-monolynx-ticket-create), i przejrzeć go skillem [ticket-review, który sprawdza ticket przed startem](https://monolynx.com/blog/jak-dziala-monolynx-ticket-review).

### Jak wygląda start sesji?

Sesja robocza dostaje nazwę z projektu, klucza ticketu i modelu, na przykład `monolynx-MON-167-opus`, oraz worktree nazwany kluczem ticketu. Model jest podany jawnie, bo sesja bez niego wzięłaby domyślny model konta, który bywa najdroższy. Po starcie tick dopisuje do ticketu komentarz z identyfikatorem sesji. To jedyny trwały ślad, po którym człowiek trafi do właściwej sesji następnego dnia.

## Co dostaję po każdym ticku?

Raport ma tabelę ticketów z werdyktem i działaniem, sekcję "Czekają na człowieka" z powodem i komendą dla każdej pozycji oraz jedną linię statusu na samym końcu:

```text title="Ostatnia linia ticka"
SPRINT-RUN: remaining=3 running=2 waiting=0 done=1
```

Linia jest kontraktem dla pętli: `remaining=0` i `running=0` oznacza, że sprint jest przerobiony.


**Przykładowy sprint: stan po kolejnych tickach (liczby ilustracyjne)**

| Tick | Do zrobienia | W toku | Gotowe |
| --- | --- | --- | --- |
| 1 | 6 | 2 | 0 |
| 4 | 5 | 2 | 1 |
| 8 | 3 | 2 | 3 |
| 12 | 1 | 2 | 5 |
| 16 | 0 | 0 | 8 |


Gdy linia pokaże zero pozostałych, przychodzi pora na [sprint-end, który zamyka sprint i aktualizuje wiki](https://monolynx.com/blog/jak-dziala-monolynx-sprint-end).

## Najczęstsze pytania


**FAQ**

### Czy dyspozytor może sam zmienić kod albo status ticketu?
Nie. Statusy przestawia sesja work w swojej turze, a kod zmieniają jej agenci. Dyspozytor czyta, komentuje i startuje sesje. Jedyna zmiana w repozytorium, jaką robi, to przewinięcie głównego checkoutu do aktualnego brancha bazowego, i tylko jako fast-forward.

### Co się stanie, jeśli uruchomię tick dwa razy pod rząd?
Nic złego. Przed startem tick sprawdza, czy sesja o tej nazwie już żyje, a przed wznowieniem czyta komentarze ticketu. Drugi tick zobaczy ten sam stan i nie zdubluje sesji.

### Ile sesji biegnie jednocześnie?
Tyle, ile slotów podasz jako argument, a bez argumentu tyle, ile wskazuje zmienna `MONOLYNX_SPRINT_PARALLEL`, domyślnie dwie. Sloty zajmują tylko sesje, które pracują.

### Co jeśli sesja padnie w połowie ticketu?
Tick wkleja ogon logu do komentarza ticketu i wznawia sesję jeden raz. Druga porażka zostawia ticket dla człowieka, bo zwykle znaczy, że problem jest w tickecie albo w projekcie, a nie w sesji.

### Czy mogę ustawić krótszy interwał niż 15 minut?
Możesz, ale zwykle nic to nie da: większość ticków zobaczy te same pracujące sesje. Krótszy interwał ma sens przy bardzo małych ticketach.


## Słownik i następny krok


**Słownik**

- **Tick** - jedno uruchomienie dyspozytora: odczyt stanu, start i zbiór sesji, raport
- **Slot** - miejsce na jedną pracującą sesję roboczą
- **Worktree** - osobny katalog roboczy gita dla jednego ticketu
- **Werdykt** - stan ticketu policzony przez skrypt z sesji, statusu i ogona logu
- **Marker STOP** - linia, którą sesja w tle kończy turę, gdy potrzebuje człowieka
- **needs-local** - etykieta ticketu, którego nie wolno uruchamiać w tle
- **Dispatch** - obsadzenie wolnych slotów nowymi sesjami



**Wezwanie do działania**

Chcesz, żeby sprint przerabiał się sam, a Ty dostawał tylko pytania, które naprawdę wymagają człowieka?

[Zobacz moduł Scrum w Monolynx](https://monolynx.com/features/scrum)

