Mijn agent.md om de codekwaliteit met LLM-ondersteuning te verbeteren

De eerste keer dat ik een LLM (Large Language Model) probeerde te gebruiken om het coderen te versnellen, was in het midden van 2025. Ik was niet onder de indruk. Ik werkte destijds aan libadbmdns, een mDNS-implementatie in Rust. De gegenereerde code compileerde niet eens.

In januari 2026 probeerde ik het opnieuw. Deze keer werkte het beter. Het model schreef niet alleen een complexe indexed-binary heap klasse, maar kon ook een obscure bug in de polling crate pinpointen, veroorzaakt door de Windows IOCP-implementatie.

De codekwaliteit was echter erbarmelijk. Het was spaghetti-code zonder commentaren en zonder structuur. Het was weliswaar indrukwekkend, maar niet realistisch om met LLM's te werken als de tijdwinst verloren ging aan het opschonen van de code om deze naar productieniveau te tillen.

Herhaaldelijk itereren

In maart 2026 begon ik agentic IDE's te gebruiken, zoals Antigravity en de Claude Code-plugin van VS Code. Hierdoor kon ik itereren over de "staged" code. Ik merkte dat ik de code aan het reviewen was alsof ik een oneindig geduldige junior informaticastudent begeleidde, met suggesties als: "gebruik geen magic numbers", "voeg hier een kort commentaar toe ter uitleg" of "gebruik kortere functienamen".

De codekwaliteit verbeterde aanzienlijk. Het kwam heel dicht in de buurt van wat ik "met de hand" zou hebben geproduceerd, maar het proces was tedious. Ik merkte dat ik mezelf in elke nieuwe sessie steeds opnieuw aan het herhalen was.

Agent.md tot redding

Wanneer een codesessie start, laadt de coding harness een bestand genaamd agent.md en injecteert dit in de prompt. Dit is de perfecte plek om voorkeuren voor de codestijl zeer nauwkeurig af te stellen. Telkens wanneer ik merkte dat ik dezelfde suggestie deed om de code te verbeteren, voegde ik deze toe aan dit bestand.

Hieronder staat mijn versie van agent.md als startpunt. Het plaatsen van dit bestand in de root van een project is doorgaans voldoende. Alternatief kunnen gemini.md of claude.md via een symlink naar agent.md verwijzen om ze overal actief te hebben.

FAB's AGENT.MD

  • Communicatie: Wanneer je iets schrijft voor menselijke consumptie (commentaren, commit-berichten, antwoorden op prompts), gebruik dan zo min mogelijk woorden. Kies elk woord zorgvuldig om het volume tot een strikt minimum te beperken. Kom direct ter zake. Less is more.
  • Toon: Vermijd superlatieven en lof. Stop met me vertellen dat ik "absoluut gelijk heb". Geef me de harde waarheid.
  • Constants: Vermijd magic numbers en strings door terugkerende of betekenisvolle waarden te extraheren naar beschrijvende constanten (const) of enums. Houd zelfverklarende, eenmalige waarden inline om clutter te voorkomen. Als een waarde uit een specificatie komt (bijv. HTTP 200 OK), gebruik dan altijd een constante.
  • Structuur: Verminder code-indentatie. Vermijd het Arrow Anti-Pattern. Maak gebruik van early return en continue.
  • Naamgeving: Houd functienamen kort (minder dan 30 tekens).
  • Parameters: Gebruik enums in plaats van booleans voor functieparameters.
  • Leesbaarheid: Geef de lezer van de code ruimte om te ademen. Voeg lege regels toe tussen logische blokken code.
  • Documentatie: Voeg een kort en bondig commentaar toe om uit te leggen wat het blok doet en waarom. Gebruik indien mogelijk voorbeelden. Stel ASCII-tekeningen voor om complete systemen uit te leggen.
  • Zichtbaarheid: Behandel wijzigingen in de zichtbaarheid van members als een fundamentele ontwerpwijziging (breaking design shift). Houd alle velden en functies privé, tenzij externe toegang strikt vereist is door het ontwerp. Vraag de gebruiker om expliciete goedkeuring voordat een toegangsmodifier van privé naar intern of publiek wordt gewijzigd.
  • Abstractie: Programmeer op abstractieniveaus. Low-level mechanismen (bijv. raw hardware I/O, sector parsing, direct socket streams) moeten worden ingekapseld in een speciale driver/abstractielaag. Bied schone, high-level API's aan voor de rest van de applicatie, zodat de aanroepende code werkt met domeinconcepten en niet met ruwe implementatiedetails.
  • Scope: Raak geen blokken code aan die niet gerelateerd zijn aan de feature die je implementeert. Voeg bijvoorbeeld geen commentaren toe aan een blok code als je dit niet zelf hebt gemaakt of gewijzigd. Probeer het aantal gewijzigde regels bij het implementeren van een feature zoveel mogelijk te minimaliseren.
  • Architectuur: Houd je strikt aan de hiërarchie van de gelaagde grenzen: elke laag mag alleen communiceren met de direct daaronder gelegen laag. "Sla nooit gaten" door lagen heen (bijv. controllers of UI-componenten mogen nooit direct database-queries, raw hardware-drivers of low-level netwerkclients aanroepen; routeer altijd via de tussenliggende service/abstractielaag).
  • Syntax: Gebruik altijd {}, zelfs bij een "if"-statement van één regel.

