Communitygithub.com

yosegi-dev/yosegi

Assemblage piloté par agent d'écrans à partir de vos composants Storybook existants — CLI, serveur MCP et compétence Agent. Sans interface graphique.

Qu'est-ce que yosegi ?

Yosegi est une compétence d'agent qui transforme les composants d'un projet hôte en faits exploitables pour construire un écran, puis émet cet écran sous la forme d'une Story CSF (Component Story Format) ou d'un composant React standard. Elle n'a ni environnement de rendu ni interface graphique propre : vous vérifiez le rendu dans le Storybook de l'hôte. La compétence s'appuie sur un registre qui est la source de vérité pour les props réelles des composants (noms, options d'énumération, props requises, signatures de fonctions), évitant les défauts liés à des suppositions erronées sur l'API d'un composant. Elle supporte les plateformes via CLI (`npx yosegi`), outils MCP équivalents, et peut être utilisée comme compétence autonome pour un agent. Le processus comprend la construction du registre (étape 1), l'inspection des composants (étape 2), la génération de l'écran (étape 3) et la validation dans Storybook (étape 4). L'utilisation d'un registre obsolète est dangereuse et doit être évitée en vérifiant son état avec `yosegi registry status`.

Compatible avec✓Claude Code~Codex CLI~Cursor
npx skills add yosegi-dev/yosegi

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Yosegi — construire des écrans à partir des composants d'un hôte

Version : 2026-08-13. Un harnais d'agent peut charger une copie obsolète d'une compétence sans le dire. Si cette date est plus ancienne que celle du fichier skills/yosegi/SKILL.md du dépôt, vous lisez une copie périmée — réinstallez-la avant de continuer.

Yosegi transforme les composants d'un projet hôte en faits que vous pouvez utiliser pour construire un écran, et émet l'écran sous la forme d'une Story (CSF) pour examen avant toute implémentation. Il n'a ni environnement de rendu ni interface graphique propre ; vous vérifiez le rendu dans le Storybook de l'hôte. Sur un hôte sans Storybook, le livrable devient un simple fichier de composant React (--target component) — la branche de l'étape 1 ci-dessous explique comment la procédure change.

Ce document est la procédure, et c'est vous qui l'exécutez. La CLI (et les outils MCP équivalents) sont les instruments qu'elle utilise.

Quand l'utiliser

  • Composer une proposition d'écran ou une maquette UI à partir d'un système de design existant, sous une forme révisable.
  • Obtenir une première ébauche d'un nouvel écran visible dans Storybook avant de l'implémenter.
  • Rechercher les composants disponibles chez un hôte, et leurs props réelles, avant d'écrire du code UI.
  • Transcrire une maquette Story approuvée en une vraie page. Effectuez les étapes 1 et 2, puis passez à l'étape 5.

Ne convient pas pour : des modifications ponctuelles de composants.

Où se trouve la valeur

Le registre a un rôle précis : il est la source de vérité pour les props d'un composant — les vrais noms de props, les vraies options d'énumération, celles qui sont obligatoires, celles qui sont des slots par rapport aux children, la signature d'une prop fonction. Les composants d'un hôte ne sont pas la bibliothèque dont ils sont issus. Leurs énumérations de variantes ont été renommées, leurs échelles de taille diffèrent entre frères, une prop icône prend une référence de composant plutôt qu'un élément, une prop ReactNode est un slot nommé plutôt que des children, et trois composants différents partagent un même nom d'exportation. Rien de tout cela n'est déduisible d'une connaissance de React ou de la bibliothèque en amont, et chacun de ces éléments est un défaut que vous livrerez si vous écrivez la prop que vous attendez au lieu de la prop que le registre indique comme existante. C'est à cela que servent les appels inspect des étapes 1 et 2, et les sauter est la façon dont une maquette plausible livre un défaut.

Le registre ne vous donne pas le squelette de l'écran, l'idiome de composition ou la mise en page — l'appel de hook de bibliothèque de grille qui pilote un DataGrid, un meta spécifique à l'hôte tel que { stickyHeader: true }, le wrapper qu'un composant attend autour de lui. Cela provient des Stories propres de l'hôte et, sur un hôte avec un générateur de page/route, de ses modèles d'exemple (étape 2). Plus la couverture des modèles et des Stories de l'hôte est riche, plus la part du registre dans ce dont vous avez réellement besoin pour construire l'écran est petite — et ce n'est pas un manque. Le registre et les propres exemples de l'hôte répondent à des questions différentes, et les deux sont essentiels pour la question à laquelle ils répondent.

