yongol — A quilha do SaaS programado com IA Imagem: Gerada por IA

Se a IA continua sobrescrevendo seu código, se o vibe coding colapsou em 200 endpoints, se você quer mudar o alvo de trabalho da IA do código para especificações — yongol é essa quilha.

O 200.o endpoint

Você constrói um SaaS com vibe coding. No início é rápido. 5 tabelas, 12 endpoints — vinte minutos e funciona.

Mas passados 50 endpoints, algo estranho acontece. A IA produz hoje um padrão que contradiz o de ontem. Passados 100, funcionalidades existentes quebram silenciosamente. Passados 200, adicionar uma única funcionalidade custa 10 vezes o que custaram as primeiras dez.

O relatório DORA 2025 demonstrou isso empiricamente — ferramentas de IA aumentam a produtividade em 2-18%, mas simultaneamente aumentam a taxa de falha de mudanças e o retrabalho[1]. A IA é um “espelho e multiplicador” que amplifica as fraquezas dos processos existentes.

Não é que o modelo seja burro.


Decisões e implementação

Três coisas estão emaranhadas no código-fonte:

  • Decisões do usuário — esta coluna é BIGINT, este endpoint é somente para o proprietário, a paginação é por cursor.
  • Lógica de negócio — precificação, fluxos de trabalho, regras de ciclo de vida.
  • Detalhes de implementação — nomes de variáveis, ordem de chamadas de bibliotecas, encapsulamento de erros.

Quando a IA lê este código, não consegue distinguir qual linha é uma decisão e qual é um detalhe. Então, quando “refatora” ou “limpa”, sobrescreve silenciosamente decisões que confundiu com detalhes. O usuário só percebe depois que o comportamento já está errado. Em 1972, Parnas disse “esconda decisões de design propensas a mudança atrás de interfaces”[2] — ele falava para humanos. Mas agora que a IA edita código, a menos que a distinção entre decisões e detalhes exista no próprio meio, ninguém — humano ou modelo — consegue mantê-la.

Esta é a razão pela qual o vibe coding colapsa em 200 endpoints. Um modelo maior não resolve. O meio — código bruto — simplesmente não preserva decisões. Todos os modelos eventualmente batem na mesma parede.


A quilha

A quilha é o primeiro osso colocado ao construir um navio. Ela suporta o peso do casco, previne o balanço lateral, e toda outra estrutura é construída sobre ela. Um navio construído sem quilha flutua em águas calmas mas se deforma quando as ondas chegam.

Um SaaS construído com vibe coding é igual. Flutua quando é pequeno. Se deforma quando cresce.

yongol é a quilha do SaaS programado com IA.

Harness with reins — não um modelo maior, mas rédeas mais precisas. Um validador determinístico julga cada artefato, uma catraca impõe progresso, e a máquina decide se o trabalho está feito.


Mover decisões para fora do código

O núcleo do yongol é simples. Separar decisões do código.

Dez especificações declarativas (SSOTs) lidam cada uma com uma única responsabilidade:

SSOTResponsabilidade
features.yamlCatálogo de funcionalidades — o que construir
manifest.yamlConfiguração do projeto — autenticação, middleware, infraestrutura
OpenAPIContrato API — rotas, parâmetros, respostas
SQL DDL + sqlcModelo de dados — tabelas, colunas, restrições, consultas
SSaCFluxo de serviço — sequência de decisões dentro de um endpoint
RegoAutorização — quem pode fazer o quê
Mermaid stateDiagramTransições de estado — ciclos de vida de entidades
FuncSpecFunções personalizadas — lógica que não pode ser expressa como CRUD
HurlCenários de teste — tricotomia smoke, scenario, invariant
STMLFrontend — Semantic Template Markup Language (HTML baseado em atributos data-*)

Oito das dez são padrões da indústria (OpenAPI, SQL, sqlc, Rego, Mermaid, Hurl, YAML). Apenas SSaC e STML são DSLs criados pelo yongol. O que a IA precisa aprender do zero é minimizado.

Cada SSOT contém apenas decisões. Nenhum detalhe de implementação. A IA edita SSOTs; yongol generate renderiza código a partir deles. Decisões vivem permanentemente nos SSOTs; o código é uma projeção descartável.


Impondo consistência

Decisões estão agora distribuídas em dez arquivos, então contradições podem surgir. DDL diz BIGINT mas OpenAPI diz string? SSaC declara @auth mas Rego não tem regra correspondente? O diagrama de estados tem uma transição mas SSaC não tem a função correspondente?

