leestijd : 12 minutes

Je codebase groeit. De afhankelijkheden tussen modules nemen toe. De architectuurdocumentatie wordt verouderd voordat ze zelfs geschreven is. En wat als jouw Gradle-build automatisch up-to-date diagrammen kon genereren op basis van de werkelijke code-structuur? Dat is precies wat de Graphify + PlantUML Gradle Plugin-pijplijn doet:`graphify . --no-viz`extraheert de Knowledge Graph,`./gradlew generateKnowledgeGraphDiagram`zet het om in PlantUML-diagrammen. Geen LLM, geen handleiding, 100% deterministisch.

Het probleem: diagrammen die altijd achterblijven bij de code

Elk project dat enkele duizenden regels overschrijdt kent dit syndroom:

  1. We tekenen een architectuurdiagram aan het begin van het project

  2. De code evolueert, de afhankelijkheden veranderen

  3. Het diagram wordt een decoratieve leugen

  4. Niemand werkt het bij omdat het vervelend is

  5. De nieuwkomers baseren zich daarop en maken fouten.

@startuml
skinparam backgroundColor #FEFEFE
skinparam ActivityBackgroundColor #FDEDEC
skinparam ActivityDiamondBackgroundColor #FFF3CD

start

:Architectuurdiagram gemaakt\n(handmatig, met de hand);

:De code evolueert\n(nieuwe klassen, nieuwe afhankelijkheden);

:verouderd diagram\n(weerspiegelt de code niet meer);

if (Qui met à jour ?) then (Personne)
    :Misleadingende documentatie;
    note right: Nieuwe ontwikkelaars\nbaseren zich daarop... en maken fouten
