Deze site draait op Astro. Dus toen Cloudflare deze week publiceerde hoe het Astro-team de eigen bugmeldingen door AI-agenten laat afhandelen, las ik dat als nieuws over mijn eigen stack, niet als algemeen AI-nieuws.
De cijfers: de Astro-repository ging van ruim 200 open issues naar ongeveer 30. Het team verwacht binnen een maand op nul te zitten. Dat zou de eerste keer zijn in het vijfjarig bestaan van de repo. En ze deden het niet door oude tickets massaal te sluiten, wat de gebruikelijke truc is als een issuelijst uit de hand loopt.
Waarom issue-triage zo duur is
Een bugmelding lezen kost een minuut. Hem reproduceren kost soms uren. Je moet het voorbeeldproject van de melder klonen, de juiste versies installeren, kijken of het probleem zich echt voordoet, en dan pas begint het zoeken naar de oorzaak. Voor een open source-maintainer is dit het werk dat nooit af is en waar niemand je voor bedankt.
Dat probleem is groter geworden. Een issue schrijven met AI kost bijna niets meer. Een issue lezen en beoordelen kost nog steeds een mens. De verhouding tussen wat erin komt en wat eruit kan is scheefgetrokken.
Vier agenten, ieder in zijn eigen kamer
Het Astro-team begon niet met een pijplijn maar met een skill: de stappen die een maintainer met de hand zet, opgeschreven zodat een coding agent ze kan volgen. Eerst lokaal op de eigen machine, later dezelfde skill in een GitHub Action.
De stappen zijn vier fases:
- Reproduceren. De repository van de melder klonen en controleren of de bug er echt is.
- Diagnosticeren. Logging aanbrengen in de code om de oorzaak te vinden.
- Verifiëren. Testsuites, comments en documentatie nalezen om te bepalen of dit een bug is of bedoeld gedrag.
- Fixen. De reproductie omzetten in falende unit tests, de oplossing zoeken via de architectuurgids, en de fix uitrollen.
Het interessante zit niet in die lijst maar in de scheiding. Elke fase draait in een eigen subagent met een eigen, lege context. Ze praten niet met elkaar en zien elkaars redenering niet. De enige overdracht is een bestand: report.md. Fase 1 schrijft op wat hij vond, fase 2 leest dat en schrijft er zijn eigen bevindingen bij.
De reden daarvoor is scherp. Een taalmodel wil een oplossing leveren. Als je hetzelfde model de bug laat reproduceren én laat beoordelen of het wel een bug is, drukt het zijn eigen eerdere conclusie door. Het heeft er al in geïnvesteerd. Door de verifieerder in een schone context te zetten, met alleen het rapport en niet de redenering die eraan voorafging, krijg je een tweede mening in plaats van een echo.
Dit is het stuk dat ik in de meeste agent-opstellingen mis. Mensen bouwen één agent met een lange instructie en veel geheugen. Astro bouwde vier korte agenten met een gedeeld notitieblok.
De pijplijn heeft geen geheugen
De hele automatisering blijkt een toestandsmachine te zijn die op GitHub-labels draait. Een nieuwe melding krijgt triage needed. Als de melder bevestigt dat de fix werkt, gaat het label naar fix verified. Buiten die labels bewaart de pijplijn niets. Bij elke run leest hij de bestaande comments op het issue terug en leidt daaruit af waar hij is.
Dat klinkt primitief en dat is precies de kracht. Er is geen database die kan gaan afwijken van de werkelijkheid. Alles wat de bot weet, staat zichtbaar op het issue, en iedereen kan de redenering nalezen.
Als de agenten een fix hebben, bouwt de pijplijn een preview-release via pkg.pr.new en plakt die terug in het issue, met een samenvatting, de volledige logs en de installatie-instructies. De melder test de patch tegen zijn eigen project. Bevestigt hij dat het werkt, dan pas opent de automatisering een pull request.
Die volgorde is het echte ontwerp. De bot mag alles doen behalve het laatste woord hebben. Bevestiging komt van de mens die het probleem meldde.
Wat er misging, en waarom dat nuttig was
Het Astro-team behandelt een falende agent niet als een modelprobleem maar als een codeprobleem. Als de agent de oplossing niet vindt, wijst dat volgens hen op drie soorten schuld in de repo: onduidelijke grenzen tussen componenten, ontbrekende comments over waaróm code doet wat hij doet, en te weinig unit tests.
Er is een concreet voorbeeld. Bij een reeks Hot Module Replacement-bugs bleef de bot dezelfde if-conditie aanpassen. Die aanpassing loste de gemelde bug op en brak elders iets anders, want juist op die conditie zat geen testdekking. Toen het team er een comment bij zette die uitlegde welke logica die regel bewaakt, stopte de bot met die aanpassing.
De les daaruit gaat verder dan bots. Elke keer dat het team zo’n fout natrekt en er een comment, een test of een duidelijker grens bijzet, wordt niet alleen de agent beter op dat stuk code, maar ook de volgende mens die eraan werkt. Een agent die vastloopt op je codebase is een gratis architectuurreview.
Wel een kanttekening: dit is geen “aanzetten en klaar”-verhaal. Het team is er maanden mee bezig geweest en noemt zelf dat het geen instant succes was. Wat je hier ziet is het resultaat van herhaald bijschaven, niet van een goede prompt.
Wat je er zelf mee kunt
De triage-logica zat eerst in de Astro-monorepo zelf. Dat maakte iedere wijziging riskant, dus is hij losgetrokken naar een aparte repo: triagebot-action. Die is open en wordt door andere teams gebruikt, deels rechtstreeks, deels als fork voor hun eigen pijplijn.
Aanhaken is een blok in je workflow:
- uses: withastro/triagebot-action@v1
with:
read-token: ${{ secrets.GITHUB_TOKEN }}
write-token: ${{ secrets.BOT_GITHUB_TOKEN }}
cloudflare-api-key: ${{ secrets.CLOUDFLARE_API_KEY }}
cloudflare-account-id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
triage-model: cloudflare-workers-ai/@cf/moonshotai/kimi-k2.7-code
verification-model: cloudflare-workers-ai/@cf/moonshotai/kimi-k2.6
triage-skill: .agents/skills/triage
Let op de twee losse modelvelden. Het model dat triageert is een ander dan het model dat verifieert. Dat is dezelfde gedachte als de geïsoleerde contexten, maar dan een laag dieper.
De motor eronder is inmiddels een eigen framework geworden, Flue. Het Astro-team merkte dat er niets aan hun opzet specifiek GitHub was. Reageren op een gebeurtenis, een rij geïsoleerde subagenten doorlopen, en de redenering scheiden van de acties die de agent mag uitvoeren: dat werkt net zo goed vanaf een Slack-bericht, een cronjob of een webhook.
Voor de meeste lezers hier is het patroon bruikbaarder dan de code. Drie dingen zijn direct te lenen, ook zonder GitHub Action:
- Knip een taak in fases en geef elke fase een schone context. Eén agent die alles doet, komt vast te zitten aan zijn eerste conclusie.
- Laat de fases via een bestand communiceren, niet via geheugen. Een
report.mdis leesbaar, controleerbaar en herstartbaar. - Zet de menselijke bevestiging op het punt waar het onomkeerbaar wordt. Bij Astro is dat de pull request. Bij jou is dat misschien de publicatie of de e-mail die de deur uit gaat.
En als je zelf een Astro-project draait: met ruim 200 open issues terug naar ongeveer 30 is de kans een stuk groter dat jouw melding daadwerkelijk wordt opgepakt. Dat is voor mijn eigen stack het meest concrete gevolg van dit hele verhaal.
Ethiek-noot
Twee dingen die in het originele stuk niet aan bod komen.
De pijplijn draait op Cloudflare Workers AI met twee dichte model-id’s. Dat is geen neutrale keuze. Wie deze opzet overneemt, koppelt zijn triage aan één aanbieder en aan modellen die hij niet kan inzien, niet kan bevriezen en niet zelf kan draaien. Verandert dat model, dan verandert je triage mee, zonder dat er iets in je repo wijzigt. Voor een open source-project, waar de hele belofte is dat je kunt nakijken wat er gebeurt, is dat een opmerkelijke plek om een blinde vlek in te bouwen.
En dan de melder. De issue-tracker was niet alleen een wachtrij, het was ook de plek waar nieuwe maintainers binnenkwamen. Iemand meldt een bug, iemand anders reageert, er ontstaat een gesprek, en soms blijft die persoon hangen. Zet daar een bot tussen die netjes en snel antwoordt, en de wachtrij wordt korter terwijl die instap verdwijnt. Dat is een reële ruil, en 200 naar 30 zegt niets over welke kant hij op valt.
Het originele stuk staat op de Cloudflare-blog en is de moeite waard, ook voor de schermafbeeldingen van de pijplijn.
