herdr: multiplekser agentów ze skryptowalnym API
Masz uruchomionych pięciu agentów. Jeden jest w środku refaktoru, jeden skończył jedenaście minut temu, jeden siedzi na promcie o uprawnienia od czasu, gdy poszedłeś po kawę, a dwóch robi coś, czego rekonstrukcja wymagałaby przeczytania 200 linii scrollbacka. W czystym tmuxie dowiadujesz się tego, odwiedzając każdy panel. Kosztem nie są naciśnięcia klawiszy — kosztem jest to, że zablokowany agent spalił jedenaście minut czasu zegarowego, nie robiąc nic, a ty nie miałeś jak o tym wiedzieć.
herdr to multiplekser terminala, który wie, czym jest agent kodujący. Te same prawdziwe panele PTY co w tmuxie, ten sam trwały serwer, ale każdy panel jest klasyfikowany jako idle, working albo blocked i pogrupowany w pasku bocznym. A pod spodem TUI siedzi socket API, które okazuje się ciekawszą połową: to prymityw dla agenta, który odpala i nadzoruje inne agenty.
Czego się nauczysz
Dział zatytułowany „Czego się nauczysz”- Uruchomionej floty herdr i uczciwej historii tego, jak działa detekcja stanu
- Dlaczego instalacja lifecycle hooków agenta zmienia
blockedz heurystyki w fakt - CLI
herdr agent: start, prompt, wait, read, send-keys — wszystkiego, czego potrzebuje skrypt - Działającego orkiestratora: jednego agenta, który rozdziela pracę workerom, czeka na nich i zbiera wyniki
- Gdzie herdr się kończy i co nadal musisz posiadać sam (izolacja, review, koszt)
Instalacja i pierwsza sesja
Dział zatytułowany „Instalacja i pierwsza sesja”herdr to pojedynczy binarny plik w Rust, około 10 MB, na licencji Apache-2.0. Bez Electrona, bez konta, bez telemetrii — twój kod zostaje na twojej maszynie.
curl -fsSL https://herdr.dev/install.sh | sh# albobrew install herdr# albomise use -g herdrLinux i macOS są stabilne; Windows to preview beta. Potem po prostu odpalasz i uruchamiasz agenty tak, jak już to robisz:
herdrModel interakcji jest mouse-first — prawy przycisk dzieli i przełącza — z ctrl+b jako prefiksem klawiaturowym, więc pamięć mięśniowa z tmuxa w większości się przenosi. To, czego w tmuxie nie ma, to pasek boczny: każdy panel pogrupowany po stanie agenta, więc „kto mnie potrzebuje” jest rzutem oka, a nie obchodem.
Jak naprawdę działa detekcja stanu
Dział zatytułowany „Jak naprawdę działa detekcja stanu”To jest funkcja, dla której adoptujesz herdr, więc warto wiedzieć dokładnie, co robi.
herdr klasyfikuje każdy panel jako idle, working albo blocked, jednym z dwóch mechanizmów, w zależności od agenta:
- Lifecycle hooks. Tam, gdzie agent je wspiera, herdr je instaluje i agent sam raportuje swoje przejścia. To jest dokładne.
- Manifesty ekranu. W przeciwnym razie herdr czyta wyrenderowany terminal. Dokumentacja jest odświeżająco precyzyjna co do ograniczenia: herdr oznacza panel jako
blockedtylko wtedy, gdy snapshot dolnej części bufora pasuje do znanego, widocznego UI zgody, pytania lub uprawnień.
Przeczytaj ten drugi punkt jeszcze raz, bo definiuje tryb awarii. Detekcja przez manifest ekranu rozpoznaje znane kształty promptów. Nowy dialog uprawnień, własny Notification dodany przez twój zespół, agent zadający otwarte pytanie w nieznanym formacie — żadne z tych nie musi się zarejestrować. Panel dalej czyta się jako working, podczas gdy czeka na ciebie.
Pokrycie różni się między agentami i to najbardziej użyteczna tabela do planowania floty:
| Poziom wsparcia | Agenty |
|---|---|
| Pełne lifecycle hooks | Pi, OMP, Kimi Code CLI, Hermes Agent, MastraCode |
| Częściowe lifecycle | Claude Code, Codex, Cursor Agent CLI, GitHub Copilot CLI, Devin CLI, Droid, OpenCode, Kilo Code CLI, Qoder CLI |
| Tylko manifest ekranu | Amp, Grok CLI, Antigravity CLI, Kiro CLI, Maki |
| Mniej przetestowane | Gemini CLI, Cline |
Trzy agenty, na których zależy temu przewodnikowi, siedzą w warstwie częściowej — to dobre miejsce, ale nie najwyższe. Dowolny agent terminalowy działa i tak jako zwykły panel; dostajesz po prostu mniej sygnału.
Sesje, które przeżyją twojego laptopa
Dział zatytułowany „Sesje, które przeżyją twojego laptopa”herdr prowadzi serwer w tle, więc panele przeżywają odłączenie, a podłączyć się możesz z dowolnego miejsca:
-
Odłącz się i odejdź. Agenty pracują dalej. To ta sama gwarancja, którą daje tmux, i powód, dla którego multiplekser terminala bije aplikację desktopową przy długich biegach.
-
Postaw serwer tam, gdzie może stać. Mały VPS albo zapasowa maszyna oznaczają, że zamknięcie klapy nic nie zatrzymuje:
ssh box -t herdri flota jest z powrotem. -
Zaglądaj z telefonu. Układ reaguje na mysz i dotyk po SSH, co brzmi jak gadżet, dopóki agent nie zablokuje się, gdy jesteś na mieście, i nie odblokujesz go z pociągu.
-
Przywracaj po reboocie świadomie. Eksport i aplikacja układu w herdr przywracają strukturę paneli. Nie przywracają rozmów agentów — połącz to z resume samego agenta (
claude --resume,codex resume).
CLI herdr agent
Dział zatytułowany „CLI herdr agent”Tu herdr odchodzi od tmuxa. Zamiast wpisywać do paneli i grepować ich wyjście, adresujesz agenty po nazwie i czekasz na stany semantyczne.
# uruchom nazwanego agenta w konkretnym paneluherdr agent start reviewer --kind codex --pane "$review_pane"
# nadaj nazwę agentowi, który już działaherdr agent rename w1:p2 reviewer
# wyślij prompt i blokuj do zakończeniaherdr agent prompt reviewer "Przejrzyj aktualny diff pod kątem pominiętych ścieżek błędów" \ --wait --timeout 120000
# blokuj do osiągnięcia stanuherdr agent wait reviewer --until blocked --timeout 120000
# przeczytaj, co wyprodukowałherdr agent read reviewer --source recent-unwrapped --lines 120
# wyślij klawisze UI (escape, strzałki, akordy control) zamiast tekstuherdr agent send-keys reviewer escNazwy agentów podlegają wzorcowi [a-z][a-z0-9_-]{0,31}, a --kind przyjmuje rozpoznawane agenty — claude, codex, cursor, pi, gemini, devin, cline i inne. Wszystko po -- idzie do własnego CLI agenta, i tak przypinasz model albo tryb uprawnień per worker.
Dwa szczegóły warte zapamiętania. --until przyjmuje stany cyklu życia (idle, done, blocked, unknown), więc skrypt potrafi odróżnić „skończył” od „potrzebuje człowieka” bez parsowania czegokolwiek. A --source recent-unwrapped ma znaczenie z tego samego powodu, z którego liczy się capture-pane -J w tmuxie: niezawijane wyjście trzyma długie ścieżki plików i ramki stosu w jednej linii, więc twój grep faktycznie trafia.
Do zwykłej pracy w shellu są odpowiedniki na poziomie paneli:
herdr pane run w1:p3 "just test --watch"herdr pane wait-output w1:p3 --regex "passed|failed" --timeout 120000herdr pane read w1:p1 --source recent --lines 50Wzorzec orkiestratora
Dział zatytułowany „Wzorzec orkiestratora”Ponieważ CLI jest skryptowalne i świadome stanu, agent może prowadzić herdr — co oznacza, że jeden agent może zbudować flotę, dać jej prompty, poczekać na nią i przeczytać wyniki. To ta rzecz, którą herdr robi, a której prawie nic innego w tej kategorii nie wystawia.
#!/usr/bin/env bash# bin/fanout -- jeden worker na zadanie, nadzorowany, wyniki zebraneset -euo pipefail
TASKS=("api-rate-limit" "webhook-idempotency" "cache-invalidation")BASE=$(herdr pane list --json | jq -r '.panes[0].pane_id')WORKERS=()
# Nazwy agentów w herdr muszą pasować do [a-z][a-z0-9_-]{0,31}. Wyznacz nazwę RAZ# i adresuj agenta po niej wszędzie; surowy slug zadania nie jest poprawnym# uchwytem. Prefiks "w-" gwarantuje wymaganą pierwszą literę.agent_name() { printf 'w-%s' "$1" | tr '[:upper:]' '[:lower:]' | tr -c 'a-z0-9_-' '-' | cut -c1-32}
# 1. zbuduj układ i uruchom jednego workera na zadaniefor task in "${TASKS[@]}"; do name=$(agent_name "$task") WORKERS+=("$name") pane=$(herdr pane split "$BASE" --direction right --json | jq -r '.pane_id') herdr agent start "$name" --kind claude --pane "$pane" -- --worktree "$task"done
# 2. daj prompt każdemu workerowi, nie blokując się na żadnymfor i in "${!TASKS[@]}"; do herdr agent prompt "${WORKERS[$i]}" \ "Posiadasz dokładnie jedno zadanie: ${TASKS[$i]}. Zostań w swoim worktree. Kiedy testy przechodzą, zacommituj na swoim branchu i zatrzymaj się. Nie dotykaj innych obszarów."done
# 3. nadzoruj: zaklasyfikuj każdego workera jako done, blocked albo timeoutfor i in "${!TASKS[@]}"; do name="${WORKERS[$i]}" if herdr agent wait "$name" --until done --timeout 1800000; then echo "== ${TASKS[$i]} DONE ==" herdr agent read "$name" --source recent-unwrapped --lines 60 elif herdr agent wait "$name" --until blocked --timeout 1000; then # już jest zablokowany, więc to drugie czekanie wraca natychmiast echo "!! ${TASKS[$i]} BLOCKED -- czeka na człowieka" herdr agent read "$name" --source recent-unwrapped --lines 30 else echo "!! ${TASKS[$i]} TIMEOUT -- nadal pracuje po 30 minutach" herdr agent read "$name" --source recent-unwrapped --lines 30 fidoneZwróć uwagę, czego skrypt nie robi: nigdy nie tworzy worktree. -- --worktree "$task" przepuszcza flagę do Claude Code, który posiada własną izolację. herdr posiada panele i stan; agent posiada system plików. Utrzymanie tej linii w czystości jest tym, co powstrzymuje obie warstwy od walki.
Drugi szczegół wart skopiowania to obejście przez agent_name. Slug zadania nie jest uchwytem agenta — nazwy w herdr muszą pasować do [a-z][a-z0-9_-]{0,31}, więc cokolwiek z wielką literą, kropką albo ukośnikiem zostaje po drodze przekształcone. Wyznacz nazwę raz, trzymaj ją w równoległej tablicy i adresuj każdy późniejszy prompt / wait / read po tej nazwie. Sanityzuj przy start, a potem adresuj po surowym slugu i dostaniesz najgorszą możliwą awarię: worker działa sobie szczęśliwie pod sanityzowaną nazwą, a twoje prompty i czekania po cichu celują w agenta, który nie istnieje.
Socket API
Dział zatytułowany „Socket API”CLI jest klientem lokalnego socket API i możesz z nim rozmawiać wprost, gdy potrzebujesz subskrypcji zdarzeń albo chcesz prowadzić herdr z czegoś innego niż bash.
Transportem jest JSON rozdzielany nowymi liniami po unixowym sockecie (nazwane potoki na Windowsie). Jedno żądanie na linię, odpowiedzi dopasowane po ID żądania:
{"id":"req_1","method":"ping","params":{}}{"id":"req_1","result":{"type":"pong"}}Kolejność rozwiązywania ścieżki socketu: jawne --session <nazwa>, potem HERDR_SOCKET_PATH, potem HERDR_SESSION=<nazwa>, potem domyślne ~/.config/herdr/herdr.sock.
Metody są pogrupowane po domenach:
| Domena | Operacje |
|---|---|
| workspace | create, list, focus, rename, close |
| tab | create, list, focus, rename, move, close |
| pane | split, swap, focus, resize, read, send input, close |
| agent | list, read, prompt, wait, start, focus |
| layout | export, apply, ustawianie proporcji podziału |
| events | subscribe, oczekiwanie na zmiany wyjścia |
{"id":"req_1","method":"pane.split","params":{"pane_id":"w1:p1","direction":"right","ratio":0.333}}{"id":"req_2","method":"pane.run","params":{"pane_id":"w1:p2","command":["npm","test"]}}Domena events jest tą, po którą warto sięgnąć: subskrybujesz na długotrwałym połączeniu i zmiany stanu są ci wypychane, zamiast żebyś odpytywał. To różnica między orkiestratorem reagującym w sekundę i takim, który reaguje na kolejnym 15-sekundowym tiku.
Zanim cokolwiek na tym zbudujesz, wygeneruj kontrakt, zamiast zgadywać:
herdr api schema --jsonherdr wersjonuje protokół, więc klient powinien sprawdzić możliwości serwera przed poleganiem na nowej metodzie i tolerować nieznane pola, a nie wywalać się na nich.
Uruchamianie każdego agenta w herdr
Dział zatytułowany „Uruchamianie każdego agenta w herdr”--kind claude, a izolację przepuszczaj dalej: -- --worktree <zadanie> umieszcza workera w .claude/worktrees/<zadanie>/ na własnym branchu. Uruchomienia interaktywne wymagają najpierw workspace trust, więc odpal raz claude w repo ręcznie, zanim to oskryptujesz.
Własne hooki Claude Code są tym, co podnosi go ze zgadywania z manifestu ekranu do prawdziwego sygnału, więc zainstaluj dla niego hooki herdr. Jeśli twój zespół używa hooków też do innych celów, trzymaj je addytywnie — hook Stop, który kończy się niezerowym kodem, objawi się jako błąd przy każdym zatrzymaniu.
--kind codex do paneli interaktywnych. Dla workerów, które mają wykonać i wyjść, codex exec "<zadanie>" jest lepszym kształtem — komponuje się z herdr pane wait-output, gdy chcesz oprzeć się na wyjściu samej komendy, a nie na stanie agenta.
Wpisz wąski AGENTS.md do każdego worktree przed promptem. To najczystszy sposób utrzymania workera w jego wycinku i w runtime’ie nic nie kosztuje.
--kind cursor prowadzi cursor-agent, headless CLI. Warto być uczciwym co do kompromisu: okno Agents w Cursorze już robi równoległe uruchomienia lokalne, w worktree, w chmurze i po SSH, z GUI, więc stawianie herdr przed nim ma sens głównie wtedy, gdy chcesz jednego terminala dla mieszanej floty — część workerów w Cursorze, część w Claude Code, część w Codeksie.
.cursor/rules per worktree zawęża wtedy każdego workera, bo agent czyta reguły katalogu, w którym startuje.
Kiedy to się psuje
Dział zatytułowany „Kiedy to się psuje”Zaufałeś working u agenta, który faktycznie był zablokowany. Detekcja przez manifest ekranu rozpoznaje tylko znane kształty promptów. Zainstaluj lifecycle hooks, a workera, który jest working bez wyjścia od dłuższego czasu, traktuj jako podejrzanego, nie zajętego.
Twój orkiestrator wisi. Czekał na done u workera, który poszedł w blocked. Zawsze podawaj --timeout, zawsze obsługuj niezerowy kod wyjścia i wypisuj wtedy ostatnie wyjście workera.
prompt albo wait celuje w agenta, który nie istnieje. Sanityzowałeś nazwę przy agent start, a potem adresowałeś surowy slug zadania. Nazwy w herdr muszą pasować do [a-z][a-z0-9_-]{0,31}, więc wyznacz uchwyt raz i używaj go ponownie — worker działa sobie spokojnie pod swoją prawdziwą nazwą, a twoje komendy po cichu nie trafiają nigdzie.
Dwie warstwy pobiły się o worktree. herdr nie zarządza izolacją i nie należy go do tego zmuszać. Niech agent utworzy swój worktree własną flagą; zadanie herdr kończy się na panelu.
Porty, .env i baza dev i tak się zderzyły. Worktree izoluje wyłącznie pliki. Sześciu workerów odpalających npm run dev bije się o port 3000 niezależnie od tego, jak czysty jest twój multiplekser. Najpierw zaudytuj repo — gotowy prompt audytowy jest w alternatywnych IDE i powłokach dla agentów — albo użyj izolacji kontener-na-agenta.
Zbudowałeś na metodach, których nie ma. Socket API jest wersjonowane i się rozwija. Uruchom herdr api schema --json i buduj z wyjścia, a nie z przykładu na blogu — w tym z przykładów w tym artykule, które są aktualne na lipiec 2026 i będą się rozjeżdżać.
Flotę zatrzymały limity, nie herdr. Każdy panel wydaje przydział tego samego konta, a worker, który uderzył w limit, często wygląda identycznie jak ten, który myśli. Sprawdź panel, zanim zaczniesz debugować harness.
Flota wyprzedziła twoje review. Pięciu workerów produkujących pięć branchy produkuje pięć review, wszystkie przychodzące naraz. Liczbą, która się liczy, jest zaakceptowana przepustowość — kalibracja sufitu w równoległości zespołowej, a strona tokenowa w optymalizacji kosztów.
Windows zachował się inaczej. Wsparcie dla Windowsa to preview beta i używa nazwanych potoków, a nie unixowych socketów. Traktuj tam skryptowaną orkiestrację jako eksperymentalną.