create-issue-interaction-ui について
Paperclip のメンテナー向けに、issue スレッドの新しいインタラクション種別を追加する手順を示します。共有契約、サーバー処理、UI、会話チャネル、外部ヘルパー、ドキュメントを扱います。
主な機能
- 01共有型とバリデーションの定義
- 02サーバーのライフサイクルとルートの実装
- 03UI カードとスレッド配線の追加
- 04会話チャネル処理の拡張
- 05CLI、MCP、プラグイン SDK、ドキュメントの更新
活用シーン
- 01issue スレッドのインタラクション追加
- 02異なるペイロードと解決結果の設計
- 03複数レイヤーにまたがる実装とテストの計画
MCP 対応
Paperclip の MCP サーバーに MCP ツールを追加し、既存の createIssueThreadInteraction の処理経路を再利用して、ペイロード形式をテストするよう案内します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ paperclipai/ paperclip --skill create-issue-interaction-uiインストール後、Claude Code で/create-issue-interaction-uiを入力して読み込まれたか確認します。
詳細
新しい課題スレッドのインタラクション UI を作成する(開発者/メンテナー向けスキル)
開発者/メンテナー向けのスキルです。本番環境の Paperclip エージェントにはインストールしないでください。
このスキルでは、Paperclip のコントリビューターが、新しい課題スレッドのインタラクション種別を、共有コントラクトから課題詳細画面への配線、ヘルパー、ドキュメントまで導入する手順を説明します。これは意図的に開発者/メンテナー向けのスキルとして作られています。対象は、デプロイ済みの Paperclip 企業内で動作する運用エージェントではなく、paperclipai/paperclip 内でコードを変更する人間またはコーディングエージェントです。
本番環境の Paperclip エージェントにはインストールしないでください。このガイドは、Paperclip 自体を変更するリポジトリーのコントリビューター向けです。
使用するタイミング
- 新しいインタラクション種別(コンパクトなピッカー、構造化された評価、スレッド内の承認カードなど)を導入する場合。
- 既存のインタラクションに、異なるペイロード形式、検証、または解決結果を持つ別バリアントを追加する場合(選択肢の数、対象のバインド、または結果の形式が異なるため、
ask_user_questionsが適さない場合)。 - 新しいカードにも「他のインタラクションと同じ監査、古さの判定、置き換え、継続のセマンティクス」を求めるレビュー担当者がいる場合。
使用しないタイミング
- 新しいペイロードスキーマが不要な既存のインタラクション種別にフィールドを追加する場合。既存のバリデーター/UI をそのまま修正してください。
- Paperclip エージェントによるインタラクションの呼び出し方を変更する場合。
skills/paperclipまたはreferences/api-reference.mdを更新してください。それはエージェント向けのガイダンスであり、カードの作業ではありません。 - スレッド以外の UI(課題詳細のサイドバー、プロジェクトボードのウィジェットなど)を作成する場合。それぞれに独自のコンポーネント規約があります。
基本モデル
課題スレッドの各インタラクションには、次の 5 つの要素があります。
| レイヤー | 担当範囲 |
|---|---|
| 共有 | 種別定数、ペイロード/結果インターフェース、Zod バリデーター、エクスポートされる型、共有テストのカバレッジ。 |
| サーバー | サービスによる作成/承認/拒否/応答、古さの判定、置き換え、冪等性、アクティビティログ、ウェイク送信。 |
| UI | カードの保留中/解決済み/古い状態、フィクスチャ、Storybook、課題スレッド/IssueDetail への配線。 |
| チャネルズ | 質問/コンテキストの完成、ネイティブな応答または Paperclip への引き継ぎ、コールバックの認可、確定済みのプロバイダーカード。 |
| ヘルパー/ドキュメント | CLI コマンド、MCP ツール、プラグイン SDK の型+ホスト+テスト経路、skills/paperclip のガイダンス。 |
現在の ISSUE_THREAD_INTERACTION_KINDS を一覧として使用してください。最も近い既存の種別を選び、独自の仕組みを作るのではなく、その配線を再利用してください。
request_confirmation—targetにバインドされた、単一のはい/いいえ形式。古さの判定/置き換えに対応します。request_checkbox_confirmation— 変更不可の選択肢セットから選ぶ、上限付きの複数選択です。ask_user_questions— 小規模な型付きフォームで、対象のバインドはありません。request_item_verdicts— 一連の項目に対して、個別の判断を求めます。suggest_tasks— 許可された解決担当者が個別に受け入れられるタスクを提案します。connection_intent— 認可された接続のセットアップまたはアクセスを要求します。
新しいカードで対象のバインドと、はい/いいえ形式の解決が必要な場合は、2 つの request_* 種別を参考にしてください。構造化フォームの場合は、ask_user_questions を参考にしてください。作成可能な子エンティティを生成する場合は、suggest_tasks を参考にしてください。
標準的な実装例
現在、エンドツーエンドの最良の参考例は、チェックボックス確認機能の導入です(4d5322c82 でマージ、GitHub PR #7649)。開始前に、その差分を確認してください。
git show --stat 4d5322c82
実装計画は、PAP-10415 の課題ドキュメントとして保存されています。この作業を Paperclip 自体を通じて進める場合は、自分の計画ドキュメントのテンプレートとして使用してください。
作業の順序
まず共有コントラクトから着手してください。これは UI が完成する前でも適切な変更としてマージできる最小のものです。また、後続のすべてのレイヤーで、その型とバリデーターを参照します。
1. 共有コントラクト(最小限の変更を最初に取り込みます)
変更するファイル:
packages/shared/src/constants.ts— 種類の文字列をISSUE_THREAD_INTERACTION_KINDSに追加し、サイズ定数も追加します(REQUEST_CHECKBOX_CONFIRMATION_OPTION_LIMIT = 200を参考にしてください)。packages/shared/src/types/issue.ts—Option、Payload、Result、Interactionインターフェースを追加します。ファイル末尾のIssueThreadInteractionおよびペイロード/結果のユニオン型を拡張します。packages/shared/src/types/index.ts— 新しい型を再エクスポートします。packages/shared/src/validators/issue.ts— ペイロード、結果、作成入力のバリアントに対する Zod スキーマを追加します。ターゲットのバインドが適用される場合は、既存のrequestConfirmationTargetSchemaを再利用します。packages/shared/src/validators/index.ts— 新しいスキーマを再エクスポートします。packages/shared/src/index.ts— パッケージのルートから再エクスポートします。packages/shared/src/issue-thread-interactions.test.ts— 新しいペイロードのバリアントについて、テーブルテストを拡張します。
すでに検討済みの、必ず満たすべき検証上の不変条件:
- 選択肢のリストには上限を設けます(チェックボックス型では 200 とし、コンパクトに表示できる数を選びます)。
- ペイロード内で選択肢 ID は一意であり、デフォルトの選択内容は既知の ID を参照する必要があります。
- ラベルと説明の長さには、既存の質問の選択肢と同じ上限を適用します。より緩い上限を新たに設けてはいけません。
- ターゲットのバインドには共有の
RequestConfirmationTargetスキーマを使用し、期限切れの処理が単一のコードパスを通るようにします。
2. サーバーのサービスとルート
変更するファイル:
server/src/services/issue-thread-interactions.ts— 次の箇所に種類を追加します。- 対応する種類のリスト(上部付近の
SUPPORTED_KINDS) mapInteractionRow(ペイロード/結果のパーサーを処理するswitch (row.kind))- 作成入力の検証(
switch (data.kind)) - 承認/拒否/回答/期限切れの処理分岐
- アクティビティログのペイロードと継続処理の wake ペイロード
- 対応する種類のリスト(上部付近の
server/src/routes/issues.ts— 種類ごとの分岐を拡張します(特に checkbox PR の 6096 行付近にあるレスポンス形式の分岐)。server/src/__tests__/issue-thread-interactions-service.test.ts— 作成、結果を伴う承認、理由を伴う拒否、古いターゲットの期限切れ、ユーザーコメント時の置き換え、冪等性の競合、wake ペイロードの形式をテストします。server/src/__tests__/issue-thread-interaction-routes.test.ts— 作成と、HTTP による回答/承認/拒否、会社スコープ、認可をテストします。
サーバー側の不変条件:
- リゾルバーの権限。共有サービスで現在のリゾルバーポリシー、会社の上限、指定された宛先のチェックを使用します。ガバナンス対象のアクションには引き続き必要な人間の承認を適用します。新しい種類やチャネルコールバックによって権限を拡大してはいけません。
- 会社スコープ。読み取り、書き込み、期限切れ処理、置き換えのすべてで
companyIdによる絞り込みを行います。issueIdだけを信用してはいけません。 - 古いターゲット。作成時に
targetが指定されていて、より新しいリビジョンが取り込まれた場合、インタラクションはoutcome: "stale_target"で期限切れになります。独自の古さ判定を実装せず、他のrequest_*型で使うのと同じヘルパーを呼び出してください。 - ユーザーコメント時の置き換え。ペイロードスキーマのデフォルト選択と明示的な選択を維持します。通常のコメントによって、保留中の質問に暗黙のうちに回答してはいけません。
- 冪等性。既存の型と同じ決定的な
idempotencyKeyの形式(<kind>:<issueId>:<decisionKey>:<revisionId>)を適用します。重複した POST ではカードを積み上げず、既存のカードを返す必要があります。 - 継続処理のポリシー。
none、wake_assignee、wake_assignee_on_acceptに対応します。質問者が回答を待って作業を止めている場合はwake_assignee、承認のみを待っている場合はwake_assignee_on_acceptとするデフォルトを選びます。
3. UI カードと issue スレッドの配線
変更するファイル:
ui/src/components/IssueThreadInteractionCard.tsx— カードコンポーネント(例:RequestCheckboxConfirmationCard)と解決コンポーネント(例:RequestCheckboxConfirmationResolution)を追加します。既存の switch をinteraction.kindで分岐させます。カードシェルを再利用し、別のカードフレームは導入しないでください。ui/src/lib/issue-thread-interactions.ts— カードを宣言的に保つため、getCheckboxConfirmationSelectedLabelsのような型付きヘルパーを追加します。ui/src/lib/issue-thread-interactions.test.ts— ヘルパーをテストします。ui/src/components/IssueThreadInteractionCard.test.tsx— 保留中、解決済み、古い、無効/送信中、検証エラーの各状態をテストします。ui/src/fixtures/issueThreadInteractionFixtures.ts— 新しい kind の保留中と解決済みのフィクスチャを少なくとも 1 つずつ追加します。ui/storybook/stories/questions-and-approvals/issue-thread-interactions.stories.tsx— 主要な状態の Storybook エントリーを追加します。ui/src/pages/IssueDetail.tsx— カードを描画する kind ごとの分岐を拡張します(コールバックの配線、応答の送信)。ui/src/components/IssueChatThread.tsx— kind がスレッドレベルの描画(バッジ、概要、件数)に影響する場合は、ここにある kind ごとの switch を更新します。ui/src/api/issues.ts— 型付きの承認/拒否/応答ボディを拡張します。
UI の不変条件:
- コンパクトに表示します。約 100 個の選択肢でもカードを快適に表示できるようにします(スクロール領域を制限し、解決済み状態では件数を先に表示する概要にします。選択済みの項目をすべてインラインでチップ表示しないでください)。
- 「すべて選択」と選択解除は、グローバルメニューではなくカード内に配置します。
- 承認ペイロードには、この kind 固有のフィールド名(例:
selectedOptionIds。suggest-tasks のselectedClientKeysではなく)を使用します。他の kind のフィールド名を再利用しないでください。 - 古い状態、置き換え済み状態、承認済み状態では、それぞれ異なる文言を表示します。既存の解決コンポーネントのシェルを再利用してください。
3a. チャネルの質問とレビューカード
チャットチャネルコネクターの仕様を確認してください。新しい kind や変更されたフォームはすべて、サポート対象の各会話チャネルで利用可能な経路を備える必要があります。安全で完全な質問/コンテキストに加え、ネイティブの応答コントロール、または認可された Paperclip サーフェスへの明示的なリンクを提供してください。ランタイム/コンポーザーのバリエーションも含めます。ボードカードを追加すれば Slack でも利用可能になると想定しないでください。
既存の表示、公開、応答、確定を担う処理を拡張します。認可と既存の継続/配信レシートを維持してください。解決済み、拒否済み、期限切れ、置き換え済み、復旧の各経路をカバーし、確定済みのリクエストがチャネル内で操作可能なままにならないようにします。却下は解決とは区別してください。
まずローカルのシリアライズとライフサイクルのテストを実行し、その後、認可されたテスト会話を使って実際のプロバイダー上で影響を受けるフォームを検証します。表示、回答の永続化、意図した継続処理、最終カード/結果の配信を記録してください。プロバイダーへの HTTP 通信をシミュレートした場合や、ライブでの受け入れ確認が未完了の場合は、その旨を明記してください。
4. CLI、MCP、プラグイン SDK ヘルパー
外部の呼び出し元が、JSON を手書きせずに新しいインタラクションを作成できるようにする必要があります。以下を変更します。
cli/src/commands/client/issue.ts— CLI サブコマンドを追加するか、汎用インタラクション作成処理を拡張します。cli/src/__tests__/issue-subresources.test.ts— 新しいフラグのセットをテストします。packages/mcp-server/src/tools.ts— 新しいペイロード形式を受け取る MCP ツールを追加し、既存のcreateIssueThreadInteractionコードパスを再利用します。packages/mcp-server/src/tools.test.ts— ツールのペイロード形式をテストします。packages/plugins/sdk/src/types.ts— 型付きのCreateIssueThreadInteractionバリアントを追加し、プラグイン開発者が自動補完を利用できるようにします。packages/plugins/sdk/src/worker-rpc-host.ts— 作成呼び出しの kind スイッチを拡張します。packages/plugins/sdk/src/testing.ts— テストハーネスを拡張し、プラグインが新しい kind をエンドツーエンドでシミュレートできるようにします。packages/plugins/sdk/tests/testing-actions.test.ts— テストハーネスを通じた新しい kind の往復テストを追加します。
5. エージェント向けガイダンス
以下を変更します。
skills/paperclip/SKILL.md— インタラクション種別の表に、使用する場面、使用しない場面、コピーして使えるペイロード例の行を追加します。skills/paperclip/references/api-reference.md— ペイロードと結果の完全なスキーマ、検証上限、作成/応答ボディ、エラーコードを追加します。
スキルのテキストは実行時のエージェントが読み取ります。簡潔さを保ち、類似する種別との違いをそれぞれ一、二文で明確にします。
レビュー依頼前に実行するテスト
チェックボックス PR では、NODE_ENV=test のもとで、以下の絞り込んだテスト一式をそのまま実行しました。新しい kind を追加する場合も、新しいテストファイルに置き換えて同じ形式で実行してください。
NODE_ENV=test pnpm run preflight:workspace-links
NODE_ENV=test pnpm exec vitest run \
packages/shared/src/issue-thread-interactions.test.ts \
server/src/__tests__/issue-thread-interaction-routes.test.ts \
server/src/__tests__/issue-thread-interactions-service.test.ts \
ui/src/components/IssueThreadInteractionCard.test.tsx \
ui/src/lib/issue-thread-interactions.test.ts \
cli/src/__tests__/issue-subresources.test.ts \
packages/mcp-server/src/tools.test.ts \
packages/plugins/sdk/tests/testing-actions.test.ts
UI の vitest が act is not a function で失敗する場合、シェルが NODE_ENV=production で実行されています(React の本番ビルドが使用されます)。NODE_ENV=test を明示して再実行してください。
マージ前チェックリスト
- 新しい kind が
ISSUE_THREAD_INTERACTION_KINDSに追加され、エクスポートされている。 - ペイロードと結果のインターフェースにバージョンが付与されている(
version: 1から開始)。 - Zod バリデーターがオプション、ラベル、説明の上限と ID の一意性を検証している。
- ターゲットのバインド(該当する場合)で、共有の
RequestConfirmationTargetパスを使用している。 - サービスが作成、承認、拒否/応答、古いターゲット、ユーザーコメント時の置き換え、冪等性、アクティビティログ、継続処理の再開に対応している。
- ルートとチャネルのコールバックが、現在のリゾルバー権限と会社のスコープを尊重している。
- UI が保留中、解決済み、古い、無効/送信中、検証エラーの各状態を表示し、解決済み状態の大きな選択肢は、まず件数を要約している。
- 新しい kind 用のフィクスチャと Storybook エントリーがある。
- サポートするすべてのチャネルに、フォーム用のネイティブな応答、または明示的な Paperclip への引き継ぎがあり、確定処理と継続処理のテストも含まれている。ローカルシミュレーションと実際のプロバイダーでの受け入れ結果は、分けて報告されている。
- CLI、MCP、プラグイン SDK の各ヘルパーが新しいペイロード形式を受け入れ、テストでカバーされている。
-
skills/paperclip/SKILL.mdとreferences/api-reference.mdが更新されている。 - 上記の絞り込んだテスト一式が成功し、CI のゲートも通過している。
レビューで見られたアンチパターン
チェックボックスに関するPRレビューのやり取りで挙がった、次回から避けるべき点です。
- 別の種類の受け入れペイロードのフィールド名を使い回すこと(例:
selectedOptionIdsを新たに導入せず、selectedClientKeysに便乗する)。フィールド名は種類ごとに固有のものを使用します。 - 既存の
request_confirmationヘルパーを経由せず、並行して古さや置き換えを判定するロジックを実装すること。これにより、挙動が気づかないうちに乖離します。 - 解決済みの状態で、選択済みオプションのチップを何百個も表示すること。解決済みの大量選択は、まず件数で要約する必要があります。
- 「API は十分汎用的だから」という理由で、プラグイン SDK/MCP/CLI のテストを省略すること。外部の呼び出し元は、型付きヘルパーがなければ新しい種類を利用できず、後になってエージェントのフローが壊れる形で問題が表面化します。
- サーバールートで受け付ける前に、スキルのガイダンスにその種類を追加すること。エージェントは新しい種類を使おうとして、本番環境で 400 エラーになります。