Références

Ouvrez-les lorsque l'étape ci-dessous vous y envoie, pas par avance. Sur la route 3a (écrire la Story directement), cela peut ne jamais être nécessaire : la sortie de registry status et component inspect plus le corps de ce fichier sont généralement suffisamment explicites pour construire l'écran entier. Une fois que vous en avez besoin, cependant, travaillez à partir de ce fichier et non de votre seule mémoire — ses détails ne sont pas répétés ici.

FichierQuand le lire
references/registry.mdLorsque la sortie de inspect contient quelque chose que vous ne pouvez pas interpréter — une ligne shape: / signature: d'une prop opaque, une prop non documentée, un spécificateur d'import qui semble erroné
references/cli.mdLorsqu'une commande ou un indicateur n'est pas couvert ci-dessus, que la CLI ne s'exécute pas, ou que vous avez besoin des équivalents MCP
references/screen-json.mdUniquement si vous empruntez la route Screen JSON (3b). Le format, et ce qu'il ne peut pas exprimer
references/errors.mdDès qu'une commande affiche une erreur ou un avertissement. Chaque code et sa correction
references/implementation.mdPour le modèle meta à l'étape 3, et avant l'étape 5

Étape 1. Construire le registre

Yosegi a besoin d'un tsconfig.json lisible de l'hôte (les props proviennent des types TypeScript, et cela seul suffit). Storybook est l'endroit où la Story va et où vous confirmez son rendu — mais ce n'est pas une exigence.

