CommunityEscrita e Ediçãogithub.com

BESSER-PEARL/BESSER-Skills

Habilidades de agente para BESSER — conhecimento profundo de BESSER para agentes de codificação de IA: modelagem UML de classes, geradores de código, resolução de problemas e fluxos de trabalho de contribuidores.

O que é BESSER-Skills?

Este skill capacita agentes de codificação de IA (como Claude Code, Cursor e Codex) com o conhecimento abrangente necessário para contribuir efetivamente com o ecossistema BESSER. Ele fornece orientação detalhada sobre configuração de desenvolvimento, criação de novos geradores de código a partir de modelos B-UML, extensão de metamodelos e sub-DSLs, execução de testes, construção de documentação e adesão a padrões de codificação. O skill é incrivelmente útil para desenvolvedores que desejam automatizar ou acelerar suas contribuições, eliminando a necessidade de consultar documentação extensa manualmente. Ele suporta integração com o backend do editor web e garante que o código gerado seja determinístico, com templates Jinja2 e testes de fidelidade de ida e volta (round-trip) para conversores. Ao seguir as instruções estruturadas neste skill, agentes de IA podem reduzir significativamente o atrito e o tempo necessário para adicionar novos geradores, metamodelos ou correções ao projeto BESSER.

Funciona com✓Claude Code~Codex CLI✓Cursor✓Windsurf
npx skills add BESSER-PEARL/BESSER-Skills

Installed? Explore more Escrita e Edição skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Contribuindo para o BESSER

Este skill cobre os fluxos de trabalho processuais para contribuir com o código-fonte do BESSER. Para detalhes de arquitetura e convenções de código, consulte também o arquivo CLAUDE.md do projeto, que é carregado automaticamente no contexto.


Configuração de Desenvolvimento

git clone https://github.com/<seu-usuario>/BESSER.git
cd BESSER
python -m venv venv
# Windows: venv\Scripts\activate
# macOS/Linux: source venv/bin/activate
pip install -r requirements.txt
pip install -r docs/requirements.txt  # para construir a documentação
pip install -e .                       # instalação editável

Verifique: python tests/BUML/metamodel/structural/library/library.py

Python 3.10+ é necessário (dependência do Django 5.x).


Adicionando um Novo Gerador

Este é o tipo de contribuição mais comum. Para pular o código boilerplate, execute o scaffold incluído:

python scripts/scaffold_generator.py <nome> <caminho/para/repo/BESSER>
# ex.: python scripts/scaffold_generator.py graphql ~/code/BESSER

Isso cria um pacote stub funcional (classe geradora + template Jinja + pytest), executável imediatamente. Você ainda precisa implementar a lógica real, registrar o gerador na configuração do editor web e adicionar documentação — coberto nas etapas abaixo.

Se preferir fazer manualmente, siga estas 6 etapas:

Etapa 1: Criar o Pacote do Gerador

besser/generators/meu_gerador/
  __init__.py               # exportar: from .meu_gerador import MeuGerador
  meu_gerador.py            # a classe geradora
  templates/                # Templates Jinja2
    output_template.py.j2

Copie a estrutura de um gerador simples existente (ex.: python_classes/).

Etapa 2: Implementar GeneratorInterface

# besser/generators/meu_gerador/meu_gerador.py
import os
from jinja2 import Environment, FileSystemLoader
from besser.generators import GeneratorInterface

class MeuGerador(GeneratorInterface):

    def __init__(self, model, output_dir: str = None):
        super().__init__(model, output_dir)

    def generate(self):
        """Gerar saída a partir do modelo B-UML."""
        templates_path = os.path.join(os.path.dirname(__file__), "templates")
        env = Environment(
            loader=FileSystemLoader(templates_path),
            trim_blocks=True,
            lstrip_blocks=True,
        )
        template = env.get_template("output_template.py.j2")
        output = template.render(
            classes=self.model.get_classes(),
            associations=self.model.associations,
        )
        file_path = self.build_generation_path("minha_saida.py")
        with open(file_path, "w", encoding="utf-8") as f:
            f.write(output)