Um SSOT contraditório é uma decisão corrompida. Não importa quão limpo o código seja, se as decisões conflitam, o comportamento se desvia.

yongol validate captura isso.

✓ manifest        ✓ openapi_ddl       ✓ ssac_rego
✓ openapi         ✓ openapi_ssac      ✓ ssac_authz
✓ ddl             ✓ hurl_openapi      ✓ ssac_sqlc
✓ query           ✓ hurl_statemachine ✓ ddl_statemachine
✓ ssac            ✓ hurl_manifest     ✓ ddl_rego
✓ statemachine    ✓ openapi_manifest  ✓ rego_manifest
✓ rego            ✓ ssac_ddl          ✓ stml_openapi
✓ hurl            ✓ ssac_statemachine
✓ funcspec        ✓ ssac_func

0 errors, 0 warnings

Primeiro valida cada SSOT individualmente, depois executa verificações cruzadas entre camadas. ~287 regras inspecionam cada referência simbólica entre todos os dez SSOTs. Se existir uma única contradição, a compilação é recusada. A revisão sistemática da literatura de Torres et al.[3] observou que a maioria das ferramentas de gerenciamento de modelos lida apenas com a consistência dentro de um único modelo, deixando a verificação cruzada entre modelos heterogêneos como um problema aberto — yongol validate preenche exatamente essa lacuna.

A IA escreve livremente. Saia dos trilhos e validate captura instantaneamente. Liberdade nos trilhos.


yongol next — O comando catraca

Enquanto yongol validate mostra todos os erros de uma vez, yongol next mostra erros um de cada vez. Isto é a catraca.

$ yongol next specs/

[ERROR] DDL-003: users.id must be BIGINT, got INT
  file: specs/db/users.sql:2
  ▶ Fix this error. Then run `yongol next specs/`.

A única instrução que um agente de IA precisa é uma frase: “Execute yongol next specs/ e corrija erros até que sejam 0.”

Corrija o erro e o próximo aparece. Passe todos e para:

$ yongol next specs/

✓ All validations passed. 0 errors.

O agente não declara “terminei”. A máquina determina “ainda restam” ou “todos passaram”. O agente não tem autoridade sobre o julgamento de término.


Criação de projetos e gestão de funcionalidades

yongol init

Gera automaticamente o scaffolding SSOT a partir de features.yaml.

yongol init Myapp features.yaml "My workflow automation SaaS"
cd Myapp && yongol validate specs     # 0 errors

Manifest, stubs de operationId OpenAPI, arquivos stub SSaC, regras de autorização Rego, testes smoke Hurl e configuração sqlc são gerados de uma vez. O projeto começa em estado de yongol validate aprovado desde o início.

yongol features add / remove

Adicionar ou remover funcionalidades:

yongol features add new_features.yaml         # Gerar stubs SSaC para novos operationIds
yongol features remove ExportWorkflow --yes    # Excluir operationId + stubs SSaC

yongol import

Gerar pacotes cliente Go a partir de especificações OpenAPI externas (Stripe, GitHub, etc.):

yongol import https://api.stripe.com/openapi.yaml ./external/

Chamar funções geradas em SSaC com @call <pkg>.<Func>({...}).


operationId é a pedra angular

Como unir dez camadas? Com um único identificador PascalCase.

Insira o operationId ExecuteWorkflow:

── Feature Chain: ExecuteWorkflow ──

  OpenAPI    api/openapi.yaml                POST /workflows/{id}/execute
  SSaC       service/workflow/execute_workflow.ssac   @get @empty @auth @state @call @publish @response
  DDL        db/workflows.sql                CREATE TABLE workflows
  DDL        db/execution_logs.sql           CREATE TABLE execution_logs
  Rego       policy/authz.rego               resource: workflow
  StateDiag  states/workflow.md              diagram: workflow → ExecuteWorkflow
  FuncSpec   func/billing/check_credits.go   @func billing.CheckCredits
  FuncSpec   func/billing/deduct_credit.go   @func billing.DeductCredit
  FuncSpec   func/worker/process_actions.go  @func worker.ProcessActions
  FuncSpec   func/webhook/deliver.go         @func webhook.Deliver
  Hurl       tests/scenario-happy-path.hurl  scenario: scenario-happy-path.hurl

Da especificação API ao esquema do banco de dados, da política de autorização às transições de estado, das implementações de funções aos cenários de teste — a topologia completa de uma funcionalidade em uma tela. Dezenas de greps substituídos por um único comando.

