lynx-a2ui について
自然言語の要望を A2UI v0.9 メッセージに変換し、レンダラーでの画面表示に使うスキルです。最新カタログを取得し、実行コードではなくスキーマに沿った JSON を出力します。
主な機能
- 01要望を A2UI メッセージに変換
- 02コンポーネントグラフとデータモデルの生成
- 03最新カタログの取得と準拠
- 04段階的更新とアクションパッチへの対応
- 05信頼されたコンポーネントデータに限定
活用シーン
- 01画面要望から A2UI データを生成
- 02最新カタログに基づくフォームやビューの作成
- 03既存画面の操作向けデータパッチ生成
MCP 対応
A2UI メッセージは MCP などのトランスポートで送信できます。このスキルはプロトコルデータを生成し、MCP トランスポート自体は実装しません。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ lynx-community/ skills --skill lynx-a2uiインストール後、Claude Code で/lynx-a2uiを入力して読み込まれたか確認します。
同梱ファイルpackage.json
詳細
A2UI ジェネレーター
このスキルは、エージェントが自然言語のリクエストをレンダリング用の A2UI プロトコルデータに変換する必要がある場合に使用します。出力はデータのみです。つまり、A2UI v0.9 メッセージの JSON 配列です。
生成ワークフロー
- カタログソースセクションの URL から最新のカタログを取得します。
- 取得したカタログが提供している場合は、
catalogId、コンポーネントスキーマ、関数スキーマ、必須フィールド、enum 値、および例を読み取ります。 - プロトコルルール、カタログスキーマ、ハードルール、およびこのスキルに埋め込まれている例のパターンに基づいて UI を構築します。
- ユーザーの意図をデータモデルと、最新の取得済みカタログに対して検証できるフラットなコンポーネントグラフに変換します。
- A2UI メッセージの最終的な JSON 配列のみを出力します。
このスキルは、サードパーティのエージェントプラットフォーム向けに自己完結しています。リポジトリローカルのファイルに依存しないでください。
プロトコルリファレンス
A2UI は JSON ベースのストリーミング UI プロトコルです。エージェントは宣言的な JSON メッセージを出力することでインターフェースを記述します。レンダラーは、アクティブなカタログから信頼されたコンポーネントのみをインスタンス化します。任意のコードはありません。JavaScript、HTML、CSS、イベントハンドラー、スクリプト、または実行可能なスニペットを決して出力しないでください。
設計原則:
- プロンプトファースト: コンテキスト内のスキーマと例に正確に従います。
- データのように安全、コードのように表現力豊か: 信頼されたコンポーネントデータのみを出力します。
- 構造とデータの分離: コンポーネントメッセージはフラットな UI グラフを定義し、データモデルメッセージは動的バインディングで使用される値を設定または更新します。
- プログレッシブレンダリング: 有効な各メッセージは到着時にレンダリングできます。まず有用な最小限の UI を優先し、その後でデータや改良を追加します。
- トランスポート非依存: A2UI メッセージは、SSE、REST、WebSocket、A2A、AG UI、MCP、またはその他のホストトランスポートを介して送信できます。
エンベロープのセマンティクス:
createSurfaceはサーフェスを作成します。作成後、そのsurfaceIdとcatalogIdは固定されます。カタログやテーマを変更するには、サーフェスを削除して再作成します。updateDataModelはサーフェスのデータモデル内の値を設定します。形状は{ "surfaceId": string, "path"?: string, "value"?: any }です。pathのデフォルトは/で、valueは任意の JSON 値にできます。updateComponentsはサーフェスのコンポーネント定義を追加または置換します。データパスを参照できますが、それらのパスは同じレスポンス内の先行するupdateDataModelメッセージによってすでに設定されている必要があります。deleteSurfaceはサーフェスを削除します。
出力契約
pretty プリントされた JSON 配列のみを返します。Markdown、散文、XML、HTML、JavaScript、CSS、コードフェンス、コメント、または末尾のカンマを返さないでください。
各配列項目は、"version": "v0.9" を持ち、以下のメッセージキーのいずれか 1 つだけを持つトップレベルオブジェクトでなければなりません:
"createSurface": 新しいレンダリングサーフェスを作成します。"updateDataModel": バインディングで使用される JSON 値を設定します。"updateComponents": コンポーネント定義を追加または置換します。"deleteSurface": 既存のサーフェスを削除します。
新規の UI レスポンスでは、次の順序でメッセージを出力します:
createSurface{ "path": ... }を通じて読み取られる初期値のためのupdateDataModel- id が
"root"のコンポーネントを含むupdateComponents - 必要に応じて追加の
updateDataModelまたはupdateComponentsメッセージ
最初の新規 updateComponents メッセージには、ちょうど 1 つの root コンポーネントを含める必要があります。以降の updateComponents メッセージは、必要に応じてさらに多くのコンポーネントを置換または追加できます。JSON を解析および検証しやすい状態に保つため、各メッセージオブジェクトとコンポーネントオブジェクトは別々の行に配置してください。
終了する前に、括弧のバランスを確認してください: すべてのコンポーネントオブジェクトが 1 回閉じ、すべての components 配列が 1 回閉じ、すべてのメッセージオブジェクトが 1 回閉じ、外側の配列がちょうど 1 回閉じていることを確認します。
カタログソース
呼び出し元が別の id を指定しない限り、サーフェス id "main" を使用してください。A2UI JSON を生成する前に、以下から最新の Lynx GenUI A2UI カタログを取得してください:
"https://unpkg.com/@lynx-js/genui/a2ui/dist/catalog.json"
取得したカタログを、生成される UI の正式な動的型定義として扱ってください。このスキルで記憶している古いコンポーネントリストに依存しないでください。カタログは次のトップレベル構造を持ちます:
{
"catalogId": "https://unpkg.com/@lynx-js/genui/a2ui/dist/catalog.json",
"components": {},
"functions": {}
}
取得した catalogId の値を createSurface.catalogId で使用してください。components にリストされているコンポーネントのみ、functions にリストされている関数のみ、そしてその最新のカタログで許可されている props、必須フィールド、enum 値、動的値の形状、およびアクションスキーマのみを使用してください。カタログを取得できない場合は、非自明な UI を生成する前に、カタログの内容または到達可能なカタログ URL を尋ねてください。
ユーザーが別のカタログ URL またはカタログ JSON を提供した場合は、デフォルト URL の代わりにそのカタログを使用し、createSurface.catalogId をアクティブなカタログと一致させてください。
例の戦略
例は精度を向上させますが、カタログを認識している必要があります。例は次のように使用してください:
- 取得したカタログに埋め込みの例がある場合は、そちらを優先してください。
- 以下の埋め込みの例は、アクション付きフォーム、データバインドされた繰り返しビュー、チャート風のデータビュー、およびアクションレスポンスパッチの再利用可能なパターンとして使用してください。
- 埋め込みの例を借用する前に、最新のカタログに対して検証してください。 欠落しているコンポーネント、欠落している props、変更された必須フィールド、変更された enum 値、または現在のカタログに存在しない関数を参照している例は、破棄するか適応させてください。
- 例の JSON がユーザーのリクエストと最新のカタログを正確に満たさない限り、最終的な回答に貼り付けないでください。
- 適合する例がない場合は、取得したスキーマから直接生成してください。
厳格なルール
- 出力は A2UI メッセージの JSON 配列でなければなりません。散文、Markdown、XML、コードフェンス、コメント、末尾のカンマを含めてはいけません。
- 各要素には
"version": "v0.9"を含める必要があります。 - 2 スペースのインデントで整形した JSON を出力してください。minify された 1 行の JSON を出力しないでください。
- 新規の非アクション応答では、最初のメッセージは
createSurfaceでなければなりません。取得したcatalogIdを使用し、ユーザーが別途指定しない限り surface id には"main"を使用してください。 { "path": ... }バインディングの場合、それらのパスを読み取る最初のupdateComponentsメッセージより前にupdateDataModelを送信してください。- 最初の新規
updateComponentsメッセージには、id が"root"のコンポーネントをちょうど 1 つ含める必要があります。 - プロパティベースのコンポーネント判別子を使用してください:
"component": "SomeComponent"であり、{ "SomeComponent": { ... } }のようなラッパーオブジェクトは使用しないでください。 - 子は id によってのみ参照されます。子コンポーネントをインライン化しないでください。
- 子参照は、同じレスポンス内に存在するコンポーネント、またはパッチ中に同じ surface 上にすでに存在するコンポーネントを指していなければなりません。
- id は kebab-case で surface ごとに一意に保ってください。たとえば
"root"、"title-text"、"submit-button"です。 - 最新で取得したカタログにないコンポーネント、props、関数、enum 値、アクション形状を創作しないでください。
- コンポーネントにレイアウトの
weightprop がある場合、それは小さな子レイアウトの比率として扱い、CSS の font weight とはみなしません。最新のカタログがその意味を明示的に定義していない限り、400、500、600、700のようなタイポグラフィ値を使用しないでください。 - ユーザーが不可能、安全でない、またはサポートされていない UI を求めた場合、散文ではなく、サポートされているカタログコンポーネントを使用した簡潔な説明の A2UI surface を返してください。
- 最新のユーザーメッセージが
A2UI_USER_ACTION:で始まる場合、既存の surface に対して空でないパッチを返してください。アクションが UI 全体の置き換えを明示的に求めない限り、新しい surface を作成しないでください。 - アクション応答では、最小の有効なパッチを優先してください: 変更されたデータに対する 1 つの
updateDataModel、および可視構造を変更する必要がある場合にのみupdateComponentsを含めます。 - インタラクション後に変更されるべき UI では、初期レスポンスをアクション前の状態に保ってください。確認、成功、エラー、または結果の詳細はアクション応答に含めてください。
コンポーネントのルール
- コンポーネントは
updateComponents.components内のフラットなオブジェクトです。子は id 文字列で参照され、インラインでネストされることはありません。 - すべてのコンポーネントは一意の kebab-case の
"id"と、取得したカタログのcomponentsオブジェクト内のキーの 1 つを値とするカタログ判別子を持ちます。 - 新規 UI の最初の可視コンポーネントツリーには
"id": "root"を含める必要があります。 - コンポーネントスキーマに
childrenがある場合、そのスキーマで許可されている形状を提供してください。単一の子参照を持つ場合、ちょうど 1 つのコンポーネント id を提供してください。複数の視覚的な子が必要な場合は、複数の子を受け入れるスキーマを持つカタログコンポーネントを使用してください。 - コンポーネントスキーマがアクションを要求する場合、取得したスキーマで許可されているアクション形状を、許可されたイベントペイロード、または関数名が
functionsに存在する関数呼び出しのいずれかで出力してください。 - アクティブなカタログにないコンポーネント、props、関数、enum 値、レイアウトフィールドを創作しないでください。
- メディア系のコンポーネントでは、URL/ソースフィールドについて取得したスキーマに従ってください。ホストが画像クエリを解決する場合、CDN URL を創作するのではなく、短い英語の検索クエリを使用してください。
- ユーザーがサポートされていない、または安全でない UI を求めた場合でも、A2UI JSON を返してください: 散文を返すのではなく、最新のカタログで利用可能なコンポーネントを使用して簡潔な説明の surface をレンダリングしてください。
データバインディング
固定テキストや単純な静的 UI にはリテラル値を使用します。値の共有、編集、繰り返し、またはアクション後の更新が必要な場合は、データモデルバインディングを使用します。
{ "someProp": "literal value" }
{ "someProp": { "path": "/data/path" } }
コンポーネントが { "path": "/..." } を読み取る場合は、その値を作成する先行する updateDataModel メッセージを送信します。
繰り返しの子要素には、取得したコンポーネントスキーマのテンプレート形状を使用します。スキーマが { "path": "...", "componentId": "..." } をサポートする場合、コンテナは絶対配列パスを指し、テンプレートコンポーネントは相対アイテムパスを使用します。
対応するデータはオブジェクトの配列である必要があります。
[
{ "label": "Alpha" },
{ "label": "Beta" }
]
テンプレートコンポーネントツリー内では、{ "path": "label" } でバインドします。"/items/*/label" のようなワイルドカードパスや { "path": "." } を使用しないでください。要求されたレイアウトとスクロール動作に最も一致する、取得したスキーマと説明を持つ繰り返しコンテンツコンポーネントを選択してください。
アクション応答
最新のユーザー入力が A2UI_USER_ACTION: で始まる場合は、新しいサーフェスを作成するのではなく、既存のサーフェスを更新します。最小の有効なパッチを含む空でない JSON 配列を返します。
- データのみが変更された場合は
updateDataModelを使用します。 - 表示構造が変更された場合にのみ
updateComponentsを追加します。 - アクションが UI を明示的に置き換えない限り、同じ
surfaceIdを維持します。
ユーザーアクションが発生する前に、成功、確認、またはアクション後の結果状態を初期応答に表示しないでください。それらの状態はアクション応答に含めます。インタラクション後に変化する UI では、初期応答をアクション前の状態に保ち、確認、成功、エラー、または結果の詳細についてはアクション応答パッチに依存します。
埋め込みサンプルパターン
これらの例は、コンテキスト内での説明的なパターンです。再利用する前に、最新のカタログを取得し、すべてのコンポーネント、prop、enum 値、およびアクション形状がまだ検証に合格することを確認してください。現在のカタログが変更されている場合は、コンポーネント名と prop を調整してください。
アクション付きフォーム
ユーザー: Generate a login card with email, password, and a submit button.
[
{
"version": "v0.9",
"createSurface": {
"surfaceId": "main",
"catalogId": "https://unpkg.com/@lynx-js/genui/a2ui/dist/catalog.json"
}
},
{
"version": "v0.9",
"updateDataModel": {
"surfaceId": "main",
"value": {
"form": {
"email": "",
"password": ""
}
}
}
},
{
"version": "v0.9",
"updateComponents": {
"surfaceId": "main",
"components": [
{
"id": "root",
"component": "Card",
"child": "form-column"
},
{
"id": "form-column",
"component": "Column",
"children": [
"title",
"email",
"password",
"submit"
]
},
{
"id": "title",
"component": "Text",
"text": "Sign in",
"variant": "h2"
},
{
"id": "email",
"component": "TextField",
"label": "Email",
"value": {
"path": "/form/email"
}
},
{
"id": "password",
"component": "TextField",
"label": "Password",
"variant": "obscured",
"value": {
"path": "/form/password"
}
},
{
"id": "submit",
"component": "Button",
"variant": "primary",
"child": "submit-label",
"action": {
"event": {
"name": "submit_login",
"context": {
"email": {
"path": "/form/email"
},
"password": {
"path": "/form/password"
}
}
}
}
},
{
"id": "submit-label",
"component": "Text",
"text": "Sign in"
}
]
}
}
]
データバインドされた繰り返しビュー
ユーザー: Show three trip ideas as a compact vertical group.
[
{
"version": "v0.9",
"createSurface": {
"surfaceId": "main",
"catalogId": "https://unpkg.com/@lynx-js/genui/a2ui/dist/catalog.json"
}
},
{
"version": "v0.9",
"updateDataModel": {
"surfaceId": "main",
"path": "/items",
"value": [
{
"name": "Canal walk",
"detail": "Morning coffee and quiet bridges"
},
{
"name": "Museum loop",
"detail": "Design exhibits plus lunch nearby"
},
{
"name": "Sunset hill",
"detail": "Short climb with skyline views"
}
]
}
},
{
"version": "v0.9",
"updateComponents": {
"surfaceId": "main",
"components": [
{
"id": "root",
"component": "Column",
"children": [
"title",
"trip-items"
]
},
{
"id": "title",
"component": "Text",
"text": "Trip ideas",
"variant": "h2"
},
{
"id": "trip-items",
"component": "Column",
"children": {
"path": "/items",
"componentId": "trip-row"
}
},
{
"id": "trip-row",
"component": "Row",
"children": [
"trip-icon",
"trip-copy"
],
"align": "center"
},
{
"id": "trip-icon",
"component": "Icon",
"name": "location_on"
},
{
"id": "trip-copy",
"component": "Column",
"children": [
"trip-name",
"trip-detail"
]
},
{
"id": "trip-name",
"component": "Text",
"text": {
"path": "name"
},
"variant": "h3"
},
{
"id": "trip-detail",
"component": "Text",
"text": {
"path": "detail"
},
"variant": "body"
}
]
}
}
]
チャート風データビュー
ユーザー: Show weekly active users as a line chart.
[
{
"version": "v0.9",
"createSurface": {
"surfaceId": "main",
"catalogId": "https://unpkg.com/@lynx-js/genui/a2ui/dist/catalog.json"
}
},
{
"version": "v0.9",
"updateDataModel": {
"surfaceId": "main",
"value": {
"chart": {
"labels": [
"Mon",
"Tue",
"Wed",
"Thu",
"Fri"
],
"series": [
{
"name": "Users",
"values": [
120,
148,
132,
171,
190
]
}
]
}
}
}
},
{
"version": "v0.9",
"updateComponents": {
"surfaceId": "main",
"components": [
{
"id": "root",
"component": "Card",
"child": "chart-column"
},
{
"id": "chart-column",
"component": "Column",
"children": [
"title",
"chart"
]
},
{
"id": "title",
"component": "Text",
"text": "Weekly active users",
"variant": "h2"
},
{
"id": "chart",
"component": "LineChart",
"labels": {
"path": "/chart/labels"
},
"series": {
"path": "/chart/series"
},
"xLabel": "Day",
"yLabel": "Users",
"showGrid": true,
"showLegend": true
}
]
}
}
]
アクション応答パッチ
ユーザー:
A2UI_USER_ACTION: {"surfaceId":"main","action":{"name":"submit_login","context":{"email":"[email protected]"}}}
[
{
"version": "v0.9",
"updateDataModel": {
"surfaceId": "main",
"path": "/status",
"value": {
"kind": "success",
"message": "Signed in as [email protected]"
}
}
},
{
"version": "v0.9",
"updateComponents": {
"surfaceId": "main",
"components": [
{
"id": "root",
"component": "Card",
"child": "status-column"
},
{
"id": "status-column",
"component": "Column",
"children": [
"status-title",
"status-message"
]
},
{
"id": "status-title",
"component": "Text",
"text": "Success",
"variant": "h2"
},
{
"id": "status-message",
"component": "Text",
"text": {
"path": "/status/message"
}
}
]
}
}
]
検証チェックリスト
最終出力の前に、次を確認してください。
- 最初の文字が
[で、最後の文字が]である。 - すべてのメッセージに
"version": "v0.9"が含まれている。 - 新規応答が
createSurfaceで始まる。 - 最初の新規
updateComponentsメッセージにrootが含まれている。 - すべての子 id 参照が同じ応答内に存在する。
- バインドされたパスに対応する先行するデータモデル値がある。
- 繰り返しテンプレートがオブジェクトアイテムと相対アイテムフィールドを使用している。
- コンポーネント、prop、enum 値、関数、またはアクション形状が最新の取得済みカタログの範囲外でない。
- JSON がコメントや末尾のカンマなしでパースされる。