Requisitos principais:

  • Chame super().__init__(model, output_dir) — isso configura self.model e self.output_dir.
  • Use self.build_generation_path(nome_arquivo) para obter o caminho correto do arquivo de saída.
  • Use self.build_generation_dir() se precisar apenas do caminho do diretório.
  • Os templates Jinja2 devem estar em um subdiretório templates/ junto ao gerador.
  • A saída deve ser determinística — o mesmo modelo produz a mesma saída todas as vezes (sem timestamps, valores aleatórios, etc.).
  • Helpers reutilizáveis vão em besser/utilities/, não no gerador.

Etapa 3: Escrever Templates Jinja2

{# besser/generators/meu_gerador/templates/output_template.py.j2 #}
# Gerado por BESSER MeuGerador
{% for cls in classes %}
class {{ cls.name }}:
    {% for attr in cls.attributes %}
    {{ attr.name }}: {{ attr.type.name }}
    {% endfor %}

{% endfor %}

Se for gerar JSX/React, use delimitadores não padrão para evitar conflitos:

env = Environment(
    loader=FileSystemLoader(templates_path),
    variable_start_string="[[",
    variable_end_string="]]",
)

Etapa 4: Registrar no Backend do Editor Web

Adicione seu gerador em besser/utilities/web_modeling_editor/backend/config/generators.py:

from besser.generators.meu_gerador import MeuGerador

GERADORES = {
    # ... geradores existentes ...
    "meu_gerador": InformacaoGerador(
        generator_class=MeuGerador,
        output_type="file",           # "file" para arquivo único, "zip" para múltiplos arquivos
        file_extension=".py",         # extensão do arquivo de saída
        category="minha_categoria",   # rótulo de agrupamento
        requires_class_diagram=True,   # True se precisar de um DomainModel
    ),
}

Também atualize get_filename_for_generator() no mesmo arquivo se o gerador produzir um nome de arquivo específico.

Etapa 5: Escrever Testes

Crie tests/generators/meu_gerador/test_meu_gerador.py:

import os
import shutil
import pytest
from besser.BUML.metamodel.structural import (
    DomainModel, Class, Property, BinaryAssociation,
    Multiplicity, StringType, IntegerType,
)
from besser.generators.meu_gerador import MeuGerador


@pytest.fixture
def domain_model():
    """Construir um modelo de teste pequeno."""
    prop_nome = Property(name="nome", type=StringType)
    prop_idade = Property(name="idade", type=IntegerType)
    pessoa = Class(name="Pessoa", attributes={prop_nome, prop_idade})
    model = DomainModel(name="ModeloTeste", types={pessoa})
    return model


@pytest.fixture
def output_dir(tmp_path):
    return str(tmp_path)


def test_gerar_cria_arquivo_saida(domain_model, output_dir):
    gen = MeuGerador(model=domain_model, output_dir=output_dir)
    gen.generate()
    assert os.path.exists(os.path.join(output_dir, "minha_saida.py"))


def test_gerar_contem_nome_classe(domain_model, output_dir):
    gen = MeuGerador(model=domain_model, output_dir=output_dir)
    gen.generate()
    with open(os.path.join(output_dir, "minha_saida.py")) as f:
        conteudo = f.read()
    assert "Pessoa" in conteudo
    assert "nome" in conteudo
    assert "idade" in conteudo

Padrões de teste usados em todo o código:

  • Use a fixture tmp_path ou tmpdir para diretórios de saída (limpos automaticamente).
  • Construa modelos inline pequenos como fixtures — não dependa de arquivos externos.
  • Teste tanto a estrutura (arquivos existem, nomes de classe presentes) quanto o conteúdo (lógica de negócios).
  • Para geradores que produzem Python importável, use importlib para importar e testar dinamicamente o código gerado.
  • Limpe com shutil.rmtree() se não estiver usando fixtures tmp do pytest.

Etapa 6: Documentar

Adicione documentação em docs/source/generators/meu_gerador.rst:

MeuGerador
==========

O MeuGerador produz ... a partir de um modelo de domínio B-UML.

Pré-requisitos
--------------

- BESSER instalado
- ...

Uso
----

.. code-block:: python

   from besser.generators.meu_gerador import MeuGerador

   gen = MeuGerador(model=meu_modelo, output_dir="./saida")
   gen.generate()

Saída
-----

O gerador produz um único arquivo ``minha_saida.py`` contendo ...

Adicione-o ao índice de geradores em docs/source/generators.rst.


Adicionando um Novo Metamodelo / Sub-DSL

Etapa 1: Projetar o Metamodelo

Crie novas classes em besser/BUML/metamodel/sua_dsl/:

besser/BUML/metamodel/sua_dsl/
  __init__.py
  sua_dsl.py    # classes do metamodelo

Siga padrões existentes:

  • Estenda NamedElement ou Element como classes base.
  • Use propriedades privadas com validação getter/setter.
  • Mantenha nomenclatura consistente com pacotes de metamodelo existentes.

Etapa 2: Adicionar Conversores (se necessário integração com editor web)

Os conversores traduzem entre JSON do frontend e objetos B-UML:

besser/utilities/web_modeling_editor/backend/services/converters/
  json_to_buml/process_sua_dsl.py    # JSON → BUML
  buml_to_json/sua_dsl_to_json.py    # BUML → JSON

Os conversores devem ser simétricos: qualquer recurso suportado em uma direção deve funcionar na outra. Teste ida e volta: JSON → BUML → JSON deve produzir o original.

Etapa 3: Adicionar Validação

Se o metamodelo tiver restrições além do que os setters impõem:

def validar(self, raise_exception=True):
    erros = []
    avisos = []
    # Verificar regras estruturais
    if alguma_condicao_ruim:
        erros.append("Mensagem de erro descritiva")
    resultado = {"success": len(erros) == 0, "errors": erros, "warnings": avisos}
    if raise_exception and erros:
        raise ValueError("\n".join(erros))
    return resultado

Etapa 4: Conectar ao Backend

  • Adicione endpoint(s) em besser/utilities/web_modeling_editor/backend/backend.py.
  • Adicione modelos de requisição/resposta Pydantic em backend/models/.
  • Adicione rota de validação sob /validate-diagram se aplicável.

Etapa 5: Escrever Testes

Coloque testes em tests/BUML/metamodel/sua_dsl/:

  • Testes de construção de modelo válido.
  • Testes de modelo inválido (espera ValueError, TypeError).
  • Testes de conversor ida e volta, se aplicável.

Etapa 6: Documentar

  • Documentação do metamodelo: docs/source/buml_language/sua_dsl.rst
  • Adicione ao índice docs/source/buml_language.rst.

Testes

Executar Todos os Testes

python -m pytest

Executar Testes Específicos

# Por diretório
python -m pytest tests/generators/sqlalchemy/

# Por palavra-chave
python -m pytest -k "test_django"

# Com saída verbosa
python -m pytest -v tests/BUML/metamodel/structural/

# Parar na primeira falha
python -m pytest -x

Convenções de Teste

  • Arquivos de teste: test_*.py
  • Funções de teste: test_*
  • Use @pytest.fixture para modelos e diretórios reutilizáveis.
  • Use tmp_path para diretórios de saída (limpos automaticamente pelo pytest).
  • Afirme conteúdo específico, não apenas a existência do arquivo.
  • Teste condições de erro com pytest.raises(ValueError).

O que Testar

Para alterações no metamodelo: validação de construção, restrições de setter, erros esperados para entrada inválida, resultados de validar().

Para geradores: existência do arquivo de saída, conteúdo chave na saída (nomes de classe, mapeamentos de relacionamento), casos de borda (modelo vazio, herança profunda, muitos-para-muitos).

Para conversores: fidelidade de ida e volta (JSON → BUML → JSON deve ser equivalente).


Construindo Documentação

cd docs

# Windows:
make.bat html

# macOS/Linux:
make html

# Visualizar:
# Abra docs/build/html/index.html no seu navegador

A documentação usa Sphinx com o tema Furo. Os arquivos fonte são reStructuredText ( .rst) em docs/source/.

Estrutura da Doc

CaminhoContém
docs/source/buml_language/Documentação do metamodelo
docs/source/generators/Documentação do gerador
docs/source/web_editor.rstDocumentação da API do editor web
docs/source/utilities/Documentação de utilitários
docs/source/contributing/Guias do contribuidor
docs/source/releases/Notas de versão
docs/source/_static/Imagens e recursos compartilhados
docs/source/img/Diagramas e capturas de tela

Referências Cruzadas

Use papéis Sphinx para links cruzados:

  • :doc:\generators/django`` — link para outra página de documentação
  • :mod:\besser.generators.django`` — link para a API do módulo
  • :class:\besser.BUML.metamodel.structural.Class`` — link para a API da classe
  • :ref:\nome-do-rotulo`` — link para uma seção rotulada

Estilo de Código

  • PEP 8 com indentação de 4 espaços.
  • Limite de linha de 120 caracteres (configurado em pyproject.toml sob [tool.pylint.'FORMAT']).
  • Type hints para APIs públicas.
  • Docstrings PEP 257.
  • Ordem de importação: biblioteca padrão, terceiros, módulos locais.
  • Funções/variáveis snake_case, classes PascalCase, constantes UPPER_CASE.
  • Sem imports curinga, sem re-exportações implícitas.
  • Linting: pylint (sem hooks ruff/black/pre-commit atualmente configurados).

Convenções de Commit e PR

Mensagens de Commit

Use Commits Convencionais:

feat: adicionar gerador Terraform para AWS EKS
fix: corrigir análise de multiplicidade para associações 0..*
refactor: extrair helpers de template compartilhados para besser.utilities
docs: documentar uso do QiskitGenerator
test: adicionar testes de ida e volta para conversor de modelo GUI

Fluxo de Trabalho do Pull Request

  1. Crie um branch de tópico: git checkout -b feature/adicionar-meu-gerador.
  2. Faça commits focados e logicamente agrupados.
  3. Execute testes localmente: python -m pytest.
  4. Construa documentação: cd docs && make html.
  5. Rebase no master mais recente: git fetch origin && git rebase origin/master.
  6. Faça push e abra PR contra master.
  7. Preencha o template do PR: descrição, testes executados, contexto extra.
  8. Duas aprovações de mantenedor necessárias para merge (uma aprovação suficiente após 14 dias).

Alterações Entre Repositórios (BESSER + Frontend)

Quando alterações afetam tanto o BESSER quanto o frontend do editor web:

  1. Implemente e comite alterações do WME no repositório WME.
  2. Implemente alterações do BESSER neste repositório.
  3. Atualize o ponteiro do submódulo:
    cd besser/utilities/web_modeling_editor/frontend
    git fetch && git checkout <commit>
    cd ../../../..
    git add besser/utilities/web_modeling_editor/frontend
    
  4. Vincule os dois PRs para que os revisores façam merge na ordem correta.

CI / Release

  • CI: Não há fluxo de trabalho automatizado de testes — os testes são executados localmente antes dos PRs.
  • Release: Acionado ao criar um GitHub Release. O fluxo de trabalho python-publish.yml constrói e publica no PyPI usando PYPI_API_TOKEN.
  • Versão: Definida em setup.cfg sob [metadata] version.
  • Notas de versão: Adicionadas como arquivos RST em docs/source/releases/.

Armadilhas Comuns de Contribuição

  1. Não duplique lógica — helpers compartilhados vão em besser/utilities/, não em geradores individuais.
  2. Mantenha determinismo — geradores devem produzir saída idêntica para entrada idêntica.
  3. Mantenha conversores simétricos — se JSON → BUML suporta um recurso, BUML → JSON deve também.
  4. Atualize a documentação — qualquer alteração no backend provavelmente precisa de atualizações em docs/source/.
  5. Não mexa no submódulo do frontend a menos que explicitamente necessário. Mudanças na UI vão para o repositório WME upstream.
  6. Limpe recursos — sempre use try/finally para diretórios temporários e manipuladores de arquivo.
  7. Teste ida e volta — especialmente para conversores (JSON → BUML → JSON deve ser identidade).

Habilidades Relacionadas