Spring til indhold
← Blog Blog

Loop-debatten er et dårligt ord for autonomi

Alle diskuterer "Claude Code loops." Efter at have målt en måneds rigtige opgaver — hver token, hver time det ville have kostet i hånden — er jeg ret sikker på, at det meste af diskussionen handler om det forkerte ord. Det er ikke loops, det er autonomi. Og ligesom microservices for ti år siden ankommer det én verificerbar opgave ad gangen, begrænset af et fundament, ingen har bygget endnu.

Loop-debatten er et dårligt ord for autonomi

Der er en genre af indlæg, der florerer lige nu. Du har sikkert set dem. “Jeg skriver ikke prompts længere — jeg designer loops.” “Loop-engineering er det nye prompt-engineering.” Jeg læser dem grundigt — jeg prøver at lære det her lige så hurtigt som alle andre, og dem, der skriver dem, er som regel langt foran mig. Men jeg sidder hver gang tilbage med den samme kløe: jeg kan ikke helt få ordet til at passe på det, jeg faktisk laver hele dagen.

Jeg bruger Claude Code de fleste dage. For dem, der ikke har mødt det: Claude Code er Anthropics kodeagent — du giver den en opgave i terminalen, og den læser filer, skriver kode, kører tests og itererer, i stedet for bare at række dig et stykke kode, du selv skal indsætte. Evnen er reel, og jeg læner mig hårdt op ad den. Det, der spænder ben for mig, er ordforrådet, så jeg prøvede at jorde det.

Jeg gjorde det kedelige: jeg målte alt. Hver rigtig opgave, jeg kørte gennem Claude Code, fik to tal ved siden af sig — hvad den kostede i tokens, og et groft estimat af, hvad det samme arbejde ville have kostet i hånden, i tid. En måneds rækker. Det er det mest uglamourøse artefakt, man kan forestille sig, og det er det, der til sidst fik “loop”-debatten til at falde på plads for mig.

Det, der faldt på plads — i hvert fald for mig — er, at en stor del af diskussionen handler om det forkerte ord. “Loop” er ikke sagen. Autonomi er. Og autonomi kommer ikke som en kontakt, du vipper; det kommer én opgave ad gangen — hvilket, hvis du var med under sidste store arkitektur-diskussion, burde føles besynderligt bekendt.

“Loop” er fire forskellige ting

En del af grunden til, at debatten føles grumset, er, at “loop” udfylder mindst fire roller på én gang, og folk taler forbi hinanden, fordi de hver især holder en forskellig en.

Der er agent-loopet — tænk, handl, observér, gentag. Det er bare sådan en agent virker. Den læser situationen, foretager en handling, ser på resultatet, beslutter hvad der er næste skridt. Det har altid eksisteret. Det er ikke en teknik, det er definitionen.

Der er Ralph — bash-hacket. Det er fællesskabets navn for det groveste tænkelige loop: pak agenten ind i et bogstaveligt while-loop i din shell, og lad den køre den samme prompt igen og igen, indtil den selv erklærer sig færdig. (Navnet er bare folklore; teknikken er pointen.) Groft, til tider effektivt — autonomiens gaffatape.

Der er funktionerne — slash-kommandoer som /loop og /goal, indbygget i værktøjer som Claude Code. De pakker den samme idé ind i noget mere kontrolleret end en bash-onelinjer.

Og der er “loop-engineering” — filosofien. Diskursen. Indlæggene.

Fire forskellige højder, ét ord. Ikke så sært, at det forvirrer.

Men her er det, de alle deler, sætningen hver af dem gentager på sin egen dialekt: mål, verifikation, stopbetingelse. Den trio er den egentlige substans. Alt andet er bare et spørgsmål om, hvilket lag den enkelte tilfældigvis stirrer på.

Lad os gøre det konkret. Tag den mest kedelige nyttige ting, jeg automatiserer: at adressere review-kommentarer på en pull request.

  • Mål: løs alle review-kommentarer på denne PR.
  • Verifikation: CI er grøn, og hver kommentar-tråd er reelt adresseret — ikke “jeg tror, jeg fiksede det,” men checket består, og tråden er lukket.
  • Stopbetingelse: ingen åbne kommentarer tilbage, eller den rammer et iterationsloft og giver bolden tilbage til mig.