operationId é a pedra angular porque em uma aplicação full-stack, a unidade de uma funcionalidade é o endpoint API. Um usuário pressiona um botão, uma API é chamada, e essa API atravessa todas as outras camadas. Um nome encadeia fisicamente dez camadas.


SSaC — Por que uma DSL personalizada

Oito dos 10 SSOTs do yongol são padrões da indústria. Apenas SSaC (Service Sequences as Code) e STML foram criados pelo yongol. SSaC captura decisões do fluxo de serviço.

A lacuna que SSaC preenche. Observe o espectro de ferramentas declarativas: em um extremo estão os padrões de contrato (OpenAPI, SQL, Rego) — declaram o quê mas não em que ordem. No outro extremo estão os runtimes de workflow (Temporal, Inngest, Restate) — esses são código. Decisões e detalhes de implementação se recombinam no mesmo arquivo. SSaC se posiciona na lacuna entre eles: “dentro de um único endpoint, o que acontece, em que ordem, com quais guardas.”

SSaC tem um total de 16 anotações. Aprendível com um manual de uma página.

Lista completa de anotações SSaC

AnotaçãoPapelFormato
@getLeitura DBType var = Model.Method({args})
@postCriação de linhaType var = Model.Method({args})
@putAtualização de linha (sem retorno)Model.Method({args})
@deleteExclusão de linhaModel.Method({args})
@emptyGuarda nil → 404var "message" [STATUS]
@existsGuarda not-nil → 409var "message" [STATUS]
@authVerificação de autorização"action" "resource" {inputs} "message" [STATUS]
@stateTransição de máquina de estadosdiagram {inputs} "transition" "message" [STATUS]
@callChamada de função[Type var =] pkg.Func({args})
@evalGuarda predicado (true → erro)pkg.Func({args}) "message" STATUS
@publishPublicação em fila"topic" {payload}
@subscribeFunção disparada por fila"topic"
@verify-passwordLogin (seguro contra timing)Model.col=source Model.hash vs source -> var STATUS "msg"
@responseRetorno JSON{ field: var, ... } ou var
@no-paginationIsenção de regra de paginação(nível de função)
@state-neutralIsenção de regra de máquina de estados(nível de função)

Exemplo SSaC — AcceptProposal

Autorização + máquinas de estado duplas + custódia + fila:

package service

import "github.com/org/project/internal/billing"

// @get Proposal p = Proposal.FindByID({ID: request.id})
// @empty p "Proposal not found" 404
// @get Gig gig = Gig.FindByID({ID: p.GigID})
// @empty gig "Gig not found" 404
// @auth "AcceptProposal" "gig" {ResourceID: request.id} "Forbidden" 403
// @state proposal {status: p.Status} "AcceptProposal" "Cannot accept" 409
// @state gig {status: gig.Status} "AcceptProposal" "Cannot accept on gig" 409
// @put Proposal.UpdateStatus({ID: p.ID, Status: "accepted"})
// @put Gig.AssignFreelancer({ID: gig.ID, FreelancerID: p.FreelancerID, Status: "in_progress"})
// @call billing.HoldEscrowResponse escrow = billing.HoldEscrow({GigID: gig.ID, Amount: gig.Budget})
// @publish "proposal.accepted" {GigID: gig.ID, FreelancerID: p.FreelancerID}
// @get Proposal updated = Proposal.FindByID({ID: p.ID})
// @response { proposal: updated }
func AcceptProposal() {}

16 linhas. 10 anotações. Duas máquinas de estado, autorização, custódia, evento de fila, resposta — cada decisão visível, cada detalhe ausente.


Benchmark: ZenFlow

ZenFlow — um SaaS de automação de workflows multi-tenant.

EtapaDescriçãoTempoAcumulado
Build inicial10 endpoints, 6 tabelas, auth, máquina de estados13 min13 min
+ Versionamentoclone de workflow, lista de versões6 min19 min
+ Webhookswebhook CRUD, backend de fila6 min25 min
+ Marketplace de templatespaginação por cursor, clone cross-org3 min28 min
+ Anexos de arquivorelatórios de execução, backend de arquivo4 min32 min
+ Agendamentoagendamento cron, backend de sessão6 min38 min
+ Logs de auditoriapaginação por offset, backend de cache3 min41 min
+ Dashboardjoins de relação, tipos de resposta func7 min48 min
+ Operações em loteinserção em massa jsonb14 min62 min
+ API externafunc geocodificação, adição de coluna3 min65 min
+ Atualização condicionalpadrão sentinela, atribuição automática4 min69 min

