yongol — La quille du SaaS code par IA Image : generee par IA

Si l’IA n’arrete pas d’ecraser votre code, si le vibe coding s’est effondre a 200 endpoints, si vous voulez deplacer la charge de travail de l’IA du code vers les specifications – yongol est cette quille.

Le 200e endpoint

Vous construisez un SaaS en vibe coding. Au debut, c’est rapide. 5 tables, 12 endpoints — vingt minutes et ca tourne.

Mais passe 50 endpoints, quelque chose d’etrange se produit. L’IA produit aujourd’hui un pattern qui contredit celui d’hier. Passe 100, les fonctionnalites existantes se cassent silencieusement. Passe 200, ajouter une seule fonctionnalite coute 10 fois ce qu’ont coute les dix premieres.

Le rapport DORA 2025 l’a demontre empiriquement — les outils d’IA augmentent le debit de 2-18%, mais augmentent simultanement le taux d’echec des changements et le retravail[1]. L’IA est un « miroir et multiplicateur » qui amplifie les faiblesses des processus existants.

Ce n’est pas que le modele est stupide.


Decisions et implementation

Trois choses sont entrelacees dans le code source :

  • Decisions utilisateur — cette colonne est BIGINT, cet endpoint est reserve au proprietaire, la pagination est par curseur.
  • Logique metier — tarification, workflows, regles de cycle de vie.
  • Details d’implementation — noms de variables, ordre des appels de bibliotheques, encapsulation d’erreurs.

Quand l’IA lit ce code, elle ne peut pas distinguer quelle ligne est une decision et laquelle est un detail. Alors quand elle « refactorise » ou « nettoie », elle ecrase silencieusement des decisions qu’elle a prises pour des details. L’utilisateur ne s’en rend compte qu’une fois le comportement deja fausse. En 1972, Parnas a dit « cachez les decisions de conception susceptibles de changer derriere des interfaces »[2] — il parlait aux humains. Mais maintenant que l’IA edite du code, a moins que la distinction entre decisions et details n’existe dans le medium lui-meme, personne — humain ou modele — ne peut la maintenir.

C’est pourquoi le vibe coding s’effondre a 200 endpoints. Un modele plus grand ne resout pas le probleme. Le medium — le code brut — ne preserve tout simplement pas les decisions. Chaque modele finit par heurter le meme mur.


La quille

La quille est le premier os pose lors de la construction d’un navire. Elle supporte le poids de la coque, empeche le roulis lateral, et toutes les autres structures sont construites dessus. Un navire construit sans quille flotte en eaux calmes mais se deforme quand les vagues arrivent.

Un SaaS construit en vibe coding, c’est pareil. Il flotte quand il est petit. Il se deforme quand il grandit.

yongol est la quille du SaaS code par IA.

Harness with reins — pas un modele plus grand, mais des renes plus precises. Un validateur deterministe juge chaque artefact, un cliquet impose la progression, et la machine decide si le travail est termine.


Sortir les decisions du code

Le coeur de yongol est simple. Separer les decisions du code.

Dix specifications declaratives (SSOT) gerent chacune une seule responsabilite :

SSOTResponsabilite
features.yamlCatalogue de fonctionnalites — quoi construire
manifest.yamlConfiguration du projet — authentification, middleware, infrastructure
OpenAPIContrat API — routes, parametres, reponses
SQL DDL + sqlcModele de donnees — tables, colonnes, contraintes, requetes
SSaCFlux de service — sequence de decisions a l’interieur d’un endpoint
RegoAutorisation — qui peut faire quoi
Mermaid stateDiagramTransitions d’etat — cycles de vie des entites
FuncSpecFonctions personnalisees — logique non exprimable en CRUD
HurlScenarios de test — trichotomie smoke, scenario, invariant
STMLFrontend — Semantic Template Markup Language (HTML base sur les attributs data-*)

Huit sur dix sont des standards industriels (OpenAPI, SQL, sqlc, Rego, Mermaid, Hurl, YAML). Seuls SSaC et STML sont des DSL crees par yongol. Ce que l’IA doit apprendre de zero est minimise.

Chaque SSOT ne contient que des decisions. Aucun detail d’implementation. L’IA edite les SSOT ; yongol generate produit le code a partir d’eux. Les decisions vivent en permanence dans les SSOT ; le code est une projection jetable.