else (Quelqu'un)
    :Handmatige update\n(2-3 uur werk);
    note right: Al verouderd\nvoor de volgende PR
endif

stop

@enduml

De vraag is niet moeten we diagrammen hebben? — iedereen weet dat ja. De vraag is :Wie houdt ze up-to-date?

Het antwoord: niemand. Tenzij het automatisch is.

De oplossing: een deterministische pijplijn Knowledge Graph → PlantUML

Het principe is simpel : in plaats van de diagrammen met de hand te tekenen, we zegenereert vanuit de werkelijke structuur van de code.

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

actor Développeur
component "Graphify\n(pip install graphifyy)" as Graphify
collections "graphify-out/graph.json\n(Knowledge Graph)" as KGJSON
component "PlantUML Gradle Plugin\n(generateKnowledgeGraphDiagram)" as Plugin
component "KnowledgeGraphParser" as Parser
component "KnowledgeGraphRenderer" as Renderer
component "PlantumlService\n(validation + weergave PNG)" as PS
collections "diagrams/knowledge-graph/\n(.puml + .png)" as Output

Développeur --> Graphify : graphify . --no-viz
Graphify --> KGJSON : extraheert de structuur\nvan de broncode
Développeur --> Plugin : ./gradlew generateKnowledgeGraphDiagram
Plugin --> Parser : parse(graph.json)
Parser --> Plugin : KnowledgeGraph\n(nodes + edges + communities)
Plugin --> Renderer : render(graph, filters)
Renderer --> Plugin : code PlantUML\ndeterminist
Plugin --> PS : validateSyntax + generateImage
PS --> Output : .puml + .png

note bottom of Plugin
Pijplijn DÉTERMINISTE
Geen oproep LLM
Reproduceerbaar resultaat
end note

@enduml

Twee commando’s. Dat is alles.

# Étape 1 : extraire le Knowledge Graph
graphify . --no-viz

# Étape 2 : générer les diagrammes PlantUML
./gradlew generateKnowledgeGraphDiagram

Het resultaat? Bestanden`.puml` et .png`in`diagrams/knowledge-graph/, versiebeheerd in Git, altijd up-to-date met de code.

Stap 1: Installeer Graphify en extraheer de Knowledge Graph

Installatie

Graphify is een Python-hulpmiddel dat uw codebase analyseert en een gestructureerde kennisgrafiek bouwt :

# Méthode recommandée
uv tool install graphifyy && graphify install --platform opencode

# Alternative avec pip
pip install graphifyy && graphify install --platform opencode

De uitsluitingen configureren

Een bestand maken`.graphifyignore`in de root van het project om bestanden uit te sluiten die geen onderdeel uitmaken van de zakelijke logica:

# Secrets — JAMAIS dans le graphe
*-context.yml
*.env

# Fichiers générés
build/
.gradle/

# Tests fonctionnels
src/functionalTest/

Extraheer de Knowledge Graph

graphify . --no-viz

De vlag`--no-viz`Sla de HTML-generatie over (onnodig in een Gradle-pijplijn). Het resultaat is een bestand`graphify-out/graph.json`bevat:

  • knopen: klassen, functies, bestanden — met hun type en gemeenschap

  • randen: relaties tussen knooppunten (EXTRACTED vanuit de code, INFERRED door de LLM)

  • gemeenschappen: automatische groeperingen van gelinkte knooppunten

Voorbeeld van structuur`graph.json`
{
  "nodes": [
    {"id": "0", "label": "LlmService", "file_type": "code", "community": 0},
    {"id": "1", "label": "ApiKeyPool", "file_type": "code", "community": 0},
    {"id": "2", "label": "PlantumlService", "file_type": "code", "community": 1}
  ],
  "links": [
    {"source": "1", "target": "0", "relation": "uses", "confidence": "EXTRACTED", "weight": 0.9},
    {"source": "0", "target": "2", "relation": "calls", "confidence": "INFERRED", "weight": 0.7}
  ]
}

De broncode (.kt, .java) wordt lokaal geanalyseerd door tree-sitter,zonder beroep LLM. Alleen de documentatiebestanden (.adoc, .md) vereisen een LLM-aanroep voor semantische extractie. Dus`--update`Werken aan Kotlin-code is vrijwel onmiddellijk.

Stap 2: De Gradle-plugin transformeert de Knowledge Graph naar PlantUML

Pijplijnarchitectuur

De plug-in`com.cheroliv.plantuml`integreert een taak`generateKnowledgeGraphDiagram`die transformeert`graph.json`in PlantUML-diagrammen op een maniervolledig deterministisch</think> </think>

@startuml
skinparam backgroundColor #FEFEFE

participant "Gradle" as G
participant "GenerateKnowledgeGraphDiagramTask" as Task
participant "KnowledgeGraphParser" as Parser
participant "KnowledgeGraphRenderer" as Renderer
participant "PlantumlService" as PS

collections "graphify-out/graph.json" as JSON

G -> Task : execute
Task -> JSON : lezen
Task -> Parser : parse(graph.json)
Parser --> Task : KnowledgeGraph\n(knooppunten + randen + gemeenschappen)
Task -> Renderer : render(graph, filters)
Renderer --> Task : code PlantUML\n(deterministisch)
Task -> PS : validateSyntax(plantumlCode)
alt syntaxe valide
    Task -> PS : generateImage → .png
else syntaxe invalide
    Task -> Task : sla .puml op met waarschuwing
end

@enduml

De interne componenten

Component Rol

KnowledgeGraphParser

Parseert`graph.json`— ondersteunt 3 formaten: native graphify (nodes+links), legacy (communities), vlak. Lost de numerieke ID’s op in labels.

KnowledgeGraphRenderer

Verander deterministisch een`KnowledgeGraph`in PlantUML-code. Groepen per type, gemeenschappen in pakketten, automatische legenda.

GenerateKnowledgeGraphDiagramTask

Gradle-taak die orchestratie uitvoert: parse → render → validate → PNG. Configureerbaar via Gradle-eigenschappen.

kgmodels.kt

Gegevensmodellen:`KnowledgeGraph`, KnowledgeGraphNode, KnowledgeGraphEdge, KnowledgeGraphCommunity, EdgeType.

PlantumlService

Syntaxisvalidatie + PNG-rendering (hergebruikt door alle taken van de plugin).

Regels voor rendering

De renderer past deterministische visuele conventies toe:

type van rand Notatie PlantUML betekenis

geëxtraheerd

-→(volle lijn, zwart)

Uit de broncode geëxtraheerde relatie (zekerheid)

AFGELEID

..>(gestippelde lijn)

Afgeleide relatie door het LLM (vertrouwensscore)

ambigu

--x(rode gestippelde lijn)

Onduidelijke relatie (te controleren)

Gemeenschappen worden weergegeven als PlantUML-pakketten met een automatische kleurenpalet.

Stap 3: Dagelijks gebruik

Volledig diagram

# Générer le diagramme du Knowledge Graph complet
./gradlew generateKnowledgeGraphDiagram

Uitvoer:`diagrams/knowledge-graph/knowledge-graph-full.puml`+.png

Filteren op gemeenschap

# Une seule communauté
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.community=community_0

# Limiter le nombre de noeuds (lisibilité)
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.community=community_0 \
  -Pplantuml.kg.maxNodes=15

Filter op randtype

# Uniquement les relations certaines (EXTRACTED)
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.edgeTypes=EXTRACTED

# Relations certaines + inférées
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.edgeTypes=EXTRACTED,INFERRED

Filteren op knooppunttype en betrouwbaarheid

# Uniquement les classes de code
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.nodeTypes=code

# Seuil de confiance minimum (pour les INFERRED)
./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.minConfidence=0.7

Aangepaste uitvoermap

./gradlew generateKnowledgeGraphDiagram \
  -Pplantuml.kg.outputDir=docs/architecture

Volledige referentie van eigenschappen

Eigendom Standaard Beschrijving

plantuml.kg.community

(alles)

Filter de gemeenschappen op naam (subtekenreeks overeenkomst)

plantuml.kg.edgeTypes

(alle)

Types van randen gescheiden door komma’s :`EXTRACTED`, INFERRED, AMBIGUOUS

plantuml.kg.minConfidence

0.0

Minimum drempel van betrouwbaarheid voor de randen

plantuml.kg.maxNodes

(onbeperkt)

Maximum aantal knooppunten om weer te geven

plantuml.kg.nodeTypes

(alle)

Soorten knopen gescheiden door komma’s (bijv.class, code)

plantuml.kg.outputDir

diagrams/knowledge-graph

Uitvoermap voor de bestanden`.puml` et .png

De volledige pijplijn in een Gradle-workflow

werkstroomtype

@startuml
skinparam backgroundColor #FEFEFE
skinparam ActivityBackgroundColor #E8F4FD
skinparam ActivityDiamondBackgroundColor #FFF3CD
skinparam ActivityBorderColor #2C3E50

start

partition "EXTRACTION" {
    :graphify . --no-viz;
    note right: Analyseer de broncode\ntree-sitter (lokaal, geen LLM)

    :graphify-out/graph.json;
    note right: Knopen + randen\n+ gemeenschappen
}

partition "GÉNÉRATION" {
    :./gradlew generateKnowledgeGraphDiagram;
    note right: Deterministische pijplijn\n→ render → validate → PNG

    if (Filtres actifs ?) then (Oui)
        :Filters toepassen\n(community, edgeTypes,\nmaxNodes, nodeTypes);
    else (Non)
        :Volledig diagram;
    endif

    :diagrammen/knowledge-graph/\nkennisgrafiek-full.puml\nkennisgrafiek-full.png;
}

partition "INTÉGRATION" {
    :git add diagrams/knowledge-graph/;
    :git commit;
    note right: Versioned diagrams\nalways up to date with the code
}

stop

@enduml

Integratie in de ontwikkelingscyclus

De pipeline integreert zich natuurlijk in de essentiële stappen van de ontwikkeling:

@startuml
skinparam backgroundColor #FEFEFE

state "Ontwikkeling" as dev
state "Extractie\ngraphify . --no-viz" as extract
state "Generatie\n./gradlew generateKnowledgeGraphDiagram" as generate
state "Commit\ndiagrammen versiegegeven" as commit

[*] --> dev
dev --> extract : Gewijzigde code
extract --> generate : graph.json bijgewerkt
generate --> commit : .puml + .png gegenereerd
commit --> dev : Diagrammen in de repo

note right of extract
Bijna onmiddellijk op code Kotlin
(tree-sitter, geen LLM)
end note

note right of generate
Deterministisch
Geen LLM
Reproduceerbaar resultaat
end note

@enduml

incrementale update

Wanneer de code verandert, bouwen we niet de hele graaf opnieuw vanaf nul op:

# Mise à jour incrémentale (fichiers modifiés uniquement)
graphify . --update

# Puis régénérer les diagrammes
./gradlew generateKnowledgeGraphDiagram

--update`her-extracteert alleen de gewijzigde bestanden (gedetecteerd door SHA256 in`graphify-out/cache/). Op Kotlin-code is het vrijwel onmiddellijk, omdat tree-sitter lokaal werkt zonder LLM-aanroep.

