03 – De lus

Altijd aan

afgerond

In de vorige aflevering kreeg OttoOps een geheugen. Hij weet wie hij is, houdt bij waar we mee bezig zijn en schrijft belangrijke dingen op.

Maar er is nog iets vreemds aan de manier waarop hij werkt.

Als ik hem via Telegram een bericht stuur, wordt hij gestart. Hij leest wat hij moet weten, doet zijn werk, geeft antwoord en verdwijnt weer. Bij mijn volgende bericht begint hetzelfde opnieuw.

Voor vragen werkt dat uitstekend. Tot je hem echt iets laat doen.

Bij mij werd OttoOps na twee minuten afgekapt. Als ik vroeg hoeveel vrije ruimte mijn server nog had, merkte ik daar niets van. Maar bij een opdracht waarbij hij iets moest uitzoeken, aanpassen en testen, waren twee minuten ineens weinig.

Het vervelende: het werk was dan soms gewoon gedaan. Alleen zijn antwoord kwam niet meer terug.

Vanuit Telegram leek het alsof hij was vastgelopen.

Je kunt zo’n tijdslimiet langer maken. Maar daarmee verschuif je het probleem alleen. Daarom gaan we het deze keer anders doen: OttoOps wordt niet meer voor ieder bericht opnieuw gestart.

Hij gaat draaien.

Teamstatus: 1 agent.

Wie doet het werk

OttoOps bouwt ook deze aflevering vrijwel alles zelf.

Ik ga dus niet op de server bestanden zitten maken of programma’s aanpassen. Ik vertel hem via Telegram wat ik wil bereiken. Hij zoekt uit hoe dat op zijn computer moet worden ingericht.

Daarmee begint deze aflevering bewust nog vanuit de situatie van aflevering 02.

Mijn eerste vraag was simpel:

Waar waren we gebleven?

Daarna wilde ik zeker weten dat er nog maar één taak mijn berichten ophaalde:

Hoeveel taken halen op dit moment mijn Telegram-berichten op, en hoe vaak draaien ze? Verander niets, ik wil het alleen weten.

Telegram-gesprek: de vraag waar we gebleven waren, en het antwoord dat er één taak elke minuut berichten ophaalt.
De begintoestand: één taak, elke minuut.

Pas toen dat klopte, begon ik te bouwen.

Wat we vandaag bouwen

De nieuwe opzet bestaat grofweg uit twee delen.

Eén ding luistert continu naar Telegram. Zodra ik iets stuur, zet het mijn bericht in een rij. Meer hoeft het niet te kunnen.

OttoOps zelf hoeft daardoor niet tegelijkertijd te luisteren en na te denken. Hij kan twintig minuten met een klus bezig zijn; berichten die ondertussen binnenkomen blijven gewoon staan tot hij eraan toe is.

Dat onderscheid bleek belangrijk.

Als je OttoOps zelf laat luisteren, luistert hij namelijk niet op het moment dat hij bezig is. Daarom is de ontvanger expres dom: bericht binnen, in de rij, klaar.

Die rij wordt bovendien groter dan alleen Telegram. Ook vaste opdrachten die op een tijdstip worden uitgevoerd gaan er later in.

Een opdracht van de klok is uiteindelijk gewoon een opdracht die niet door mij is verstuurd.

En OttoOps krijgt nog een nieuwe mogelijkheid: hij moet zelf naar Telegram kunnen schrijven. Tot nu toe zat er altijd iets om hem heen dat zijn antwoord opving en doorstuurde. Dat verdwijnt zodra hij blijft draaien.

Maar voordat ik daarmee begon, moest ik eerst het probleem oplossen waarmee deze aflevering eigenlijk begon.

Die maatregel is tijdelijk. Tijdens het bouwen wil ik niet dat hij midden in een wijziging wordt afgekapt.

De taak die mijn berichten ophaalt kapt jou na twee minuten af. Zet die grens tijdelijk op tien minuten, want ik ga je nu dingen laten inrichten in plaats van beantwoorden en daar is twee minuten te krap voor. Zet er een aantekening bij dat het tijdelijk is en waarom, zodat we het straks kunnen terugdraaien. Zeg me alleen of het gelukt is.

