leestijd : 12 minutes

Uw codebase groeit. De afhankelijkheden tussen modules nemen toe. De architectuurdocumentatie wordt verouderd voordat het zelfs is geschreven. En wat als uw Gradle-build automatisch up-to-date diagrammen kon genereren vanuit de echte code-structuur? Dat is precies wat de Graphify + PlantUML Gradle Plugin-pipeline doet:`graphify . --no-viz`extraheert de Knowledge Graph,`./gradlew generateKnowledgeGraphDiagram`het omzet in PlantUML-diagrammen. Geen LLM, geen handleiding, 100% deterministisch.

Het probleem: diagrammen die altijd achterlopen op de code

Elk project dat meer dan 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 updateert het omdat het vervelend is.

  5. Nieuwkomers baseren zich daarop en maken fouten

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

start

:Architectuurdiagram aangemaakt\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)
    :Misleidende documentatie;
    note right: De nieuwe ontwikkelaars\nbasen zij zich daarop... en maken fouten
else (Quelqu'un)
    :Handmatige bijwerking\n(2-3 uur werk);
    note right: Déjà obsolète\nà la prochaine PR
endif

stop

@enduml

De vraag is niet moeten er diagrammen zijn? — iedereen weet dat ja. De vraag is:wie houdt ze up to date?

Het antwoord: niemand. Tenzij het automatisch is.

De oplossing: een deterministische Knowledge Graph → PlantUML pipeline

Het principe is eenvoudig: 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 : extraheer de structuur\nvan de code bron
Développeur --> Plugin : ./gradlew generateKnowledgeGraphDiagram
Plugin --> Parser : parse(graph.json)
Parser --> Plugin : KnowledgeGraph\n(knopen + randen + gemeenschappen)
Plugin --> Renderer : render(graph, filters)
Renderer --> Plugin : code PlantUML\ndeterministiek
Plugin --> PS : validateSyntax + generateImage
PS --> Output : .puml + .png

note bottom of Plugin
Pipeline 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 : Graphify installeren en de Knowledge Graph extraheren

Installatie

Graphify is een Python-tool die jouw codebase analyseert en een gestructureerde kennisgraaf opbouwt:

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

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

Configureer de uitsluitingen

Een bestand maken`.graphifyignore`in de projectmap om bestanden uit te sluiten die geen onderdeel uitmaken van de bedrijfslogica:

# 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`oversla de HTML-generatie (nutteloos in een Gradle-pipeline). Het resultaat is een bestand`graphify-out/graph.json`bevattend :

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

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

  • gemeenschappen: automatische groeperingen van gekoppelde 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,onherroepelijk LLM. Alleen de documentatiebestanden (.adoc, .md) vereisen een LLM-aanroep voor semantische extractie. Dus`--update`op Kotlin code is bijna direct.

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

Architectuur van de pijplijn

De plugin`com.cheroliv.plantuml`integreert een taak`generateKnowledgeGraphDiagram`die transformeert`graph.json`in PlantUML-diagrammen op een maniervolledig deterministisch:

@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 : uitvoeren
Task -> JSON : lezen
Task -> Parser : parse(graph.json)
Parser --> Task : KnowledgeGraph\n(noeuds + arêtes + communautés)
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 : opslaan .puml met waarschuwing
end

@enduml

De interne onderdelen

Component Rol

KnowledgeGraphParser

Parse`graph.json`— ondersteunt 3 formaten : graphify natief (nodes[No text provided for translation]links), legacy (communities), vlak. Lost de numerieke IDs naar labels.

KnowledgeGraphRenderer

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

GenerateKnowledgeGraphDiagramTask

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

kgmodels.kt

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

PlantumlService

Syntactische validatie + PNG-weergave (hergebruikt door alle taken van de plug-in).

Renderregels

De renderer past deterministische visuele conventies toe:

Type rand Notatie PlantUML Betekenis

EXTRACTED

-→(volle lijn, zwart)

Uit de broncode geëxtraheerde relatie (zekerheid)

INFERRED

..>(stippellijn)

Relatie afgeleid door de LLM (betrouwbaarheidsscore)

AMBIGUOUS

--x(rode gestippelde lijn)

Ambigue relatie (te controleren)

Gemeenschappen worden weergegeven als PlantUML-pakketten met een automatisch 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

Filter per 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

Filteren per randtype

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

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

Filter op knooptype 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

(alle)

Filter de gemeenschappen op naam (subtekenreeks-match)

plantuml.kg.edgeTypes

(alle)

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

plantuml.kg.minConfidence

0.0

Minimale betrouwbaarheidsdrempel voor de randen

plantuml.kg.maxNodes

(onbeperkt)

Maximum aantal knooppunten om weer te geven

plantuml.kg.nodeTypes

(alle)

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

plantuml.kg.outputDir

diagrams/knowledge-graph

Uitvoermap voor de bestanden`.puml` et .png

De volledige pipeline in een Gradle-workflow

type workflow

@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: Knooppunten + randen\n+ gemeenschappen
}

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

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

    :diagrams/knowledge-graph/\nknowledge-graph-full.puml\nknowledge-graph-full.png;
}