Dogfooding: de plugin documenteert zichzelf

Het PlantUML-plugin bestaat om prompts te transformeren naar diagrammen. Het kan ook de Knowledge Graph van zijn eigen codebase omzetten naar documentatiediagrammen. Het is dogfooding : het plugin gebruikt zijn eigen dienst.

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package "Normale pipeline\n(gebruiker → diagrammen)" as normal {
    [Fichier .prompt] as prompt
    [LlmService\n+ ApiKeyPool] as llm1
    [ProcessPlantumlPromptsTask] as task1
    [Diagramme PNG] as out1

    prompt --> task1
    task1 --> llm1
    llm1 --> out1
}

package "Knowledge Graph pipeline\n(deterministisch, geen LLM)" as kg {
    [graphify-out/graph.json] as kgjson
    [KnowledgeGraphParser] as parser
    [KnowledgeGraphRenderer] as renderer
    [PlantumlService] as ps
    [Diagramme PNG\n(documentation du plugin)] as out2

    kgjson --> parser
    parser --> renderer
    renderer --> ps
    ps --> out2
}

package "Dogfooding pipeline\n(LLM → documentatie van de plugin)" as dogfood {
    [GraphifyPromptAdapter] as gpa
    [Fichiers .prompt\nauto-générés] as auto_prompt
    [LlmService\n+ ApiKeyPool] as llm2
    [ProcessPlantumlPromptsTask] as task2
    [Diagramme PNG\n(documentation LLM)] as out3

    kgjson --> gpa
    gpa --> auto_prompt
    auto_prompt --> task2
    task2 --> llm2
    llm2 --> out3
}

