De kluis en de dichter: een AI die elke dag mijn boekhouding bijwerkt — zonder ooit zelf te boeken
Ik bouwde een AI-agent die elke ochtend mijn ledenadministratie in de boekhouding bijwerkt. Het ongemakkelijke deel: een taalmodel dat gokt, los op mijn financiële kern. Dit is hoe ik dat veilig maakte — met een principe van ERP-pionier Jan Baan als kompas.
Het idee waar ik ‘s nachts wakker van lag
Sinds dit voorjaar lopen onze lidmaatschappen via Stripe. Elke betaling moet als volwaardige ledenadministratie terug in onze boekhouding in Odoo: een debiteur, een verkoopfactuur, een betaling, netjes afgeletterd. Tot nu toe deed ik dat met de hand of half-automatisch. Het kon eleganter: laat een AI-agent het elke dag doen.
En precies daar wrong het. Want wat je dan in feite zegt is: “Beste taalmodel, hier zijn de sleutels van mijn grootboek — boek jij even.” Een model dat van nature gokt, dat soms hallucineert, dat een goede dag en een rare dag heeft, ongezien op de plek waar één verkeerd getal je jaarrekening scheeftrekt. Dat is geen automatisering, dat is roulette.
De verleiding van dit soort tools is om de AI de actie te laten zijn. Het slimme antwoord is het tegenovergestelde.
Wat Jan Baan erover zegt
Halverwege juni schreef Jan Baan — de man achter Baan Company, een van de grondleggers van het ERP — een scherpe analyse op LinkedIn. Zijn punt: maak je kernsysteem nooit de “actie-motor”. Generatieve AI loslaten op de rigide tabellen van een boekhouding noemt hij “AI on broken systems” — het levert “probabilistic spaghetti” op in precies de kern die honderd procent moet kloppen.
Zijn alternatief is een strikte machtenscheiding. Het kernsysteem wordt een Iron Fort: geen actie-motor, maar een zwaar beveiligde kluis — de plek waar de waarheid staat, puur deterministisch. De actie verhuist naar een laag erboven, verdeeld over drie rollen:
- De Dichter (The Poet) — de gokkende AI. Mag ideeën opperen en een voorstel maken. Meer niet.
- Het Slot (The Lock) — een mens kijkt naar dat voorstel en zet er bewust een handtekening onder.
- De Boekhouder (The Accountant) — een domme, exacte machine die alléén uitvoert wat is goedgekeurd, letter voor letter, zonder eigen interpretatie.
De ene zin die alles samenvat, en die boven mijn scherm had moeten hangen: “De gokkende AI raakt nooit direct de live-omgeving. 1 + 1 blijft altijd 2.”
Dit is geschreven voor de enterprise — voor SAP-achtige kolossen en Java-code. Maar het principe is niet groot of klein. Het is gewoon juist. En dus bouwde ik het, klein en concreet, in de boekhouding van onze stichting.
Mijn vertaling van de drie rollen
De mapping was bijna te mooi:
- Claude is de Dichter. Het model haalt de Stripe-transacties op, beoordeelt ze, en ruikt of er iets niet klopt. Maar het boekt nooit zelf één cent.
- Ik ben het Slot. Ik review het voorstel — de “dry-run” — vóór er geld wordt geboekt.
- Een doodgewoon Python-script is de Boekhouder. Dom, exact, en idempotent: het boekt precies wat is goedgekeurd, en als je het per ongeluk twee keer draait, gebeurt er niets dubbels.
- Odoo is de kluis. Daar staat de waarheid, en daar mag alleen de Boekhouder in.
Het cruciale verschil met “AI die je boekhouding doet” zit in dat ene woord: het script is de boekmotor, niet het model. Claude start het en bewaakt het. Het is de waakhond, niet de hand aan de pen.
De Boekhouder spreekt Python
Tot nu toe noemde ik het “de Boekhouder” — de domme, exacte machine die uitvoert wat is goedgekeurd. Tijd om te zeggen wat dat concreet ís: een Python-script. Geen AI, geen model, geen magie. Een paar honderd regels code die precies één ding doen, elke keer hetzelfde, en die ik regel voor regel kan lezen.
Hier loopt een aardige lijn naar Jan Baan. In zijn architectuur is de deterministische uitvoerder een engine die alles vertaalt naar Java 21 — de taal van de enterprise, robuust en bewezen. Bij ons is diezelfde rol een Python-script. Andere taal, identiek principe: een taalmodel mag bedenken, maar de uitvoering is gewone, voorspelbare, leesbare code. Determinisme is geen eigenschap van de taal; het is een eigenschap van het ontwerp.
En hier zit het mooie toeval — of misschien geen toeval. Want de kluis zelf, Odoo, is óók in Python geschreven. Onze Boekhouder spreekt dus letterlijk de moedertaal van de boekhouding waarin hij boekt. Dat maakt het niet alleen elegant, het maakt het bouwbaar: ik draai een aparte Odoo-omgeving op Odoo.sh, waar niet alleen het systeem draait maar ook de volledige broncode beschikbaar is. Ik kan zien hoe het van binnen werkt, en daar passende scripts omheen bouwen die exact aansluiten op hoe Odoo de dingen doet.
Voor iemand die uit de wereld van Exact komt, is dat een kleine verademing. Ik heb decennia met gesloten boekhoudsystemen gewerkt — degelijk, maar een zwarte doos: je krijgt wat de leverancier je geeft. Odoo is van een andere generatie. Open, modern, in een taal die ik kan lezen, met een omgeving waarin ik zelf mag bouwen. Je kunt iets immers alleen goed beveiligen als je naar binnen mag kijken.
Wat “veilig” hier letterlijk betekent
Praten over beveiliging is makkelijk. Laat ik het laten zien. Dit is — licht ingekort — de enige functie waarmee in onze boekhouding een factuur wordt aangemaakt:
def safe_create_vendor_bill(..., dry_run=True, prod_confirmed=False):
# 1. Standaard verandert dit niets. Het toont alleen wat het zóu doen.
if dry_run:
return {"dry_run": True, "would_create": {"state": "draft", ...}}
# 2. Pas als je bewust 'boek echt' zegt: de rem op productie.
guard_production_write("vendor bill aanmaken", confirmed=prod_confirmed)
# 3. Boeken gebeurt altijd als concept (draft) — nooit direct definitief.
bill_id = rpc(session, "account.move", "create", [bill_data])
# 4. En elke boeking laat een spoor na.
_audit_log("create_vendor_bill", "account.move", {...})
Vier regels commentaar, vier waarborgen — en geen ervan is optioneel:
- De veilige stand is de standaard. De functie heet niet
create_vendor_billmaarsafe_create_vendor_bill, en hij begint indry_run. Je moet er bewust uitstappen om iets te schrijven. Vergeet je dat, dan gebeurt er simpelweg niets — het ergste wat kan misgaan is dat er geen boeking is. - De rem staat tussen het besluit en de daad.
guard_production_writedoet op de testomgeving niets, maar weigert op productie — behalve als er een expliciete ja is. En die ja kan de AI niet zelf geven; die komt van mij. Dit is het Slot, in één regel. - Geboekt wordt altijd als concept. Een concept kun je nakijken en weggooien; een definitieve boeking niet. De Boekhouder zet nooit zelf de onomkeerbare stempel.
- Geen mutatie zonder spoor. Wie, wat, op basis van welk voorstel — alles landt in een logboek.
En de rem zelf is even nuchter als de rest:
def guard_production_write(action, confirmed=False):
if not is_production: return # testomgeving: vrij
if confirmed: return # je hebt bewust 'ja' gezegd
raise RuntimeError(f"Productie-{action} GEWEIGERD: geen bevestiging.")
Geen AI in deze regels. Geen kans. Een productie-boeking zonder bewuste bevestiging wordt niet afgeraden of gelogd — hij wordt geweigerd. Dat is het verschil tussen een systeem dat hóópt dat het goed gaat, en een systeem waarin het niet anders kán.
Hoe de waakhond zijn dag doorbrengt
Elke ochtend draait dezelfde cyclus. Niet één grote magische sprong, maar vijf nuchtere stappen:
- Dry run. Haal het plan op. Boek nog niets. Wat zou er vandaag geboekt worden?
- Oordeel. Hier doet de Dichter zijn echte werk — het werk dat een kale automatisering niet kan. Zijn er terugbetalingen? Een onbekend producttype? Een lid dat verdacht op een bestaand contact lijkt? Een raar bedrag? Bij een harde twijfel: stop, boek niets, waarschuw mij.
- Boek. Pas als het plan schoon is, draait het deterministische script. Idempotent, dus veilig.
- Controleer. En dit is mijn favoriete stap, want hier woont Baans zin. Het saldo van de Stripe-rekening in Odoo moet op de cent gelijk zijn aan het werkelijke saldo bij Stripe. Klopt dat niet, dan klopt er iets niet in de keten. 1 + 1 moet 2 zijn — en als het 1,98 is, gaat de boel op slot.
- Laat een spoor na. Elke boeking krijgt een bijlage in Odoo met zijn herkomst: van welke Stripe-transactie hij komt, welk bedrag, welke fee. Elke regel in het grootboek is terug te lopen tot de bron.
Groen? Dan hoor ik niets — zoals het hoort. Geel of rood? Dan krijg ik een bericht. De agent repareert nooit zelf; een half-afgemaakte run is veilig (idempotent), maar een gegokte reparatie is dat niet.
Eén subtiliteit die ik onderweg leerde: een naïeve controle die bij élk verschil alarm slaat, schreeuwt de hele dag. Want bij een levend betaalsysteem komen er constant nieuwe betalingen binnen. De richting van het verschil is het signaal. Heeft Stripe meer dan Odoo? Dan staan er nog transacties te wachten — onschuldig, even bijboeken. Heeft Odoo meer dan Stripe? Dán is er iets mis. Verdacht. Rood.
Waar de agent draait — en waar hij níét mag komen
Deze dagelijkse run draait in Claude Cowork: de variant van Claude die niet in een chatvenster leeft, maar als een echte medewerker zelfstandig taken uitvoert op een vast ritme. Het bijzondere zit onder de motorkap. Zodra een taak start, opent Cowork een eigen, afgeschermde Linux-omgeving op de machine — een wegwerp-werkplek waarin de agent bestanden mag lezen, scripts mag draaien en zijn werk mag doen, zonder ooit bij de rest van het systeem te kunnen.
Die afscherming heeft één bewuste, scherpe kant: het netwerk van die werkplek is dichtgetimmerd. Een script dat van bínnen die schil rechtstreeks de buitenwereld probeert te bellen — Stripe, de boekhouding — wordt geblokkeerd. En dat is precies goed. Je wilt niet dat een autonome agent vanuit een sandbox ongelimiteerd het internet op kan.
Maar het betekende wel dat ik bewust moest kiezen wáár de boekmotor draait. De oplossing past naadloos bij het hele principe van dit verhaal: de motor draait niet in de sandbox, maar op de gastheer-machine zelf, via een aparte, expliciete koppeling. De agent in de sandbox gebruikt die koppeling alleen — hij geeft het startsein en leest de uitkomst. Het zware werk gebeurt buiten de schil, waar het netwerk open is, langs een weg die ik zelf heb opengezet en die ik ook weer kan dichtzetten.
Het is geen omweg, het is het ontwerp. Veiligheid is nooit één muur; het is een reeks bewuste keuzes over wáár iets mag draaien en wát het mag aanraken. De sandbox bewaakt de agent, de koppeling bewaakt het netwerk, en de boekmotor blijft het enige dat de kluis aanraakt.
Eerst de kluis zelf op orde
In ruim veertig jaar met boekhoudsystemen, ERP en integraties heb ik één regel nooit losgelaten: in een grootboek schrijf je met grote omzichtigheid. Een boekhouding is geen gewone database — het is de financiële waarheid van een organisatie. Daar mag niets ongezien in veranderen, en niets onomkeerbaars gebeuren zonder dat een mens er bewust voor tekent. Dat is precies waar Baans 1 + 1 = 2 over gaat. Het is ook de kern van wat ik zelf het BAAS-principe noem: de eigenaar blijft baas over zijn eigen cijfers, en het systeem mag hem nooit in een staat brengen waar hij niet meer uit terug kan.
Met die lat heb ik de boekhoudkern ingericht vóór ik er een agent op losliet. Want juist de zwaarste handelingen — boeken, betalen, afletteren, een boekjaar afsluiten — verdienen de zwaarste beveiliging. Precies op de plek waar het hardst geldt dat 1 + 1 = 2, moet het poortje het strakst dicht.
Dus heb ik het zo gebouwd. Een verplichte voordeur rond de hele boekhoudkern, waar elke boeking, betaling en aflettering eerst als voorstel langskomt, dan mijn go krijgt, en pas daarna letter voor letter wordt uitgevoerd. Een onomkeerbare stap — zoals het vergrendelen van een boekjaar — heeft zijn eigen, aparte ceremonie, los van de dagelijkse correcties, met een afgedwongen herstelpunt ervóór. Een luide waarschuwing die geen twijfel laat of je in de test- of de echte omgeving werkt. En een logboek dat elke mutatie vastlegt: wie, wat, op basis van welk voorstel.
De kern laat zich in één verschuiving samenvatten: van “het gaat goed omdat we opletten” naar “het kán niet misgaan door het ontwerp”. Discipline die toevallig goed gaat is geen fundament; het is geluk met een strak gezicht. Dat onderscheid ken ik te lang om het aan toeval over te laten.
Waarom dit voor het MKB juist nu telt
Het mooie van Baans betoog is dat de grote jongens precies dezelfde kant op bewegen — kernsysteem als kluis, actie in een aparte laag, deterministische uitvoering. Maar waar dat bij de enterprise in zware Java-fundamenten wordt gegoten, kun je het bij een MKB-boekhouding bouwen met een handvol scripts, een goede koppeling en een model dat zich gedraagt als waakhond in plaats van als boekhouder.
En dat is precies waar het de moeite waard wordt. Want voor een MKB-onderneming is “zekerheid” geen luxe-feature — het is de hele basis van vertrouwen in een systeem dat met je geld werkt. Het spoor dat elke boeking achterlaat, het feit dat een mens tekent vóór er geld beweegt, de garantie dat het gokkende deel de kluis nooit aanraakt: dát is wat een AI-agent op je administratie bruikbaar maakt in plaats van eng.
Mijn ledenadministratie draait nu elke dag. De agent boekt — en raakt de boekingen nooit zelf aan. De dichter denkt, ik teken, de boekhouder voert uit, de kluis bewaart de waarheid.
1 + 1 blijft 2. Dank, Jan.
Met dank aan Jan Baan, wiens LinkedIn-analyse over de ERP als “Iron Fort” het kompas was voor dit werk. De techniek hierachter — een deterministisch boekscript, een AI-waakhond en een dagelijkse run — heb ik als herbruikbaar patroon vastgelegd, zodat de volgende betaalprovider dezelfde route volgt.