すべてのスキル

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

React コンポーネントを複合コンポーネントや再利用可能な API にリファクタリングし、真偽値プロパティの増殖を防ぎます。

vercel-composition-patterns:boolean プロップの React コンポーネントをコンパウンドコンポーネント API に変換し(対照群 3.7、スキルあり 4.4)、追加トークンなしで済みますが、同じアドバイスの一文プロンプトは 4.7 を獲得します。

状況次第安全

Codex CLI · gpt-6-astra

25.1 / 30

スキルなしに対するリフト:+0.68 · 状況次第 · 18 実行

状況次第:リフト +0.68 が +1.0 未満。推奨には合計 22/30、出力品質 3.5、リフト +1.0 が必要です。

SOTA

合格

Codex でテスト済み。

カバー対象 Codex, Claude Code

Codex CLI 0.166(SOTA ティア):採点対象 18 実行。当ティアのルールでは、ここでの合格は Claude Code もカバーします。第2ティアについては何も述べません。

スコア

各ディメンションは 0〜5 点で、6 つの合計が 30 点満点の合計スコアになります。すべてのディメンションで 5 が最良です。コスト 5 は低コストで高速、インストール 5 は簡単であることを意味します。

トリガーの信頼性
5.0
スキルなしに対するリフト
2.7
出力品質
4.4
トークンと時間のコスト
5.0
インストールと移植性
4.0
安全性
4.0

セキュリティレビュー

安全

静的スキャン:CRITICAL 0 / HIGH 0 / MEDIUM 0。手動レビュー:ネットワーク無効のサンドボックスで実行しても安全(指摘なし)。クリーンなスキャン結果はスキルの安全性を証明しません。

インストール

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

ソース

固定コミット: 1a2c79d4e6c4a2283dc2c614b6538cbe1ed5ca62

テスト済み: 2026-11-02

テスト内容

  • boolean プロップをコンポジションで置き換え — Composer.tsx には boolean プロップが山積みになっています。それらを必要としない柔軟なコンポーネント API にリファクタリングしてください。単一ファイル Composer.tsx のままにして、振る舞いは維持してください。
  • プロップを増やさずにバリアントを追加 — 「クイック返信」コンポーザーを追加します:Enter で送信する 1 行入力で、添付も絵文字ボタンもありません。Composer に boolean プロップをこれ以上追加しないでください。Composer.tsx を編集してください。
  • コンポーネント API のレビュー — Composer.tsx のコンポーネント API をレビューしてください:どこに問題があり、何を変更しますか?ファイルは変更しないでください。

長所

  • スキルなしと比べ平均スコアを 3.71 から 4.39 に引き上げ(+0.68)。
  • スキルは名前を出さずとも採用されました:スキルあり群 6/6 実行でスキルファイルが読み込まれました。
  • トークンのオーバーヘッドなし:スキルなしの 1.03 倍。

短所

  • 一文プロンプトは 4.7、スキルありは 4.39(-0.31)。
  • タスク・群ごとに n=2。1 ポイント未満の差はノイズです。

レビュー

専用の Windows テスト PC 上で Codex CLI 0.166(gpt-6-astra、低推論)、実行ごとに新規の一時プロジェクトと一時 HOME/TMPDIR/キャッシュを使用、スキルをインストール(スキルあり群)、スキルなし(対照群)、またはスキルの中核要件をプロンプト末尾に付けた一文に圧縮(一文プロンプト群)、タスクごとに各群 2 実行、ネットワーク無効、/tmp への書き込みはブロック。プロンプトはスキル名に一切言及しません(以下で注記する表現を除く)。boolean プロップが山積みになったチャットコンポーザーコンポーネント(Composer.tsx)が 1 つあります。タスク:振る舞いを保ったまま柔軟な API にリファクタリング、boolean を増やさずに「クイック返信」の 1 行コンポーザーを追加、コンポーネント API のレビュー(編集なし)。プロンプトはどのパターンにも名前を出しません。一文プロンプトはパターン名を示します(コンパウンドパーツからの明示的なバリアント、state/actions を共有するコンテキスト、renderX ではなく children、state を provider にリフトアップ)。

3群の比較

群平均スコア(0〜5)1実行あたりのトークン
スキルなし3.71103k
一文プロンプト4.7105k
スキルあり4.39105k

Codex CLI で 18 実行を計測し、LLM 判定なしのルールベースのチェックで採点。合計 25.1 / 30、判定は 状況次第。

