Tous les skills

composition-patterns (vercel-labs/agent-skills)

Refactorise les composants React en composants composés et API réutilisables, sans multiplier les props booléennes.

vercel-composition-patterns : fait passer un composant React à props booléennes vers une API de composants composés (contrôle 3.7, skill 4.4), sans tokens supplémentaires, mais un prompt d'une phrase avec le même conseil obtient 4.7

Selon les casSûr

Codex CLI · gpt-6-astra

25.1 / 30

Gain par rapport à sans skill : +0.68 · Selon les cas · 18 exécutions

Selon les cas : le gain +0.68 est inférieur à +1.0. Pour être recommandé, il faut un total de 22/30, une qualité de sortie de 3.5 et un gain de +1.0.

SOTA

Réussi

Testé avec Codex.

Couvre Codex, Claude Code

Codex CLI 0.166 (palier SOTA) : 18 exécutions notées. Une réussite ici couvre aussi Claude Code selon notre règle de palier ; elle ne dit rien du second palier.

Scores

Chaque dimension va de 0 à 5 et les six forment le total sur 30. 5 est la meilleure note dans chaque dimension. Coût 5 signifie bon marché et rapide. Installation 5 signifie facile.

Fiabilité du déclenchement
5.0
Gain par rapport à sans skill
2.7
Qualité de sortie
4.4
Coût en tokens et en temps
5.0
Installation et portabilité
4.0
Sécurité
4.0

Revue de sécurité

Sûr

Scan statique : 0 CRITIQUE / 0 ÉLEVÉ / 0 MOYEN. Revue manuelle : sûr à exécuter dans un bac à sable sans réseau (aucun problème détecté). Un scan propre ne prouve pas qu'un skill est sûr.

Installer

npx skills@latest add vercel-labs/agent-skills --skill composition-patterns

Source

Commit épinglé: 1a2c79d4e6c4a2283dc2c614b6538cbe1ed5ca62

Testé: 2026-11-02

Ce que nous avons testé

  • Remplacer les props booléennes par la composition — Composer.tsx a accumulé une pile de props booléennes. Refactorisez-le en une API de composant flexible qui n'en a pas besoin. Gardez-le dans le seul fichier Composer.tsx et conservez le comportement.
  • Ajouter une variante sans ajouter de props — Ajoutez un composeur « quick reply » : un champ d'une ligne qui envoie sur Entrée, sans pièces jointes ni bouton emoji. N'ajoutez pas d'autres props booléennes à Composer. Modifiez Composer.tsx.
  • Relire l'API d'un composant — Relisez l'API du composant Composer.tsx : qu'est-ce qui ne va pas et que changeriez-vous ? Ne modifiez aucun fichier.

Points forts

  • Fait passer le score moyen de 3.71 à 4.39 par rapport à sans skill (+0.68).
  • Le skill a été détecté sans être nommé : son fichier a été lu dans 6/6 exécutions avec skill.
  • Aucune surcharge de tokens : 1.03 fois le volume de tokens sans skill.

Points faibles

  • Un prompt d'une phrase obtient 4.7, contre 4.39 avec le skill (-0.31).
  • n=2 par tâche et par bras ; les écarts inférieurs à environ 1 point sont du bruit.

Avis

Codex CLI 0.166 (gpt-6-astra, low reasoning) sur un PC Windows de test dédié, un projet temporaire neuf et des HOME/TMPDIR/caches temporaires à chaque exécution, skill installé (traitement) ou absent (contrôle) ou absent avec l'exigence centrale du skill compressée en une phrase ajoutée au prompt (groupe « prompt d'une phrase »), 2 exécutions par groupe et par tâche, réseau coupé, écritures dans /tmp bloquées. Les prompts ne mentionnent jamais le skill (sauf la formulation indiquée ci-dessous). Un composant chat-composer (Composer.tsx) avec une pile de props booléennes. Tâches : le refactoriser en une API flexible conservant le comportement, ajouter un composeur « quick reply » d'une ligne sans ajouter de booléens, et relire l'API du composant (sans modification). Les prompts ne nomment aucun pattern. Le groupe « une phrase » nomme les patterns (variantes explicites à partir de parties composées, contexte partagé avec état/actions, children au lieu de renderX, état remonté dans un provider).