Det er et loop. Det er også bare en opgave med en klar definition af færdig og en regel for, hvornår man stopper. Trioen er hele spillet.

Og læg mærke til, hvad der får eksemplet til at virke: en maskine, ikke mig, kan afgøre, om målet er nået — checket er grønt, eller det er ikke. Det er det, jeg fremover vil kalde verifikation — et automatisk, dømmefrit signal om, at arbejdet faktisk er gjort. Hold fast i ordet. Hvor meget af det en opgave har, er det, der afgør alt det senere.

Det er ikke loops. Det er autonomi.

Her er den del, det tog mig et stykke tid at se. Læs de tre kriterier igen — mål, verifikation, stopbetingelse — og spørg: ændrer noget af det sig, alt efter om jeg trykker enter mellem hvert skridt, eller en harness (scriptet eller værktøjet, der omslutter agenten) gør det for mig? Nej. Intet. Målet er målet, verifikationen er verifikationen, stopbetingelsen er stopbetingelsen; de er identiske, uanset om et menneske rykker hver iteration frem, eller et script gør det. Den eneste variabel er hvem der drejer håndsvinget mellem skridtene — og det er slet ikke et spørgsmål om loops. Det er et spørgsmål om autonomi: hvor meget du stoler på, at tingen kører videre uden dig i stolen.

Hvilket giver mening, når man ser, hvor lidt der egentlig er ved et loop — nogenlunde sådan her:

while not done:
    observe()              # look at where things stand
    act_toward(goal)       # take the next step
    done = verified()      # the stop condition: is the goal actually met?

Det er det hele. Så “bør jeg designe loops” er lidt af en kategorifejl — loopet er trivielt, et while og et if. De svære dele gemmer sig bag ordet, og der er to af dem. Den første: hvor langt er du villig til at træde væk fra en kørende proces? Det er tillid. Den anden, den jeg næsten aldrig ser nævnt: når du først træder væk, hvor kører tingen så rent faktisk, og har du råd til at køre den der? Det er infrastruktur — og i modsætning til tillid er det ikke rigtig op til dig endnu, fordi det billige, standardiserede sted at køre autonome agenter ikke findes.

Hvad arbejdet faktisk koster

Det andet spørgsmål — har du råd til at køre det — er det, ingen lader til at blogge om, sandsynligvis fordi næsten ingen tænker på at måle det. Så det gjorde jeg. Min hverdag med Claude Code er overvåget — jeg kører det på min egen maskine, med mig selv i stolen. Men det tal, jeg var ude efter, var det andet: hvad det samme arbejde ville koste målt pr. forbrug, betaling pr. token, sådan som du ville være nødt til at betale for at køre det i skyen uden mig som barnepige. Det er den dyre bane, og det er den, der afgør, om uovervåget overhovedet er på bordet. Så i en måned loggede jeg den forbrugsmålte pris for hver rigtig opgave, ved siden af et ærligt estimat af, hvor lang tid det ville have taget mig i hånden.

Tohundrede og tyve opgaver. Omkring $1.360 i forbrugsmålt pris — og, efter mit eget estimat, tæt på 540 timers tilsvarende håndarbejde. Femhundrede og fyrre timer er den bedre del af tre måneders fuldtids-ingeniørarbejde. Det røg ud ad døren på én.

Sæt et hvilket som helst rimeligt tal på en ingeniørtime, og de forbrugsmålte $1.360 står over for arbejde til tyve til fyrre gange så meget — omkring tredive til en normal fuldt belastet timepris, hvor man tæller løn plus overhead og ikke bare det, der ryger på kontoen. Multiplikatoren behøver ikke være præcis: halvér mine timeestimater, hvis du synes, de er rundhåndede, og det er stadig en størrelsesorden.

Formen på forbruget betyder lige så meget som størrelsen. Median-opgaven kostede $2,45. To tredjedele af alt lå under fem dollars — bugfixes, små features, skrøbelig CI-konfig, dependency-bumps. De dyre kørsler er sjældne, og det er de tunge af slagsen: en hel feature, bygget fra ende til anden, koster nogle tiere af dollars, og de største enkeltrækker er features i $40–55-lejet. Læg flere runder review oven på en af dem, og en komplet ændrings-livscyklus kan runde $100. Det er undtagelserne, ikke normen.