Telegram-gesprek: de opdracht om de tijdslimiet tijdelijk op tien minuten te zetten, en de bevestiging dat het gelukt is.
Twee minuten wordt tijdelijk tien.

Eerst een rij

Daarna liet ik hem één plek maken waar alles terechtkomt wat nog op hem wacht:

Maak in je thuismap een wachtrij voor alles wat je moet doen: één bestand waar dingen aan het eind bij komen en waar ze op volgorde weer uit gelezen worden. Nu zijn dat mijn berichten; straks komen er ook opdrachten in die niet van mij komen maar van een vast tijdstip. Bouw hem dus breed genoeg.

Per regel leg je vast wanneer hij binnenkwam, waar hij vandaan komt, de tekst zelf, en of jij hem al hebt opgepakt.

Twee dingen moeten kloppen:

  • Er kan iets bijkomen op het moment dat jij aan het lezen bent. Zorg dat er dan niets kwijtraakt en dat de inhoud niet door elkaar loopt.
  • Wat je hebt opgepakt blijft staan, maar je krijgt het niet nog een keer.

Maak er twee kleine hulpmiddelen bij: één om iets in de rij te zetten, en één om te lezen wat er nog niet is opgepakt. Dat tweede geeft in één keer alles terug wat openstaat, op volgorde van binnenkomst — niet één bericht per keer.

Leg in je onderwerpbestand over communicatie vast hoe de rij werkt en waar hij staat.

Telegram-gesprek: de opdracht om een wachtrij te maken, en OttoOps' overzicht van wat hij bouwde en hoe hij het testte.
Wat OttoOps ervan maakte, inclusief zijn eigen proeven.

Die rij heb ik meteen laten testen:

Zet drie testberichten in de rij. Lees de rij daarna uit, en laat me zien wat je terugkrijgt. Lees hem vervolgens meteen nog een keer uit, zonder er iets bij te zetten, en laat me dat ook zien.

De eerste keer moeten er drie berichten uitkomen. De tweede keer niets. Wat OttoOps eenmaal heeft opgepakt, mag niet opnieuw langskomen.

Iets dat alleen luistert

Nu kon de ontvanger worden gebouwd.

Maak een programma dat blijft luisteren naar mijn Telegram-berichten en elk bericht meteen in de wachtrij zet. Meer niet: het beantwoordt niets en het start niets op.

Eisen:

  • Het blijft draaien. Hapert de verbinding met Telegram of geeft Telegram een fout, dan wacht het even en probeert het opnieuw; het stopt daar niet mee.
  • Het houdt bij welke berichten het al heeft gehad, zodat er na een herstart niets dubbel binnenkomt en niets wordt overgeslagen.
  • Het reageert alleen op berichten van mij, hetzelfde account als bij de taak die je nu hebt. Iedereen die de naam van de bot kent kan hem aanschrijven, en dat mag niet in mijn wachtrij belanden. Maak er een lijstje van toegestane afzenders van, ook al sta ik er nu als enige op.
  • Wat het doet schrijft het weg in een apart bestand: elk bericht dat binnenkomt, elke fout, en verder één regel per uur dat het nog luistert. Niet elke ronde een regel, dan staat er na een week een bestand van honderden megabytes. Zorg ook dat het bestand niet eindeloos doorgroeit.

Start hem nog helemaal niet — ook niet één keer om me te laten zien dat het werkt, en ook niet op de achtergrond. Zolang de taak van elke minuut nog draait, kapen die twee elkaars berichten weg en ben ik je kwijt. We starten hem hieronder, met die taak vijf minuten uit.

Dat laatste is belangrijk. Tijdens het bouwen bestaan er tijdelijk twee manieren om dezelfde Telegram-berichten op te halen. Die mogen niet tegelijk draaien.

Voor de proef gaf ik daarom één opdracht die zichzelf na vijf minuten weer moest herstellen:

