tempo de leitura : 12 minutes

Sua base de código cresce. As dependências entre módulos se multiplicam. A documentação da arquitetura torna-se obsoleta antes mesmo de ser escrita. E se seu build Gradle pudesse automaticamente gerar diagramas atualizados a partir da estrutura real do código ? É exatamente isso que o pipeline Graphify + PlantUML Gradle Plugin :`graphify . --no-viz`extrai o Knowledge Graph,`./gradlew generateKnowledgeGraphDiagram`o transforma em diagramas PlantUML. Zero LLM, zero manual, 100% determinista.

O problema: diagramas sempre atrasados em relação ao código

Todo projeto que ultrapassa alguns milhares de linhas conhece esse sintoma:

  1. Desenha-se um diagrama de arquitetura no início do projeto.

  2. O código evolui, as dependências mudam

  3. O diagrama se torna uma mentira decorativa

  4. Ninguém o atualiza porque é chato

  5. Os novos chegados baseiam-se nisso e cometem erros

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

start

:Diagrama de arquitetura criado\n(manualmente, à mão);

:O código evolui\n(novas classes, novas dependências);

:Diagrama obsoleto\n(não reflete mais o código);

if (Qui met à jour ?) then (Personne)
    :documentação falsa;
    note right: Os novos desenvolvedores\nse baseiam nisso... e cometem erros
