mcptask runner – AI vývojář na vašem stroji. Dotahuje úkoly až do zmergovaného PR.
mcptask_runner promění vaše coding CLI — Claude Code, Codex CLI nebo OpenCode — v samostatného člena týmu. Funguje s Claude, Kimi, DeepSeekem, lokální Ollamou nebo s jakýmkoli modelem — bez vendor lock-inu. Vybere úkol, napíše kód i testy a otevře PR. V režimech auto-squash ho po zeleném CI zmerguje, v manuálních režimech nechá PR otevřené k vaší kontrole. Zadáte večer dobře specifikovanou práci, ráno ji najdete hotovou.
30 dní zdarma. Bez kreditní karty. Kdykoli zrušíte.
Plný autonomní harness nad vaším coding CLI
mcptask_runner je jedna statická binárka bez runtime závislostí — řídí coding CLI na vašem stroji a projde celý agentní cyklus: najde úkol → posoudí složitost → zvolí model → spustí coding CLI → hlídá běh watchdogem → dodrží denní kvótu → (volitelně) po zeleném CI zmerguje PR. Funguje s jakýmkoli projektem, který používá git, na GitHubu, na Bitbucket Cloudu, nebo na GitLabu — za běhu nikde nepotřebuje Ruby, bundler ani Gemfile, metadata projektu se berou z CLAUDE.md a `bin/ci` je konvence (když `bin/ci` chybí, krok se přeskočí). Žádný prompt, který runner skládá, už nejmenuje příkaz konkrétního frameworku: projekt, který se před browser testy potřebuje připravit, si to řekne sám — ve svém CLAUDE.md, nebo v příkazu, který předá `/test-runner`.
Není to jen „tupý spouštěč“ coding CLI. Přidává orchestraci, dohled, zotavení a řízení kvality, které holé CLI nemá.
Vyberte CLI, které bude řídit váš projekt
Harness je coding CLI, které runner řídí. V binárce jsou tři profily — Claude Code, Codex CLI a OpenCode — a vlastní profil žije v ~/.mcptask/harnesses/. Volba se dělá jednou pro každý stroj a projekt, udělá ji init a zapíše harness: do config/mcptask_runner.yml. Ten soubor je per-stroj a je v .gitignore, takže dva vývojáři nad stejným repozitářem mohou řídit různá CLI.
mcptask_runner init --cli codexTři přibalené profily
Claude Code
mcptask_runner init --cli claude- Skills
- 12 v .claude/skills
- MCP konfigurace
- .mcp.json
- Instrukce
- CLAUDE.md
- Modely
- aliasy opus / sonnet / haiku
- Oprávnění
- .claude/settings.local.json
Codex CLI
mcptask_runner init --cli codex- Skills
- 9 v .agents/skills
- MCP konfigurace
- .codex/config.toml
- Instrukce
- ukazatel v AGENTS.md
- Modely
- gpt-6-astra, gpt-5.6-terra, gpt-5.6-luna
- Preflight
- codex login status musí projít
OpenCode
mcptask_runner init --cli opencode- Skills
- 9 v .claude/skills
- MCP konfigurace
- opencode.json
- Instrukce
- CLAUDE.md
- Modely
- provider/model
- Oprávnění
- permission mapu vloží runner
Žádný default neexistuje
Projekt, který CLI nikdy nepojmenoval, runner odmítne jménem — nepředpokládá tiše Claude Code. launcher.command zůstává override samotného argv a je křížově kontrolován proti harness: — nemůže protlačit jiné CLI, než jaké projekt deklaroval.
Co je na všech třech stejné
Profil drží binárku, argv, resume flag, literály selhání, jména nástrojů a skillů a to, co zapisuje init. Všechno, co dělá runner runnerem, je nad profilem a s volbou CLI se nemění.
Limity, řečené naplno
Fork skills jsou jen na Claude Code
discover, memory-search a mcptask-read forkují levného subagenta, aby se surový výstup nikdy nedostal do rodičovského kontextu. To umí jen Claude Code, takže profily Codex a OpenCode mají devět skillů místo dvanácti. Devět helper skriptů je na všech třech stejných.
Codex potřebuje funkční login
codex login status musí projít, než běh začne. Preflight raději odmítne, než aby spotřeboval kvótu na CLI, které spadne při prvním volání.
OpenCode nemá read-only flag
Není co předat, takže runner místo toho vloží permission mapu. Read-only garance je stejná; mechanismus ne.
Ověřeno, nejen tvrzeno
Conformance a chaos suity běží v CI proti všem třem dialektům a profily nejsou funkce na papíře: reálný běh na Codexu dokončil úkol 9. 9. 2026 a OpenCode má za sebou vlastní reálné běhy.
Na vašem stroji, proti realitě
Agenti v cloudu běží ve sterilních sandboxech. Runner běží ve vašem reálném projektu.
Reálná databáze
Pracuje s databází, kterou váš projekt už používá — se schématem, seed daty i migrační historií, které ji zformovaly. (PostgreSQL je jeden konkrétní příklad; runner řídí to, co běží ve vašem projektu.)
Reálné systémové testy
Spouští vstupní body testů vašeho projektu, od začátku do konce — Capybara a Selenium proti vaší reálné aplikaci jako jeden konkrétní příklad, se screenshoty a kontrolami v prohlížeči, které dokazují, že se změna opravdu projevila v aplikaci.
Reálné commity a PR
Větve, commity a pull requesty žijí ve vašem repozitáři, s vaším CI a ve vaší historii gitu — na GitHubu, na Bitbucket Cloudu, nebo na GitLabu, a na všech je otevírá `mcptask_runner pr`. Runner spouští to, co spouští váš `bin/ci`.
Pull requesty na GitHubu, na Bitbucketu nebo na GitLabu
Runner pracuje s repozitářem na GitHubu, na Bitbucket Cloudu nebo na GitLabu (gitlab.com i self-managed) a pull request na všech otevírá jeden příkaz: mcptask_runner pr. Žádný prompt ani přibalený skill už nejmenuje CLI konkrétního hostu — binárka se hostu zeptá sama, takže stejné instrukce fungují bez ohledu na to, kde váš repozitář žije.
PR neotevře nic jiného než mcptask_runner pr
Je to pátý veřejný subcommand. Každý subcommand vypíše na stdout jeden JSON objekt, chyby jdou na stderr s nenulovým exit kódem a --git-host přepíše hosta pro jedno zavolání. Samotné git_host: je nepovinné — runner ho odvodí z git remote get-url origin a init --git-host bitbucket|gitlab je tu pro aliasy, mirrory a self-managed instance.
Šest subcommandů
pr createOtevře pull request pro aktuální větev.
pr listVypíše pull requesty, filtrované přes --task, --branch, --open nebo --state.
pr viewPřečte jeden pull request jako JSON.
pr reviewsPřečte review, která na pull requestu zůstala.
pr mergeZmerguje ho — --squash a --delete-branch jsou default, protože právě to auto-squash znamená.
pr checksZeptá se hosta, co jeho checky říkají o head commitu.
Tři hosti, tři modely přihlášení
GitHub
Autentizace přes gh a jeho vlastní login. Šablona pull requestu se čte z .github/pull_request_template.md, což je cesta, kterou zná jen GitHub.
Bitbucket Cloud
REST API 2.0, s jedním ze dvou přihlášení a nikdy s oběma: BITBUCKET_ACCESS_TOKEN pro stroj (Bearer), nebo BITBUCKET_EMAIL a BITBUCKET_API_TOKEN pro člověka (Basic). App passwords jsou odmítnuté — Atlassian je 9. 6. 2026 ukončil. init zapíše ~/.mcptask_env.d/bitbucket_credentials s právy 0600 (kontrola práv se na Windows přeskakuje), nikdy nepřepíše existující hodnotu ničím a nikdy přihlašovací údaj nevypíše. Mimo GitHub se šablona deklaruje jako pr_template: path:.
GitLab
Řídí ho CLI glab, které si drží vlastní přihlášení — glab auth login, a runner si žádný GitLab credential neukládá. Funguje gitlab.com i self-managed instance: self-managed projekt deklaruje git_host: gitlab (mcptask_runner init --git-host gitlab), protože jeho origin URL není gitlab.com, a runner po vás URL instance nikdy nechce — glab už ví, kam je přihlášený. To, co tam pr create otevře, je merge request.
Auto-squash se před mergem zeptá hosta
Merge není naděje, že CI bylo zelené. Runner si nejdřív přečte checky hosta pro head commit: FAILED ukončí běh jako ci_failed a PR nechá otevřené, IN_PROGRESS zkusí desetkrát po dvou minutách a NONE — repozitář, který u hosta žádné checky nemá — spadne na lokální gate. GitLab hlásí jeden stav pipeline na merge request, takže výpis checků je tam jeden řádek, ne seznam.
GitHub Enterprise není GitHub a je odmítnut jménem
Host se poznává podle přesného hostname, takže instanci GitHub Enterprise runner odmítne se zprávou, která to říká, místo aby ji považoval za github.com. PR otevřené proti špatnému API hosta je horší než běh, který odmítne začít.
Kde končí runner a začíná mcptask.online
Tady jde o runner pracující s repozitářem na Bitbucket Cloudu — ne o Bitbucket integraci na úrovni mcptask.online. Párování commitů a pull requestů zpět na pieces jede na webhoocích a ty zůstávají GitHub a GitLab.
Smyčka bere úkoly, cíl je dotahuje
mcptask_runner spojuje pracovní smyčku (bere úkol za úkolem z fronty) s cílem (dotahuje každý úkol až do zeleného PR, nejen k „nějakým úpravám“). Zvolte režim podle toho, jak dlouho má běžet:
| Tvar smyčky | Režim | Auto-squash vs. ruční | Povinný přepínač |
|---|---|---|---|
| Spustí jednoho vykonavatele a skončí | once | ruční | — |
once_dry | ruční | — | |
once_auto_squash | auto-squash | — | |
review | ruční | — | |
| Iteruje, dokud nenastane stop-status | today | ruční | — |
today_auto_squash | auto-squash | — | |
queue_manualaliasy: queue | ruční | — | |
queue_auto_squash | auto-squash | — | |
workflow | ruční | — | |
reviews | ruční | — | |
| Projde podúkoly story | story_manualaliasy: story | ruční | --story-id |
story_auto_squash | auto-squash | --story-id | |
task_manualaliasy: task | ruční | --task-id | |
task_auto_squash | auto-squash | --task-id | |
| Dělá to celý den, každý den | daily | ruční | — |
Některé režimy se chovají jinak, než napovídá tvar, do kterého jsou zařazené
- once_dry je jediný režim, který úplně přeskočí triage — jen ukáže další úkol a skončí.
- workflow má dvě fáze: nejdřív revize (PR, která blokují člověka), potom dnešní úkoly.
- daily se nikdy sám nevrátí — smyčku ukončí jen pád, signál nebo nepovedené předání. Cestou do noční pauzy se navíc může předat novější binárce, kterou už má na disku (viz samoaktualizace níže); smyčka, která se zítra probudí, je stále ta samá smyčka, jen běží na novějším kódu.
- queue_manual a queue_auto_squash nejsou nijak časově omezené; běží, dokud přicházejí úkoly.
Co dělá autonomii skutečně autonomií
Níže je technický detail za tvrzením, že runner je „více než spouštěč“. Každá vlastnost existuje proto, že by se bez ní reálný běh rozsypal.
Když narazí na cizí bug, založí na něj úkol a pozastaví se
Pokud runner během práce narazí na URGENTNÍ bug, který nesouvisí s aktuálním úkolem, commitne a pushne rozdělanou práci na feature větev, přepne na main (čistý strom), založí nový urgentní bug úkol a vrátí jeho id a název. Runner si bug připne do souboru tmp/mcptask_runner/urgent_pin.txt v adresáři projektu (pin přežije pád a nemůže kolidovat mezi projekty), takže i po restartu jde nejdřív opravit bug a teprve pak se vrátit k původnímu úkolu. Chaos „narazil jsem na něco cizího“ se změní ve sledovatelný úkol, který má svého vlastníka.
Zotavení po zaplnění kontextu nebo přerušení
Když běh skončí kvůli přeplnění kontextu, kvótě nebo zásahu urgentního bugu, úkol zůstane in_progress a nedokončená práce zůstane na feature větvi. Další běh na něj naváže: přečte git log i stav větve, fetchne a zmerguje origin/main, přeskočí hotové kroky a povýší model na nejsilnější nakonfigurovanou úroveň, ať má úkol na dotažení víc síly. Dlouhá úloha tak přežije i několik běhů za sebou. Jak se overflow detekuje a jaký tlak na kontext runner měří, popisuje sekce o overflow.
Watchdog a detekce zaseknutí
Watchdog nečinnosti zabije běh po 20 minutách bez postupu, po třech minutách měkce upozorní na zamrzlý proces a na zaseknuté příkazy má strop podle konkrétního nástroje; absolutní backstop ticha je 50 minut, s podlahou 45 minut pro nástroje, která se adaptivně zvedá podle naměřených délek až ke stropu 90 minut. Detektor zaseknutí čte stream CLI — dekódovaný podle harnessu, takže stejný detektor funguje na Claude Code, Codex CLI i OpenCode — řádek po řádku a pozná „točení se dokola“ — opakované chyby nástroje Edit, opakované chyby nástroje Bash nebo tentýž podpis nástroje v několika smyčkách po sobě; dlouhé pomocné příkazy jako CI wait a test wait jsou z toho výslovně vyňaté. Při zaseknutí proces zabije; úkol zůstane in_progress a příště se obnoví na nejsilnější úrovni. Kde se hlídá denní rozpočet, najdete v sekci o kvótě, a log běhu v sekci o pozorovatelnosti.
Triage a volba modelu (tři role)
Před prací proběhne triage: posoudí složitost úkolu a doporučí roli modelu. Role jsou tři: nejsilnější úroveň (těžké kódování), střední úroveň (triage, revize) a nejrychlejší úroveň (jen čtení). Runner se dodává s výchozím nastavením pro hosta Anthropic — CLI si generické aliasy přeloží za běhu, takže konkrétní ID modelů jde vyměnit, aniž byste přepisovali retry řetězce. Codex CLI a OpenCode mapují stejné tři role na svá vlastní ID — gpt-6-astra / gpt-5.6-terra / gpt-5.6-luna, respektive provider/model — takže triage se s volbou CLI nemění.
Kvalita: testy, CI, auto-merge
Celý workflow běží od začátku do konce: větev → kód → unit testy → screenshoty → systémové testy → push → `mcptask_runner pr create` → lokální CI → `mcptask_runner pr merge`. Úkol není hotový, dokud neprojde CI, a merge se nejdřív zeptá na checky hosta. V režimech auto-squash runner PR po zeleném CI sám squash-merguje, v manuálních režimech zůstane PR otevřené k lidské revizi. Runner umí zpracovat i připomínky z revize existujícího PR. Úplnou tabulku režimů najdete v sekci loop a goal.
Jedno číslo, tři místa, kde se ověřuje
Runner nikdy nevěří vlastnímu odhadu. Každé rozhodnutí o kvótě čte živé číslo z mcptask.online přes REST a vynucuje ho před úkolem, mezi úkoly i během úkolu.
Odkud se číslo bere
Denní rozpočet se načítá živě z mcptask.online přes REST (GET /api/{account}/users/current/time_status). Runner nikdy neodhaduje rozpočet přes agenta a nikdy nečte cache — účet je jediný zdroj pravdy.
Tři brány, v tomto pořadí
| Kdy | Co se kontroluje |
|---|---|
PŘED BĚHEM (po fázi triage) | Znovu se dotáže živého REST endpointu po triage. Samotná triage trvá minuty; čerstvý dotaz zachytí cokoliv, co uživatel utratil, zatímco runner úkol třídil. |
MEZI ÚKOLY (decider) | Zastaví smyčku při jakémkoliv selhaném úkolu, při zabití kvótou uprostřed úkolu nebo při vyčerpaném denním rozpočtu. Žádný třetí pokus týž den. |
BĚHEM ÚKOLU (každých 360 s) | Přeptá se každý DefaultQuotaPollInterval. Při překročení zabije potomka a ukončí smyčku s quota_exceeded_mid_task — bez retry. Kill streak (DefaultQuotaFailureKillStreak = 3) absorbuje asi 18minutový výpadek RESTu, než to runner vzdá. |
Záměrné rozdělení na fail-closed a fail-open
Na dvě otázky se schválně neodpovídá stejně. „Byla kvóta překročena?“ selhává do CLOSED, „Můžu dnes pracovat?“ selhává do OPEN. Jedna chyba zablokuje běh, druhá ho nechá začít.
Když se ptáme „už jsme dnes utratili rozpočet?“ a REST neumí odpovědět, odpověď je NE. Lepší je přeskočit úkol než přečerpat.
Když se ptáme „zbývá mi dnes rozpočet?“ a REST neumí odpovědět, odpověď je ANO. Lepší je spustit běh než promarnit pracovní den kvůli přechodnému výpadku.
Výpadek vs. vyčerpaný rozpočet
Výpadek RESTu, který zabil zdravou práci, je jiný bug než vyčerpaný denní rozpočet. Runner je záměrně rozlišuje (ErrQuotaPollOutage) — jedno není ničí vina, druhé je 20minutový incident, který stojí za založení ticketu.
| Scénář | Co runner udělá |
|---|---|
| Denní rozpočet vyčerpán | Decider mezi úkoly zastaví smyčku. Žádný bug. |
| Výpadek RESTu (pod kill streakem) | Zkusí to znovu v dalším intervalu. Smyčka pokračuje. |
| Výpadek RESTu (nad kill streakem, ~18 min) | Ukončí smyčku fail-closed se statusem error a vlastní terminací quota_poll_outage — ne s quota_exceeded_mid_task. Ta terminace není na seznamu měkkých ukončení, takže bug úkol se založí vždy, aby se ten dvacetiminutový incident sledoval. |
--ignore-quota přeskočí všechny tři brány. Runner se pak RESTu nikdy neptá a nikdy neodmítne úkol; operátor přebírá odpovědnost za útratu.
Co přežije, když kontext přeteče
SESSION se nedá obnovit. PRÁCE ano — protože práce je větev a commity na disku. Dva nezávislé mechanismy nesou zbytek dál a třetí verdikt říká harnessu, aby přestal zakládat šum.
Přežije
Co runner předá dalšímu pokusu
Git větev a její commity
Samotná práce je větev s commity na disku. I když se ztratí každý bajt kontextu session, diff jde pořád projít, PR pořád otevřít a změny pořád obnovit.
Poslední 3 akce (restart uvnitř procesu)
Když je rozpočet čerstvý a proces se restartuje na místě, preamble restartu nese poslední tři akce (RecentActionsCap = 3) a naměřené poznatky o ceně kontextu, takže nový pokus navazuje na rozjetou práci, ne naslepo.
Pravidla ContextBudget
Každý restart zdědí sdílená pravidla handoff.ContextBudget() — co se počítá do limitu, co ne, a jak runner rozhodne, že je bezpečné spustit další pokus.
Ztraceno
Co žádný mechanismus nezachrání
Celý kontext konverzace
--continue by znovu načetl stejný přerostlý kontext, takže SESSION je neobnovitelná. V preamble restartu jsou jen poslední tři akce; vše předtím je pryč.
Dva nezávislé mechanismy
| Mechanismus | Rozsah | Co se nese dál |
|---|---|---|
| In-process fresh restart | Uvnitř téhož procesu runneru (retry.go, handleContextOverflow) | Rozpočet = 1 restart na proces (maxOverflowRestarts = 1, záměrně — přezkoumáno v úkolu #11474, ponecháno na 1 v commitu f6bce1e). Nový pokus čte poslední 3 akce, poznatky o ceně a pravidla rozpočtu. |
| Cross-process TaskHandoff | internal/handoff/ — jedna poznámka na úkol (engine.go, recordTaskHandoff) | Zapíše log/handoffs/task_<id>.json v OBOU větvích — v restartu i v terminální (terminální konec tohoto procesu, ne úkolu). Další NOVÝ proces ji čte jako preamble promptu pro první pokus — nikdy při --continue retry. overflow_count se sčítá napříč procesy runneru. Poznámky se zahodí, jakmile běh skončí jinak, a mažou se po 30 dnech. |
Třetí verdikt: overflow_pr_open
Když je rozpočet restartu vyčerpán A existuje otevřené PR k úkolu, status je overflow_pr_open, NIKOLIV error. PR je výstup; otevřené PR se zelenými checky znamená, že práce prošla. Zakládat tady error stojí celý denní loop kvůli úkolu, který už je hotový (úkol #11466 přišel o 79a6f6aa, o PR #1659 i o zbytek dne přesně kvůli tomuhle špatnému zařazení, které mu navíc automaticky založilo bug #11467, jaký si nezasloužil).
| overflow_pr_open (ne error) | error (co to bývalo) |
|---|---|
| rozpočet restartu vyčerpán + PR otevřené → overflow_pr_open | rozpočet restartu vyčerpán + bez PR → error |
Proč to není kouzlo
Souběžně běží čtyři věci: potomek ve vlastní process group, čtečka streamu, watchdog a event stream. Stavový automat pod nimi má deset pojmenovaných stavů a explicitní allow-list — zamítnutý přechod je varování, nikdy důvod k zastavení.
Potomek ve vlastní process group
Runner spouští coding CLI v nové process group (syscall.SysProcAttr{Setpgid: true}, internal/executor/process_unix.go, configureProcessGroup), takže SIGTERM a SIGKILL z runneru zasáhnou celý strom a nikdy neprobublají k rodiči. Čekání na dokončení čteček je omezené na 30 s (engine.go, stderrJoinTimeout + defaultStdoutJoinTimeout), aby zaseknutý potomek nemohl zablokovat vypnutí.
Čtečka streamu
Čte výstup CLI (stream-json) řádek po řádku, jak vzniká, v tom dialektu, který deklaruje profil harnessu. Parsuje eventy, hledá TASKRUNNER_RESULT completion contract a krmí StallDetector. Nečeká na konec procesu — reaguje průběžně na každý řádek, který přistane.
Watchdog
Nezávislé hlídací vlákno s 30sekundovým heartbeatem. Zabití po 20 minutách nečinnosti, měkké varování na zamrzlý proces po 3 minutách, stropy pro zaseknuté nástroje (quick / long), absolutní backstop a živý REST dotaz na kvótu každých 6 minut. Jediný externí dozorce nad procesem potomka.
Event stream
Perzistentní WebSocket na mcptask.online přes ActionCable (RunnerSessionChannel). Snapshoty jsou throttlované na ~0,5 s; změnu stavu FSM protlačí okamžitě. Při výpadku následuje asynchronní reconnect s throttlem 30 s a odkladovým oknem 0,5 s na finálním snímku „closed“, aby živá karta nezamrzla na starém stavu. Proměnná MCPTASK_RUNNER_DISABLE není jen vypínač streamu — je to globální kill switch veškerého provozu na mcptask.online: stream, poll kvót i hlášení chyb (internal/mcptask/endpoint.go, DisableEnv).
Stavový automat pod tím
schema verze 3Deset pojmenovaných stavů. Každý přechod je na allow-listu; cokoliv jiného se zapíše jako warning a práce běží dál. Frozen, pending, stalled a closed jsou vždy povolené cíle přechodu z jakéhokoliv stavu; vynucuje je watchdog (frozen, pending), detektor zaseknutí (stalled) a uzavření session ve smyčce (closed).
Stavy
Allow-list (ukázka)
Pár přechodů, které smyčka používá každou minutu — a vynucené přechody, které odpalují watchdogy samy od sebe.
| z | do | kým | poznámka |
|---|---|---|---|
| starting | triage | smyčka | Po spawnu, než se vybere první úkol |
| triage | processing | smyčka | Úkol zvolen, kontext předán CLI |
| processing | waiting | smyčka | Backoff mezi pokusy o tentýž úkol |
| processing | stalled | detektor zaseknutí | Opakované chyby nástroje Edit, opakované stejné chyby Bashe nebo tentýž podpis nástroje v klouzavém okně |
| libovolný | frozen | watchdog | Nečinnost delší než FROZEN_WARN_THRESHOLD, žádné aktivní nástroje |
| libovolný | pending | watchdog | Jeden nástroj přetáhl svůj varovný strop |
| libovolný | closed | smyčka | end_session — finální snímek |
Co je vidět za běhu
Tři nezávislé plochy — run log na disku, provozní log procesu a živá karta přes ActionCable — plus explicitní opt-out proměnné. Ze své podstaty jsou jen best-effort: samotné pozorování — snapshoty a logy — běh nikdy nepřeruší.
Run log — jeden JSON soubor na spuštění procesu potomka
Nejužitečnější plocha ve chvíli, kdy otázka zní „proč už runner devadesát minut visí“. Soubor se otevře IHNED při spawnu, takže i okamžitý pád zanechá něco čitelného.
log/runs/run_*.json (jeden soubor na spuštění procesu potomka)Otevřen
Při spawnu — dřív, než se přečte první řádek stream-json
Heartbeat
Obnovuje stream_events, inactive_s a stream_quiet_s při každém ticku, takže zaseknutý běh zanechá svůj rozpracovaný stav na disku
Finalizace
Orazítkuje, proč pokus skončil
Změní „proč runner visí už 90 minut“ z grepu nad 268 000 řádky stream logu na přečtení jednoho souboru.
Provozní log procesu — širší než run log
Není to lidsky formátovaná kopie JSON run logu. Je to chronologický textový log celého procesu: každý podsystém do něj píše svá volání Debug/Info/Warn/Error, takže obsahuje i to, co se v žádném run logu neobjeví — a naopak nenese pole run logu jako session_id nebo stream_events.
log/mcptask_runner_YYYYMMDD_HHMMSS.log[timestamp] SEVERITY - message (internal/observe/logger.go)Živá karta — jeden ActionCable WebSocket
Jeden perzistentní WebSocket nese celé snapshoty, nikdy jednotlivé události. Ztracený frame stojí čerstvost, ne správnost, a reconnect nepotřebuje replay.
| Kanál | Payload | Throttle | Timeouty |
|---|---|---|---|
| RunnerSessionChannel (internal/eventstream/eventstream.go, channelIdentifier) | Pouze celé snapshoty — žádný replay událostí | 500 ms snapshot, 30 s reconnect throttle, 500 ms final-frame grace | 10 s subscribe + dial |
Ukončená karta: Zůstane 60 s po konci smyčky (snapshotCloseTTL)
Bez tokenu: Runner spuštěný bez tokenu to řekne jednou, nahlas, při startu — nikdy tiše nepropásne první událost
Hranice — a opt-outy
Každá z těchto ploch je ze své podstaty jen best-effort. Odchozí pozorování běh nikdy nepřeruší; nil *Log je fungující no-op. Dvě proměnné prostředí ukládání čistě vypnou.
| Run log | Task handoff |
|---|---|
MCPTASK_RUN_LOG=0 — Vypne JSON run log | MCPTASK_TASK_HANDOFF=0 — Vypne poznámku task-handoff mezi procesy |
Jediná výjimka — přeřazení: Kanál RunnerSessionChannel je obousměrný: kromě odchozích snapshotů přijímá i řídicí události piece_assigned a set_aside_cleared (internal/eventstream/eventstream.go). Přeřazení úkolu je přes abandonReassigned (internal/runner/loop.go) zapojené do AbandonReassigned v enginu — zabije běžícího potomka a jeho smrt překlasifikuje na přeřazení. Je to jediná, záměrná řídicí role tohoto kanálu.
Co to NEZNAMENÁ: Žádná z pozorovacích ploch — run log, provozní log, odchozí snapshoty — nemůže běh zastavit, restartovat ani klasifikovat. Vlastnost best-effort je přesná hranice premisy „žádné fallbacky“: je to jediné místo, kde runner ustoupí — a nahlas to říká.
Flotila runnerů: Všechny instance runneru v účtu jsou navíc na stránce Flotila runnerů (uživatelské menu): jeden řádek na stroj a projekt s CLI, modelem, stavem, posledním nahlášeným úkolem, dnešními hodinami proti dennímu limitu a verzí runneru, živě aktualizováno. Manažeři účtu a vlastníci firmy vidí všechny runnery, členové projektu runnery svých projektů.
Když nastane tvrdý pád, bug piece se založí sám
Žádný manuální příkaz spouštět nemusíte. Když nastane tvrdý pád, runner za něj automaticky založí bug piece. Skutečný pád se stane úkolem, který někdo může zvednout — ne tichou mezerou, kterou nikdo nehledá.
Kdy se bug piece založí
Za tvrdý pád se počítá jen status error, status crash nebo status anomaly. To jsou tři hodnoty v hardStatuses (internal/bugreport/runner_error.go). Každý jiný výsledek — success, stalled_for_genius, urgent_bug_pending nebo graceful quota bail — znamená, že runner pracuje, jak má, a nezakládá nic.
Založí se
status error, status crash, status anomalyCo je anomaly
vlastní pojistka runneru, která v běhu neplatila, a běh přesto pokračoval — nic nespadlo, denní práce jela dál a zvenčí není co vidět. Error se ohlásí tím, že ukončí běh, a crash tím, že zabije proces; anomaly se neohlásí nikomu, a právě proto dostane piece.
NEzakládá se
success, stalled_for_genius, urgent_bug_pending, graceful quota bail — to jsou verdikty „pracuje, jak má“
Měkká výjimka
zabití kvótou uprostřed úkolu, vyčerpané rate-limit okno i odebrání piece během běhu přicházejí se statusem error a žádný piece nezaloží (softTerminations = {"quota", "rate_limited", "reassigned"}, internal/bugreport/runner_error.go)
Co bug piece nese s sebou
K založenému piece se přiloží tři artefakty (internal/bugreport/runner_error.go, attachArtifacts), aby ten, kdo ho zvedne, mohl číst pád bez nového spuštění.
Run log selhaného pokusu
JSON, se kterým run log na disku skončil
Konec stream logu
nejnovější stream log, oříznutý na 512 KB (internal/bugreport/runner_error.go, streamTailBytes)
Redigované configy
.mcp.json, .claude/settings.json, .claude/settings.local.json — s vyříznutými tokeny (mcptask/piece.go, ConfigFiles + Redact)
Jedna událost je jeden piece
Identické pády dostanou otisk, projdou throttlem a nahlásí se jen jednou. Bez toho by těsná smyčka založila stejný bug 200× dřív, než si toho někdo všimne.
| Fingerprint | Normalizace | Throttle okno | Razítko se nárokuje před založením |
|---|---|---|---|
| sha256 nad termination + normalizovaná zpráva + task id + projekt, oříznutý na 16 hex znaků (internal/bugreport/runner_error.go, fingerprint) | odstraňuje cesty, hex řetězce a desetinná čísla — co vypadá jako stejný pád jen s jiným časovým razítkem, se počítá jako stejný pád | šest hodin (internal/bugreport/runner_error.go, throttleWindow + claim) — druhý stejný fingerprint v okně se zahodí | razítko s fingerprintem se nárokuje PŘED založením piece a UVOLNÍ se, pokud se piece nikdy nezaloží (commit 3ae0d6e). Pád, který nejpravděpodobněji rozbije CreatePiece, je přesně ten, který by retry jinak tiše potlačil |
Paniky — vyhozené znovu, se stack trace
Panic je tvrdý pád se stopou pro forenzní analýzu. Piece dostane trace; smyčka si panic ponechá (loop.go, reportPanic, commit 1681e79). Jinak by zotavení z paniky trace spolklo a ten, kdo piece zvedne, by o něj přišel.
Fail-safe všude
Každá reportovací cesta polyká vlastní chyby, včetně vlastní paniky (internal/bugreport/runner_error.go, MaybeReport defer/recover). Chyba reportéra nikdy nesmí ukončit běh. Celá premisa stojí na tom, že nejhorší reportér je ten, který stojí nejméně — spolknutý řádek v logu, ne promeškaný pád.
Slepé místo, otevřeně řečeno
Reportér se autentizuje stejným tokenem jako vše ostatní, takže NEMŮŽE založit bug, který říká, že token chybí. Chybějící nebo nenastavený token reportéra tiše přeskočí — OutcomeSkippedDisabled nezapíše žádný chybový řádek, takže to nese jen vlastní exit kód a log runneru. Token, který server odmítne, je naopak hlasitá cesta: OutcomeRefused zaloguje chybu, která token pojmenuje (internal/bugreport/runner_error.go). Alternativou bylo mezeru skrýt; volba tady je ji pojmenovat.
Model-agnostický přes konfiguraci
Tři úrovně si namapujete na libovolného poskytovatele i na libovolné ze tří coding CLI. Runner nasměrujete na jakýkoli endpoint kompatibilní s Anthropic API — doloženým příkladem je lokální Ollama — změnou launcheru a modelové sekce.
Sekce models: je volitelná. Bez ní každý harness používá své vlastní obecné aliasy, které si dané CLI přeloží za běhu: opus / sonnet / haiku na Claude Code, gpt-6-astra / gpt-5.6-terra / gpt-5.6-luna na Codex CLI a ID ve tvaru provider/model na OpenCode. Konkrétní ID připínejte jen tehdy, když chcete deterministické retry, nebo když runner provozujete přes jiný backend než Anthropic — a jakmile to uděláte, platí VŠE NEBO NIC: všechny tři úrovně genius / smart / primitive musí být nastavené, jinak forkovaní subagenti spadnou s chybou „model may not exist“.
# models: je volitelná. Bez ní každý harness použije obecné aliasy,
# které si jeho vlastní CLI přeloží za běhu.
# Claude Code
models:
genius: opus
smart: sonnet
primitive: haiku
# Codex CLI
models:
genius: gpt-6-astra
smart: gpt-5.6-terra
primitive: gpt-5.6-luna
# OpenCode — každé ID je provider/model
models:
genius: /
smart: /
primitive: /
models:
genius: minimax-m3:cloud
smart: kimi-k2.7-code:cloud
primitive: deepseek-v4-flash:cloud
launcher:
# Lokální Ollama
command: [env, "ANTHROPIC_BASE_URL=http://localhost:11434", "ANTHROPIC_AUTH_TOKEN=ollama", "claude"]
ID níže jsou jeden příklad, ne doporučení — stárnou nejrychleji ze všeho na téhle stránce. Důležitý je tvar.
Flagy v launcher.command (launcher.go, Flag* constants): null flag se z argv VYNECHÁ, value flag bez tokenu se předá POZIČNĚ.
Loader nikdy neselže
Chybějící, prázdný nebo poškozený config/mcptask_runner.yml se bere jako „žádná konfigurace“ (config.go, LoadFile) a použijí se vestavěné defaulty. Neexistuje exit kód „soubor nenalezen“ — runner naběhne ve všech třech případech.
Žádný pin
Žádný dodávaný skill nedeklaruje `model:` — ForkModelEnv proto dosáhne na každého forkovaného subagenta, včetně těch, kteří běží na jiném launcheru než Anthropic.
Konfigurace žije v config/mcptask_runner.yml a hledá se relativně k pracovnímu adresáři launcheru (config.go, FileName; README.md) — je to stejný soubor, jaký čte Ruby gem, se stejnou sémantikou. Můžete tam nastavit i další volby, například cílový Epic pro automaticky nalezené bugy nebo prodlevy mezi běhy.
GEM — přesná cesta k souboru, přesná sémantika
update --self a záměrně chybějící automatika
Runner je statická binárka instalovaná stažením, ne gem, který se posune při každém bundle. Binárkou hýbou dva příkazy: update --self stáhne novější release a vymění za něj tu stávající, update --check oznámí, jestli nějaký existuje, a nic víc neudělá. Třetí rozhodnutí — jestli se runner vůbec smí povýšit sám před naplánovaným během — je to, které záměrně neautomatizujeme.
Jak update --self vymění binárku
Nová binárka přistane ve stejném adresáři jako ta stávající a přejmenování ji posune na místo (selfupdate.go). Ten postup je důležitější, než vypadá: přejmenování je atomické jen v rámci JEDNOHO souborového systému a /tmp jím obvykle není, takže se nový soubor připraví vedle, nepřepisuje se z jiného místa. Když stažení selže nebo nesedí kontrolní součet, k výměně vůbec nedojde — binárka na disku zůstane nedotčená a příkaz skončí nenulově.
1. Stažení z veřejného mirroru s vydáními
binárka pro dané GOOS/GOARCH se stáhne z jchsoft/mcptask-releases (selfupdate.go, DefaultRepo). Zdrojový repozitář je soukromý, takže veřejný mirror je jediné místo, odkud může stahování přijít bez tokenu
2. Ověření proti checksums.txt vydání
sha256 assetu se porovná s hodnotou, kterou zveřejnilo vydání (selfupdate.go, verify). Neshoda zruší běh dřív, než se do instalačního adresáře vůbec něco zapíše
3. Připravit vedle, běžící binárku přejmenovat stranou
nová binárka se zapíše vedle běžící, pak se běžící přejmenuje na sousední název. Tenhle krok je zároveň to, díky čemu celé funguje na Windows — přepsat soubor, který je namapovaný pro spouštění, na Windows nejde, a přejmenování stranou to obchází
4. Připravenou binárku atomicky přejmenovat na místo
závěrečné os.Rename na stejném souborovém systému přesune připravenou binárku do instalační cesty. Atomické v rámci toho souborového systému. Příkaz skončí nulou až po výměně
update --check — jen dotaz na tag, žádné stažení
update --check zjistí tag nejnovějšího vydání, porovná ho s běžící verzí, oznámí výsledek a skončí. Nestahuje žádný asset a neověřuje žádný kontrolní součet — ani jeden ze čtyř kroků výše se neprovede. Binárka na disku zůstane nedotčená. Je to správný příkaz, pokud si chcete do nočního jobu přidat upozornění bez instalace.
Záměrně chybějící funkce
Runner se před naplánovaným během NEaktualizuje sám. Pokud existuje novější release, vypíše jednořádkové upozornění a nic jiného neudělá, protože jedno špatné vydání nesmí v 08:05 zasáhnout každý host bez obsluhy. Upgrade zůstává rozhodnutím operátora — tohle ujištění stojí za to vyslovit nahlas každému, kdo nechá binárku běžet bez dozoru.
Co upozornění dělá
selfupdate.Hint vypíše jeden řádek, když existuje novější release (hint.go, hintTimeout + hintInterval). Limit 2 s, cache 24 h, ignoruje každou chybu — výpadek sítě ani rate-limit se k běhu nikdy nedostanou
Jak upozornění vypnout
nastavte MCPTASK_NO_UPDATE_CHECK=1 v prostředí hosta. To chce host v izolované síti nebo s měřeným připojením, a kontrola se umlčí dřív, než se vůbec sáhne na cache
Jedna ze dvou cest, které re-exec povolují — bundle adoption
BUNDLE ADOPTION (commit 00ced53, úkol #11478): pouze u run, a jen pokud Gemfile.lock projektu sám jmenuje novější verzi wrapper-gemu, než je běžící binárka — pak se run na té binárce re-execne. NIC NESTAHUJE — operátor to rozhodl už tím, že ten lockfile zmergoval. Host v 08:05 čte lock, který si stáhl z mainu, a běží na tom, co lock říká.
MCPTASK_ADOPTED
nastavený v prostředí re-execovaného potomka zastaví adoption, aby se z ní nestala nekonečná smyčka execů (adopt.go, EnvMarker). Binárka, která hlásí starší verzi, než říká lock, by jinak adoptovala, spustila se execem, znovu se shledala zastaralou a zacyklila se
MCPTASK_NO_ADOPT
nastavte na 1, ať zůstane nainstalovaná binárka připnutá bez ohledu na to, co nesou projekty. Host, který chce jednu verzi runneru napříč všemi projekty, to nastaví jednou a dá pokoj
Druhá cesta — daily se cestou na kutě předá sám sobě
Cestou do noční pauzy daily běh zkontroluje, jestli je binárka na disku pořád ta, se kterou vyběhl. Pokud ne, uvolní instance lock a execem spustí tu nainstalovanou — restartOnCurrentBinary (restart.go). Ani tahle výměna NIC NESTAHUJE — jen přebírá to, co na disk už dřív dal update --self nebo operátor. Na pořadí kroků záleží: denní práce je hotová, takže neběží žádný potomek a žádný pracovní strom není rozepsaný, a proces, který se zítra probudí, je ten, co dnes večer vyběhl.
Proč to existuje
všechno, co novou verzi zaznamená, se odehraje jen jednou, při startu. Daily proces se spustí jednou a nikdy neskončí, takže by host bez obsluhy jinak držel binárku, se kterou náhodou vyběhl, ať vyjde jakkoli mnoho vydání — přesně ten host, na který se nikdo nedívá. Zvažovalo se místo toho daily ukončovat, a bylo to zamítnuto (úkol #11728): runner, který zmizí, se přes chybějící nebo nenačtený naplánovaný job už nikdy nevrátí
ErrLockLost — třetí konec
restart.go deklaruje ErrLockLost — výměnu, která se vzdala instance locku a pak si ho nedokázala vzít zpět. Tenhle konec smyčku SKUTEČNĚ ukončí, záměrně a nahlas — pokračovat bez locku by druhému naplánovanému startu dovolilo pustit do stejného checkoutu druhý runner
Aktualizace skillů bez ztráty vašich úprav
Nainstalovaný projekt se rozchází s runnerem, jak runner přibírá skilly. Jeden příkaz ho sesynchronizuje: mcptask_runner update. Porovná každý skill a helper proti instalačnímu manifestu, u každého oznámí, co s ním udělal, a odmítne přepsat cokoli, co jste si upravili sami. Je to taky způsob, jak nainstalovaný projekt přestane volat `gh`: přibalené skilly přešly na `mcptask_runner pr` a právě `update` tuhle migraci donese do projektu nainstalovaného předtím.
Příkaz
mcptask_runner updatePět výsledků, jeden na soubor
Updater si drží obsahový hash každého souboru, který nainstaloval. Každý skill a helper proti tomuto manifestu zařadí a výsledek vypíše — pět výsledků, ne tiché přepsání.
addedSoubor na disku není. Updater ho zapíše. Takhle přistávají nové schopnosti runneru, aniž byste si o ně museli říct jménem.
up-to-dateSoubor na disku má stejný hash jako záznam v manifestu. Nic se nezapisuje. Host nainstalovaný přes gem se této binárce jeví jako aktuální — ověřeno přímo proti souboru, ne odvozeno z instalačního kanálu.
updatedSoubor odpovídá staršímu záznamu v manifestu, takže je to dodávaná verze a vy jste se jí nikdy nedotkli. Je bezpečné ho nahradit — a nahradí se.
conflict-skippedHash souboru neodpovídá ani aktuální, ani žádné známé dodávané verzi — upravili jste ho. Updater ho nechá přesně tak, jak je, a řekne to. Tohle je výchozí chování a právě proto je bezpečné příkaz spustit na projektu, který jste si přizpůsobili.
force-updatedTentýž konflikt, vyřešený opačně, protože jste o to požádali. Dosažitelné jen s --force nebo FORCE=1.
Přepsání konfliktu s cestou zpět
mcptask_runner update --force--force (nebo FORCE=1) lokálně upravené soubory místo přeskočení přepíše — a ke každému přepsanému nechá .bak. Vaše úpravy se nemažou; odsunou se stranou, kde si je můžete porovnat.
Čeho se prosté update záměrně nedotkne
update sahá POUZE na skilly a helpery. Všechno ostatní, co instalátor kdysi zapsal, zůstává přesně tam, kde je. Ta zdrženlivost je přednost, ne opomenutí: sesynchronizování skillů nesmí potichu znovu aktivovat plánovanou úlohu ani přepsat konfigurační soubor, který jste si ručně doladili.
Plánovaná úloha
LaunchAgent, uživatelský systemd timer ani úloha v Task Scheduleru se negenerují znovu a znovu se nezapínají. Když ji chcete opravdu vygenerovat znovu, použijte init --schedule.
.mcp.json
Vaše konfigurace MCP klienta se neotevírá, nepřepisuje ani nedegraduje. Transport i název tokenové proměnné, které jste deklarovali, aktualizaci přežijí nedotčené.
Konfigurační sekce
config/mcptask_runner.yml si ponechá hodnoty, které jste nastavili — pracovní okno, příkaz launcheru, hodinu konce pracovního dne. update na ně nemá názor.
Aktualizace binárky je samostatné rozhodnutí
update sesynchronizuje projekt. Nehýbe binárkou, která tu synchronizaci provedla. To dělají dva jiné příkazy a ani jeden z nich se nespustí sám: mcptask_runner update --self vymění novější release a mcptask_runner update --check jen oznámí, jestli nějaký existuje, a nic nezmění.
Runner se před během nikdy neaktualizuje sám
Na začátku běhu runner může vypsat jeden řádek o tom, že existuje novější release. To je celá ta funkce — strop 2 s, cache na 24 h, každá chyba ignorována a úplně se umlčí přes MCPTASK_NO_UPDATE_CHECK=1. Rozhodnutí o povýšení zůstává na operátorovi, protože runner, který by se před plánovaným během posunul sám, by bez zeptání měnil to, co tu práci dělá. To je podstatné, pokud necháváte binárku běžet bez dozoru.
Vadné stažení se k výměně nikdy nedostane
update --self stahuje z veřejné mirror repozitáře jchsoft/mcptask-releases a ověřuje soubor proti checksums.txt daného release. Neúspěšné nebo nesouhlasící stažení skončí dřív, než jakýkoli zápis sáhne do instalačního adresáře: binárka na disku zůstává nedotčená a příkaz skončí nenulovým návratovým kódem.
Celá sekvence výměny — a proč právě přejmenovávací tanec zajišťuje funkčnost na Windows — patří na stránku Runner.
Přečíst mechaniku self-updatePět veřejných subcommandů, dva persistent flagy, tři exit kódy
Runner je jediná binárka s jedním cobra rootem: run, init, update, version, pr. Šestý subcommand internal je schovaný před --help, protože ho volají vygenerované launcher skripty, ne operátor: internal launcher-log-name je to, čím si windowsový launcher pojmenuje vlastní log. Skrytý neznamená dočasný — launcher na něm za běhu stojí. Dva persistent flagy --verbose a --ignore-quota se čtou z odpovídající proměnné prostředí bez ohledu na velikost písmen (verbose=true, ignore_quota=true). Flagy jednotlivých subcommandů jsou vypsané u každého příkazu níže. Exit kód je 0 při úspěchu, 3 u neimplementovaného módu, 1 u čehokoliv jiného a 128+N při signálu. Trojka je navržená pojistka, ne konec, na který dnes dosáhnete: každý mód je implementovaný, takže ErrModeNotImplemented nikdo nevrátí.
Subcommandy
runSpustí work-loop mód. Mód je povinný; aliasy queue, story a task jsou zkratkou pro queue_manual, story_manual a task_manual.
initNainstaluje runner na tomto hostu. Zapíše skilly, helpery, oprávnění, token, záznam v .mcp.json, sekce configu a scheduled job.
updateObnoví bundled skilly a helpery. --self přehodí binárku na místě; --check oznámí verzi bez instalace.
versionVypíše banner (verze a výsledná konfigurace) a skončí.
prOtevře, vypíše, přečte, zreviduje, zmerguje nebo zkontroluje pull request na GitHubu, na Bitbucket Cloudu nebo na GitLabu. Jeden JSON objekt na stdout za zavolání.
Persistent flagy
Tyto dva flagy žijí na root příkazu a platí pro každý subcommand. Každý má ekvivalent v proměnné prostředí, která se bez ohledu na velikost písmen porovnává přesně s řetězcem „true“.
--verboseverbose=true
Vypíše každý řádek streamu místo filtrovaného pohledu.
--ignore-quotaignore_quota=true
Přeskočí všechny kontroly kvóty.
run — spustí work-loop mód
Vybere mód a spustí ho. Mód je povinný; aliasy queue, story a task jsou zkratkou pro queue_manual, story_manual a task_manual. story_manual a story_auto_squash vyžadují --story-id, task_manual a task_auto_squash vyžadují --task-id. Po startu runner vypíše banner s verzí, zdrojem modelů, zdrojem launcheru, cílem bug reportů, strategií čekání, pracovním oknem a dnešním skip listem, za ním souhrn rozpuštěné konfigurace, pak proběhne kontrola bundle adoption, update hint, token preflight, single-instance lock a signal handler — v tomto pořadí — a teprve potom se rozjede samotná smyčka.
--story-id N-
Vyžadují ho story_manual a story_auto_squash; bez čísla runner mód odmítne.
--task-id N-
Vyžadují ho task_manual a task_auto_squash; bez čísla runner mód odmítne.
init — nainstaluje runner na tomto hostu
Zapíše bundled skilly — dvanáct pro Claude Code, devět pro Codex CLI a OpenCode — deklaraci testů v .claude/test-commands.json, kterou bundled test skilly čtou, devět helper skriptů (devátý, runner-log, je jediný, který operátor píše sám v shellu), baseline oprávnění, výměnu tokenu, záznam mcptask-online v .mcp.json, blok bug_destination v config/mcptask_runner.yml, defaulty waiting_strategy a scheduled job. --at a --until určují čas běhu a hodinu konce pracovního dne; --schedule vygeneruje jen scheduled job. init se interaktivně ptá na dvě věci — do kterého Epicu padají automaticky nalezené chyby a jaký mód scheduled job spouští — a --epic-id, --epic-name a --mode na ně odpoví bez terminálu, protože binárku, kterou instaluje provisioning skript, musí jít nainstalovat i bez terminálu. --cli pojmenuje coding CLI, které tento projekt řídí, a je povinné při prvním init, bez jakéhokoli defaultu; --git-host připíchne hosta PR, když to URL originu neumí říct. --helper-bin-dir a --home-dir přesměrují to, co init zapisuje, --force přepíše, co už na hostu je. Scheduled job se vygeneruje, ale nikdy se neaktivuje — zapnutí jobu, který každé ráno utrácí kvótu, je rozhodnutí operátora.
--cli NÁZEV-
Které coding CLI tento projekt řídí — claude, codex, nebo opencode. Povinné při prvním init; žádný default neexistuje a projekt, který CLI nikdy nepojmenoval, runner odmítne jménem. Zapíše se do config/mcptask_runner.yml jako harness:.
--git-host HOST-
github, bitbucket, nebo gitlab, zapsaný jako git_host:. Nepovinné — runner ho odvodí z git remote get-url origin; tohle je pro aliasy, mirrory a self-managed instance GitLabu, jejichž origin URL není gitlab.com. Runner po vás URL GitLabu nikdy nechce: instanci si drží glab, do kterého jste přihlášení.
--at HH:MMMCPTASK_RUN_AT
Čas, kdy scheduled job běží. Výchozí je 08:00. Hodnotu, která není časem dne, runner odmítne, nikdy ji nezaokrouhlí.
--until HH:MMMCPTASK_WORKDAY_UNTIL
Hodina konce pracovního dne, zapsaná do configu pod work_window.end_of_workday_hour. Nenastavená znamená žádný konec dne. Jde ji později upravit, aniž byste znovu generovali schedule.
--schedule-
Vygeneruje znovu jen scheduled job — skilly, oprávnění, token a sekce configu zůstanou přesně tak, jak jsou.
--mode MÓD-
Mód work-loopu, který scheduled job spouští, např. today_auto_squash. Když ho zadáte, přeskočí se otázka na mód, kterou by init jinak položil.
--epic-id N-
Epic na mcptask.online, do kterého padají automaticky nalezené chyby; 0 je nechá v kořeni projektu. Když ho zadáte, přeskočí se otázka na Epic.
--epic-name NÁZEV-
Zobrazovaný název zapsaný vedle --epic-id, aby config říkal, který Epic to číslo je.
--helper-bin-dir CESTA-
Kam se instalují helper skripty pro CI a testy. Výchozí je ~/.claude/bin.
--home-dir CESTA-
Přesměruje adresář s tokenem, shellový rc soubor i scheduled job. Výchozí je domovský adresář uživatele.
--forceFORCE=1
Přepíše to, co už na hostu je — skilly, sekce configu i scheduled job. Širší než --force u update, který přepisuje jen upravené skilly a nechává .bak.
update — obnoví skilly a helpery
Holý update se dotkne jen bundled skillů (dvanáct pro Claude Code, devět pro Codex CLI a OpenCode) a devíti helper skriptů; záměrně nechá scheduled job, .mcp.json a sekce configu na pokoji. --self stáhne nejnovější release a přehodí binárku na místě (stejný souborový systém, obvyklý tanec s přejmenováním); --check oznámí, jestli existuje novější binárka, a nic nezmění. --force přepíše lokálně upravené skilly a nechá u nich .bak. Bundle adoption je jedna ze dvou cest, kdy se run re-execne — pouze u run, a jen když Gemfile.lock projektu ukazuje na novější wrapper-gem než běžící binárka. Tou druhou je daily, které se cestou do noční pauzy předá novější binárce, kterou už má na disku.
--self-
Stáhne nejnovější release, ověří ho proti checksums.txt a přehodí binárku na místě. Stažení, které selže nebo nesedí na kontrolní součet, se k přehození nikdy nedostane.
--check-
Zjistí tag nejnovějšího vydání, porovná verze, oznámí výsledek a skončí. Žádné stažení, žádné ověření kontrolního součtu. Binárka na disku zůstane nedotčená.
--forceFORCE=1
Přepíše lokálně upravené skilly a nechá u nich .bak vedle přepsaného souboru.
version — vypíše banner a výslednou konfiguraci
Vypíše banner (verze + výsledné modely + zdroj launcheru + bug destination + waiting strategy + pracovní okno + dnešní skip list) a za ním blok se shrnutím výsledné konfigurace — ten samý, který vypíše init na konci instalace — a skončí. Verze pochází z razítka v ldflags, jinak z verze modulu a nakonec je 0.0.0-dev, když se binárka sestavila bez razítka.
pr — otevře, přečte a zmerguje pull request
Jediná věc, která otevře pull request. Šest subcommandů — create, list, view, reviews, merge a checks — a každý vypíše na stdout jeden JSON objekt; chyby jdou na stderr s nenulovým exit kódem, takže je volající pozná bez čtení věty. merge má ve výchozím stavu --squash --delete-branch. Host je GitHub, Bitbucket Cloud, nebo GitLab (gitlab.com i self-managed, řízený přes CLI glab), odvozený z git remote get-url origin, pokud git_host: neříká jinak, a --git-host ho přepíše pro jedno zavolání. Host se poznává podle přesného hostname, takže GitHub Enterprise runner odmítne jménem, ne že by ho tiše považoval za GitHub.
--git-host HOST-
Přepíše hosta PR pro toto zavolání — github, bitbucket, nebo gitlab. Bez něj host pochází z git_host:, nebo z URL originu.
--task N-
Jen u list: pull requesty otevřené pro jeden úkol na mcptask.online.
--branch NÁZEV-
Jen u list: pull requesty, jejichž head je tato větev.
--open / --state STAV-
Jen u list: omezí výběr podle stavu. --open je zkratka pro ty otevřené.
Exit kódy
0Úspěch — včetně běhu, jehož úkol skončil s {"status":"error"}.
1Cokoliv jiného.
3Neimplementovaný mód (ErrModeNotImplemented) — navržená pojistka; každý mód je implementovaný, takže na ni dnes nic nedosáhne.
128+NZabit signálem N.
Konformanční scénáře a matice CI
Důkaz za každým tvrzením o spolehlivosti na této stránce. Obnova, watchdog, detekce zaseknutí i kvóta se všude jinde tvrdí bez jediného důkazu; tahle sekce je ten doklad.
Čtrnáct konformančních scénářů
Každý scénář je zaznamenaný rozhovor s claude CLI plus chování, které musí runner při přehrávání předvést. Scénáře jsou implementačně neutrální: čisté YAML plus kontrakt v conformance/README.md, ani řádek Go nebo Ruby. Spouští se přes `go run ./cmd/conformance {list,run --impl go}`.
Každý režim pádu, o kterém runner tvrdí, že ho přežije, má vlastní zaznamenaný scénář v conformance/scenarios/. Obě implementace spouští stejné soubory; Ruby gem je vysloužilá, zmrazená referenční implementace, proti které se dá suite porovnat, a bránou je zelená Go suite.
| Scénáře | |
|---|---|
01 — success | šťastná cesta: čistý run skončí zeleným verdiktem, bez retry, a větev je připravená k pushnutí |
02 — missing_marker_retry | run log nikdy nezafixuje marker; runner to zkouší znovu, dokud mu nedojde rozpočet, a pak skončí verdiktem místo zaseknutí |
03 — context_overflow_fresh_restart | přetečení kontextu, když engine ještě běží — práci nese dál in-process restart a run zůstane naživu |
04 — context_overflow_terminal | přetečení kontextu poté, co engine skončil — carry-forward mechanismus předá soubor novému procesu a jedině tak se run dostane ven |
05 — api_overload_529 | upstream vrátí 529 — runner couvne, run zůstane na správném úkolu a marker na přechodném stavu nepostoupí |
06 — tool_not_enabled_fresh_restart | nástroj, který run potřebuje, chybí na prvním pokusu; `--continue` ho spustí jako fresh restart a run se zotaví |
07 — tool_not_enabled_terminal | tentýž nástroj chybí i po fresh restartu — run skončí verdiktem, ne zaseknutím |
08 — stall_edit_failures | engine edituje soubor, který harness sleduje; edity se rozcházejí a watchdog to chytí dřív, než marker postoupí na základě lži |
09 — inactivity_kill_then_recover | proces potomka přestane komunikovat — watchdog ho zabije, debug dump zůstane na disku a další pokus zvedne tentýž úkol |
10 — recoverable_retries_exhausted | vyčerpají se všechny zotavitelné pokusy a run pořád není hotový — to je verdikt, a verdikt je jediný bezpečný výsledek |
11 — quota_mid_task | rozpočet se vyčerpá uprostřed editu — přijde měkké zabití, run uloží čistý stav a půlnoční strop dalšího okna odstartuje čerstvý pokus |
12 — stream_closed | upstream zavře stream v půlce tahu — runner zavření detekuje, run vyhodnotí jako neúplný a další pokus odvodí stav z disku, ne ze streamu, který zmizel |
13 — hung_tool_kill | nástroj, který engine zavolal, přestal odpovídat — watchdog zabije potomka signálem kill-on-hang a run jde spustit znovu |
14 — triage_unverified_pick | next-task picker vrátí úkol, který nebyl ověřený — runner ho odmítne nastartovat, nezaloží nic a počká na ověřeného kandidáta, místo aby slepě něco vybral |
Binárka nenese žádný vlastní test hook
Runner je nasměrovaný na mock CLI přes běžný override `launcher.command` (README.md) — je to stejná konfigurace na hostu, jakou vývojář použije pro řízení skutečného CLI. Suity běží ve všech třech dialektech harnessu (Claude Code, Codex CLI, OpenCode) a konformanční projekt na Bitbucket Cloudu a jeden na gitlab.com pokrývají zbylé dva hosty PR, takže zelený běh není zelený běh na jednom dialektu proti jednomu hostovi. Technický čtenář v tom pozná signál kvality — v binárce není žádná test-only code path, o kterou by se konformanční suite opírala, takže zelený run tady je stejný kód, jaký si uživatel nainstaluje.
Matice CI
Každý commit projde maticí tří OS × dvou verzí Go (ubuntu / macos / windows × 1.25.x / stable), dále go vet, race-detector testy na Unixu + stable, bin/smoke na SESTAVENÉ binárce, gofmt, golangci-lint, kontrolou goreleaser configu plus cross-compilem na šest cílů a celou konformanční suitou (.github/workflows/ci.yml). Matice existuje, protože runner se instaluje na vývojářské stroje — každá desktopová platforma musí projít buildem i testy.
Upřímná půlka
Zelený LOKÁLNÍ run vypíše, co NEpokryl — „Tenhle stroj jen: <goos>/<goarch>“ — protože jeden OS, jedna architektura a jedna verze Go není to, co běží v CI (bin/ci). Zelená lokálně je nutná, ne dostačující. Porovnání proti Ruby je referenční kontrola, ne brána: když vysloužilý gem není checkoutnutý, přeskočí se, neselže — stroj, který se k referenci nedostane, by měl umět zkontrolovat aspoň svou vlastní práci.
Hranice, pojmenovaná
Konformanční harness spouští jeden proces runneru na scénář, takže nedokáže pokrýt tu půlku přežití přetečení, která jde napříč procesy; to pokrývají testy, které pustí dva enginy za sebou a sdílejí jen soubor (README.md). Porovnání proti Ruby se přeskočí, neselže, když vysloužilý gem není checkoutnutý, a merge tak jako tak nedrží.
Technické FAQ
Krátké odpovědi na otázky, které tato stránka otevírá, ale přímo v textu na ně neodpovídá. Každá odpověď odkazuje na sekci, které otázka patří, a neopakuje ji.
Potřebuje runner Ruby, bundler nebo Gemfile?
Ne. Metadata projektu čte z CLAUDE.md a konfiguraci z config/mcptask_runner.yml — ani jedno z toho neprochází přes Ruby. Viz sekce 1. Žádný prompt nejmenuje ani příkaz konkrétního frameworku: projekt, který před browser testy potřebuje build krok, si ho deklaruje ve vlastním CLAUDE.md.
Funguje na projektu mimo Rails?
Ano — na libovolném projektu pod gitem, na GitHubu, na Bitbucket Cloudu, nebo na GitLabu (gitlab.com i self-managed), s jedním ze tří podporovaných coding CLI na hostu a s CLAUDE.md, který deklaruje account_code a project_relative_id. Žádné výchozí CLI neexistuje: vybírá ho init --cli claude|codex|opencode, launcher.command přepisuje jen argv a je křížově kontrolován proti harness:. Viz sekce 2.
Mohou dva runnery sdílet jeden checkout?
Ne. Druhý runner odmítne nastartovat; lock.go (AcquireInstanceLock) vynucuje jeden runner na checkout. Viz sekce 1.
Co se stane, když denní kvóta dojde uprostřed úkolu?
Aktuální pokus skončí jako soft termination (status error, nikdy se nezaloží bug piece) a smyčka počká na další bránu. Viz sekce 6.
Co po pádu zůstane a kdo se to dozví?
Hard failure (status error, status crash nebo status anomaly — vlastní pojistka runneru, která v běhu neplatila, a běh přesto pokračoval) založí vlastní bug piece s připojeným run logem, s otiskem a throttlem na šest hodin. Reportér nemůže nahlásit bug, který říká, že chybí jeho vlastní token — ten se projeví exit kódem a logem. Viz sekce 9 a 10.
Aktualizuje se sám bez dozoru?
Ne, záměrně. `update` se ve výchozím stavu dotýká jen skillů a helperů; `update --self` aktualizuje binárku v terminálu uživatele, ne v běhu na pozadí. Viz sekce 12.
Na kterých OS běží a co nepokryje zelený lokální běh testů?
macOS (launchd), Linux (systemd user timer) a Windows (Task Scheduler) mají každý vlastní naplánovanou úlohu. Zelený lokální běh testů pokryje unit a systémové testy na té verzi Go, kterou má host; nepokryje matici tří OS × dvou verzí Go ani čtrnáct conformance scénářů, které hlídají vydání. Viz sekce 14.
Ráno zapněte stroj
mcptask_runner nenahrazuje váš tým — násobí ho. Jeden statický binární soubor, jeden instalační řádek, a váš backlog se hýbe sám.
30 dní zdarma. Bez kreditní karty. Kdykoli zrušíte.