Final: 32 endpoints, 14 tabelas, 47 requisições Hurl. 11/11 etapas aprovadas.

Adicionar funcionalidades nunca desacelerou. Testes existentes nunca quebraram. A parede dos 200 endpoints não existiu.

Benchmark Opus 4.7 — 32 endpoints, 14 tabelas, 47 requisições Hurl, ~69 min. Benchmark Sonnet 4.6 — 32 endpoints, 9 tabelas, 37 requisições Hurl, ~43 min.


yongol agent

Um LLM corrige automaticamente arquivos SSOT através de um loop validate-fix.

yongol agent specs/ --model ollama:gemma4:e4b --max-rounds 20

Erros de validate são realimentados ao LLM, o LLM os corrige, e a validação roda novamente. O loop se repete até 0 erros. Funciona até com um modelo local de 4.5B (Gemma4).

Backends suportados: ollama (local), xai (Grok), gemini.


Pode-se editar o código gerado?

Sim. yongol generate preserva edições do usuário ao re-executar:

  • Cada arquivo gerado recebe uma anotação //yg:checked llm=yongol-gen hash=<8hex>.
  • Se o hash difere, o arquivo é marcado como preservado e pulado no próximo generate.
  • yongol status mostra arquivos preservados e deriva de contrato (erros PRV-01/PRV-02).
  • Para registrar a intenção, adicione //yg:preserve reason="..." (opcional). Para des-preservar, exclua o arquivo.

Funções e modelos integrados

Funções integradas (chamadas via @call em SSaC)

PacoteFunçãoDescrição
authhashPassword, verifyPasswordHash/verificação bcrypt
authissueToken, verifyToken, refreshTokenTokens JWT
authgenerateResetTokenRedefinição de senha
cryptoencrypt, decryptAES-256-GCM
cryptogenerateOTP, verifyOTPTOTP
storageuploadFile, deleteFile, presignURLS3
mailsendEmail, sendTemplateEmailSMTP
textgenerateSlug, sanitizeHTML, truncateTextProcessamento de texto
imageogImage, thumbnailGeração de imagens

Modelos integrados (configurados via manifest.yaml)

PacoteInterfaceBackendUso em SSaC
sessionSessionModel (Set/Get/Delete + TTL)PostgreSQL, Memorysession.Session.Get({key: ...})
cacheCacheModel (Set/Get/Delete + TTL)PostgreSQL, Memorycache.Cache.Set({key: ..., value: ..., ttl: ...})
fileFileModel (Upload/Download/Delete)S3, LocalFilefile.File.Upload({key: ..., body: ...})
queuesingleton Pub/Sub (Publish/Subscribe)PostgreSQL, Memory@publish "topic" {payload}

Geração automática de migrações DDL

yongol generate detecta alterações DDL e gera automaticamente arquivos de migração.

specs/db/
└── users.sql                         # SSOT — edite aqui

artifacts/db/
├── .latest_schema.sql                # Snapshot de referência
└── migrations/
    ├── 0001_initial.up.sql
    ├── 0001_initial.down.sql
    ├── 0002_add_users_email.up.sql
    └── 0002_add_users_email.down.sql

Alterações ambíguas (renomeação de colunas, casting de tipos, backfill NOT NULL) são desambiguadas com hints em comentários DDL (-- @rename, -- @cast, -- @backfill, -- @data_migration, -- @allow_destructive). Seis regras (MIG-001 a MIG-006) controlam alterações perigosas. A aplicação real no banco de dados é delegada a ferramentas padrão como golang-migrate, flyway, etc.


Por que um modelo maior não é a resposta

“GPT-6 vai resolver isso.”

Não vai. O problema não é a inteligência do modelo — é o meio.

Código como meio não distingue decisões de implementação. Qualquer modelo que leia o código vê texto onde decisões e detalhes estão entrelaçados. Não importa quão inteligente o modelo seja, se o meio não fornece a distinção, o modelo não pode fazê-la.

yongol muda o meio. Ele move o que a IA edita do código para especificações declarativas. Como as especificações contêm apenas decisões sem detalhes de implementação, a IA nunca pode confundir uma decisão com um detalhe. A sobrevivência das decisões torna-se independente do tamanho do modelo.

Um LLM pequeno editando apenas SSOTs, com validate fornecendo feedback preciso a cada erro, pode manter a mesma integridade de decisões que um modelo muito maior editando código bruto. yongol preenche essa lacuna.


