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.mddu 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.
| Fichier | Quand le lire |
|---|---|
references/registry.md | Lorsque 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.md | Lorsqu'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.md | Uniquement si vous empruntez la route Screen JSON (3b). Le format, et ce qu'il ne peut pas exprimer |
references/errors.md | Dès qu'une commande affiche une erreur ou un avertissement. Chaque code et sa correction |
references/implementation.md | Pour 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 scriptstorybookdans lepackage.jsonde l'hôte, aucunindex.jsonvers 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 builds'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.
- Pouvez-vous exécuter la CLI ?
npx yosegi(oupnpm yosegi,yarn yosegi,bunx yosegi) sans arguments affiche chaque commande, une fois que@yosegi/yosegiest 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" dansreferences/cli.md; l'action la plus utile est de lire le fichier<data-dir>/registry.json'sbuiltWithCliPathsi un registre existe déjà d'une session précédente. - Corrigez un
--data-dirmaintenant et passez le même à chaque commande. Utilisez.yosegisous 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. - 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 signalesource: currentousource: staleavec la commande de reconstruction exacte, au lieu que vous vérifiiez vous-même l'en-tête decomponent 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 verdictsource: current. Reconstruisez chaque fois questatussignale stale, chaque fois que quelque chose afficheREGISTRY_VERSION_MISMATCH, ou chaque fois questatussignalesource: unknownparce 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: 0avecfilespositif, ouwithNodeSlots: 0avec un nombre élevé deanyShapedProps→ 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/reactn'a pas été résolu, donc chaque propReactNodes'est aplatie enjsonet aucun slot n'a été détecté. Une ligneWarning: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, untypes.tsgé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 existantebookings.calendar._indexpourrait 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 statuset 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 leAGENTS.mdde l'hôte ou un scriptpackage.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
metaspé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
- Assurez-vous que le Storybook de l'hôte est en cours d'exécution (voir la configuration de l'hôte).
- 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).
- 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 ?
- 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.
- 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 :
- Identifiez le modèle de page de l'hôte (générateur existant, route manuelle, etc.).
- 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.
- Supprimez ou adaptez toute configuration Storybook (meta, decorators) spécifique à la Story.
- Intégrez la page dans le routeur de l'hôte (par exemple, dans
app/routes/ou équivalent). - Validez le rendu dans l'application hôte, pas seulement dans Storybook.
Dépannage
| Problème | Action |
|---|---|
yosegi: commande introuvable | Assurez-vous que @yosegi/yosegi est installé dans le projet hôte (voir references/cli.md) |
Erreur : registre introuvable | Exécutez d'abord yosegi registry build (étape 1) |
| L'écran généré est vide ou ne s'affiche pas correctement | Vérifiez les inspections des composants ; la description peut être trop vague |
Avertissement : REGISTRE VERSION MISMATCH | Reconstruisez le registre avec la version actuelle de Yosegi |
| Le Storybook de l'hôte ne démarre pas | Vé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.