Regels voor commit-berichten:

  1. Scheid de onderwerpregel van het lichaam met één lege regel.
  2. Beperk de onderwerpregel tot 50 tekens (72 is de absolute harde limiet).
  3. Begin de onderwerpregel met een hoofdletter.
  4. Beëindig de onderwerpregel niet met een punt.
  5. Gebruik de gebiedende wijs in de onderwerpregel (bijv. "Fix bug" of "Add feature", niet "Fixed" of "Adds"). Testformule: de zin moet kloppen in: "If applied, this commit will [onderwerpregel]".
  6. Wrap de tekst van het lichaam handmatig op 72 tekens om Git-formateringsproblemen te voorkomen.
  7. Gebruik het lichaam om uit te leggen wat en waarom versus hoe. Ga ervan uit dat de code het hoe uitlegt; het bericht moet de context en redenering uitleggen.

Bugfixes: Als de prompt aangeeft dat een bug wordt opgelost, schrijf dan niet direct de fix. Schrijf eerst de test. Observeer dat deze faalt. Schrijf daarna de fix en observeer dat de test slaagt.

***

Hoewel deze "truc" de gegenereerde code aanzienlijk heeft verbeterd, is het geen wondermiddel waardoor ik kan stoppen met het lezen van de code. LLM's hallucineren constant en kunnen niet blindelings worden vertrouwd. Ik moet nog steeds veel verifiëren en itereren, maar ik focus me nu meestal op architectuur en ontwerp in plaats van op de codestijl.

Omgaan met "diluties"

Er is een irritant fenomeen bij LLM's genaamd "context dilution" of "attention dilution", zoals beschreven in het paper Lost in the Middle. Naarmate de context groeit, begint een model minder aandacht te besteden aan instructies in het midden van de context, ten gunste van wat aan het begin en aan het einde staat. De redenen waarom dit gebeurt, zijn op dit moment nog niet volledig begrepen. Ik heb twee manieren gevonden om de impact te minimaliseren:

  1. Houd de context kort. Dit betekent dat ik per feature een nieuwe sessie start.
  2. Vraag de harness expliciet om agent.md opnieuw te laden. "Reload agent.md" is voldoende wanneer ik merk dat de codekwaliteit afneemt.

Automatisch bijwerken van agent.md

Je hoeft niet elke keer een editor te openen wanneer je een nieuwe regel wilt toevoegen. Wat ik nu doe, is de agent vragen om agent.md zelf bij te werken.