Si vous ne pouvez pas détecter Storybook — aucun répertoire de configuration .storybook/ (ou équivalent), aucun script storybook dans le package.json de l'hôte, aucun index.json vers lequel pointer --index — le livrable est un fichier de composant React simple au lieu d'une Story (screen generate --target component, references/cli.md). Ne choisissez pas vous-même l'emplacement de sortie ou la méthode de révision : avant de construire quoi que ce soit, demandez à l'utilisateur (a) où le fichier de composant doit aller, et (b) comment il souhaite confirmer le résultat (en le rendant sur une route de test de l'application hôte, par exemple). Yosegi ne prescrit pas la surface de révision, et deviner l'une ou l'autre réponse viole la même règle que deviner une prop. Avec ces réponses, la procédure ci-dessous reste la même, avec trois différences : registry build s'exécute sans --index / --storybook-url (vous perdez la conservation, rien d'autre) ; sur la route 3a, vous écrivez le fichier de composant à l'emplacement nommé par l'utilisateur, et sur la route 3b, vous passez --target component --out <cet emplacement>.tsx ; et les vérifications Storybook de l'étape 4 sont remplacées par la vérification de type de l'hôte plus la méthode de confirmation nommée par l'utilisateur.

  1. Pouvez-vous exécuter la CLI ? npx yosegi (ou pnpm yosegi, yarn yosegi, bunx yosegi) sans arguments affiche chaque commande, une fois que @yosegi/yosegi est déjà une dépendance de l'hôte — installez-la d'abord si ce n'est pas le cas (references/cli.md). Node.js 20 ou plus récent, hôte React + TypeScript. Si la commande échoue à la place, consultez "Si la CLI ne s'exécute pas" dans references/cli.md ; l'action la plus utile est de lire le fichier <data-dir>/registry.json's builtWithCliPath si un registre existe déjà d'une session précédente.
  2. Corrigez un --data-dir maintenant et passez le même à chaque commande. Utilisez .yosegi sous la racine du package de l'hôte, qui est également la valeur par défaut ; les exemples ci-dessous l'écrivent encore, car la valeur par défaut suit votre répertoire de travail actuel et une commande exécutée depuis ailleurs ne trouvera pas ce que vous avez construit.
  3. Existe-t-il déjà un registre, et est-il à jour ? Exécutez d'abord yosegi registry status --data-dir .yosegi — il recalcule la version du registre à partir de ses propres entrées enregistrées et signale source: current ou source: stale avec la commande de reconstruction exacte, au lieu que vous vérifiiez vous-même l'en-tête de component list. "Registre non trouvé" signifie que c'est la première exécution. Sa moitié basée sur l'index Storybook est au mieux et peut signaler l'index comme inaccessible alors que le verdict sur la source tient toujours — lisez cette moitié comme "impossible de vérifier", pas comme "périmé" ou "à jour", et ne laissez pas un serveur de développement inaccessible vous empêcher de faire confiance à un verdict source: current. Reconstruisez chaque fois que status signale stale, chaque fois que quelque chose affiche REGISTRY_VERSION_MISMATCH, ou chaque fois que status signale source: unknown parce que le registre est antérieur aux entrées enregistrées (built: not recorded) — il n'y a rien à recalculer à partir de là, donc l'âge est le seul signal dont vous disposez. Reconstruisez également chaque fois qu'une commande avertit que le registre a été construit par une version Yosegi différente de celle que vous exécutez : un Yosegi plus ancien ne peut pas émettre de champs que celui-ci peut (les signatures d'appel d'une prop fonction, par exemple), et aucun autre signal ne montre cette lacune — la chaîne de version, étant un hachage de contenu, reste identique, donc un registre reconstruit à partir d'un hôte inchangé conserve la même. Le registre est un instantané, et un registre obsolète est pire que pas de registre du tout.
yosegi registry build \
  --source "app/components/**/*.tsx" \
  --tsconfig <host>/tsconfig.json \
  --index http://localhost:6006/index.json \
  --storybook-url http://localhost:6006 \
  --report tmp/registry-report.json \
  --data-dir .yosegi

6006 ci-dessus est la valeur par défaut de Storybook, utilisée uniquement parce que c'est la première construction et que rien ne vous a encore indiqué le contraire — ce n'est pas nécessairement le port de l'hôte. Vérifiez le script Storybook dans le package.json de l'hôte (ou demandez) pour le port sur lequel il s'exécute réellement avant d'exécuter cette commande. Chaque reconstruction après cette première a une meilleure source qu'une supposition : l'en-tête de component list imprime une ligne rebuild: portant l'URL --storybook-url exacte avec laquelle le registre a été construit pour la dernière fois (references/cli.md).

Les indicateurs et les valeurs par défaut se trouvent dans references/cli.md. --index est la seule partie avec un prérequis : une URL de serveur de développement signifie que le Storybook de l'hôte doit déjà être en cours d'exécution. Sans cela, vous perdez les catégories dérivées des Stories et les marques recommended, rien d'autre.

Lisez les statistiques qu'il affiche :

  • files: 0 → le glob n'a rien trouvé. La commande réussit quand même et écrit un registre contenant uniquement les trois primitives synthétiques, donc ne lisez pas "3 composants écrits" comme un succès.
  • componentCandidates: 0 avec files positif, ou withNodeSlots: 0 avec un nombre élevé de anyShapedProps → la construction s'est dégradée même si elle a réussi. Le premier signifie que le glob ne couvrait aucun composant React ; le second signifie que @types/react n'a pas été résolu, donc chaque prop ReactNode s'est aplatie en json et aucun slot n'a été détecté. Une ligne Warning: nomme la correction dans les deux cas — résolvez-la et reconstruisez avant de continuer.
  • propsUnreadable élevé par rapport à extractedComponents → le tsconfig est probablement erroné. Résolvez-le maintenant (references/cli.md, registry metadata) ; un composant dans cet état rejette plus tard des props parfaitement réelles.

Étape 2. Rechercher chaque composant que vous avez l'intention d'utiliser

Si le modèle d'exemple d'un générateur de page/route est la correspondance la plus proche de l'écran que vous construisez, lisez-le en premier, ou en parallèle des commandes ci-dessous — il décide le squelette et l'idiome de composition, et le registre confirme ensuite les props exactes que le modèle laisse ouvertes.

yosegi component list --category app/components/ui --data-dir .yosegi
yosegi component list --query card --data-dir .yosegi
yosegi component inspect "app/components/ui/button#Button" --data-dir .yosegi

Le registre peut contenir plusieurs centaines d'entrées, alors réduisez avec --category / --query, repérez-vous à partir du résumé, puis inspectez chaque composant que vous allez écrire. inspect est faisant autorité et votre connaissance du framework ne l'est pas. Lisez references/registry.md pour comprendre comment lire ce qu'il vous donne — les options d'énumération, les lignes shape: et signature: sous une prop opaque, le spécificateur d'import que l'hôte écrit réellement, et ce qu'une prop non documentée signifie.

Préférez les composants marqués recommended ; ils ont leur propre Story.

Ensuite, recueillez les conventions de l'hôte. La Story atterrit dans le dépôt de l'hôte et est examinée comme le code de l'hôte ; sauter cette étape produit une UI qui fonctionne et qui est quand même renvoyée.

  • Trouvez le contrat de données, s'il existe déjà — une définition OpenAPI/JSON Schema, un schéma GraphQL, des types TypeScript écrits à la main pour la réponse de l'API, quelle que soit la forme utilisée par la couche de données de l'hôte. Lisez-le avant d'inventer des données fictives. Il décide plus que les props de composant : quels champs sont obligatoires par rapport à nullables et ce que null signifie pour un champ donné (une limite null peut signifier "illimité", pas "inconnu"), quels champs s'excluent mutuellement, et — tout aussi utile — ce qui n'est pas là (aucun champ de tri ou de recherche dans le contrat signifie que l'écran ne devrait pas non plus en inventer un). C'est ce qui transforme la maquette d'une proposition d'apparence en quelque chose qui reflète la forme réelle des données. L'endroit où il se trouve varie selon l'hôte (openapi/schemas/, un fichier .graphql, un types.ts généré) ; trouvez celui qui existe pour ce domaine et suivez-le plutôt qu'une supposition plausible.
  • Recherchez dans le répertoire des routes/pages de l'hôte (app/routes/, ou là où il sert les pages) un écran existant dans le même domaine. Dans un produit mature, il en existe souvent un, et le trouver peut recadrer complètement la tâche — par exemple, une route existante bookings.calendar._index pourrait transformer "créer un écran de réservation" en "proposer une liste transversale par rapport au flux de réservation existant". Cela détermine si la maquette qui vous a été demandée est même la bonne chose à construire, alors faites-le avant le point de contrôle ci-dessous et laissez-le façonner les questions que vous y poserez.
  • Exécutez git status et regardez le répertoire de sortie avant de construire quoi que ce soit. Une tentative antérieure non validée du même écran peut déjà se trouver dans l'arbre de travail — courant après une réinitialisation de contexte et une demande réémise. Conciliez-vous avec elle au lieu de créer un doublon à côté. Pour refaire un fichier qui existe déjà — un générateur hôte refuse lorsque le chemin cible existe, ou une tentative antérieure doit être remplacée — déplacez-le (renommez) plutôt que de le supprimer ; la suppression peut ne pas vous être disponible, et un renommage libère le chemin de toute façon.
  • Vérifiez si l'hôte a un générateur pour les nouvelles pages ou écrans — un générateur plop/hygen, un script de style bun add-route, souvent documenté dans le AGENTS.md de l'hôte ou un script package.json. Sur un hôte qui en possède un, écrire manuellement un nouveau fichier d'écran à partir de zéro est erroné : le générateur clone le modèle sanctionné et applique les conventions de fichier et de nommage, alors exécutez-le plutôt que de créer le fichier vous-même. Cela règle également le choix de l'étape 3 entre une Story en arbre en ligne et un module de page plus une Story wrapper mince — un hôte avec un tel générateur veut presque toujours cette dernière.
  • Lisez AGENTS.md / CLAUDE.md à chaque niveau, de la racine du dépôt jusqu'au répertoire de sortie, et suivez tout document vers lequel ils pointent.
  • Lisez une ou deux Stories existantes près de l'emplacement de sortie. Les exemples composés qui combinent plusieurs composants sont ceux qui valent la peine d'être imités pour le squelette de la page, l'espacement et la sélection des composants. Pour l'idiome de composition — comment un composant est réellement assemblé, pas seulement quelles props il prend : l'appel de hook de bibliothèque de grille qui pilote un DataGrid, un meta spécifique à l'hôte tel que { stickyHeader: true }, le wrapper qu'un composant attend autour de lui — une Story existante est la source de vérité, et le registre ne l'est pas. Le registre

…

[Le contenu a été tronqué pour la traduction. La version complète suit.]

… peut vous dire quelles props une DataGrid attend, mais pas l'appel de hook du fournisseur de grille que l'hôte utilise pour la piloter. Les exemples composés fournissent ce contexte.

Point de contrôle avant de générer. Vous avez maintenant de quoi répondre à ces quatre questions, et continuer sans réponse à l'une d'elles est la cause la plus fréquente d'une demande de modification : (1) Quel est le squelette et le modèle de mise en page de l'écran (axe principal, largeur, espacement, remplissage) ? (2) Quelle est la convention d'import et l'idiome de composition de l'hôte ? (3) Quel est l'emplacement de sortie et quel fichier y sera écrit ? (4) Quels composants et quelles props allez-vous utiliser — avez-vous inspecté chaque composant et lu les conventions de l'hôte ? Les questions (1) et (2) trouvent leur réponse dans les Stories et modèles de l'hôte ; (3) vient du générateur de l'hôte ou de la réponse de l'utilisateur ; (4) vient du registre. Si l'une des quatre n'est pas claire, demandez avant de générer.

Étape 3. Générer l'écran

Deux routes. La route 3a (Story directement) est plus courte et est celle que vous devriez suivre par défaut ; la route 3b (fichier Screen JSON) n'est là que pour le cas où le squelette exigerait une réorganisation de composants que vous ne pouvez pas exprimer dans le code de la Story directement.

Route 3a — Écrire la Story directement

yosegi screen generate \
  --description "Saisissez ici votre description de l'écran en langage naturel" \
  --component-inspections inspect-output-1.json inspect-output-2.json \
  --data-dir .yosegi

--description est une description en langage naturel de l'écran (par exemple, "une page de connexion avec un champ email, un champ mot de passe et un bouton de soumission"). --component-inspections est optionnel mais recommandé : un ou plusieurs fichiers JSON contenant la sortie de component inspect pour les composants que vous avez l'intention d'utiliser. Sans cela, la génération s'appuiera uniquement sur la description et les types connus du registre, ce qui peut être moins précis.

Route 3b — Via un fichier Screen JSON (cas avancé)

Pour une réorganisation complexe, créez d'abord un fichier décrivant la structure de l'écran :

yosegi screen draft \
  --description "Saisissez ici votre description de l'écran en langage naturel" \
  --out screen-proposal.json \
  --data-dir .yosegi

Éditez screen-proposal.json si nécessaire, puis générez la Story :

yosegi screen generate \
  --proposal screen-proposal.json \
  --data-dir .yosegi

Étape 4. Valider dans Storybook

  1. Assurez-vous que le Storybook de l'hôte est en cours d'exécution (voir la configuration de l'hôte).
  2. Localisez la Story générée dans l'interface Storybook (elle sera listée sous la catégorie/chemin que vous avez spécifié, ou dans un emplacement par défaut).
  3. Vérifiez visuellement le rendu : l'apparence est-elle conforme à la description ? Les composants sont-ils correctement disposés ? Les props sont-elles appliquées comme prévu ?
  4. Si le rendu n'est pas satisfaisant, mettez à jour la description de l'écran ou modifiez le fichier JSON de proposition (route 3b) et régénérez. Répétez jusqu'à ce que le résultat soit satisfaisant.
  5. Soumettez la Story pour révision dans le cadre du flux de travail de l'hôte (Pull Request, etc.).

Étape 5. Transcrire en une vraie page

Si l'étape 4 a abouti à une Story approuvée, vous pouvez la transcrire en une vraie page de l'application :

  1. Identifiez le modèle de page de l'hôte (générateur existant, route manuelle, etc.).
  2. Remplacez les données fictives par des appels API réels ou des données d'état, conformément au contrat de données trouvé à l'étape 2.
  3. Supprimez ou adaptez toute configuration Storybook (meta, decorators) spécifique à la Story.
  4. Intégrez la page dans le routeur de l'hôte (par exemple, dans app/routes/ ou équivalent).
  5. Validez le rendu dans l'application hôte, pas seulement dans Storybook.

Dépannage

ProblèmeAction
yosegi: commande introuvableAssurez-vous que @yosegi/yosegi est installé dans le projet hôte (voir references/cli.md)
Erreur : registre introuvableExécutez d'abord yosegi registry build (étape 1)
L'écran généré est vide ou ne s'affiche pas correctementVérifiez les inspections des composants ; la description peut être trop vague
Avertissement : REGISTRE VERSION MISMATCHReconstruisez le registre avec la version actuelle de Yosegi
Le Storybook de l'hôte ne démarre pasVérifiez la configuration du port et les dépendances ; envisagez d'utiliser --target component

Référez-vous aux fichiers de references/ pour un dépannage détaillé de codes d'erreur spécifiques.


Remarque : Ce document est la procédure. En tant qu'agent, exécutez chaque étape dans l'ordre, ne sautez pas les points de contrôle, et utilisez les commandes et les références comme indiqué. Le registre est un outil temporaire — une fois l'écran généré et validé, il peut être mis en cache pour des sessions futures.

Skills associés