Den del, der afgør, hvor man skal starte: jeg markerede de rækker, der er rent review-og-fix-arbejde — at adressere PR-kommentarer, fikse et fejlende build, løse merge-konflikter. Hele den kategori lå under en tiendedel af det samlede forbrug — de fleste opgaver fra et par cents til et par dollars, halvdelen under en dollar. Og den krævede sjældent meget af mig. Kommentarerne er afgrænsede, fiksen er som regel lokal, og verifikationen er allerede sat op: buildet er grønt, eller det er ikke. Det er den mest checkbare, mindst dømmekrævende del af cyklussen — hvilket gør den til det oplagte første sted at lade noget køre på egen hånd.

Den reelle pengelækage er ikke prisen på den enkelte opgave. Det er churn — kørsler, der brændte krudt af på noget, der ikke havde brug for det. En ændring, der burde have kostet tyve dollars, kostede hundrede, fordi jeg lod den male løs på et problem, jeg bare burde have styret den igennem. Det spild, ikke prisen pr. opgave, er det, der er værd at lave ingeniørarbejde imod.

Det skræmmende tal er mest af alt en måle-artefakt

Der findes en version af det her, hvor nogen ser den månedlige total og får et chok. “Brugte du hvor meget på en AI?” Og jeg forstår det godt — $1.360 om måneden er et oprigtigt alarmerende tal.

Men det er mest af alt en artefakt af, hvordan det opgøres, ikke af, hvad arbejdet er værd — og det er ikke engang det, jeg betaler. De $1.360 er det forbrugsmålte tal, jeg målte. Min faktiske regning er det faste abonnement, jeg kører det hele på: en “Max”-plan i mellemlaget, brugt i et normalt tempo — ikke et hamr-alt-igennem-modellen, lad-mig-lige-google-det-med-Claude-også-tempo, bare støt rigtigt arbejde — som løber op i omkring €110 om måneden, lad os sige $120. Samme tastetryk, samme output, samme måneds arbejde; det forbrugsmålte tal er cirka ti gange abonnementet, udelukkende på grund af hvordan det afregnes.

Og her er den del, der stille og roligt afvæbner hele pris-panikken: du arbejder overvåget alligevel. Du sidder der. Du styrer. Det dyre, ubegrænsede “åh gud, hvad laver den”-scenarie er det uovervågede — agenten, der maler løs på egen hånd, mens måleren spinner. Hvilket er præcis det, du er mindst klar til at stole på i første omgang.

Så de to store bekymringer — “det er for dyrt” og “jeg kan ikke lade den køre selv endnu” — viser sig at være den samme grænse set fra to sider.

Så hvad bygger man egentlig?

Ikke et autonomt loop — ikke endnu, og ikke til det meste af det. Det, jeg bygger i stedet, er en menneske-udløst kæde af skills, hvor “skill” bare betyder en navngiven, genbrugelig opgave, du kan række agenten, som en gemt kommando. En af mine passer pull requests: når jeg har åbnet en PR, sætter jeg den i gang, og den holder øje med de ting, der kræver en reaktion — en ny runde review-kommentarer, et fejlende build — og arbejder dem, indtil PR’en er grøn, eller den rammer noget, den ikke kan håndtere, og prikker mig på skulderen. Jeg starter den; den starter ikke sig selv.

Det interessante er, hvad der ikke kører modellen. Overvågningen er et almindeligt shell-loop, der poller GitHub hvert par minutter for en håndfuld billige signaler — åbne, uafklarede kommentar-tråde, CI-status, om PR’en er blevet godkendt — og den vækker kun agenten, når det sæt rent faktisk ændrer sig:

# the watcher is dumb and free — no model in this loop
while pr_is_open; do
    signals="$(unresolved_threads)::$(failing_ci)"   # cheap GitHub calls
    if [ -n "$signals" ] && [ "$signals" != "$last" ]; then
        wake_agent "$signals"     # the only line that spends tokens
    fi
    last="$signals"
    sleep 600                     # 10 min; an idle PR costs nothing
done