note "Zelfde LlmService, dezelfde ApiKeyPool,\ndezelfde PlantumlService\n— NUL duplicatie" as N

@enduml

Geassocieerde Gradle-taken:

taak LLM ? Beschrijving

generateKnowledgeGraphDiagram

Nee

Transformeer`graph.json`in PlantUML (deterministisch)

generateDiagramDocs

Ja

Genereert`.prompt`Vanaf de graaf, verwerkt ze via LLM (dogfooding)

# Documentation déterministe (rapide, pas de LLM)
./gradlew generateKnowledgeGraphDiagram

# Documentation LLM (plus riche, consomme des tokens)
./gradlew generateDiagramDocs

Waarom het deterministisch is (en waarom het uitmaakt)

Het sleutelpunt van de pijplijn`generateKnowledgeGraphDiagram`:hij roept geen LLM aan. De transformatie`graph.json`→ PlantUML is een zuivere functie.

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

rectangle "DETERMINISTISCHE pipeline\n(generateKnowledgeGraphDiagram)" as det {
    [graph.json] as json
    [KnowledgeGraphParser] as parser
    [KnowledgeGraphRenderer] as renderer
    [PlantUML code] as puml

    json --> parser : parse
    parser --> renderer : KnowledgeGraph
    renderer --> puml : render (fonction pure)
}