Zet de taak van elke minuut uit en start de ontvanger. Zorg dat over vijf minuten allebei de dingen weer goed staan — ontvanger uit, taak weer aan — zonder dat jij daar op dat moment iets voor hoeft te doen; jij kunt dan afgekapt zijn of met iets anders bezig. Zeg me wanneer het loopt.

In die periode stuurde ik een bericht. Ik kreeg geen antwoord — precies de bedoeling. De ontvanger luistert, maar praat niet terug.

Daarna:

Laat me zien wat er in de rij staat.

Mijn bericht moest daar tussen staan.

OttoOps moet zelf kunnen terugpraten

De volgende stap lijkt klein, maar zonder deze stap zou ik straks een perfect werkende OttoOps hebben waar ik niets meer van hoor.

Maak een commando waarmee je zelf een bericht naar mijn Telegram kunt sturen, los van een vraag van mij. Je gebruikt dezelfde bot als nu.

Twee dingen:

  • De tekst geef je mee via een bestand, niet op de opdrachtregel. Op deze server kan iedereen zien welke opdrachten er draaien, inclusief wat erin staat. Dat is nu nog niet spannend, maar straks staan er meer agents op deze machine en dan wil ik dit niet hoeven terugdraaien.
  • Lukt het versturen niet, dan zeg je dat en schrijf je het weg. Een bericht dat stilletjes niet aankomt is erger dan een foutmelding.

Zet in CLAUDE.md dat dit commando bestaat en dat dit voortaan de manier is waarop je mij iets stuurt.

En natuurlijk meteen testen:

Stuur me via dat nieuwe commando het bericht: de lijn werkt.

Telegram-gesprek: de opdracht om zelf te kunnen versturen, en het eerste bericht dat OttoOps uit zichzelf stuurt.
De eerste keer dat OttoOps uit zichzelf iets zegt.

Toen dat bericht in Telegram verscheen, wist ik dat OttoOps voortaan ook iets kon zeggen zonder dat ik vlak daarvoor iets had gevraagd.

Dat is een klein maar belangrijk verschil tussen een chatvenster en een agent.

Leren wachten

Nu kwam het onderdeel waar de rest op steunt.

Maak een commando waarmee je op een bericht kunt wachten. Het blijft hangen tot er iets in de wachtrij staat, en geeft dan terug wat er binnenkwam en waar het vandaan komt.

  • Staat er al iets in de rij als je het aanroept, dan krijg je dat meteen — je wacht niet op het volgende.
  • Is er na een paar minuten nog niets, dan geeft het niets terug en stopt het. Dat is geen fout.
  • Wat je zo ophaalt geldt als opgepakt: je krijgt het niet nog een keer.

Zeg me één ding: hoe lang je hoogstens wacht voordat je het opgeeft.

Daarna wilde ik juist de saaie situatie testen: er gebeurt helemaal niets.

Roep het wachtcommando aan zonder dat er iets in de rij staat, en laat me zien wat je terugkrijgt en hoe lang het duurde.

Bij mij duurde dat ongeveer vijf minuten. Daarna kwam er een lege uitkomst terug.

Telegram-gesprek: het wachtcommando op een lege rij geeft na ruim vijf minuten een leeg resultaat zonder foutmelding.
Vijf minuten wachten, en dan netjes niets.

Dat lege resultaat is straks belangrijk: niets te doen hebben is geen storing.

Daarna testte ik wachten met een echt bericht:

Zet de taak van elke minuut uit en start de ontvanger. Zorg dat over vijf minuten allebei de dingen weer goed staan — ontvanger uit, taak weer aan — zonder dat jij daar op dat moment iets voor hoeft te doen; je bent dan namelijk aan het wachten.

Stuur me met het verstuurcommando een berichtje zodra het loopt. Roep daarna het wachtcommando aan. Komt er iets binnen, stuur me dan meteen — weer met het verstuurcommando — wat je kreeg en hoe laat je het kreeg. Komt er niets, stuur me dan hoe lang je hebt gewacht.

