De Digitale Assistent biedt ondernemers hulp met regelgeving, subsidies en bedrijfsregistratie. Twee LLM-backends (VLAM en Claude) raadplegen overheidsbronnen via twee transportmechanismen: MCP en CLI. Beide zijn API-wrappers die dezelfde externe API's aanspreken — het verschil zit in hoe ze worden aangeroepen (zie PDR-005).
Quickstart, endpoints, .env-configuratie en Docker-instructies staan in de root README. Dit document beschrijft de architectuur, routering en scenario's.
Zie Product Decision Records voor gemaakte keuzes in de opzet.
- PDR-001 — dual-backend keuze (VLAM + Claude)
- PDR-005 — CLI vs MCP als transport
- PDR-006 — feasibility-onderzoek en conclusie
- PDR-007 — demo-persona's, netbeheerder/Business Wallet en EML-maatregelen
- PDR-008 — generieke RegelRecht-tool en energiegegevens via de Business Wallet
┌──────────────────────────────────────────┐
moza-portaal ─────▶│ host (poort 8000) │
/chat endpoint │ VLAM (Mistral) of Claude │
│ + tools via MCP of CLI (instelbaar) │
└──────┬───────┬───────┬───────┬───────────┘
│ │ │ │
MCP: server server server server (Python, persistent)
CLI: kvk-cli koop-cli rr-cli rvo-cli (Bash, on-demand)
│ │ │ │
▼ ▼ ▼ ▼
kvk.nl koop regelrecht rvo
(API) (API) (API) (API)
| Bron | MCP-server | CLI-tool | Type | Externe API |
|---|---|---|---|---|
| KvK | Resource + Tool | kvk-cli |
Bedrijfsgegevens (sessie-gebonden) | KvK Test API + BAG (Kadaster) |
| KOOP | Resource + Tool | koop-cli |
Regelingenbank | wetten.overheid.nl |
| RegelRecht | Tool (non-muterend) | regelrecht-cli |
Generieke regel-executie (execute_law) |
poc-machine-law API |
| RVO | Tool (muterend) | rvo-cli |
Subsidies en rapportages | RVO API (mock) |
| Business Wallet (netbeheerder) | Tool | (geen) | Energiegegevens als credential, met toestemming gedeeld | netbeheerder (mock) |
De host werkt ook zonder MCP-servers of CLI-tools; de assistent antwoordt dan op basis van eigen kennis.
RegelRecht-tool (MCP) en CLI-divergentie: op MCP biedt RegelRecht één generieke tool
regelrecht__execute_law(law, parameters, overrides)waarmee elke wet (informatieplicht, EML-maatregelen) wordt uitgevoerd (zie PDR-008). Het CLI-transport loopt bewust achter en houdtregelrecht__check(geen netbeheerder/Business Wallet); de demo draait daarom op MCP (vlam/claude). Business Wallet: de energiegegevens komen als een door de Business Wallet gepresenteerde credential (uitgever = netbeheerder), demo-presentatielaag, geen echte Business Wallet-koppeling (PDR-008). De woonfunctie/gebruiksdoel komen live uit de BAG (Kadaster, metBAG_API_KEY) met demo-fallback.
MCP vs CLI: MCP-servers draaien als permanente processen en ondersteunen zowel tools als resources. CLI-tools zijn Bash-scripts die on-demand worden aangeroepen en alleen tools ondersteunen (geen resources). Zie PDR-005 voor een uitgebreide vergelijking.
KvK testomgeving: De KvK-server haalt bedrijfsgegevens op via de KvK Test API (
api.kvk.nl/test/api/v1/basisprofielen) voor het KvK-nummer dat de host per aanroep meegeeft. De host bepaalt dat nummer server-side uit de sessie (zie PDR-009); het LLM en de gebruiker kunnen het niet kiezen. Er is geen hardcoded demo-bedrijf meer. In de Beta wordt het KvK-nummer bepaald door echte authenticatie (eHerkenning/DigiD, BETA-02).
De identiteit wordt server-side vastgesteld en afgedwongen (PDR-009). De frontend stuurt per request het KvK-nummer van de gekozen persona mee in de header X-Test-User; de host controleert dat tegen de allowlist TEST_KVK_NUMMERS in de backend-env en injecteert het nummer vervolgens bij elke bron-aanroep. Een testgebruiker voeg je toe door het KvK-nummer aan die lijst toe te voegen en de host te herstarten. Staat een nummer er niet in, of ontbreekt de header, dan blokkeert de host met een nette "log eerst in"-melding en raadpleegt geen bron. Wisselen van persona kan zonder herstart.
De allowlist is geen geheim — de KvK-nummers van de persona's staan al publiek in _data/personas.json van de frontend. Ze is wél een harde grens: zonder die grens zou de KvK-server voor een willekeurig meegestuurd nummer de echte KvK Test API gaan bevragen. De garantie die er wél toe doet staat hier los van: het LLM ziet kvk_nummer niet (het is uit alle tool-schema's gestript) en kan de identiteit dus niet kiezen, ook niet als de gebruiker in het gesprek een ander nummer noemt.
De gesloten testgroep telt vier profielen. Ze zijn zo gekozen dat dezelfde vraag over de informatieplicht energiebesparing verschillende kanten op loopt, zodat een gebruikerstest niet één tak van de regel test:
| KvK | Bedrijf | Persona (frontend) | Verbruik | Uitkomst informatieplicht |
|---|---|---|---|---|
| 85234567 | Koffiezaak Noon | koffiezaak |
61.250 kWh / 9.800 m³ | geldt, elektriciteit boven de drempel |
| 62345681 | Kwekerij De Bloesem | bloemenkweker |
420.000 kWh / 140.000 m³ | geldt, gas boven de drempel, onder de onderzoeksdrempel |
| 56789012 | Roots & Locks | haarstylist |
14.800 kWh / 1.900 m³ | geldt niet, onder beide drempels |
| 61234570 | Vogel Bouwregie B.V. | bouwmanagement |
88.400 kWh / 12.600 m³ | geldt, elektriciteit boven de drempel |
Alle vier zijn volledig mock-bediend in de KvK-server (MOCK_PROFIELEN, MOCK_VESTIGINGEN, MOCK_VESTIGINGSPROFIELEN, MOCK_EIGENAREN, _BAG_DEMO_FALLBACK) en de netbeheerder-server (MOCK_VERBRUIK), dus ze werken zonder netwerk of API-key. De persona-id's corresponderen met _data/personas.json in MinBZK/moza-poc. De overige persona's daar staan bewust niet in de allowlist: de assistent antwoordt dan "log eerst in" in plaats van gegevens van een bedrijf te tonen dat de backend niet kent.
De frontend bepaalt welk profiel nodig is, niet deze repo. Zet MinBZK/moza-poc een persona op actief die hier ontbreekt, dan leest de respondent zijn bedrijf op het scherm en krijgt hij van de assistent "log eerst in" — de sessie is voorbij voordat er één vraag is gesteld. services/host/tests/test_personas_frontend_pariteit.py leest _data/personas.json van een checkout naast deze repo (of via MOZA_POC_PERSONAS) en faalt op precies dat gat, en op elk veld dat uiteenloopt met het scherm. Staat die checkout er niet, dan slaat de test over met een luide reden: de pariteit is dan ongetoetst, niet in orde.
Welk veld op welk niveau hoort, volgt de echte KvK-API en niet wat handig uitkomt. Het basisprofiel draagt totaalWerkzamePersonen; de uitsplitsing naar voltijd en deeltijd staat in het vestigingsprofiel (/v1/vestigingsprofielen/<nr>), dat kvk__mijn_bedrijf erbij haalt en in de hoofdvestiging mengt. Het RSIN komt van kvk__eigenaar. Zet je zulke velden op de profielwortel, dan werkt de mock wél en een echt KvK-nummer niet.
Het LLM kiest op basis van de systeemprompt welke MCP-server wordt aangesproken. De routeringsregels zijn gedefinieerd in host/prompts/blocks/shared/tool_usage.md en volgen onderstaande beslisboom:
flowchart TD
Start([Gebruikersvraag]) --> Q1{Vraagt naar eigen\nbedrijfsgegevens?}
Q1 -- ja --> KVK_TOOL[/Tool: kvk__mijn_bedrijf/]
Q1 -- nee --> Q5{Vraagt of een verplichting\nvan toepassing is?}
Q5 -- ja --> KVK_TOOL
KVK_TOOL --> Q5b{KvK-nummer\nverkregen}
Q5b --> RR_TOOL[/Tool: regelrecht__execute_law/]
RR_TOOL --> Q5c{Wil gebruiker\nde wettekst lezen?}
Q5c -- ja --> KOOP_RES[/Resource: koop://regeling/bwb_id/]
Q5c -- nee --> Antwoord
Q5 -- nee --> Q4{Vraagt naar een\nspecifieke wet of regel?}
Q4 -- ja --> KOOP_TOOL[/Tool: koop__zoek_regelgeving/]
KOOP_TOOL --> Q4b{Wil gebruiker\nde inhoud lezen?}
Q4b -- ja --> KOOP_RES
Q4b -- nee --> Antwoord
Q4 -- nee --> Q3{Bevat een\nBWB-ID?}
Q3 -- ja --> KOOP_RES
Q3 -- nee --> Q6{Vraagt naar subsidies\nof rapportage?}
Q6 -- ja --> Q6b{Wil indienen\nof alleen informatie?}
Q6b -- informatie --> RVO_ZOEK[/Tool: rvo__zoek_regeling/]
Q6b -- indienen --> Q6c{Gebruiker\nbevestigt?}
Q6c -- ja --> RVO_IND[/Tool: rvo__indienen/]
Q6c -- nee --> Antwoord
Q6 -- nee --> Q7{Algemene vraag\nover regelgeving?}
Q7 -- ja --> KOOP_TOOL
Q7 -- nee --> Q8{Binnen het taakgebied?\nbedrijf, verplichting,\nregelgeving, subsidie}
Q8 -- ja --> EIGEN[Eigen kennis\n+ disclaimer]
Q8 -- nee --> AFWIJZING[Afwijzing in 3 delen:\nonderwerp benoemen,\nbuiten taakgebied,\nvoorbeeldvraag die wel kan]
KOOP_RES --> Antwoord([Antwoord aan gebruiker])
RVO_ZOEK --> Antwoord
RVO_IND --> Antwoord
EIGEN --> Antwoord
AFWIJZING --> Antwoord
style KVK_TOOL fill:#4A90D9,color:#fff
style KOOP_RES fill:#48BB78,color:#fff
style KOOP_TOOL fill:#4A90D9,color:#fff
style RR_TOOL fill:#4A90D9,color:#fff
style RVO_ZOEK fill:#4A90D9,color:#fff
style RVO_IND fill:#ED8936,color:#fff
style EIGEN fill:#A0AEC0,color:#fff
style AFWIJZING fill:#A0AEC0,color:#fff
Legenda: groen = Resource (read-only ophalen) blauw = Tool (read-only zoeken/berekenen) oranje = Tool (muterend, vereist bevestiging) grijs = geen bron geraadpleegd (eigen kennis of een afwijzing met brug)
Bij gecombineerde vragen geldt de volgorde: KvK (wie?) → RegelRecht (wat geldt er?) → KOOP (verdieping wettekst) → RVO (actie ondernemen).
Informatieplicht-flow (demo, persona Claudia/Noon): deze flow voegt stappen toe die de beslisboom hierboven niet apart toont: (1) eerst toestemming vragen voordat er bronnen worden geraadpleegd, (2) energieverbruik uit de Business Wallet (
netbeheerder__verbruik, met toestemming), (3)regelrecht__execute_lawvoor de informatieplicht, (4)regelrecht__execute_lawvoor de geldende EML-maatregelen, (5)rvo__indienenmet geautomatiseerde toets. Zie PDR-007 en PDR-008.
Gebruiker: "Wat zijn mijn bedrijfsgegevens?"
sequenceDiagram
actor Gebruiker
participant Host as AI-platform (Host)
participant KvK as MCP Server (KvK)
Gebruiker->>Host: "Wat zijn mijn bedrijfsgegevens?"
Note over Host: Routeringsregel: eigen gegevens<br/>→ kvk__mijn_bedrijf
Host->>KvK: tools/call [mijn_bedrijf]
Note over KvK: Sessie-gebonden:<br/>retourneert profiel van<br/>de ingelogde gebruiker
KvK-->>Host: basisprofiel (KvK API-formaat) + provenance
Host->>Gebruiker: "Uw bedrijf Test BV Donald (KvK 68750110)<br/>is een Besloten Vennootschap gevestigd<br/>in Lollum. SBI-code: 01241."
Gebruiker: "Welke regels gelden er voor energiebesparing?"
sequenceDiagram
actor Gebruiker
participant Host as AI-platform (Host)
participant KOOP as MCP Server (KOOP)
participant SRU as SRU zoekservice
Gebruiker->>Host: "Welke regels gelden er voor energiebesparing?"
Note over Host: Routeringsregel: vraag over regelgeving<br/>→ koop__zoek_regelgeving
Host->>KOOP: tools/call [zoek_regelgeving, trefwoord="energiebesparing"]
KOOP->>SRU: GET zoekservice.overheid.nl/sru/Search<br/>?x-connection=BWB&query=overheidbwb.titel any "energiebesparing"
SRU-->>KOOP: XML met regelingen
KOOP-->>Host: resultaten + provenance
Host->>Gebruiker: "Er zijn 86 regelingen gevonden, waaronder..."
Gebruiker->>Host: "Wat staat er in de Subsidieregeling energiebesparing?"
Note over Host: Routeringsregel: BWB-ID bekend<br/>→ resource koop://regeling
Host->>KOOP: resources/read [koop://regeling/BWBR0038472]
KOOP->>SRU: SRU lookup → resolve naar XML-URL
SRU-->>KOOP: locatie_toestand URL
KOOP->>SRU: GET repository XML
SRU-->>KOOP: volledige wettekst
KOOP-->>Host: artikelen + provenance
Host->>Gebruiker: "De regeling bevat X artikelen. Artikel 1 bepaalt..."
Gebruiker: "Moet mijn bedrijf voldoen aan de Informatieplicht Energiebesparing?"
sequenceDiagram
actor Gebruiker
participant Host as AI-platform (Host)
participant KvK as MCP Server (KvK)
participant RR as MCP Server (RegelRecht)
participant Engine as RegelRecht Engine
Gebruiker->>Host: "Moet mijn bedrijf voldoen aan de<br/>Informatieplicht Energiebesparing?"
Note over Host: Stap 1: bedrijfsgegevens ophalen<br/>via sessie-gebonden KvK
Host->>KvK: tools/call [mijn_bedrijf]
KvK-->>Host: Test BV Donald, KvK 68750110,<br/>SBI 01241 + provenance
Note over Host: Stap 2: verplichting checken<br/>met verkregen KvK-nummer
Host->>RR: tools/call [check, kvk_nummer="68750110"]
RR->>Engine: POST /mcp/rpc [execute_law,<br/>service=RVO, law=informatieplicht]
Engine-->>RR: beslisboom-resultaat + wettelijke grondslag
RR-->>Host: resultaat + provenance
Host->>Gebruiker: "Op basis van art. 5.15d Bal: de informatieplicht<br/>is van toepassing als uw energieverbruik boven<br/>50.000 kWh of 25.000 m³ gas per jaar ligt.<br/>Wat is uw jaarlijks energieverbruik?"
Gebruiker: "Welke subsidies zijn er voor energiebesparing?"
sequenceDiagram
actor Gebruiker
participant Host as AI-platform (Host)
participant KvK as MCP Server (KvK)
participant RVO as MCP Server (RVO)
Gebruiker->>Host: "Welke subsidies zijn er voor energiebesparing?"
Note over Host: Routeringsregel: vraag over subsidies<br/>→ rvo__zoek_regeling
Host->>RVO: tools/call [zoek_regeling, trefwoord="energiebesparing"]
Note over RVO: Zoekt in mock-regelingen<br/>op naam en beschrijving
RVO-->>Host: 3 resultaten (EBR-2026, EIA-2026, ISDE-2026) + provenance
Host->>Gebruiker: "Er zijn 3 regelingen gevonden:<br/>1. Informatieplicht Energiebesparing (open, deadline 2026-12-01)<br/>2. Energie-investeringsaftrek EIA (open)<br/>3. Investeringssubsidie Duurzame Energie ISDE (open)"
Gebruiker->>Host: "Ik wil mijn energiebesparingsrapportage indienen"
Note over Host: Muterende actie →<br/>eerst bedrijfsgegevens ophalen,<br/>dan bevestiging vragen
Host->>KvK: tools/call [mijn_bedrijf]
KvK-->>Host: Test BV Donald, KvK 68750110 + provenance
Host->>Gebruiker: "Ik kan de rapportage voor Test BV Donald (KvK 68750110)<br/>indienen bij regeling EBR-2026.<br/>Welke maatregelen heeft u genomen?"
Gebruiker->>Host: "LED-verlichting en HR++ beglazing"
Host->>Gebruiker: "Ter bevestiging: ik dien de volgende rapportage in:<br/>• Bedrijf: Test BV Donald (68750110)<br/>• Regeling: Informatieplicht Energiebesparing (EBR-2026)<br/>• Maatregelen: LED-verlichting, HR++ beglazing<br/>Wilt u doorgaan?"
Gebruiker->>Host: "Ja"
Host->>RVO: tools/call [indienen, kvk_nummer="68750110",<br/>regeling_id="EBR-2026",<br/>maatregelen=["LED-verlichting","HR++ beglazing"]]
Note over RVO: Mock: simuleert succesvolle<br/>indiening en genereert<br/>referentienummer
RVO-->>Host: status=INGEDIEND,<br/>ref=RVO-EBR-2026-68750110-001 + lopende_zaak + provenance
Host->>Gebruiker: "Uw rapportage is ingediend (ref. RVO-EBR-2026-68750110-001)<br/>en in behandeling genomen. U vindt de status terug onder 'Lopende zaken',<br/>u hoort het zodra er een vervolgactie nodig is."
Let op: De
indienen-tool is muterend. Het AI-platform vraagt daarom altijd om expliciete bevestiging van de gebruiker voordat de tool wordt aangeroepen. Dit is afgedwongen via deToolAnnotations(readOnlyHint=False) én de systeemprompt.
Gebruiker: "Welke regels gelden voor voedselveiligheid?"
sequenceDiagram
actor Gebruiker
participant Host as AI-platform (Host)
participant KOOP as MCP Server (KOOP)
participant SRU as SRU zoekservice
Gebruiker->>Host: "Welke regels gelden voor voedselveiligheid?"
Host->>KOOP: tools/call [zoek_regelgeving, trefwoord="voedselveiligheid"]
KOOP->>SRU: GET zoekservice.overheid.nl/sru/Search...
SRU--xKOOP: timeout / 503
KOOP-->>Host: error: SOURCE_UNAVAILABLE
Host->>Gebruiker: "De regelgeving-database (KOOP Regelingenbank)<br/>is op dit moment niet bereikbaar. Probeer het<br/>over een minuut opnieuw, of kijk rechtstreeks<br/>op wetten.overheid.nl."
De melding komt uit de foutcatalogus in services/host/errors.py
(PDR-011) en bestaat altijd uit
twee delen: wat er gebeurde en wat de gebruiker kan doen. De host
vertaalt de foutcode van de bron; het LLM krijgt de melding mét de instructie om
niets te verzinnen, en de technische oorzaak blijft in de log.
Wat de gebruiker per situatie ziet:
| Situatie | Foutcode | Wat de gebruiker ziet |
|---|---|---|
| Bron reageert niet of geeft 5xx | SOURCE_UNAVAILABLE |
naam van de bron + het alternatief (bijv. wetten.overheid.nl) |
| Bron geeft een 4xx op de aanvraag | API_FOUT |
idem; de bron werkt wel, maar wees deze aanvraag af |
Antwoord afgekapt op max_tokens |
LLM_ANTWOORD_AFGEKAPT |
dat het antwoord niet compleet is, mét de deeltekst erbij |
| Model gaf niets terug | LLM_LEEG_ANTWOORD |
dat er geen antwoord kwam, met het advies anders te formuleren |
| Bron kwam bij het starten niet op | BRON_NIET_GESTART |
welke bron ontbreekt, en dat wachten daar niet bij helpt |
| Tool bestaat niet in dit transport | TOOL_NIET_IN_TRANSPORT |
dat de mogelijkheid hier ontbreekt (CLI kent minder tools dan MCP, PDR-005) |
Bron reageert niet binnen TOOL_TIMEOUT |
SOURCE_UNAVAILABLE |
idem als hierboven; zonder deze grens bleef de stream hangen |
| Bron vindt niets | NIET_GEVONDEN |
waar niets is gevonden, met het advies een algemener trefwoord te proberen |
| Bron mist een gegeven van de gebruiker | ONTBREKEND_VELD / ONTBREKENDE_VELDEN |
welk gegeven ontbreekt, in woorden die de ondernemer herkent (niet de tekst van de bron) |
| Bron mist een gegeven van de assistent | ONTBREKEND_INTERN_VELD |
dat de gebruiker er zelf niets aan kan doen (bv. het KvK-nummer uit de sessie) |
| LLM te traag | LLM_TIMEOUT |
hoelang er is gewacht, met het advies de vraag korter te stellen |
| LLM-sleutel geweigerd | LLM_SLEUTEL_ONGELDIG |
dat de sleutel niet wordt geaccepteerd (opnieuw proberen heeft geen zin) |
| Geen sleutel, override uit | LLM_NIET_INGESTELD |
dat de beheerder aan zet is (een sleutel invullen wordt tóch genegeerd) |
| Fout in de assistent zelf | HOST_FOUT |
dat de vraag niet kon worden afgerond, zonder het aan het model toe te schrijven |
| LLM overbelast of rate limit | LLM_OVERBELAST / LLM_TE_DRUK |
dat het tijdelijk is, met het advies het over een minuut te proberen |
| Gesprek te lang voor het model | LLM_GESPREK_TE_LANG |
het advies een nieuw gesprek te beginnen |
| Te veel stappen nodig | LLM_MAX_STAPPEN |
het advies de vraag op te splitsen, met een voorbeeld |
| Lege of te lange vraag | LEGE_VRAAG / VRAAG_TE_LANG |
wat er mis is met de invoer, vóór er een bron of LLM wordt geraakt |
| Geen geldige sessie | GEEN_SESSIE |
dat er eerst ingelogd moet worden (PDR-009) |
Ligt een bron er al bij het starten uit, dan komt dat ook in de systeemprompt te
staan (prompts/blocks/shared/bronnen_status.md), zodat de assistent er niet
overheen praat en niet terugvalt op eigen kennis. Liggen alle bronnen eruit,
dan vervangt geen_bronnen.md het no_tools.md-blok: dat laatste zegt juist
"antwoord op eigen kennis", en twee tegengestelde instructies in één prompt is
slechter dan één.
Het SSE-error-event draagt naast message (de volledige zin) ook code,
bericht, actie, bron en herstelbaar, zodat de frontend een retry-knop of
een bron-vermelding kan tonen. Valt een bron uit terwijl het gesprek doorloopt,
dan stuurt de host een bron_fout-event; het antwoord zelf volgt daarna gewoon.
moza-poc-digitale-assistent/
pyproject.toml uv-project (dependencies + ruff/pytest config)
uv.lock
compose.yaml Docker Compose (host + MCP via stdio-subproc)
docs/
architecture.md (dit document)
ai-verantwoording.md Verantwoording inzet Claude Code in ontwikkeling
test-vragen.md Handmatige testvragen
decisions/ Product Decision Records
scripts/
validate-mcp-servers.sh Validatie tegen mcp-standaard
services/
host/
api.py FastAPI REST-server
vlam_host.py LLM-orchestrator (VLAM + Claude, MCP + CLI)
mcp_client.py MCP-server verbindingen
cli_executor.py CLI tool-aanroepen via subprocess
config.py Configuratie
errors.py Foutcatalogus (melding + actie per foutcode)
prompts/ Modulaire systeemprompts
composer.py Stelt blokken samen tot system prompt
blocks/
identity/ Per-model identiteit (vlam.md, claude.md)
shared/ Gedeelde blokken (tone, format, guardrails, ...)
domain/ Domeinkennis per onderwerp
model_specific/ Fijnsturing per model
examples/ Few-shot voorbeelden (naast blocks/, niet eronder)
tests/ Pytest smoke-tests
scripts/ Handmatige integratie-scripts (vereisen API-keys)
Dockerfile
.env.example
mcp/ MCP-servers (Python, persistent)
kvk/ Resource + Tool — Bedrijfsgegevens (KvK Test API + BAG)
koop/ Resource + Tool — Regelingenbank
regelrecht/ Tool — generieke regel-executie (execute_law)
rvo/ Tool — subsidies en rapportages
netbeheerder/ Tool — energiegegevens als Business Wallet-credential (mock)
cli/ CLI-tools (Bash, on-demand)
kvk-cli API-wrapper KvK
koop-cli API-wrapper KOOP
regelrecht-cli API-wrapper RegelRecht
rvo-cli API-wrapper RVO
lib/ Gedeelde modules (output, provenance, audit)