rectangle "LLM-pipeline\n(processPlantumlPrompts)" as llm {
    [.prompt] as prompt
    [LlmService] as llmSvc
    [ChatModel] as model
    [PlantUML code] as puml2

    prompt --> llmSvc
    llmSvc --> model : API call
    model --> puml2 : réponse non-déterministe
}

note bottom of det
Zelfde input → zelfde output
Geen netwerklatentie
Geen tokenkosten
Reproduceerbaar in CI
end note

note bottom of llm
Zelfde input → variabele output
Netwerklatentie (1-5s)
Tokenkosten
Vereist een API-sleutel
end note

@enduml

De concrete voordelen:

voordeel Invloed

Reproduceerbaarheid

zelfs`graph.json`→ hetzelfde diagram. Exact. Elke keer.

Geen kosten

Geen LLM-aanroep = geen tokens = geen API-factuur.

Nul latentie

Parse + render duurt ~100ms, niet 1-5 seconden.

Compatibel CI

Geen API-sleutel nodig. Geen flaky test door een variabele LLM-reactie.

versiebaar

Le .puml`gegenereerd is tekst. We kunnen het`diff, de reviewer in PR, het versiebeheren in Git

diagrammen van de pipeline zelf

Om de lus te sluiten, hier is het diagram van de pijplijn zoals dit door de plugin zou worden gegenereerd:

@startuml
skinparam backgroundColor #FEFEFE

participant "Ontwikkelaar" as Dev
participant "Gradle" as G
participant "GenerateKnowledgeGraphDiagramTask" as Task
participant "KnowledgeGraphParser" as Parser
participant "KnowledgeGraphRenderer" as Renderer
participant "PlantumlService" as PS
collections "graphify-out/graph.json" as JSON
collections "diagrams/knowledge-graph/" as Out

Dev -> G : ./gradlew generateKnowledgeGraphDiagram
G -> Task : uitvoeren
Task -> JSON : lezen
Task -> Parser : parse(graph.json)
Parser --> Task : KnowledgeGraph

alt filtres actifs
    Task -> Task : toepassen filters\n(community, edgeTypes, maxNodes…)
end

Task -> Renderer : render(graph, filters)
Renderer --> Task : code PlantUML

Task -> PS : validateSyntax()
alt valide
    Task -> PS : generateImage()
    PS --> Out : .puml + .png
else invalide
    Task -> Out : .puml (met waarschuwing)
end

@enduml

Integratie in het projectbestuur