Telegram-gesprek: OttoOps meldt zelf wat hij tijdens het wachten ontving, terwijl de oude taak uitstaat.
Hij meldt zelf wat hij ontving — terwijl niemand meer meeluistert.

Nu hadden we alle losse onderdelen.

De rij.

De ontvanger.

Terugpraten.

Wachten.

Wat nog ontbrak was OttoOps zelf.

De belangrijkste instructie van deze aflevering

Dit is de opdracht waar bij mij uiteindelijk het meeste vanaf hing.

Schrijf in je thuismap een bestand waarin staat hoe je werkt zodra je doorlopend draait. Noem het zo dat duidelijk is dat het over je werkwijze gaat, en zet in CLAUDE.md dat het bestaat.

Dit staat erin, in je eigen woorden maar zonder dat er iets afvalt:

  1. Je roept het wachtcommando aan en je wacht er echt op — op de voorgrond, niet op de achtergrond. Je geeft het meer tijd dan het zelf nodig heeft, zodat het commando zelf kan bepalen wanneer het klaar is. Kap je het eerder af, dan krijg je een foutmelding waar een leeg antwoord had moeten staan, en dat leest als een storing terwijl er niets aan de hand is.
  2. Komt er iets uit de rij, dan handel je het af en roep je daarna meteen weer het wachtcommando aan. Hoort er een gesprek bij — er is iemand die op antwoord wacht — dan stuur je je antwoord met het verstuurcommando terug naar de plek waar het vandaan kwam, wie de afzender ook is. Is het een opdracht zonder gesprek, zoals een taak op een tijdstip, dan doe je wat er staat en meld je alleen iets als er iets te melden valt.
  3. Kwam er niets, dan roep je meteen weer het wachtcommando aan. Een lege rij is normaal en is geen reden om iets te melden of om te stoppen.

En de regel waar het om draait: je bent nooit klaar. Er is niemand die je opnieuw start. Stop je, dan blijven mijn berichten in de rij staan en hoor ik niets meer van je, zonder dat er een foutmelding komt. Je beurt eindigt dus niet na een antwoord, niet na een samenvatting en niet als het even stil is. Hij eindigt alleen als ik zeg dat je mag stoppen.

Zet die laatste regel bovenaan, niet onderaan.

Daarna liet ik hem letterlijk teruglezen wat hij ervan had gemaakt:

Lees me voor wat je hebt opgeschreven.

Die regel je bent nooit klaar klinkt nogal nadrukkelijk.

Dat is niet voor niets.

Een agent is gewend een opdracht af te maken. Vraag beantwoord? Klaar. Klus uitgevoerd? Klaar. Niets meer in de rij? Klaar.

Maar vanaf het moment dat OttoOps doorlopend draait, is klaar precies wat niet mag gebeuren.

Er staat straks niemand meer naast hem die bij het volgende bericht weer een nieuwe agent start. Als OttoOps zelf stopt, blijft de ontvanger gewoon luisteren en blijven mijn berichten keurig in de rij terechtkomen.

Alleen niemand pakt ze nog op.

Geen foutmelding. Geen storing. Gewoon stilte.

Dat is waarom de instructie niet alleen zegt wat hij moet doen als er een bericht komt, maar ook wat hij moet doen als er helemaal niets komt.

Weer wachten.

De klok gaat dezelfde rij in

Uit aflevering 02 stond al een dagelijkse controle gepland. Alleen startte die nog een eigen agent.

Dat wilde ik niet meer.

Als OttoOps gisterenavond iets met mij heeft besproken, moet degene die ’s ochtends een vaste taak uitvoert dezelfde OttoOps zijn. Niet een nieuwe versie die alleen wat bestanden heeft gelezen.

Daarom:

De dagelijkse controle draait nu als een losse taak die zelf een agent start. Zet dat om: de taak zet zijn opdracht voortaan in de wachtrij, net als een bericht van mij, en start zelf niets meer.

Straks, als je doorlopend draait, pak je hem daar gewoon uit op — net als al het andere.