Imposer la coherence

Les decisions sont maintenant reparties dans dix fichiers, donc des contradictions peuvent apparaitre. Le DDL dit BIGINT mais OpenAPI dit string ? SSaC declare @auth mais Rego n’a pas de regle correspondante ? Le diagramme d’etats a une transition mais SSaC n’a pas la fonction correspondante ?

Un SSOT contradictoire est une decision corrompue. Peu importe la proprete du code, si les decisions sont en conflit, le comportement devie.

yongol validate attrape cela.

✓ 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

Il valide d’abord chaque SSOT individuellement, puis effectue des verifications croisees entre couches. ~287 regles inspectent chaque reference symbolique parmi les dix SSOT. Si une seule contradiction existe, la compilation est refusee. La revue systematique de la litterature de Torres et al.[3] a note que la plupart des outils de gestion de modeles ne traitent que la coherence intra-modele, laissant la verification croisee entre modeles heterogenes comme un probleme ouvert — yongol validate comble precisement cette lacune.

L’IA ecrit librement. Elle sort des rails, validate l’attrape instantanement. Liberte sur rails.


yongol next — La commande cliquet

Alors que yongol validate montre toutes les erreurs d’un coup, yongol next montre les erreurs une par une. C’est le cliquet.

$ 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/`.

La seule instruction dont un agent IA a besoin est une phrase : « Execute yongol next specs/ et corrige les erreurs jusqu’a ce qu’il y en ait 0. »

Corrige l’erreur, la suivante apparait. Passe-les toutes et ca s’arrete :

$ yongol next specs/

✓ All validations passed. 0 errors.

L’agent ne declare pas « j’ai fini ». La machine prononce « il en reste » ou « tout est passe ». L’agent n’a pas autorite sur le jugement de terminaison.


Creation de projet et gestion des fonctionnalites

yongol init

Genere automatiquement l’echafaudage SSOT a partir de features.yaml.

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

Manifest, stubs d’operationId OpenAPI, fichiers stub SSaC, regles d’autorisation Rego, tests smoke Hurl et configuration sqlc sont generes en une fois. Le projet demarre en etat de reussite yongol validate des le depart.

yongol features add / remove

Ajouter ou supprimer des fonctionnalites :

yongol features add new_features.yaml         # Generer des stubs SSaC pour les nouveaux operationIds
yongol features remove ExportWorkflow --yes    # Supprimer operationId + stubs SSaC

yongol import

Generer des packages client Go a partir de specs OpenAPI externes (Stripe, GitHub, etc.) :

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

Appeler les fonctions generees dans SSaC avec @call <pkg>.<Func>({...}).


operationId est la cle de voute

Comment lier dix couches ensemble ? Avec un seul identifiant PascalCase.

Entrez l’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

De la spec API au schema de base de donnees, de la politique d’autorisation aux transitions d’etat, des implementations de fonctions aux scenarios de test — la topologie complete d’une fonctionnalite sur un seul ecran. Des dizaines de grep remplaces par une seule commande.

operationId est la cle de voute parce que dans une application full-stack, l’unite d’une fonctionnalite est l’endpoint API. Un utilisateur appuie sur un bouton, une API est appelee, et cette API traverse toutes les autres couches. Un nom chaine physiquement dix couches.


SSaC — Pourquoi un DSL personnalise

Huit des 10 SSOT de yongol sont des standards industriels. Seuls SSaC (Service Sequences as Code) et STML ont ete crees par yongol. SSaC capture les decisions de flux de service.

Le vide que SSaC comble. Regardez le spectre des outils declaratifs : a une extremite se trouvent les standards de contrat (OpenAPI, SQL, Rego) — ils declarent quoi mais pas dans quel ordre. A l’autre extremite se trouvent les runtimes de workflow (Temporal, Inngest, Restate) — ce sont du code. Decisions et details d’implementation se recombinent dans le meme fichier. SSaC s’assoit dans le vide entre les deux : « a l’interieur d’un seul endpoint, que se passe-t-il, dans quel ordre, avec quels gardes. »

SSaC a un total de 16 annotations. Maitrisable avec un manuel d’une page.

Liste complete des annotations SSaC

AnnotationRoleFormat
@getLecture DBType var = Model.Method({args})
@postCreation de ligneType var = Model.Method({args})
@putMise a jour de ligne (sans retour)Model.Method({args})
@deleteSuppression de ligneModel.Method({args})
@emptyGarde nil → 404var "message" [STATUS]
@existsGarde not-nil → 409var "message" [STATUS]
@authVerification d’autorisation"action" "resource" {inputs} "message" [STATUS]
@stateTransition de machine d’etatsdiagram {inputs} "transition" "message" [STATUS]
@callAppel de fonction[Type var =] pkg.Func({args})
@evalGarde predicat (true → erreur)pkg.Func({args}) "message" STATUS
@publishPublication dans file"topic" {payload}
@subscribeFonction declenchee par file"topic"
@verify-passwordLogin (securise contre timing)Model.col=source Model.hash vs source -> var STATUS "msg"
@responseRetour JSON{ field: var, ... } ou var
@no-paginationExemption de regle de pagination(niveau fonction)
@state-neutralExemption de regle de machine d’etats(niveau fonction)

Exemple SSaC — AcceptProposal

Autorisation + double machine d’etats + sequestre + file :

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 lignes. 10 annotations. Deux machines d’etats, autorisation, sequestre, evenement de file, reponse — chaque decision visible, chaque detail absent.


Benchmark : ZenFlow

ZenFlow — un SaaS d’automatisation de workflows multi-tenant.

EtapeDescriptionTempsCumule
Build initial10 endpoints, 6 tables, auth, machine d’etats13 min13 min
+ Versionnementclone de workflow, liste de versions6 min19 min
+ Webhookswebhook CRUD, backend de file6 min25 min
+ Marketplace de templatespagination curseur, clone cross-org3 min28 min
+ Pieces jointesrapports d’execution, backend fichier4 min32 min
+ Planificationplanification cron, backend session6 min38 min
+ Journaux d’auditpagination offset, backend cache3 min41 min
+ Tableau de bordjoins de relation, types de reponse func7 min48 min
+ Operations par lotsinsertion en masse jsonb14 min62 min
+ API externefunc geocodage, ajout de colonne3 min65 min
+ Mise a jour conditionnellepattern sentinelle, attribution auto4 min69 min

Final : 32 endpoints, 14 tables, 47 requetes Hurl. 11/11 etapes reussies.

L’ajout de fonctionnalites n’a jamais ralenti. Les tests existants ne se sont jamais casses. Le mur des 200 endpoints n’existait pas.

Benchmark Opus 4.7 — 32 endpoints, 14 tables, 47 requetes Hurl, ~69 min. Benchmark Sonnet 4.6 — 32 endpoints, 9 tables, 37 requetes Hurl, ~43 min.


yongol agent

Un LLM corrige automatiquement les fichiers SSOT via une boucle validate-fix.

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

Les erreurs de validate sont renvoyees au LLM, le LLM les corrige, et la validation s’execute a nouveau. La boucle se repete jusqu’a 0 erreurs. Fonctionne meme avec un modele local de 4.5B (Gemma4).

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


Peut-on editer le code genere

Oui. yongol generate preserve les modifications utilisateur lors de la re-execution :

  • Chaque fichier genere porte une annotation //yg:checked llm=yongol-gen hash=<8hex>.
  • Si le hash differe, le fichier est marque comme preserved et ignore lors du prochain generate.
  • yongol status montre les fichiers preserves et la derive de contrat (erreurs PRV-01/PRV-02).
  • Pour enregistrer l’intention, ajoutez //yg:preserve reason="..." (optionnel). Pour annuler la preservation, supprimez le fichier.

Fonctions et modeles integres

Fonctions integrees (appelees via @call dans SSaC)

PackageFonctionDescription
authhashPassword, verifyPasswordHachage/verification bcrypt
authissueToken, verifyToken, refreshTokenJetons JWT
authgenerateResetTokenReinitialisation de mot de passe
cryptoencrypt, decryptAES-256-GCM
cryptogenerateOTP, verifyOTPTOTP
storageuploadFile, deleteFile, presignURLS3
mailsendEmail, sendTemplateEmailSMTP
textgenerateSlug, sanitizeHTML, truncateTextTraitement de texte
imageogImage, thumbnailGeneration d’images

Modeles integres (configures via manifest.yaml)

PackageInterfaceBackendUsage 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}

Generation automatique de migrations DDL

yongol generate detecte les changements DDL et genere automatiquement des fichiers de migration.

specs/db/
└── users.sql                         # SSOT — editez ici

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

Les changements ambigus (renommage de colonnes, casting de types, backfill NOT NULL) sont desambiguises avec des hints en commentaire DDL (-- @rename, -- @cast, -- @backfill, -- @data_migration, -- @allow_destructive). Six regles (MIG-001 a MIG-006) controlent les changements dangereux. L’application reelle a la base de donnees est deleguee a des outils standards comme golang-migrate, flyway, etc.


Pourquoi un modele plus grand n’est pas la reponse

« GPT-6 reglera ca. »

Non. Le probleme n’est pas l’intelligence du modele — c’est le medium.

Le code comme medium ne distingue pas les decisions de l’implementation. Quel que soit le modele qui lit le code, il voit du texte ou decisions et details sont entrelaces. Aussi intelligent soit le modele, si le medium ne fournit pas la distinction, le modele ne peut pas la faire.

yongol change le medium. Il deplace ce que l’IA edite du code vers des specifications declaratives. Comme les specifications ne contiennent que des decisions sans details d’implementation, l’IA ne peut jamais confondre une decision avec un detail. La survie des decisions devient independante de la taille du modele.

Un petit LLM editant uniquement les SSOT, avec validate fournissant un feedback precis a chaque erreur, peut maintenir la meme integrite decisionnelle qu’un modele beaucoup plus grand editant du code brut. yongol comble cet ecart.


Tests d’execution

Les tests Hurl sont tous ecrits par l’utilisateur. Ecrivez-les dans specs/tests/ et yongol generate les recopie dans artifacts/tests/. Lors de la validation, les regles XOH-01 a XOH-09 verifient Hurl de maniere croisee contre OpenAPI, les machines d’etats et manifest.auth.

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

Trois categories :

  • smoke.hurl — Tests smoke des endpoints
  • scenario-*.hurl — Tests de scenarios metier
  • invariant-*.hurl — Tests d’invariants cross-endpoint

Etat actuel

Generation backend Go+Gin : Beta — fonctionnel de bout en bout. Generation frontend React : Alpha (en cours de developpement).


Commencer

Methode 1 : Installer le Skill (Recommande)

npx skills add park-jun-woo/yongol

Installez le skill yongol dans votre agent IA (Claude Code, Cursor, Copilot et plus). L’agent apprend le workflow a l’installation.

/yongol Construis un SaaS de taches multi-tenant avec auth et CRUD.

Methode 2 : Installation directe

Necessite Go 1.25+ et gcc (dependance cgo : pg_query_go lie libpg_query pour le parsing DDL).

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

0 errors, 0 warnings.

Pointez une IA sur ces specifications et dites-lui d’ajouter une fonctionnalite. validate pose les rails ; l’IA court dessus. Il n’y a pas de mur.


References

  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

Articles lies

Code : github.com/park-jun-woo/yongol


Historique des modifications

DateModifications
2026-05-18Publication initiale
2026-05-19Ajout du benchmark Opus. Mise a jour des 10 SSOT
2026-05-21Synchronisation README : mise a jour des benchmarks (Opus 32ep/14tbl/47hurl/69min, Sonnet 32ep/9tbl/37hurl/43min), ajout de la declaration “Harness with reins”, ajout de l’exemple SSaC (AcceptProposal), ajout de la commande yongol agent, ajout du systeme Preserve, ajout de la liste des fonctions/modeles integres, ajout de la generation automatique de migrations DDL, ajout de la description STML, ajout du lien vers l’article ifeval-ratchet
2026-05-26Synchronisation v0.6.10 : ajout de la commande cliquet yongol next, ajout de yongol init/features add/features remove creation et gestion de projet, ajout de yongol import importation OpenAPI externe, ajout de la liste complete des annotations SSaC (16) (@eval, @subscribe, @verify-password, @no-pagination, @state-neutral), trichotomie des tests Hurl (smoke/scenario/invariant), section tests d’execution, detail Preserve (codes d’erreur PRV), expansion des hints de migration DDL (@data_migration, @allow_destructive, regles MIG), etat actuel (Go+Gin Beta, React Alpha), installation divisee en 2 methodes

Journal des modifications

  • 2026-05-18: Version initiale