partition "INTÉGRATION" {
    :git add diagrams/knowledge-graph/;
    :git commit;
    note right: Diagrammen versiebeheerde\n zijn altijd up‑to‑date met de code
}

stop

@enduml

Integratie in de ontwikkelingscyclus

De pijplijn integreert zich natuurlijk in de belangrijkste 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\nversiebeheerde diagrammen" as commit

[*] --> dev
dev --> extract : Gewijzigde code
extract --> generate : graph.json up-to-date
generate --> commit : .puml + .png tegen
commit --> dev : diagrammen in het repo

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

note right of generate
deterministiek
Geen LLM
resultaat reproduceerbaar
end note

@enduml

Incrementale update

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

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

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

--update`opnieuw extraheert 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: het plugin documenteert zichzelf

De PlantUML-plugin bestaat om prompts om te zetten naar diagrammen. Het kan ook de Knowledge Graph van zijn eigen codebase omzetten naar documentatiediagrammen. Dit is dogfooding : de plug-in maakt gebruik van 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 → plugin-documentatie)" 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, zelfde ApiKeyPool,\nzelfde PlantumlService\n— NUL duplicatie" as N

@enduml

Gerelateerde Gradle-taken:

Taak LLM ? Beschrijving

generateKnowledgeGraphDiagram

Nee

Verander`graph.json`in PlantUML (deterministisch)

generateDiagramDocs

Ja

Genereer enkele`.prompt`vanaf de graf, ze behandelt 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 dat telt)

Het sleutelpunt van de pijplijn`generateKnowledgeGraphDiagram`:Hij belt geen LLM. 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`→ zelfde diagram. Precies. Altijd.

Nul kosten

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

Nul latentie

Parse + render neemt ~100ms in beslag, niet 1-5 seconden.

Compatibel CI

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

Versiebaar

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

Diagrammen van de pipeline zelf

Om de cirkel rond te maken, hier is het diagram van de pipeline zoals deze 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 de project governance

In ons project wordt deze pijplijn geïntegreerd 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 geladen)" 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 — Strategie\n(op aanvraag)" as lazy_strat {
    [Méthodologies] as meth
    [Archives sessions] as sessions
}

package "LAZY — Graphify\n(gerichte aanvragen)" 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 : Laden als type gedetecteerd
Agent ..> lazy_graph : indien nodig structureel
kgTask --> diagrams : deterministisch
ddTask --> diagrams : Via LLM

note right of gr
Samenvatting van het Knowledge Graph
God-knooppunten + 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— governance, werkstroom, archivering

  • Graphify beheert het wat en het waar— code structuur, relaties, gerichte query’s

_ De sessiestrategie beheert deWANNEER et le Hoe(governance, workflow, drempels), Graphify beheert hetwat et le WAAR(code structuur, relaties, gerichte query’s). Het PlantUML-pijplijn beheert hetmet wat(deterministische diagrammen, versiebeheerd, altijd up-to-date). _

Voorbereiding: checklist in 5 minuten

# Stap Bestelling

1

Installeer Graphify

uv tool install graphifyy

2

Uitsluitingen configureren

Creëren`.graphifyignore`

3

Extraheer het Knowledge Graph

graphify . --no-viz

4

De 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 verzachtende maatregelen

val Beschrijving mitigatie

Te dichte grafiek

Een groot project genereert honderden onleesbare knooppunten

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

Te brede uitsluitingen

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

Begin met alleen credentials en build uitsluiten

Richting van de pijlen

De randen INFERRED kunnen een ambiguë richting hebben

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

verouderde graf

De code verandert maar de grafiek wordt niet opnieuw opgebouwd

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

Bijgewerkte kosten

Incrementele updates zijn bijna 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 "APRÈS" as apres {
    card "Automatisch gegenereerde diagrammen\nAltijd up-to-date met de code\nVersiebeheerd in Git\nDeterministisch en reproduceerbaar" as ap1 #E8F8E8
}

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

@enduml

Concrete voordelen:

winst detail

Documentatie altijd up-to-date

De diagrammen weerspiegelen de huidige code, niet een handmatige snapshot

Geen onderhoudsinspanning

De diagrammen worden bij elke build opnieuw gegenereerd

Vermindering van de technische schuld

Geen noodzaak meer om de diagrammen handmatig bij te houden

Visuele context voor de nieuwe

Een nieuwe ontwikkelaar begrijpt de architectuur door de diagrammen te bekijken.

Fine-tuning potentieel

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

_ Degene die een _waarom heeft kan alle hoe verdragen. __

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

Gerelateerde artikelen