Na tej strani
- septembra 2026 ob 00.33 UTC je Tobi Lütke objavil tole: „MCP proti CLI za LLM je napačna razprava. Ljudje razpravljajo na napačni ravni.“ Nato je 23. oktobra opozoril na nov repozitorij dquickts. Gre za fork QuickJS, ki zna program ustaviti sredi zanke
for, vso njegovo kopico zapisati v bajte in ga nadaljevati v drugem procesu. „Odlično okolje za code mode,“ je zapisal.
Glede ravni ima prav. Najprej se želim z njim strinjati, z njegovimi lastnimi besedami, nato pa trditev zožiti, dokler ne pove nečesa, kar lahko uporabi sinhronizacija.
Raven, ki jo ima v mislih
Tukaj je argument, kot ga je oblikoval sam, kar je edini pošten način citiranja argumenta, ki ga človek namerava upogniti:
Oboje deluje neverjetno dobro, če teče skozi okolje, podobno REPL, ki zna ohranjati stanje. Pri CLI je zabavno to, da do orodij CLI običajno dostopamo prek BASH, ki je po naključju REPL s trajnim stanjem (datotečnim sistemom), zato CLI deluje veliko bolje kot MCP. A to še zdaleč ni notranja lastnost MCP. Pomeni le, da potrebujemo boljša izvajalna okolja.
To drži in pojasni opažanje, ki ga je imelo veliko ljudi, ne da bi ga pojasnili. Agent, ki dobi CLI, zapiše datoteko, jo tri korake pozneje prebere nazaj, jo preišče z grep, jo pošlje naprej po cevi. Agent, ki dobi gol MCP strežnik, dobi en rezultat na klic in mora vse drugo nositi v svojem kontekstnem oknu. CLI ni zmagal zaradi protokola. Zmagal je, ker je bash prinesel prostor, kamor se stvari lahko odložijo.
Iz tega sledi njegova stava. Nekdo zgradi vgradljiv pogon v slogu SQLite, ki bash, TypeScript ali klice orodij spremeni v en sam načrt, preverjen pred zagonom in zgrajen za trajno (durable) izvajanje. dquickts je korak v to smer. Njegov README opisuje REPL, „katerega funkcije in spremenljivke preživijo ponovne zagone“. Opisuje tudi trajen klic gostitelja: „skript pokliče funkcijo gostitelja, katere odgovor pride čez nekaj ur. Proces skript shrani in se zaključi.“
Doslej popolno strinjanje. Zdaj pa zoženje.
Katero stanje, za katero delo
„Ohranjati stanje“ skriva vprašanje: čigavo stanje in v kakšni obliki? Za programerskega agenta sta stanje repozitorij in lupina, REPL, ki preživi ponovne zagone, pa je dober odgovor. Za agenta, ki gradi sinhronizacijo med dvema sistemoma SaaS, je stanje, ki ga potrebuje med koraki, že določeno s samim delom. Nosijo ga štirje zapisi in nobeden od njih ni spremenljivka v skriptu.
Kurzor. Sinhronizacija bere vir po oknih in mora vedeti, kje se je končalo zadnje okno. V sinhronizacijskem pogonu Tajo je to shranjen kurzor za vsako sinhronizacijo in obseg, zapisan po vsakem paketu brez neuspešnih zapisov, naslednji zagon pa nadaljuje od njega. Načrtovani zagon shrani svojo izhodiščno točko, preden naredi karkoli drugega, zato prvi zagon, ki spodleti, naslednjemu pusti branje z iste točke. Načelo za tem, pošiljaj razliko in nikoli tabele, je opisano v razlagi reverse ETL. Kurzor bom pustil tam.
Čakajoči predlog. Pri MCP orodjih za konektorje Tajo je pisanje sestavljeno iz dveh klicev. brevo_propose preveri vhod glede na deklarirano dejanje in zabeleži predlog. Nič se ne pošlje. Rezultat vsebuje id predloga in, ko mora odločiti človek, stran, kjer ga odobri. brevo_apply po vrsti izvede odobrena pisanja te povezave in se ustavi pri prvem, ki še čaka na človeka. Zapis vmes je stanje. Vsebuje vhod in njegov povzetek (digest), zato odobrenega pisanja ni mogoče urediti med odločitvijo in izvedbo. Ne vsebuje vrednosti iz odgovora ponudnika, ker se zapis odobritev, v katerega se samo dodaja, ne sme spremeniti v shrambo osebnih podatkov.
Zaklep (lease). Zagon sinhronizacije ves čas svojega trajanja drži en izključni zaklep z žetonom lastnika, časovno omejitvijo privzeto petnajst minut in podaljševanjem. Zastarel lastnik ne more sprostiti novejšega zaklepa. Če shramba zaklepov ni dosegljiva, zagon raje ne začne, kot da bi ugibal. Kateri delavec (worker) drži zagon, je dejstvo v zaklepu, ne v pomnilniku kateregakoli procesa.
Načrt. syncs.dryRun iz kurzorja prebere naslednje okno, za vsak zapis določi vstavljanje, posodobitev, brisanje ali brez spremembe in zapiše natanko eno vrstico: načrt, ki se hrani eno uro. Ne premakne nobenega kurzorja in ne zapiše ničesar v nobenega od obeh sistemov. syncs.apply ta načrt zapiše enkrat. Zavrne, če se je kurzor premaknil ali če se je medtem spremenil večji delež zapisov od dopustnega. Ponovitev vrne prvi rezultat, namesto da bi pisala znova.
To je stanje med koraki: štirje zapisi z id-ji, berljivi za vsakega agenta, ki jih sme videti.
Zakaj stran MCP v seji ne hrani ničesar
Ko je stanje v zapisih, seja nima več česa hraniti. Zato MCP končne točke Tajo seje ne hranijo. Vsaka zahteva dobi svež strežnik in transport brez id-ja seje. Branja so ena zahteva na klic, z omejenimi rezultati, da en odgovor ne more preplaviti poteze. Pisanja so predlog, nato izvedba, in kar nosite naprej, je id predloga.
Protokol se je premaknil v isto smer. Revizija specifikacije MCP z dne 2026-07-28 je iz transporta Streamable HTTP odstranila seje na ravni protokola in glavo Mcp-Session-Id. Strežnik, ki potrebuje kontinuiteto, zdaj ustvari lasten ročaj in ga dobi nazaj kot običajen argument. Prav to je id predloga. Kaj je MCP strežnik obravnava to revizijo in kako se klic orodja razlikuje od trajne sinhronizacije; ta članek govori le o tem, kam gre stanje.
Posledica je tista, ki šteje pri integracijskem delu. Recimo, da agent v Claude Code predlaga pisanje in se njegova seja konča. Človek ga eno uro pozneje odobri. Agent v drugem odjemalcu, ali isti jutri, pokliče apply z id-jem in pisanje se izvede, enkrat. Sesuti agent izgubi svoje kontekstno okno in nič drugega. Nič ni bilo začasno ustavljeno, zato ni bilo treba ničesar nadaljevati.
Česa nimamo in koliko to stane
Pošten ugovor prihaja s strani REPL in se glasi takole: „Prav, vaši zapisi preživijo. Toda vsak klic znova bere, kar je prejšnji klic že imel. Skript bi stike prebral enkrat, jih združil, filtriral in vrnil število. Vaš agent naredi pet klicev in plača za vsakega.“ Ugovor ima prav glede mehanizma, cene pa nismo izmerili. Vrednotenje, ki bi štelo klice na nalogo s prenesenim stanjem in brez njega, ni zgrajeno. Dokler ne bo, trditev, da način klicev stane več žetonov, ostaja brez odgovora.
Še tri stvari je treba povedati naravnost, ker si jih bralec, ki prebere ta članek do konca, ne bi smel predstavljati:
- Danes ne teče nobena koda, ki bi jo napisale stranke. Branja prek konektorjev so ena zahteva na klic, brez peskovnika na poti. V našem skladu obstaja izvajalnik kode, ki je interno orodje. V produkciji je izklopljen, razen če sta nastavljeni dve ločeni zastavici, in odgovarja samo skrbnikom. Vsak klic dobi svež kontekst, vezave, ki dovoljujejo samo branje, in proračun dveh sekund za sinhrono kodo. Njegova lastna glava z velikimi črkami pravi, da je meja pravilnosti, ne varnosti.
- Brez REPL. Nič, kar agent izračuna v enem klicu, ni na voljo v naslednjem, razen če je bilo shranjeno kot zapis z id-jem.
- Brez trajne seje agenta. Odjemalec hrani svoj pogovor. Tajo hrani predloge, načrte, kurzorje in zaklepe. Tretje stvari ni.
Čemu je namenjen trajni pogon
Nič od tega ni argument proti dquickts. Njegov README našteva, čemu so namenjeni posnetki (snapshots), in seznam je dober. Uspavati nedejaven skript in sprostiti njegov pomnilnik. Izvajati dolg izračun po rezinah na katerem koli prostem delavcu. Toplo zagnati vsak primerek iz posnetka, namesto da se priprava ponavlja. Parkirati skript na klicu gostitelja, katerega odgovor pride pozneje. Za delovni prostor programerskega agenta ali zvezek (notebook), ki naj preživi ponovni zagon, je to pravo orodje.
Sinhronizacija pa vseeno ne bi smela biti odvisna od njega, iz treh razlogov, ki mi jih da README sam. Prvič: „Datoteka seje se naloži samo v gradnjo qjs, ki jo je zapisala.“ Kopica, ki jo je zapisala ena različica pogona, je po nadgradnji mrtva datoteka; kurzor je niz. Drugič: „Posnetki so zaupanja vreden vhod, kot bajtna koda“ in „zlonamernih se ne zazna“. Shranjeno kopico morate varovati, pregledati je ne morete; predlog je vrstica, ki jo človek prebere, preden ga odobri. Tretjič, posnetek vsebuje vse, kar je skript prebral, vključno z zapisi strank. Zgoraj opisani zapisi so zgrajeni ravno obratno: načrt hrani povzetke, ne vrednosti, zapis predloga pa nikoli ne hrani odgovora ponudnika.
Eno od pravil, po katerih gradimo, pravi, da deterministično premaga pametno. Kopica, ki nadaljuje sredi zanke, je pametna. Kurzor, predlog, zaklep in načrt so dolgočasni, pregledni in enaki na vsakem pogonu, v vsakem odjemalcu, po vsakem sesutju.
Lütke je zastavil pravo vprašanje. Kje živi stanje? Pri sinhronizaciji odgovor nikoli ni mogel biti v procesu. Vedno je moral biti v zapisih, ker ga mora prav tam lahko prebrati človek, ki pisanje odobri.
Pogosto Zastavljena Vprašanja
Je za AI agente boljši MCP ali CLI?
Sam po sebi nobeden. Opažanje Tobija Lütkeja z dne 21. septembra 2026 drži: oboje deluje, ko klici tečejo skozi nekaj, kar med koraki ohranja stanje. CLI se danes zdi boljši, ker bash hrani stanje v datotečnem sistemu. Razlika ni protokol, ampak izvajalno okolje.
Kakšno stanje potrebuje agent med koraki sinhronizacije?
Lastne zapise integracije: kurzor, ki pove, kje se je zadnji zagon ustavil, predlog, ki čaka na odobritev človeka, zaklep (lease), ki pove, kateri delavec drži zagon, in načrt preizkusnega zagona (dry run), s katerim se mora izvedba ujemati. Nič od tega ni spremenljivka v skriptu. To so vrstice z id-ji.
Zakaj MCP strežnik Tajo v seji ne hrani ničesar?
Vsaka zahteva dobi svež strežnik in transport brez id-ja seje. Kar koli potrebuje naslednji klic, je zapis: id predloga, id načrta, kurzor. Tako lahko drugi agent v drugem odjemalcu nadaljuje tam, kjer je prvi končal, sesuti agent pa ne izgubi ničesar razen svojega kontekstnega okna.
Ali Tajo izvaja kodo, ki jo napišejo agenti?
Za stranke ne. Branja prek orodij konektorjev so ena zahteva na klic, brez peskovnika. Izvajalnik kode, ki obstaja, je interno orodje za dvema zastavicama, dosegljivo samo skrbnikom, z vezavami samo za branje in svežim kontekstom za vsak klic. Sam o sebi pravi, da ni varnostna meja. Ni REPL in ni trajne seje.
Za kaj je dober trajni JavaScript pogon, kot je dquickts?
Njegov README našteva uporabe: uspavati nedejaven skript, razrezati dolg izračun med delavce, toplo zagnati iz posnetka in parkirati skript na klicu gostitelja, katerega odgovor pride čez nekaj ur. Vse to je resnično. Sinhronizacija pa vseeno ne bi smela biti odvisna od njega: posnetek se naloži samo v gradnjo pogona, ki ga je zapisala, za pregledovalca je neprozoren in vsebuje vse podatke strank, ki jih je skript prebral.