判定:状況次第(25.1 / 30)。 出典:vercel-labs/agent-skills、skills/composition-patterns、コミット 1a2c79d 時点。インストール:npx skills@latest add vercel-labs/agent-skills --skill composition-patterns。ライセンス: MIT(リポジトリの LICENSE)。

概要

vercel-composition-patterns スキル(vercel-labs/agent-skills)。React のコンポジションのガイダンスです。boolean プロパティの増殖を避け、context(汎用的な state/actions インターフェース)を通じて状態を共有するコンパウンドコンポーネントを構築し、明示的なバリアントコンポーネントを作り、renderX プロパティより children を優先し、状態をプロバイダーに持ち上げます。React 19 のノートも含みます。SKILL.md に rules フォルダを加えた構成です。

テスト方法

専用の Windows テスト PC 上で Codex CLI 0.166(gpt-6-astra、低推論)、実行ごとに新規の一時プロジェクトと一時 HOME/TMPDIR/キャッシュを使用、スキルをインストール(スキルあり群)、スキルなし(対照群)、またはスキルの中核要件をプロンプト末尾に付けた一文に圧縮(一文プロンプト群)、タスクごとに各群 2 実行、ネットワーク無効、/tmp への書き込みはブロック。プロンプトはスキル名に一切言及しません(以下で注記する表現を除く)。

boolean プロパティが山盛りのチャットコンポーザーコンポーネント 1 つ(Composer.tsx)。タスク:挙動を保ったまま柔軟な API にリファクタリングする、boolean を増やさずに「クイック返信」の 1 行コンポーザーを追加する、コンポーネント API をレビューする(編集なし)。プロンプトはどのパターンも名指ししません。一文プロンプト群にはパターンを名指しします(コンパウンドパーツから作る明示的なバリアント、state/actions を共有する context、renderX ではなく children、プロバイダーに持ち上げる状態)。

  1. boolean プロパティをコンポジションに置き換える — Composer.tsx に boolean プロパティが山のように増えました。それらを必要としない柔軟なコンポーネント API にリファクタリングしてください。単一ファイル Composer.tsx のまま、挙動を保ってください。
  2. プロパティを増やさずにバリアントを追加する — 「クイック返信」コンポーザーを追加してください。Enter で送信する 1 行の入力で、添付や絵文字ボタンはありません。Composer に boolean プロパティをこれ以上追加しないでください。Composer.tsx を編集してください。
  3. コンポーネント API をレビューする — Composer.tsx のコンポーネント API をレビューしてください。何が問題で、何を変えるか? ファイルは変更しないでください。

採点はプログラム的(隠しテスト/仕込み問題の検出/制約チェック/該当する場合はレンダリング+OCR)で、実行ごとに 0〜5 点。スコアはどの LLM 判定者も決めていません。

結果

第3群に与えた一文プロンプト:"boolean プロパティの増殖を避ける:モードを、汎用的な state/actions インターフェースを持つ context を共有するコンパウンドパーツから作る明示的なバリアントコンポーネントに分割し、renderX プロパティではなく children を使い、状態をプロバイダーに持ち上げる。"

タスク対照群スコア一文プロンプトスキルあり対照群トークン一文プロンプトトークンスキルありトークンスキル読込
t1-refactor3.04.54.0126k127k144k2/2
t2-add-variant4.385.05.099k106k100k2/2
t3-review3.754.584.1781k80k70k2/2

平均スコア:スキルなし 3.71 対 スキルあり 4.39(差分 +0.68)。1 実行あたりのトークン:103k 対 105k(1.03 倍)、時間 53 秒 対 49 秒。一文プロンプト群:4.7(一文プロンプトに対するスキルの上乗せ:-0.31、スキルなしに対する一文プロンプト自身の上乗せ:+0.99)。一文プロンプトのトークンは 1 実行あたり 105k で、スキルのコストは一文プロンプトの 1.00 倍です。