Twee dingen:

  • In de rij moet te zien zijn dat dit een opdracht van de klok is en geen bericht uit een gesprek. Er wacht niemand op antwoord, dus je stuurt alleen iets terug als er iets te melden valt.
  • Staat er in de rij nog iets dat niet is opgepakt, dan zet de taak er niets bij en slaat hij deze ronde over. Dat er al iets wacht betekent dat ik bezig ben of nog niet toe ben gekomen aan wat er staat; er hoeft dan niet ook nog een controle bovenop. De volgende keer komt hij vanzelf weer langs.

Kijk daarna je hele computer na op andere taken die uit zichzelf een agent starten, en zeg me welke dat zijn. Ook de taken die nu uitstaan — die staan misschien ooit weer aan.

Vervolgens twee proeven:

Laat de dagelijkse controle nu één keer aflopen alsof het zijn tijd is, en laat me daarna zien wat er in de rij staat.

En terwijl die opdracht nog onaangeraakt in de rij stond:

Die opdracht van zonet staat nog steeds in de rij en is nog niet opgepakt. Laat de controle nu nog een keer aflopen en zeg me wat hij doet.

De tweede keer hoort er niets bij te komen. Er staat immers al werk te wachten.

Daarna kon de proefrommel weg:

Haal die testregels weer uit de rij.

Vanaf dit moment geldt voor mij één eenvoudige regel:

alles wat OttoOps laat nadenken gaat door dezelfde rij.

Aanzetten

Nu kon de oude manier van werken echt verdwijnen.

Dit was mijn opdracht:

Maak één opdracht waarmee alles aangaat: eerst de ontvanger, daarna jezelf.

  • Bij het starten krijg je een openingsopdracht mee. Daarin staat kort wie je bent, wat de stand van zaken is, en de werkwijze uit je werkwijze-bestand — inclusief de regel dat je nooit uit jezelf klaar bent.
  • De ontvanger en jij blijven draaien nadat mijn verbinding met de server wegvalt. Ik wil ze kunnen starten en dan mijn laptop dicht kunnen doen.
  • Draait er al een ontvanger of al een agent, dan start je er geen tweede bij. Twee agents op dezelfde wachtrij is de vervelendste storing die je hier kunt krijgen: de een pakt het bericht op waar de ander op wachtte, en je krijgt half antwoord op alles.
  • Maak er ook een opdracht bij om alles te stoppen, en één om te zien of het draait.

Zet daarna de taak uit die elke minuut mijn berichten ophaalt — nu definitief, niet tijdelijk. Verwijder hem niet, zet hem uit, met een aantekening erbij waarom. Vanaf nu doet de ontvanger dat.

Vanaf nu is de rij de enige weg naar binnen, en een taak die zijn eigen agent start praat langs mij heen.

Zet ook de tijdslimiet terug die we aan het begin van deze aflevering tijdelijk hebben verruimd. Die hoorde bij de oude taak en die zet je nu uit; in de lus geldt hij niet meer.

Schrijf in je onderwerpbestand over communicatie hoe je start, hoe je stopt en hoe je kijkt of het draait. Ik wil dat kunnen opzoeken zonder het jou te hoeven vragen — als jij niet draait, kan ik het je immers niet vragen.

Daarmee sluit ook het verhaal van die tijdslimiet.

Aan het begin moest twee minuten tijdelijk tien minuten worden, omdat OttoOps steeds één losse beurt kreeg.

Nu is die oude taak uit.

De limiet mag dus weer terug. Niet omdat tien minuten ineens genoeg is, maar omdat OttoOps geen losse beurt meer heeft die na zoveel minuten eindigt.

Op dit punt is er wel één praktisch probleem: OttoOps kan zichzelf niet starten als hij niet draait.

Daarvoor gebruik ik LocalClaude, de reservesleutel vanaf mijn eigen computer. Ik liet die de startopdracht uitvoeren die OttoOps zelf had gemaakt. Daarna kon ik weer gewoon verder via Telegram.

Hij schrijft het ook op als het gesprek lang wordt