In ons project integreert deze pijplijn in een strategie voor EAGER/LAZY-contextbeheer voor de AI-agent. Het Knowledge Graph vervangt de handmatige architectuurdocumentatie door een gestructureerde, querybare en automatisch bijgewerkte graaf.

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package "EAGER\n(altijd opgeladen)" as eager {
    [PROMPT_REPRISE.adoc\n(contexte session)] as pr
    [INDEX.adoc\n(vue d'ensemble)] as idx
    [GRAPH_REPORT.adoc\n(~50 lignes)] as gr
}

package "LAZY — Stratégie\n(op verzoek)" as lazy_strat {
    [Méthodologies] as meth
    [Archives sessions] as sessions
}

package "LAZY — Graphify\n(gerichte verzoeken)" as lazy_graph {
    [graph.json] as gj
    [Queries\n(query/path/explain)] as queries
}

package "Pipeline PlantUML\n(automatisch gegenereerd)" as puml {
    [generateKnowledgeGraphDiagram] as kgTask
    [generateDiagramDocs] as ddTask
    [Diagrammes PNG] as diagrams
}

Agent --> eager : Gelezen aan het begin van de sessie
Agent ..> lazy_strat : Laad wanneer type gedetecteerd
Agent ..> lazy_graph : Query indien nodig structurele
kgTask --> diagrams : deterministisch
ddTask --> diagrams : Via LLM

note right of gr
Samenvatting van de Knowledge Graph
God nodes + gemeenschappen
Vervang ECOSYSTEM_OVERVIEW
(225 regels → 50 regels)
end note

@enduml

Het huwelijk van de twee systemen is complementair:

  • De strategie beheert het WANNEER en het HOE— bestuur, workflow, archivering

  • Graphify beheert QUOI en OÙ— code structuur, relaties, gerichte query’s

_ De sessiestrategie beheert hetWanneer et le hoe(governance, werkstroom, drempels), Graphify beheert hetwat et le waar(structuur van de code, relaties, gerichte queries). De PlantUML-pipeline beheert hetMET WAT(deterministische diagrammen, versies, altijd up-to-date). _

Voorbereiding: checklist in 5 minuten

# Stap bestelling

1

Installeer Graphify

uv tool install graphifyy

2

Uitsluitingen configureren

Maken`.graphifyignore`

3

Extraheer de Knowledge Graph

graphify . --no-viz

4

Diagrammen genereren

./gradlew generateKnowledgeGraphDiagram

5

Commit de resultaten

git add diagrams/knowledge-graph/

# Script complet en 5 commandes
uv tool install graphifyy
cat > .graphifyignore << 'EOF'
*-context.yml
*.env
build/
.gradle/
EOF
graphify . --no-viz
./gradlew generateKnowledgeGraphDiagram
git add graphify-out/GRAPH_REPORT.adoc graphify-out/graph.json diagrams/knowledge-graph/

Valkuilen en mitigaties

val Beschrijving Mitigatie

Te dichte graf

Een groot project genereert honderden onleesbare knooppunten

gebruiken`-Pplantuml.kg.maxNodes=30`en filteren op gemeenschap

Uitsluitingen te ruim

Te veel bestanden in`.graphifyignore`vermindert de waarde van de grafiek

Begin met alleen credentials en build uit te sluiten

Richting van de pijlen

De randen INFERRED kunnen een onduidelijke richting hebben

Filteren op`-Pplantuml.kg.edgeTypes=EXTRACTED`voor de bepaalde relaties alleen

Verouderd graphe

De code verandert maar de graaf wordt niet herbouwd

Gebruiken`graphify . --update`regelmatig of de git-hook`graphify hook install`

Kosten bijgewerkt

Incrementale updates zijn praktisch gratis (tree-sitter lokaal)

Alleen de docs (.adoc) verbruiken LLM-tokens

Wat men uiteindelijk krijgt

@startuml
skinparam backgroundColor #FEFEFE

rectangle "AVANT" as avant {
    card "handgetekende diagrammen\nAltijd verouderd\nNiemand werkt ze bij" as av1 #FDEDEC
}

rectangle "APRin" as apres {
    card "automatisch gegenereerde diagrammen\nAltijd up-to-date met de code\nVersiebeheerd in Git\ndeterminisitische en reproduceerbare" as ap1 #E8F8E8
}

avant --> apres : graphify . --no-viz\n+ ./gradlew generateKnowledgeGraphDiagram

@enduml

De concrete voordelen:

Winst Detail

Documentatie altijd up-to-date

De diagrammen spiegelen de huidige code weer, niet een handmatige snapshot

Geen onderhoudsinspanning

De diagrammen worden bij elke build opnieuw gegenereerd

Vermindering van de technische schuld

Je hoeft de diagrammen niet meer handmatig bij te houden.

Visuele context voor de nieuwe

Een nieuwe ontwikkelaar begrijpt de architectuur door naar de diagrammen te kijken.

Potentiële fijnafstelling

De paren (ondergraf → diagram) zijn voorbeelden van AI-training

Automatische validatie

`PlantumlService.validateSyntax()`controleert elk gegenereerd diagram

Snelle onboarding

5 diagrammen = volledig overzicht van de architectuur

_ Wie een _waarom heeft, kan elke hoe verdragen. __

De waarom : diagrammen die altijd up-to-date zijn. De hoe : twee opdrachten in een Gradle-pipeline.

Gerelateerde artikelen