Agenten spinder kun op, når sættet ændrer sig, og selv da gør den det afgrænsede — læser de nye tråde, fikser de værdige i arbejdstræet, kender forskel på et “min kode er i stykker”-build og et “infrastrukturen væltede”-build — og lægger sig så til at sove igen. Den dyre del, modellen, sidder bag den billige del, et script der ved, hvordan man læser en status. Den gating er det meste af tricket til at holde de her ting overkommelige.

Min er den pragmatiske udgave, dog, ikke evangeliet. Peg den mod en andens repo, og den har brug for rigtige guardrails. En PR-kommentar er upålideligt input, hvilket gør en åben watcher til en prompt-injection-flade: nogen kan efterlade en kommentar, der styrer agenten mod noget, der intet har med PR’en at gøre, eller bare spamme kommentarer for at blive ved med at vække den og stille og roligt drive regningen op. Forbi legetøjsstadiet vil du have en classifier, der afgør, hvad der overhovedet er værd at reagere på, og en eskaleringsvej — en OS-notifikation, et Slack-ping, en ticket — til de ting, den ikke selv bør røre. Men man kommer overraskende langt på de rå signaler alene; “åbne, uafklarede kommentarer plus CI-status” er allerede nok til at være reelt nyttigt.

Og formen kan generaliseres. En anden, jeg bliver ved med at ville gøre færdig: et ugentligt job, der scanner de åbne Dependabot- og Renovate-pull requests, merger og rydder op i de kedelige, hvor intet reelt skal ændres, og eskalerer resten — de bumps, der kræver en egentlig refaktorering, eller hvor et API kan brække under dig. Samme skelet hver gang: en billig trigger, et afgrænset job, og en klar linje, hvor det giver bolden tilbage til et menneske. At bygge de loops, og de små toolkits omkring dem, er stille og roligt ved at blive sin egen slags software engineering — mindre “prompt modellen,” mere “design den harness, modellen kører inde i.”

To regler, jeg ville hugge i sten, før jeg byggede noget af det. For det første: release er ikke et job for modellen — det er din CI/CD. Lær ikke en agent at gøre det, din pipeline allerede gør gratis, deterministisk, med et revisionsspor; det er ikke autonomi; det er at genopfinde et løst problem. For det andet: monitorering er ikke et job for modellen — det er Sentry og Grafana. Betal ikke en hjerne for at glo på et dashboard; kobl i stedet alarmen tilbage til en trigger, så agenten kun får problemet i hænderne, når noget rent faktisk er gået i stykker. Og uanset hvad du bygger, så sæt et loft på fiks-loopet — en hård iterationsgrænse plus en menneskelig “godt nok, send det”-port — ellers bliver den $20-fiks stille og roligt til en $100-fiks, mens du er til frokost.

Intet af det er forsigtighed. Menneske-i-loopet er ganske enkelt måden, man starter på: du løsner snoren én iteration ad gangen, efterhånden som dine egne evner skærpes og — vigtigere — efterhånden som din verifikation bliver god nok til, at du ville stole på resultatet uden at stå og kigge over skulderen.

Vi har haft præcis den her diskussion før

Hvis alt det her føles bekendt, er det, fordi vi spillede hele stykket igennem for ti år siden. Det hed microservices, og jeg var med. Hurtig genopfriskning, hvis du gik glip af den æra: omkring 2014 begyndte teams at hakke store, enkeltstående applikationer — “monolitter” — op i mange små, uafhængigt deploybare services. Den højlydte diskussion gik på, hvor små de skulle være.

Frådet er identisk. Dengang var det ubesvarlige spørgsmål “hvor lille er en microservice — kan den være 200 linjer?” I dag er det “Ralph eller /goal, og hvor mange agenter?” I begge tilfælde er det et fællesskab, der størrelses-diskuterer sig igennem en ting, før nogen overhovedet ved, hvad der faktisk betyder noget.

Den gode praksis kom også før navnet. Vi opdelte systemer efter domæne — rene snit, ejede grænser — længe før nogen sagde “microservices.” Og agent-loopet plus en verifikations-harness fandtes længe, før nogen brandede det som “loop-engineering.” Navnet dukkede op og tog æren for arbejde, folk allerede lavede.