Testes em tempo de execução

Testes Hurl são todos escritos pelo usuário. Escreva-os em specs/tests/ e yongol generate espelha em artifacts/tests/. Durante a validação, as regras XOH-01 a XOH-09 verificam cruzadamente Hurl contra OpenAPI, máquinas de estado e manifest.auth.

hurl --test --variable host=http://localhost:8080 artifacts/my-project/tests/*.hurl

Três categorias:

  • smoke.hurl — Testes smoke de endpoints
  • scenario-*.hurl — Testes de cenários de negócio
  • invariant-*.hurl — Testes de invariantes cross-endpoint

Estado atual

Geração de backend Go+Gin: Beta — funcional de ponta a ponta. Geração de frontend React: Alpha (em desenvolvimento).


Começar

Método 1: Instalar o Skill (Recomendado)

npx skills add park-jun-woo/yongol

Instale o skill yongol no seu agente de IA (Claude Code, Cursor, Copilot e mais). O agente aprende o fluxo de trabalho na instalação.

/yongol Construa um SaaS de tarefas multi-tenant com auth e CRUD.

Método 2: Instalação direta

Requer Go 1.25+ e gcc (dependência cgo: pg_query_go linka libpg_query para parsing DDL).

git clone https://github.com/park-jun-woo/yongol && cd yongol
make install
yongol validate examples/zenflow

0 errors, 0 warnings.

Aponte uma IA para estas especificações e diga para adicionar uma funcionalidade. validate traça os trilhos; a IA corre sobre eles. Não há parede.


Referências

  1. Google DORA Team. DORA State of AI-Assisted Software Development 2025. Google Cloud, 2025. dora.dev/dora-report-2025
  2. David L. Parnas. “On the Criteria to Be Used in Decomposing Systems into Modules.” Communications of the ACM 15(12): 1053-1058, 1972. doi:10.1145/361598.361623
  3. Weslley Torres, Mark G.J. van den Brand, Alexander Serebrenik. “A Systematic Literature Review of Cross-Domain Model Consistency Checking by Model Management Tools.” Software and Systems Modeling 20(3): 897-916, 2021. doi:10.1007/s10270-020-00834-1
  4. Deepak Babu Piskala. “Spec-Driven Development: From Code to Contract in the Age of AI Coding Assistants.” arXiv:2602.00180, January 2026. arxiv.org/abs/2602.00180
  5. Ehsani et al. “When AI Code Doesn’t Stick: An Empirical Study on Reverted Changes Introduced by AI Coding Agents.” MSR 2026 Mining Challenge, April 2026. 2026.msrconf.org
  6. Anton Jansen, Jan Bosch. “Software Architecture as a Set of Architectural Design Decisions.” EWSA 2005, LNCS 3527, Springer, 2005. semanticscholar.org
  7. Marco Brambilla, Jordi Cabot, Manuel Wimmer. Model-Driven Software Engineering in Practice. 2nd ed., Springer, 2017. doi:10.1007/978-3-031-02546-4
  8. GitClear. AI Copilot Code Quality 2025. February 2025. gitclear.com

Artigos relacionados

Código: github.com/park-jun-woo/yongol


Histórico de alterações

DataAlterações
2026-05-18Publicação inicial
2026-05-19Adicionado benchmark Opus. Atualizados 10 SSOTs
2026-05-21Sincronização README: atualização de benchmarks (Opus 32ep/14tbl/47hurl/69min, Sonnet 32ep/9tbl/37hurl/43min), adicionada declaração “Harness with reins”, adicionado exemplo SSaC (AcceptProposal), adicionado comando yongol agent, adicionado sistema Preserve, adicionada lista de funções/modelos integrados, adicionada geração automática de migrações DDL, adicionada descrição STML, adicionado link para artigo ifeval-ratchet
2026-05-26Sincronização v0.6.10: adicionado comando catraca yongol next, adicionados yongol init/features add/features remove criação e gestão de projetos, adicionado yongol import importação de OpenAPI externo, adicionada lista completa de anotações SSaC (16) (@eval, @subscribe, @verify-password, @no-pagination, @state-neutral), tricotomia de testes Hurl (smoke/scenario/invariant), seção de testes em tempo de execução, detalhe Preserve (códigos de erro PRV), expansão de hints de migração DDL (@data_migration, @allow_destructive, regras MIG), estado atual (Go+Gin Beta, React Alpha), instalação dividida em 2 métodos