Doorlopend draaien levert nog een nieuw probleem op.

In de vorige aflevering begon OttoOps bij ieder bericht opnieuw. Daardoor móést hij belangrijke informatie opschrijven: anders was hij die bij mijn volgende bericht kwijt.

Nu onthoudt hij dingen vanzelf, want ons gesprek loopt door.

Dat is prettig. Tot dat gesprek heel lang wordt en het oudste deel moet worden ingekort, of totdat zijn sessie stopt.

Daarom gaf ik hem ook dit:

Zorg dat je stand van zaken wordt bijgewerkt op twee momenten waarop het anders misgaat: vlak voordat ons gesprek wordt ingekort omdat het te lang wordt, en op het moment dat je sessie afloopt.

Claude Code kan je op allebei die momenten iets laten doen. Zoek uit hoe dat heet en richt het in.

Wat er dan moet gebeuren: je kijkt of de stand van zaken nog klopt met waar we werkelijk zijn, je werkt hem bij als dat niet zo is, en wat er afvalt schrijf je weg in je logboek onder de dag van vandaag. Dat is dezelfde regel die je al had — alleen gebeurt hij nu ook als je er zelf niet aan denkt.

Zeg me daarna alleen hoe ik straks kan zien dat het gewerkt heeft — de techniek erachter hoef ik niet te weten.

Dit vervangt het gewone bijwerken niet. Het is een vangnet.

Als OttoOps tijdens ons gesprek iets belangrijks leert, moet hij dat nog steeds gewoon vastleggen. Deze extra momenten beschermen me vooral tegen dingen die op een ongelukkig moment nog niet waren opgeschreven.

Resultaat

Toen alles eenmaal draaide wilde ik iets testen dat onmogelijk kon werken door alleen zijn bestanden te lezen.

Dus:

Onthoud het getal 47.

OttoOps antwoordde:

47 – onthouden.

Daarna stuurde ik:

Wat waren we ook alweer aan het doen?

Hij wist het nog. We hadden zojuist geregeld dat zijn stand van zaken automatisch wordt bijgewerkt als het gesprek wordt ingekort of zijn sessie eindigt. En hij wist dat hij 47 moest onthouden.

Toen:

Wat was dat getal?

Antwoord:

47.

Telegram-gesprek: het getal 47 wordt onthouden, er wordt iets anders gevraagd, en drie berichten later noemt OttoOps het getal weer.
Het bewijs: 47 stond nergens opgeschreven.

Dat is het bewijs waar ik naar zocht.

Niet dat OttoOps een getal kan onthouden. Dat kon hij in aflevering 02 ook als hij het ergens opschreef.

Het bijzondere is juist dat 47 nergens hoefde te worden opgeslagen.

Het stond gewoon een paar berichten terug in hetzelfde gesprek.

OttoOps was in de tussentijd niet verdwenen.

Voor het eerst voelde Telegram daardoor niet meer als een knop waarmee ik steeds een nieuwe OttoOps opstartte.

Hij zat er gewoon.

Wat dit nog niet kan

Er is nu wel iets veranderd dat je makkelijk over het hoofd ziet.

In aflevering 02 kwam OttoOps na een herstart van de server vanzelf weer terug. De taak die iedere minuut mijn Telegram controleerde werd namelijk automatisch weer actief en startte hem zodra er een bericht kwam.

Die taak hebben we nu bewust uitgezet.

Daardoor draaien de ontvanger en OttoOps zolang alles goed gaat, maar er is nog niets dat ze opnieuw start als de server wordt herstart.

Dat is dus zelfs even een stap achteruit.

Als de server vannacht opnieuw opstart, stuur ik morgenochtend een bericht en krijg ik niets terug.

Geen foutmelding.

Geen waarschuwing.

Gewoon stilte.

Dat lossen we in aflevering 04 op.

OttoOps is nu altijd aan — zolang niets hem uitzet.

Jouw reactie

Je eerste reactie lees ik eerst even mee voor hij verschijnt. Daarna staat hij er meteen op. Geen account nodig.