何が起きたか

  • 対照群 3.71、スキルあり 4.39、一文プロンプト 4.70(各 n=6)。ガイダンスなしでは、対照群のリファクタリングはコンパウンドパーツこそ使いましたが、2 実行とも共有 context が state/actions インターフェースを公開せず、クイック返信の 2 実行では新しいコンポーザーが Enter で送信しませんでした。
  • スキルのリファクタリングは state と actions を持つ context を備え(2/2)、クイック返信コンポーザーは Enter で送信しました(2/2)。ただしスキルありのリファクタリング 2 実行は、対照群と同様に明示的なバリアントコンポーネントを作りませんでした(一文プロンプト群は 2/2 で作成)。レビュータスクでは、スキルありの 2 実行と対照群の 2 実行の両方が「boolean プロパティの増殖」という点を見落としました(弱いチェックパターン。レビュアーが別の表現をすることがあります)。
  • トークンはスキルあり、一文プロンプト、対照群で同じです(105k、105k、103k)。スキルは名前を出さずともスキルあり群 6/6 実行で読み込まれ、追加コストはかかりません。
  • スキルあり群の実行は rules フォルダをプロジェクトにコピーします(1 実行あたり 14.7 個の新規ファイル)。

次元別スコア

次元スコア理由
1_output_quality4.39

スキルありの平均スコア 4.39/5(プログラム的チェック。タスク別の 表を参照)。

2_lift_vs_no_skill2.68

スキルなしの 3.71 に対して +0.68 ポイント(タスクごとに n=2。約 1 ポイント未満はノイズ)。

3_trigger5.0スキルあり群 6/6 実行でスキルファイルが読み込まれました。
4_instructions_portability4SKILL.md に AGENTS.md インデックスと rules フォルダを加えた構成。ドキュメントのみ。
5_efficiency5

トークン 1.03 倍(1 実行あたり 105k 対 103k)、時間 0.93 倍(49 秒 対 53 秒)。

6_safety_hygiene4散文のみ。security.md を参照。

このテストの限界

  • コードテキストへのルールベースのチェック(context/プロバイダーのパターン、バリアントコンポーネント、key プロパティ)。TypeScript はコンパイルもレンダリングもしていません(サンドボックスに React がインストールされていないため)。
  • レビュータスクの 1 つのチェックは弱いです。文字どおりの「boolean prop」という表現を探すもので、レビュアーは別の言い方ができます。
  • 単一コンポーネントのフィクスチャ。セルごとに n=2。
  • タスク・群ごとに n=2。1 ポイント未満の差はノイズです。
  • ルールベースの採点はチェックで見えるものだけを測ります。センスや、その結果が可能な限り最良かどうかは判定できません。

セキュリティ

security.md を参照。スキャン:0 CRITICAL / 0 HIGH / 0 MEDIUM。判定:実行しても安全(ネットワーク無効のサンドボックス)。クリーンなスキャン結果はスキルの安全性を証明しません。

まとめ

まずまずのパターンガイドです。コンパウンドコンポーネント構造は、スキルがあれば確実に現れ、なければほとんど現れません。しかも無料です。パターンを名指しした一文のほうがここでは良い結果だったため、スキルの利点は利便性と網羅性であって、品質の上限ではありません。

トランスクリプト

実行ログ:composition-patterns (Codex CLI, network off, per-run temp HOME/TMPDIR, one row per graded run.)
列:タスク、群-回、スコア(0-5)、トークン、秒、合格したチェック、エージェントが開いたスキルファイル。

t1-refactor control-1: スコア 3.0, トークン 130032, 秒 72.5, チェック 3/5, 開いたファイルなし
t1-refactor control-2: スコア 3.0, トークン 123317, 秒 64.3, チェック 3/5, 開いたファイルなし
t1-refactor oneliner-1: スコア 4.0, トークン 127545, 秒 101.8, チェック 4/5, 開いたファイルなし
t1-refactor oneliner-2: スコア 5.0, トークン 127024, 秒 89.6, チェック 5/5, 開いたファイルなし
t1-refactor treatment-1: スコア 4.0, トークン 158276, 秒 67.7, チェック 4/5, 開いたファイル composition-patterns
t1-refactor treatment-2: スコア 4.0, トークン 130234, 秒 59.2, チェック 4/5, 開いたファイル composition-patterns
t2-add-variant control-1: スコア 4.38, トークン 99946, 秒 40.3, チェック 3/4, 開いたファイルなし
t2-add-variant control-2: スコア 4.38, トークン 100013, 秒 39.2, チェック 3/4, 開いたファイルなし
t2-add-variant oneliner-1: スコア 5.0, トークン 106946, 秒 70.9, チェック 4/4, 開いたファイルなし

18 実行、3 成果物

サンプル出力

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]

Pro を見る