Runtimecontroles voor agents (hooks en checkpoints)
Wat zijn runtimecontroles voor agents?
Runtimecontroles zijn de checks die de software rond een agent uitvoert op vaste momenten in een run. Ze zitten in code en draaien of het model het er nu mee eens is of niet. Twee mechanismen doen het meeste werk.
Een hook is code die de runtime oproept op een afgesproken punt, bijvoorbeeld net voor een tool-call vertrekt. Die code bekijkt wat er staat te gebeuren en antwoordt op één vraag: doorlaten, de argumenten aanpassen, een mens erbij halen, of weigeren. Een checkpoint is een bewaarde kopie van de toestand van voor een wijziging, zodat je alles kan terugzetten.
Het verschil dat de term de moeite waard maakt, zit tussen iets vragen en iets uitvoeren. Zet "raak nooit de productiedatabank aan" in een system prompt en je hebt een instructie die het model meestal volgt. Zet dezelfde regel in een hook en de call vertrekt gewoon niet, wat het model ook besloten had. Guardrails is het bredere woord voor elke beschermlaag rond een AI-toepassing; deze uitleg gaat over de laag die code is.
Waar een hook afgaat en wat hij daar kan doen
De namen verschillen per runtime. Claude Code spreekt van hook-events, het Microsoft Agent Framework noemt hetzelfde idee middleware, en de momenten zijn dezelfde.
Voor een tool-call. Het nuttigste punt. Claude Code noemt het
PreToolUseen laat een hook antwoorden metallow,denyofrequireApproval, en de argumenten herschrijven viaupdatedInput. Hij kan de call dus blokkeren, een klantnaam uit wat vertrekt halen, of de call naar een menselijke beslissing duwen.Bij een permissiebeslissing. Een hook kan in de plaats van de mens antwoorden, via een
decision-object metapproveden een reden. Het ja of nee komt dan uit je eigen policycode en niet van iemand die om elf uur 's avonds op een venster klikt.Na een tool-resultaat. De actie is al gebeurd, dus hier valt niets meer tegen te houden. Een hook leest het resultaat en stuurt er iets over terug naar de run: de tests staan rood, de query gaf 40.000 rijen terug.
Voor de run eindigt. Een hook kan dat einde weigeren en de agent terug aan het werk zetten. Zo wordt "de linter moet eerst groen zijn" een regel in plaats van een wens.
Bij het starten en stoppen van een sessie. De context laden die de run nodig heeft, en op het einde een auditlijn wegschrijven.
Het framework van Microsoft heeft dezelfde vorm met andere woorden: om iets te blokkeren roep je gewoon de volgende stap niet op, door context.result te zetten en MiddlewareTermination te gooien.
Een hook die één actie tegenhoudt
Neem een operationele agent die leveranciersgegevens opkuist. Hij mag het ERP lezen, hij mag een verbeterd adres wegschrijven, en hij mag nooit rechtstreeks iets uitvoeren op de productiedatabank. Een hook op de shell-tool kijkt elk commando na op een connectiestring naar productie en antwoordt hiermee:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Schrijfacties op productie lopen via het wijzigingsproces. Zet het statement in een bestand en vraag een collega om het uit te voeren."
}
}Wat er daarna gebeurt, wordt vaak onderschat. De agent crasht niet. Hij leest de reden en maakt de taak langs een andere weg af: hij zet het statement in een bestand, noemt dat bestand in zijn samenvatting en vraagt jou om het uit te voeren. De formulering van die reden doet echt werk, want het is het enige dat het model vertelt welke weg wel mag. Een kaal "geweigerd" levert je een agent op die eerst vier varianten van hetzelfde verboden commando probeert.
Wat een checkpoint wel en niet terugdraait
Checkpoints werken achteraf in plaats van vooraf. Claude Code legt de toestand van je bestanden vast voor elke prompt die je stuurt, houdt snapshots bij voor de 100 recentste checkpoints in een sessie, en gooit ze samen met de sessie weg na 30 dagen. Cursor maakt er een voor elke grotere wijziging van de agent.
De beperkingen zijn het interessantste deel. Claude Code volgt geen bestanden die via bash-commando's gewijzigd zijn, dus een rm of een mv die de agent uitvoerde, draai je met terugspoelen niet terug, en wijzigingen van een subagent op de achtergrond worden meestal ook niet hersteld. Cursor zegt het droog: herstellen zet enkel bestanden terug. Een checkpoint herstelt toestand die van jou is, niet de buitenwereld.
Een mail die vertrokken is, een betaling die geboekt staat, een rij die via een API in het systeem van een leverancier belandde: dat komt niet terug. Bestanden en lokale toestand dek je af met checkpoints, alles wat het huis verlaat met een hook voor de actie, want achteraf valt er niets meer te beschermen.
Lezen en voorstellen als standaardinstelling
Voor de meeste bedrijven past het verstandige startpunt in één zin: de agent mag alles lezen binnen zijn scope en mag niets wijzigen zonder dat een mens de diff bevestigt.
Runtimes ondersteunen dat rechtstreeks. Claude Code heeft een plan mode waarin de agent bestanden leest en read-only shell-commando's uitvoert om rond te kijken, maar je broncode niet aanpast. Een run eindigt dan in een voorstel dat je op één plek goedkeurt, met het geheel voor je, in plaats van vijftien losse vensters die je rond nummer zes niet meer leest.
Je budget en je goedkeuringen hang je op precies dezelfde haak. Een budgetcheck is een hook: tel het verbruik tijdens de run en stop de loop aan het plafond, in plaats van dat de factuur dat een maand later doet. Een goedkeuring is een hook op de mailtool, de betaaltool en de verwijdertool, terwijl de rest doorloopt. De echte autonomie die je een agent gaf, staat niet in je beleidsdocument: het is de vraag welke van zijn acties nog door een hook passeren.
Een hook tegenover een regel in de system prompt
Allebei drukken ze dezelfde regel uit. Ze verschillen op één punt: wat er gebeurt als het model anders beslist.
Een instructie in de system prompt wordt gelezen samen met al de rest die het model ziet: de tekst van het ticket, de opgehaalde webpagina, de PDF die een klant doorstuurde. Die input kan eigen instructies bevatten, en dat is het probleem van prompt injection. OWASP is daar duidelijk over: het is onduidelijk of er waterdichte methodes bestaan om prompt injection te voorkomen. Hun advies is om functies met verhoogde rechten in code af te handelen in plaats van ze aan het model te geven. Beslist het model anders, dan levert een instructie niets op. Geen event, geen logregel, geen blokkade.
Een hook maakt geen deel uit van het gesprek en laat zich dus niet ompraten. De call wordt geweigerd, de weigering staat in de logs, en het model verneemt het als tool-resultaat. Daarom is het ene een controle en het andere een suggestie. De prompt blijft wel de juiste plek om te zeggen wat de agent zou moeten doen, en de verkeerde plek voor de handvol regels die je je niet kan permitteren te zien breken.
Waar moet je op letten bij runtimecontroles
Een hook dekt enkel af wat hij matcht. Hooks hangen vast aan toolnamen, dus koppel één nieuwe MCP-server en de agent heeft tools waar jouw matcher nog nooit van gehoord heeft, zonder bewaking. Elke keer als de lijst met tools groeit, komt de vraag naar dekking terug.
Shell-toegang gaat rond bijna alles heen. Een agent die commando's kan uitvoeren, heeft veel wegen naar hetzelfde effect: curl in plaats van de mailtool, een Python-script in plaats van de verwijdertool. Eén commandonaam blokkeren is niet hetzelfde als de mogelijkheid blokkeren, en dat is het argument voor een agent sandbox onder de hooks.
Weet hoe een check faalt. In Claude Code blokkeert een hook die in een timeout loopt voor een tool-call die call niet, dus een trage check wordt stilletjes geen check.
Hooks staan niet boven permissieregels. Claude Code past deny- en ask-regels toe los van wat een hook antwoordde, dus een passende deny-regel blokkeert de call ook als de hook allow zei. Zet de absolute verbodsbepalingen daar, waar een kapot hook-script ze niet kan openzetten. En een hook is code van jezelf, die draait met jouw rechten, dus review hem zoals de rest van je code.