Og så lagde det sig. Det ærlige tilbageblik på microservices er ikke “vi revolutionerede alt.” Det er “vi byggede stort set videre, som vi allerede byggede, bare med renere snit.” De fleste teams gik fra en monolit til to eller fem services, ikke fra én til to hundrede natten over. Forandringen var reel, og den var udramatisk, fordi det meste af det, vi byggede, allerede var småt.

Men her er korrektionen, der faktisk betyder noget, den del størrelses-diskussionen overså dengang. For microservices var den reelle forskel aldrig mønsteret. Det var fundamentet. Containere, så skyen, så Kubernetes gjorde små, uafhængigt deploybare services billige og standardiserede at køre. Mønsteret lå nedstrøms for infrastrukturen — og infrastrukturen dukkede op for at møde det.

For loops er vi kun halvvejs. Kapacitets-fundamentet er ankommet, og det er modellen. En enkelt række på mit ark er en feature, jeg ville have sat to dages håndarbejde af til, leveret for omkring halvtreds dollars. Det var fuldstændig umuligt for to år siden, til enhver pris, med ethvert loop. Loopet ændrede sig ikke; det, der sad inde i det, blev godt nok til, at man kan betro det rigtigt arbejde. Det er container-øjeblikket — den rå kapacitet, der lander.

Det, der ikke er ankommet, er resten af stakken. Der findes ikke et billigt, standardiseret, sikkert sted til rent faktisk at køre autonomi uovervåget — ingen pendant til den managed sky og Kubernetes, der forvandlede “jeg har en lille service” til “og her er det oplagte, overkommelige sted at køre den.” Intet siger endnu “lad denne agent male løs på egen hånd natten over, uden at det koster en formue eller løber af sporet.”

Så: modellen er containerne; Kubernetes er ikke bygget endnu. Og “loops” — filosofien, størrelseskrigene — er nanoservices-frådet om igen: “hvor absurd småt kan vi gøre det?"-overdrivelsen, der udspiller sig på en stak, der stadig mangler sin nederste halvdel.

Autonomi er gradvist, ikke en kontakt

Hvilket bringer mig tilbage til, hvor jeg startede. Du vipper ikke fra “jeg holder øje med alt” til “den kører selv.” Ingen gik fra én service til to hundrede på en weekend, og ingen ved deres fulde fem går fra overvåget-alt til autonom-alt heller.

Snoren løsnes én verificerbar opgaveklasse ad gangen, begrænset af præcis én ting: hvor checkbar verifikationen er. Det sker allerede. En PR-watcher, der auto-fikser fejlede builds, er snoren allerede løsnet — på en snæver, afgrænset, maskin-checkbar klasse, hvor prisen for at tage fejl er lav, og et grønt check fortæller sandheden. Imens forbliver feature-design og produktionsændringer i snor længe, måske for altid, fordi verifikationen er dømmekraft, og dømmekraft passer ikke ind i et CI-check.

Så når du læser “jeg designer loops, ikke prompts,” så forstå, hvor det kommer fra. Det er ikke en løgn. Men læg mærke til, hvem der plejer at sige det: folk i de store AI-labs — dem, der bygger modellerne — eller med reelt ubegrænsede token-budgetter, eller begge dele. For dem mangler det manglende fundament ikke; måleren gælder ikke på samme måde, som den gælder for dig. “Bare kør loops” er en fuldstændig ærlig beskrivelse af deres virkelighed. Det er rapportering fra forkanten: sandt der, hvor det rapporteres fra, med det bedste værktøj og de mest checkbare problemer, solgt som en universel recept, det ikke er endnu — ikke for nogen, der arbejder mod et reelt budget.

Så jeg melder mig ikke ud af debatten — jeg melder mig ud af ordet. Jeg bygger den overvågede kæde, skærper mine egne evner og min verifikation, og lader hver opgaveklasse fortjene sit slæk ét check ad gangen. Det er den del, jeg kan handle på i dag, mens resten bliver diskuteret færdigt.

Hvilket er det samme træk, der viste sig at være rigtigt med microservices: spot frådet, lad størrelseskrigene rase, og bliv ved med at sende den kedelige udgave, der rent faktisk virker.