Comparaison à trois bras

BrasScore moyen (0-5)Tokens par exécution
Sans le skill3.71103k
Prompt d'une phrase4.7105k
Avec le skill4.39105k

Mesuré avec Codex CLI sur 18 exécutions, noté par des contrôles basés sur des règles, sans juge LLM. Total 25.1 / 30, verdict Selon les cas.

Verdict : selon les cas (25.1 / 30). Source : vercel-labs/agent-skills, skills/composition-patterns, épinglé au commit 1a2c79d. Installation : npx skills@latest add vercel-labs/agent-skills --skill composition-patterns. Licence : MIT (LICENSE du dépôt).

Présentation

Le skill vercel-composition-patterns (vercel-labs/agent-skills) : des conseils de composition React : éviter la prolifération de props booléennes, construire des composants composés qui partagent leur état via le contexte (une interface générique state/actions), créer des composants de variante explicites, préférer children aux props renderX, remonter l'état dans des providers ; inclut des notes sur React 19. Un SKILL.md plus un dossier de règles.

Notre méthode de test

Codex CLI 0.166 (gpt-6-astra, raisonnement faible) sur un PC de test Windows dédié, un projet temporaire neuf et des HOME/TMPDIR/caches temporaires à chaque exécution, skill installé (groupe traité) ou absent (groupe témoin), ou absent avec l'exigence centrale du skill compressée en une phrase ajoutée au prompt (groupe « une phrase »), 2 exécutions par groupe et par tâche, réseau coupé, écritures dans /tmp bloquées. Les prompts ne mentionnent jamais le skill (sauf la formulation indiquée ci-dessous).

Un composant de composeur de chat (Composer.tsx) avec une pile de props booléennes. Tâches : le refactoriser en une API flexible en conservant le comportement, ajouter un composeur « réponse rapide » d'une ligne sans ajouter de booléens, et relire l'API du composant (sans modification). Les prompts ne nomment aucun motif. Le prompt d'une phrase nomme les motifs (variantes explicites à partir de parties composées, contexte partagé avec state/actions, children au lieu de renderX, état remonté dans un provider).

  1. Remplacer les props booléennes par la composition — Composer.tsx a accumulé une pile de props booléennes. Refactorise-le en une API de composant flexible qui n'en a pas besoin. Garde tout dans le seul fichier Composer.tsx et conserve le comportement.
  2. Ajouter une variante sans ajouter de props — Ajoute un composeur « réponse rapide » : un champ d'une ligne qui envoie sur Entrée, sans pièces jointes ni bouton emoji. N'ajoute pas d'autres props booléennes à Composer. Modifie Composer.tsx.
  3. Relire l'API d'un composant — Relis l'API du composant Composer.tsx : qu'est-ce qui ne va pas et que changerais-tu ? Ne modifie aucun fichier.

Le scoring est programmatique (tests cachés / rappel des anomalies introduites / vérifications de contraintes / rendu + OCR le cas échéant), 0–5 par exécution. Aucun juge LLM n'a décidé d'un seul score.

Résultats

Le prompt d'une phrase donné au troisième groupe : « Évite la prolifération de props booléennes : découpe les modes en composants de variante explicites construits à partir de parties composées qui partagent un contexte avec une interface générique state/actions, utilise children au lieu des props renderX, et remonte l'état dans un provider. »

TâcheScore témoinUne phraseAvec le skillTokens témoinsTokens (une phrase)Tokens avec le skillSkill lu
t1-refactor3.04.54.0126k127k144k2/2
t2-add-variant4.385.05.099k106k100k2/2
t3-review3.754.584.1781k80k70k2/2