else (Quelqu'un)
    :Atualização manual\n(2-3 horas de trabalho);
    note right: Já obsoleto\npara a próxima PR
endif

stop

@enduml

A questão não é é necessário ter diagramas? — todo mundo sabe que sim. A questão é:Quem os mantém atualizados?

A resposta: ninguém. A menos que seja automático.

A solução: um pipeline determinístico Knowledge Graph → PlantUML

O princípio é simples: em vez de desenhar os diagramas à mão, osgera a partir da estrutura real do código.

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

actor Développeur
component "Graphify\n(pip install graphifyy)" as Graphify
collections "graphify-out/graph.json\n(Grafo de Conhecimento)" as KGJSON
component "PlantUML Gradle Plugin\n(generateKnowledgeGraphDiagram)" as Plugin
component "KnowledgeGraphParser" as Parser
component "KnowledgeGraphRenderer" as Renderer
component "PlantumlService\n(validação + renderização PNG)" as PS
collections "diagramas/knowledge-graph/\n(.puml + .png)" as Output

Développeur --> Graphify : graphify . --no-viz
Graphify --> KGJSON : extrair a estrutura\ndo código fonte
Développeur --> Plugin : ./gradlew generateKnowledgeGraphDiagram
Plugin --> Parser : parse(graph.json)
Parser --> Plugin : KnowledgeGraph\n(nós + arestas + communautés)
Plugin --> Renderer : render(graph, filters)
Renderer --> Plugin : code PlantUML\ndeterminístico
Plugin --> PS : validateSyntax + generateImage
PS --> Output : .puml + .png

note bottom of Plugin
Pipeline DÉTERMINISTE
Nenhuma chamada LLM
Resultado reprodutível
end note

@enduml

Dois comandos. É isso.

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

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

O resultado? Arquivos`.puml` et .png`em`diagrams/knowledge-graph/, versionados no Git, sempre atualizados com o código.

Passo 1: Instalar Graphify e extrair o Knowledge Graph

Instalação

Graphify é uma ferramenta Python que analisa sua base de código e constrói um grafo de conhecimento estruturado:

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

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

Configurar as exclusões

Criar um arquivo`.graphifyignore`à raiz do projeto para excluir os arquivos que não fazem parte da lógica de negócios :

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

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

# Tests fonctionnels
src/functionalTest/

Extrair o Knowledge Graph

graphify . --no-viz

O flag`--no-viz`Salta a geração de HTML (desnecessária em um pipeline Gradle). O resultado é um arquivo`graphify-out/graph.json`contendo :

  • Nós: classes, funções, ficheiros — com o seu tipo e comunidade

  • Arestas: relações entre nós (EXTRACTED do código, INFERRED pelo LLM)

  • Comunidades: agrupamentos automáticos de nós ligados

Exemplo de estrutura`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}
  ]
}

O código-fonte (.kt, .java) é analisado localmente pelo tree-sitter,sem apelo LLM. Apenas os arquivos de documentação (.adoc, .md) precisam de uma chamada LLM para a extração semântica. Portanto`--update`sobre do código Kotlin é quase instantâneo.

Passo 2 : O plugin Gradle transforma o Knowledge Graph em PlantUML

Arquitetura do pipeline

O plugin`com.cheroliv.plantuml`incorpora uma tarefa`generateKnowledgeGraphDiagram`que transforma`graph.json`em diagramas PlantUML de maneiratotalmente determinista:

@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 : executar
Task -> JSON : ler
Task -> Parser : parse(graph.json)
Parser --> Task : KnowledgeGraph\n(nós + arestas + comunidades)
Task -> Renderer : render(graph, filters)
Renderer --> Task : código PlantUML\n(determinista)
Task -> PS : validateSyntax(plantumlCode)
alt syntaxe valide
    Task -> PS : generateImage → .png
else syntaxe invalide
    Task -> Task : salvar .puml com aviso
end

@enduml

Os componentes internos

Componente Papel

KnowledgeGraphParser

Analisar`graph.json`— suporta 3 formatos : graphify nativo (nodes+links), legacy (communities), plano. Resolve os IDs numéricos para rótulos.

KnowledgeGraphRenderer

Transforma deterministicamente um`KnowledgeGraph`em código PlantUML. Grupos por tipo, comunidades em pacotes, legenda automática.

GenerateKnowledgeGraphDiagramTask

Tarefa Gradle que orquestra: parse → render → validate → PNG. Configurável via propriedades do Gradle.

kgmodels.kt

Modelos de dados :`KnowledgeGraph`, KnowledgeGraphNode, KnowledgeGraphEdge, KnowledgeGraphCommunity, EdgeType.

PlantumlService

Validação sintática + renderização PNG (reutilizado por todas as tarefas do plugin).

Regras de renderização

O renderer aplica convenções visuais determinísticas :

Tipo de aresta Notação PlantUML Significação

extraído

-→(traço cheio, preto)

Relação extraída do código fonte (certeza)

deduzido

..>(traço pontilhado)

Relação inferida pelo LLM (pontuação de confiança)

AMBÍGUO

--x(traço vermelho pontilhado)

Relação ambígua (a verificar)

As comunidades são renderizadas como pacotes PlantUML com uma paleta de cores automática.

Passo 3 : Uso diário

Diagrama completo

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

Saída:`diagrams/knowledge-graph/knowledge-graph-full.puml`+.png

Filtrar por comunidade

# 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

Filtrar por tipo de aresta

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

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

Filtrar por tipo de nó e confiança

# 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

Diretório de saída personalizado

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

Referência completa das propriedades

Propriedade defeito Descrição

plantuml.kg.community

(todas)

Filtrar as comunidades por nome (correspondência de subcadeia)

plantuml.kg.edgeTypes

(todos)

Tipos de arestas separados por vírgulas:`EXTRACTED`, INFERRED, AMBIGUOUS

plantuml.kg.minConfidence

0.0

Limite mínima de confiança para as arestas

plantuml.kg.maxNodes

(ilimitado)

Número máximo de nós a exibir

plantuml.kg.nodeTypes

(todos)

Tipos de nós separados por vírgulas (ex.class, code)

plantuml.kg.outputDir

diagrams/knowledge-graph

Diretório de saída para os arquivos`.puml` et .png

O pipeline completo em um workflow Gradle

Tipo de workflow

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

start

partition "EXTRACTION" {
    :graphify . --no-viz;
    note right: Análise o código-fonte\ntree-sitter (local, sem LLM)

    :graphify-out/graph.json;
    note right: Nós + arestas\n+ comunidades
}

partition "GERADORATION" {
    :./gradlew generateKnowledgeGraphDiagram;
    note right: Pipeline determinístico\nparse → render → validate → PNG

    if (Filtres actifs ?) then (Oui)
        :Aplicar filtros\n(community, edgeTypes,\nmaxNodes, nodeTypes);
    else (Non)
        :Diagrama completo;
    endif

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

partition "INTÉGRATION" {
    :git add diagrams/knowledge-graph/;
    :git commit;
    note right: Diagramas versionados\nsempre atualizado com o código
}

stop

@enduml

Integração no ciclo de desenvolvimento

O pipeline integra-se naturalmente nas etapas-chave do desenvolvimento:

@startuml
skinparam backgroundColor #FEFEFE

state "Desenvolvimento" as dev
state "Extração\ngraphify . --no-viz" as extract
state "Geração\n./gradlew generateKnowledgeGraphDiagram" as generate
state "Commit\ndiagramas versionados" as commit

[*] --> dev
dev --> extract : Código modificado
extract --> generate : graph.json atualizado
generate --> commit : .puml + .png gerados
commit --> dev : Diagramas no repositório

note right of extract
Quase instantâneo em código Kotlin

(tree-sitter, sem LLM)
end note

note right of generate
Determinístico
Sem LLM
Resultado reproduzível
end note

@enduml

Atualização incremental

Quando o código muda, não reconstruímos todo o grafo do zero :

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

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

--update`reextraído apenas os arquivos modificados (detectados por SHA256 em`graphify-out/cache/). Em código Kotlin, é quase instantâneo porque o tree-sitter trabalha localmente sem chamada ao LLM.

Dogfooding: o plugin se documenta por si mesmo

O plugin PlantUML existe para transformar prompts em diagramas. Ele também pode transformar o Knowledge Graph da sua próprio codebase em diagramas de documentação. É dogfooding: o plugin consome o seu próprio serviço.

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package "Pipeline normal\n(usuário → diagramas)" 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 "Pipeline Knowledge Graph\n(determinístico, sem 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 "Pipeline Dogfooding\n(LLM → documentação do 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 "Mesmo LlmService, mesmo ApiKeyPool,\nmesmo PlantumlService\n— ZERO duplicação" as N

@enduml

Tarefas Gradle associadas :

tarefa LLM ? Descrição

generateKnowledgeGraphDiagram

Não

Transforma`graph.json`em PlantUML (determinístico)

generateDiagramDocs

Sim

gere alguns`.prompt`a partir do grafo, os trata via LLM (dogfooding)

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

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

Por que é determinístico (e por que isso importa)

O ponto-chave do pipeline`generateKnowledgeGraphDiagram`:ele não chama nenhum LLM. A transformação`graph.json`→ PlantUML é uma função pura.

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

rectangle "Pipeline DÉTERMINISTE\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 (função pura)
}

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

    prompt --> llmSvc
    llmSvc --> model : API ligar
    model --> puml2 : resposta não-determinística
}

note bottom of det
Mesma entrada → mesma saída
Sem latência de rede
Sem custo em tokens
Reprodutível em CI
end note

note bottom of llm
Mesma entrada → saída variável
Latência de rede (1-5s)
Custo em tokens
Necessita uma chave API
end note

@enduml

Os benefícios concretos:

vantagem Impacto

Reproducibilidade

mesmo`graph.json`→ mesmo diagrama. Exatamente. Sempre.

Custo zero

Sem chamada LLM = sem tokens = sem fatura da API.

Zero latência

Parse + render demora ~100ms, não 1-5 segundos.

Compatível CI

Nenhuma chave API necessária. Nenhum teste flaky devido a uma resposta LLM variável.

Versionável

Le .puml`gerado é texto. Pode`diff, o revisor no PR, versioná-lo no Git.

Diagramas do próprio pipeline

Para fechar o ciclo, aqui está o diagrama do pipeline como seria gerado pelo plugin :

@startuml
skinparam backgroundColor #FEFEFE

participant "Desenvolvedor" 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 : executar
Task -> JSON : ler
Task -> Parser : parse(graph.json)
Parser --> Task : KnowledgeGraph

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

Task -> Renderer : render(graph, filters)
Renderer --> Task : código PlantUML

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

@enduml

Integração na governança do projeto

No nosso projeto, este pipeline integra-se numa estratégia de gestão de contexto EAGER/LAZY para o agente IA. O Knowledge Graph substitui a documentação de arquitetura manual por um grafo estruturado, consultável e auto-atualizado.

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

package "EAGER\n(sempre carregado)" 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 — Estratégia\n(sob demanda)" as lazy_strat {
    [Méthodologies] as meth
    [Archives sessions] as sessions
}

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

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

Agent --> eager : Lido no início da sessão
Agent ..> lazy_strat : Carregue se o tipo for detectado
Agent ..> lazy_graph : Se necessário estrutural
kgTask --> diagrams : Determinístico
ddTask --> diagrams : Via LLM

note right of gr
Resumo do Knowledge Graph
God nodes + comunidades
Substitua ECOSYSTEM_OVERVIEW
(225 linhas → 50 linhas)
end note

@enduml

O casamento dos dois sistemas é complementar :

  • A estratégia trata do QUANDO e do COMO— governança, workflow, arquivamento

  • Graphify gerencia o quê e o onde— estrutura do código, relações, consultas direcionadas

_ A estratégia de sessão gerencia oQUANDO et le como(governança, workflow, limites), Graphify gerencia oO QUE et le ONDE(estrutura do código, relações, consultas direcionadas). O pipeline PlantUML gerencia oCOM O QUE(diagramas determinísticos, versionados, sempre atualizados). _

Preparação: lista de verificação em 5 minutos

# Etapa encomenda

1

Instalar Graphify

uv tool install graphifyy

2

Configurar as exclusões

Criar`.graphifyignore`

3

Extrair o Knowledge Graph

graphify . --no-viz

4

Gerar os diagramas

./gradlew generateKnowledgeGraphDiagram

5

Fazer commit dos resultados

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/

Armadilhas e mitigações

armadilha Descrição mitigação

Grafo muito denso

Um grande projeto gera centenas de nós ilegíveis

Utilizar`-Pplantuml.kg.maxNodes=30`e filtrar por comunidade

Exclusões demasiado largas

Muitos arquivos em`.graphifyignore`reduce o valor do grafo

Começar por excluir apenas credentials e build

Direção das setas

As arestas INFERRED podem ter uma direção ambígua

Filtrar por`-Pplantuml.kg.edgeTypes=EXTRACTED`para as relações certas apenas

Grafo obsoleto

O código muda, mas o grafo não é reconstruído

Utilizar`graphify . --update`régulièrement ou o hook git`graphify hook install`

Custo atualizado

As atualizações incrementais são quase gratuitas (tree-sitter local)

Apenas os docs (.adoc) consumem tokens LLM

O que se obtém no final

@startuml
skinparam backgroundColor #FEFEFE

rectangle "ANTES" as avant {
    card "Diagramas desenhados à mão\nSempre obsoletos\nNinguém os atualiza" as av1 #FDEDEC
}

rectangle "DEPOIS" as apres {
    card "Diagramas gerados automaticamente\nSempre atualizados com o código\nVersionados no Git\nDeterminísticos e reproduzíveis" as ap1 #E8F8E8
}

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

@enduml

Os benefícios concretos :

Benefício Detalhe

Documentação sempre atualizada

Os diagramas refletem o código atual, não um instantâneo manual

Zero esforço de manutenção

Os diagramas são regenerados a cada build

Redução da dívida técnica

Não precisa mais manter os diagramas à mão

Contexto visual para os novos

Um novo desenvolvedor entende a arquitetura olhando os diagramas

Potencial de fine-tuning

Os pares (subgrafo → diagrama) são exemplos de treinamento de IA

Validação automática

`PlantumlService.validateSyntax()`verifica cada diagrama gerado

Onboarding rápido

5 diagramas = visão completa da arquitetura

</think>

O porquê : diagramas sempre atualizados. O como : dois comandos em um pipeline Gradle.

Artigos relacionados