Als er iets stukgaat in productie, is de nuttige vraag zelden "schrijf een fix". Het is "waarom gebeurt dit", en om dat te beantwoorden moet je dingen bekijken: de logs van het afgelopen uur, een paar rijen in de orderstabel, de status van een container, het codepad dat de fout opleverde. Een AI-agent kan veel van dat kijkwerk snel doen. Het probleem is dat dezelfde toegang waarmee hij kijkt, hem ook laat aanraken.
Daarom bouwden we troubleshoot-sessies rond één regel: we vertrouwen er nooit op dat de agent alleen leest omdat hem dat gezegd is. Elke manier waarop hij je omgeving bereikt, is een smalle functie die alleen het veilige kan doen. Hieronder lees je hoe dat werkt en wat er nog steeds bij jou ligt.
Een chat die onderzoekt, en dan stopt
Een troubleshoot-taak is geen run. Er is geen specificatie en geen pull request. Je krijgt een gesprek: elk bericht dat je stuurt wordt één beurt waarin de agent onderzoekt en antwoordt, met het bewijs dat hij vond in plaats van een geponeerde oorzaak. Vervolgvragen hervatten dezelfde agentsessie, dus hij onthoudt wat hij al gelezen heeft.
Heb je genoeg gezien, dan vraag je hem af te ronden. Hij schrijft een diagnose in een vaste vorm: oorzaak, bewijs, impact, voorgestelde fix en hoe je die controleert. Vanuit die diagnose maak je één bugfix-taak aan. Die komt binnen als concept en doorloopt de normale pipeline, met een specificatie, goedkeuring, verificatie, self-review en een securityscan, voordat er een pull request opengaat. Het onderzoek wordt nooit zelf de fix.
De code: plan mode en drie tools
De repositories van het project worden voor de sessie in een sandbox gekloond. De agent draait Claude Code in plan mode, dat wijzigingen weigert, en zijn tools zijn beperkt tot Read, Glob en Grep. Bash ontbreekt bewust. Een commando op de live omgeving moet via de allowlist hieronder, en een commando in de sandbox heeft een onderzoek dat alleen leest niet nodig.
De omgeving: per mogelijkheid aan te zetten
Een live omgeving bereiken gaat via drie tools, en elk daarvan zet je per omgeving apart aan. Je kunt op productie alleen logs openzetten en op staging ook SQL en een paar commando's toestaan. Een mogelijkheid die aanstaat maar niet volledig is ingesteld, wordt helemaal niet verleend. Of een tool beschikbaar is, bepalen wij aan onze kant op basis van de instellingen van de omgeving. Vraagt de agent om een tool die de omgeving niet aanbiedt, dan wordt dat geweigerd, wat zijn prompt ook zei.
Logs. De agent kan recente logs opvragen met een filter en een tijdvenster. Waar ze vandaan komen, kiest hij niet: het endpoint hoort bij de configuratie van de omgeving. We ondersteunen een gewoon HTTP-endpoint, Grafana Loki, Sentry en de logs van GitHub Actions-runs, met een maximum aantal regels per aanroep.
SQL. Eén statement per aanroep, en dat moet beginnen met SELECT, WITH, EXPLAIN, SHOW of TABLE. Voordat het de database bereikt, worden commentaar en tekstwaarden verwijderd en wordt de rest doorzocht op elk schrijvend, DDL- of sessiewoord. Zo wordt ook een schrijvend statement dat in een WITH-clausule verstopt zit, gevonden. Functies die bestanden lezen of andere databases bereiken, zoals dblink, worden geweigerd. Een optionele allowlist van tabellen beperkt welke tabellen een query mag lezen. Daarna wordt de transactie READ ONLY geopend, met een statement-timeout en een maximum aantal rijen.
Commando's. Alleen commando's die overeenkomen met een allowlist die jij schrijft, als letterlijke prefixen: "docker logs" staat het lezen van de logs van een container toe, niet "docker exec". Commando's draaien zonder shell, dus puntkomma's, pipes en backticks worden nooit uitgevoerd, en we weigeren ze meteen, omdat de agent dan blijkbaar iets anders verwachtte. Shells, interpreters en wrappers die alles kunnen uitvoeren (bash, python, xargs, sudo, find en dergelijke) kun je niet op de allowlist zetten. Volgvlaggen zoals -f worden geweigerd, omdat ze nooit klaar zijn. Een lege allowlist staat niets toe.
Een budget per vraag
De agent roept een tool aan door een klein JSON-blok in zijn antwoord te schrijven; wij voeren de aanroep uit, geven het resultaat terug en laten hem verdergaan. Eén vraag mag maximaal twaalf toolaanroepen gebruiken. Daarna krijgt hij de opdracht te antwoorden met wat hij heeft en te zeggen wat hij hierna zou controleren. Die grens beperkt de kosten, en hij beperkt hoeveel van een live systeem één vraag kan aanraken. Een geweigerde aanroep beëindigt de beurt niet; de agent krijgt de weigering te zien, zodat hij iets kan kiezen wat wel mag.
Elke aanroep, de invoer en een voorproefje van de uitvoer worden bij de beurt vastgelegd. Die lijst zie je in het gesprek als het spoor van het onderzoek, en het is het verslag van wat de agent in je omgeving heeft aangeraakt.
Waar het draait, maakt uit
Beurten kunnen op ons platform draaien of op je eigen runner. Op een self-hosted runner is het bereiken van je privénetwerk juist de bedoeling. Op ons platform zou dat gevaarlijk zijn, dus daar gelden strengere regels: commando's gaan alleen over ssh, log-endpoints, databasehosts en ssh-doelen moeten publieke adressen zijn, en de verbinding wordt vastgezet op het adres dat gecontroleerd is. In beide gevallen draaien commando's met een minimale omgeving en een wegwerp-homemap, zodat zelfs een toegestaan commando de eigen secrets van de uitvoerende machine niet kan tonen. Secrets van de omgeving worden versleuteld opgeslagen en pas ontsleuteld voor de beurt die ze nodig heeft.
Wat het niet garandeert
- De SQL-controle is een filter, geen parser van de volledige grammatica van je database. De garantie die telt, is een databaserol met alleen SELECT-rechten. Geef de sessie er een; dan zijn de controle van het statement, de READ ONLY-transactie en de rechten drie onafhankelijke lagen.
- Het filter weigert liever te veel dan te weinig. Een kolom die toevallig "comment" of "set" heet, struikelt erover, en de agent moet een andere manier vinden om het te vragen.
- Databasetoegang werkt alleen met PostgreSQL.
- Een query die alleen leest, kan nog steeds zwaar zijn. De timeout en het maximum aantal rijen beperken dat; de sessie op een replica laten werken is beter.
- Logs en queryresultaten gaan naar het model. Staan er persoonsgegevens in je logs, beslis dan per omgeving of je logs überhaupt openzet.
Een verstandige eerste opzet
Begin met alleen de code, waarvoor helemaal geen omgeving nodig is, en kijk hoe ver de agent komt met een stack trace en de repository. Koppel daarna logs voor productie en een rol met alleen leesrechten op een replica. Bewaar commando's voor staging tot je weet welke drie of vier je echt pakt als er iets stukgaat. Alle schakelaars staan op de pagina over troubleshooten, en mag productie nooit van buiten je netwerk bereikt worden, laat de sessies dan op een self-hosted runner draaien.