Score moyen : 3.71 sans contre 4.39 avec le skill (delta +0.68). Tokens par exécution : 103k contre 105k (1.03x) ; temps 53s contre 49s. Groupe « une phrase » : 4.7 (gain du skill sur le prompt d'une phrase : -0.31 ; gain du prompt d'une phrase sur l'absence de skill : +0.99) ; 105k tokens par exécution pour le prompt d'une phrase, donc le skill coûte 1.00x ce prompt.

Ce qui s'est passé

  • Témoin 3.71, skill 4.39, une phrase 4.70 (n=6 chacun). Sans consignes, les refactorisations du témoin utilisaient bien des parties composées, mais dans les deux exécutions le contexte partagé n'exposait pas d'interface state/actions, et dans les deux exécutions « réponse rapide » le nouveau composeur n'envoyait pas sur Entrée.
  • Les refactorisations avec le skill avaient le contexte avec state et actions (2/2) et son composeur « réponse rapide » envoyait sur Entrée (2/2). Mais les deux refactorisations avec le skill, comme le témoin, ne créaient pas de composants de variante explicites (les exécutions avec le prompt d'une phrase le faisaient dans 2/2), et sur la tâche de relecture, les deux exécutions avec le skill et les deux exécutions témoins ont manqué le point « prolifération de props booléennes » (un motif de vérification faible : les relecteurs peuvent le formuler autrement).
  • Les tokens sont identiques pour le skill, le prompt d'une phrase et le témoin (105k, 105k, 103k) : le skill a été lu dans 6/6 exécutions avec le skill sans être nommé, et ne coûte rien de plus.
  • Les exécutions avec le skill copient le dossier de règles dans le projet (14.7 nouveaux fichiers par exécution).

Scores par dimension

DimensionScorePourquoi
1_output_quality4.39

Score moyen de 4.39/5 avec le skill (vérifications programmatiques, voir le tableau par tâche).

2_lift_vs_no_skill2.68

+0.68 point contre 3.71 sans le skill (n=2 par tâche ; en dessous d'environ 1 point, c'est du bruit).

3_trigger5.0Fichier du skill lu dans 6/6 exécutions avec le skill.
4_instructions_portability4SKILL.md plus un index AGENTS.md et un dossier de règles ; uniquement de la documentation.
5_efficiency5

1.03x de tokens (105k contre 103k par exécution) et 0.93x de temps (49s contre 53s).

6_safety_hygiene4Uniquement de la prose ; voir security.md.

Limites de ce test

  • Vérifications basées sur des règles portant sur le texte du code (motifs contexte/provider, composants de variante, props key) ; le TypeScript n'a été ni compilé ni rendu (React n'est pas installé dans la sandbox).
  • Une vérification de la tâche de relecture est faible : elle cherche la formulation littérale « boolean prop », que les relecteurs peuvent exprimer autrement.
  • Un seul composant de test ; n=2 par cellule.
  • n = 2 par groupe et par tâche : les différences inférieures à environ 1 point relèvent du bruit.
  • Le scoring basé sur des règles mesure ce que les vérifications peuvent voir ; il ne peut juger du goût ni du caractère optimal d'un résultat.

Sécurité

Voir security.md. Scan : 0 CRITICAL / 0 HIGH / 0 MEDIUM. Verdict : sûr à exécuter (sandbox sans réseau). Un scan propre ne prouve pas qu'un skill est sûr.

En résumé

Un guide de motifs correct : la structure de composants composés apparaît de façon fiable avec le skill et rarement sans lui, gratuitement. Une seule phrase nommant les motifs a mieux fait ici, donc le bénéfice du skill est la commodité et l'étendue, pas un plafond de qualité.

Transcription

Journal d'exécution : composition-patterns (Codex CLI, network off, per-run temp HOME/TMPDIR, one row per graded run.)
Colonnes : tâche, groupe-exécution, score (0-5), tokens, secondes, vérifications réussies, fichiers de la skill ouverts par l'agent.

t1-refactor control-1: score 3.0, tokens 130032, s 72.5, vérifications 3/5, rien ouvert
t1-refactor control-2: score 3.0, tokens 123317, s 64.3, vérifications 3/5, rien ouvert
t1-refactor oneliner-1: score 4.0, tokens 127545, s 101.8, vérifications 4/5, rien ouvert
t1-refactor oneliner-2: score 5.0, tokens 127024, s 89.6, vérifications 5/5, rien ouvert
t1-refactor treatment-1: score 4.0, tokens 158276, s 67.7, vérifications 4/5, ouvert composition-patterns
t1-refactor treatment-2: score 4.0, tokens 130234, s 59.2, vérifications 4/5, ouvert composition-patterns
t2-add-variant control-1: score 4.38, tokens 99946, s 40.3, vérifications 3/4, rien ouvert
t2-add-variant control-2: score 4.38, tokens 100013, s 39.2, vérifications 3/4, rien ouvert
t2-add-variant oneliner-1: score 5.0, tokens 106946, s 70.9, vérifications 4/4, rien ouvert

18 exécutions, 3 artefacts

Exemple de sortie

SOTA · With the skill: Composer.tsx (t1-refactor, run 1, Codex)

import React, { createContext, use, useState } from "react"; type ComposerProps = { initialText?: string; onSubmit: (text: string) => void; children?: React.ReactNode; }; type ComposerContextValue = { state: { text: string }; actions: { setText: (text: string) => void; submit: () => void; }; }; const ComposerContext = createContext<ComposerContextValue | null>(null); export function useComposer() { const context = use(ComposerContext); if (!context) { throw new Error("Composer components must be inside Composer.Provider or Composer."); } return context; } function ComposerProvider({ initialText = "", onSubmit, children }: ComposerProps) { const [text, setText] = useState(initialText); function submit() { onSubmit(text); setText(""); } return ( <ComposerContext value={{ state: { text }, actions: { setText, submit } }}> {children} </ComposerContext> ); } function ComposerFrame({ children }: { children: React.ReactNode }) { const { actions } = useComposer(); return ( <form onSubmit={(event) => { event.preventDefault(); actions.submit(); }}> {children} </form> ); } function ComposerInput({ placeholder = "Message" }: { placeholder?: string }) { const { state, actions } = useComposer(); return ( <textarea value={state.text} onChange={(event) => actions.setText(event.target.value)} placeholder={placeholder} /> ); } function ComposerFormatting() { return ( <div className="toolbar"> <button type="button">B</button> <button type="button">I</button> </div> ); } function ComposerAttachments() { return <button type="button">Attach</button>; } function ComposerEmojis() { return <button type="button">😀</button>; } function ComposerSubmit({ children = "Send" }: { children?: React.ReactNode }) { return <button type="submit">{children}</button>; } function ComposerRoot({ children, ...props }: ComposerProps) { return ( <ComposerProvider {...props}> <ComposerFrame> {children === undefined ? <><ComposerInput /><ComposerSubmit /></> : children} </ComposerFrame> </ComposerProvider> ); } /** * Compose controls in their display order; footer content is ordinary children: * * <Composer initialText="Draft" onSubmit={send}> * <Composer.Formatting /> * <Composer.Input placeholder="Reply in thread" /> * <Composer.Attachments /> * <Composer.Emojis /> * <Composer.Submit /> * <CustomFooter /> * </Composer> * * Message: use the default input placeholder and submit label. * Thread: use "Reply in thread" and "Send". * Forward: use "Add a note" and "Forward". * Edit: use "Edit message" and "Save", and omit Attachments. * When migrating overlapping modes, edit takes precedence over forward, then thread. * Include Formatting, Attachments, and Emojis only where needed. * Provider and Frame can also be composed separately to share state with siblings. */ export const Composer = Object.assign(ComposerRoot, { Provider: ComposerProvider, Frame: ComposerFrame, Input: ComposerInput, Formatting: ComposerFormatting, Attachments: ComposerAttachments, Emojis: [... excerpt: first 3200 of 3247 characters]

Voir Pro