building-canvases について
PostHog で独立したアプリを作るためのスキルです。サンドボックス iframe で動く freeform canvas の選択、編集、公開を案内し、React、HTML、データクエリ、検証の各スキルへ作業を振り分けます。
主な機能
- 01依頼に応じた canvas の選択・作成
- 02ツール経由でのソース取得と編集
- 03用途に応じた React または HTML の選択
- 04編集可能なコンポーネントのパラメーター設定
- 05検証、公開、ビルド結果の確認
活用シーン
- 01PostHog でのダッシュボードや分析ツールの作成
- 02フォーム、チェックリスト、軽量ワークフローの作成
- 03ドキュメントやナラティブレポートの制作
- 04ジェネレーティブグラフィックやアニメーションの作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ posthog/ ai-plugin --skill building-canvasesインストール後、Claude Code で/building-canvasesを入力して読み込まれたか確認します。
同梱ファイルreferences/blocks.md
詳細
キャンバスの構築
キャンバスは、PostHog 内のサンドボックス化された iframe で動作する、クライアントサイドのブラウザーアプリケーションです。
そのソースはリポジトリではなく PostHog にあり、canvas-* ツールを使って読み書きします。キャンバスをローカルファイルに書き込んではいけません。ツール経由で公開することで保存されます。
キャンバスの作業は、通常のタスクなら何からでも始められます。専用のキャンバスモードや、事前に作成されたキャンバスは必要ありません。ユーザーが PostHog 上に置くボード、ドキュメント、フォーム、ビジュアライゼーション、小規模なアプリを求めた場合は、キャンバスの依頼として扱い、このスキルに従ってください。
このスキルが担当するのは freeform キャンバス(スタンドアロンアプリ)です。ほかに、grid キャンバス(ユーザーのホームキャンバスを含むウィジェットグリッド)と component キャンバス(グリッドに配置する再利用可能なウィジェット)の 2 種類があります。対象がグリッドまたはホームキャンバス、配置、再利用可能なウィジェット/コンポーネントの場合は、代わりに composing-grid-canvases を読み込んでください。このスキルが、ストアの検索 → 設定 → フォーク → 構築という手順と、レイアウトのパッチ適用ループを担当します。コンポーネントのソース作成には、引き続き以下の実装用スキルを使います。
対象のキャンバスを特定する
- タスクでキャンバス ID が指定されている場合(キャンバスから開始されたタスクでは指定されています)、それが対象です。別のキャンバスを作成してはいけません。
- それ以外の場合、対象のチャンネルはタスクが作成されたチャンネルです。これはタスクのコンテキスト(
channel_contextブロックまたは生成指示)に記載されています。canvas-listを使って、そのチャンネルのキャンバスを一覧表示します(channelで対象を絞ります)。リクエストが指していると明らかなキャンバス(同じボードやツールの以前のバージョンなど)があれば、よく似たものを新たに作るのではなく、それを基に構築してください。結果がどこに保存されたのかユーザーに分かるよう、返信でその旨を伝えます。 - 既存のキャンバスがどれも適切でない場合に限り、同じチャンネルで
canvas-createを使って作成します。リクエストに基づく短く分かりやすいタイトルを付け、「Untitled canvas」は使わないでください。 - 対象を選ぶためにチャンネルを調べ回ってはいけません。ユーザーが指定したチャンネルを ID に解決する場合に限り、
channel-listを使います。一覧の先頭には個人用の #me チャンネルが表示されますが、#me を既定にしてはいけません。そこに保存されたキャンバスは、ほかのユーザーには見えません。タスクでキャンバスもチャンネルも指定されていない場合は、推測せず、使用するチャンネルを尋ねてください。
実装用のコンパニオンスキルを読み込む
このスキルが担当するのは、キャンバスの選択と作成ライフサイクルです。実装の要件はコンパニオンスキルが定めています。ソースを書き始める前に、該当するコンパニオンスキルをすべて読み込んでください。
- ダッシュボード、データボード、フォーム、ツール、アプリケーションのような状態を持つもの、または PostHog に自然になじむ見た目にするものには、
building-react-quill-canvasesを使います。使用可能なインポート、Quill の構成、テーマ設定、チャート、読み込み状態とエラー状態、日付ピッカーを担当します。 - ドキュメント、記事、焦点を絞った実験、生成グラフィックス、
<canvas>、またはアプリケーションコンポーネントが役立つ構造を追加しない WebGL 作業には、building-html-canvasesを使います。セマンティックなマークアップ、ブラウザー API の直接利用、アニメーションのクリーンアップ、Quill を使わないテーマ設定を担当します。 - キャンバスが PostHog のデータを読み取る場合、イベントをキャプチャする場合、または遷移する場合は、
querying-canvas-dataを使います。phSDK、保存済みインサイトの優先設定、結果の形式、変数、日付範囲、クエリごとの段階的な読み込み、宣言されたデータ機能を担当します。データを扱う場合は、いずれかの実装スキルと併せて読み込んでください。 - すべてのキャンバスで、
validating-and-publishing-canvasesを使います。プロジェクトの構成、機能の宣言、検証診断、安全措置付きの公開、下書き、ビルド、競合からの復旧を担当します。
適切であれば、実装方法を組み合わせてください。React にアプリケーションの枠組みを任せ、ブラウザーのグラフィックスコードでキャンバス要素を扱うことも、ほぼ静的なページにインタラクティブな領域を 1 つだけマウントすることもできます。
これは判断が必要な選択であり、永続化されるモードではありません。選択によってユーザーに見える要件が変わり、それを推測できない場合に限り、ユーザーに確認してください。
ブロック
キャンバスには、数値、目標、トレンド、トップリスト、ファネル、リテンション、保存済みインサイト、ライブイベントフィード、SQL テーブル、フィルター、比較・更新コントロール、コールアウトなど、あらかじめ用意されたブロックを配置できます。
これらは src/blocks/ にある React コンポーネントで、デスクトップアプリでキャンバスにドラッグして配置するため、ソースコードの一部です。
src/blocks/runtime.tsx があるキャンバスを変更する前に、references/blocks.md をお読みください。
パラメーター
ユーザーが変更したい値は、パラメーターとして公開してください。そうすれば、新しいタスクを実行しなくてもデスクトップエディターで変更できます。 パラメーターは必須ではありませんが、変更する価値のある値(タイトル、コピー、イベント、プロパティ、しきい値、上限、色)がある各パネル、カード、ツールには追加してください。 パラメーターには React コンポーネントが必要です。プレーンな HTML キャンバスにはパラメーターがありません。
エディターでの editable() の使い方
デスクトップエディターでは、ユーザーは見出し、段落、セクションなど、キャンバス上の任意の要素を選択できます。移動、複製、削除したり、テキストをダブルクリックして変更したりできます。これらの操作に editable() の呼び出しは必要ありません。
editable() を使うと、コンポーネントが1つのブロックになります。するとエディターは、そのブロックを1つの単位として扱います。
- クリックすると、ブロック内の要素ではなくブロック全体が選択されます。
- 移動、複製、削除はブロック全体に対して実行されます。
- サイドパネルにはブロックのパラメーターがフィールドとして表示されます。値を変更すると、新しい値がソース内のブロックの props に書き込まれます。
- ブロック内の要素にアクセスするには、ブロックをダブルクリックして開きます。
そのため、カード、チャート、テーブル、フォームなど、ユーザーが1つのものとして捉え、1つのものとして設定する部分に editable() を使ってください。その周囲のページレイアウトはプレーンな JSX のままにします。するとユーザーはカードをブロックとして選択しつつ、ページの見出しやセクションも直接選択できます。ページ全体を保持するコンポーネントに editable() を使うと、ページ全体が1つのブロックになり、クリックするたびにそのすべてが選択されます。
パラメーターの追加
- 各パネルを個別のコンポーネントにします。コンポーネントは、デフォルト値を持つこれらの値を props として受け取ります。
@posthog/canvas-sdkのeditable(name, props, params)をコンポーネントのルート要素に展開して渡します。nameはコンポーネント名です。paramsでは各 prop を対応するフィールドにマッピングします。<SignupFunnel blockId="b-k3m9x2" title="Signup" windowDays={14} />のように、リテラルの props を使ってコンポーネントを使用します。エディターは変更をこれらの props に書き込むため、インラインで計算しないでください。<SignupFunnel blockId="b-k3m9x2" … />のように、使用箇所ごとに一意のblockIdprop を指定して、ユーザーがエージェントに特定のカードを指定できるようにします。使用できるのは英字、数字、_、-、.、:のみです。それ以外の場合、エディターは ID を無視します。リストでは、``blockId={kpi-${item.id}}` のように、項目の安定したキーから ID を作成します。
import { editable } from '@posthog/canvas-sdk'
export function SignupFunnel(props: { blockId?: string; title?: string; steps?: string[]; windowDays?: number }) {
const { title = 'Signup funnel', steps = ['$pageview', 'signed_up'], windowDays = 14 } = props
return (
<Card
{...editable('SignupFunnel', props, {
title: { type: 'text', label: 'Title', default: 'Signup funnel' },
steps: { type: 'events', label: 'Steps', default: ['$pageview', 'signed_up'] },
windowDays: { type: 'number', label: 'Conversion window (days)', min: 1, max: 90, default: 14 },
})}
>
…
</Card>
)
}
フィールドの種類:text、longtext、number(min、max、step を指定できます。min と max の両方を指定すると、エディターにはスライダーが表示されます)、boolean、select(options は文字列、または { value, label })、event、events、property、insight(保存済みインサイトの短い ID)、color。各フィールドには description も指定できます。
各フィールドには、例のように prop のデフォルト値と同じ default を指定してください:{ type: "boolean", label: "Show legend", default: true }。prop が設定されていない場合、エディターは default の値を表示します。
color パラメーターのデフォルトには、var(--primary) のようなテーマトークンを指定します。これにより、ユーザーがエディターで16進数の色を選ぶまでは、キャンバスがライトモードとダークモードに追従します。
パラメーターを通じて渡す値は、JSON 値(文字列、数値、ブール値、文字列配列)のみにしてください。関数やクエリ結果は含めないでください。
画像
キャンバス内の画像には、公開メディアライブラリの URL を使用します。最初に
posthog:media-images-list を purpose="canvas" で呼び出し、適した画像がすでにある場合は再利用してください。
ローカル画像を追加するには:
- ファイル名と
purpose="canvas"を指定して、posthog:media-image-upload-startを呼び出します。 - シェルから、返された
upload_urlにファイルをマルチパートフォームデータとして POST します。返されたform_fieldsの各項目を含め、ファイルのパートを最後に配置してください。 - 返された ID を指定して
posthog:media-image-upload-completeを呼び出し、返された永続 URL を画像のsrcとして使用します。 - URL の正確なオリジンを
project.capabilities.network.originsに追加します。キャンバスの検証ではこの宣言が確認され、公開された成果物ではこれが Content Security Policy に使用されます。
キャンバスのメディア URL は公開されており、認証は不要です。シークレット、認証情報、顧客データ、機密性の高いスクリーンショットは決してアップロードしないでください。画像は 4 MB 未満で、PNG、JPEG、GIF、WebP、AVIF、BMP のいずれかとしてデコードできる必要があります。画像データを Base64 エンコードしてツール呼び出しに含めないでください。
一般的なリクエストパターン
これらはルーティングの例として使用し、固定テンプレートとして扱わないでください。
- 製品ダッシュボード、ウェブ分析ボード、メトリクスエクスプローラー: React + Quill とデータクエリを使用します。
- チェックリスト、フォーム、軽量なワークフロー: React + Quill を使用し、PostHog の読み取り、イベントの記録、ナビゲーションにはデータクエリを追加します。チェックリストやランブックの場合は、
building-react-quill-canvasesの実例(references/checklist-example.md)を出発点として使用してください。チームで共有する進捗には、ステップごとのph.stateキーを使用します。利用可能な API で提供されていない永続性を示唆しないでください。 - ドキュメントまたはナラティブレポート: ほぼ静的な閲覧体験には HTML を使用します。ライブの PostHog データ、フィルター、アプリケーションのようなインタラクションが必要な場合は、React + Quill とデータクエリを使用します。
- 生成グラフィックまたはアニメーション: HTML とブラウザーのグラフィックス API を使用します。アプリケーションの状態管理や UI 外枠を大幅に簡素化できる場合にのみ React を追加します。
リクエストに dashboard や web-analytics などの従来のパターン指定が含まれている場合は、上記の対応する形式を適用します。パターンはヒントであり、ユーザーの実際のリクエストが優先されます。
イテレーションの流れ
canvas-source-retrieveを使って、現在のソースとバージョンポインターを読み込みます。current_version_idを控えておきます。公開時には、この値を使ったガードが必要です。- 上記で選択した実装用コンパニオンを使って、プロジェクトファイルを編集します。キャンバスに表示される PostHog データについては、
querying-canvas-dataに従ってください(保存済みインサイトはphSDK を使って読み込みます。データを取得したり、独自の PostHog クライアントを使ったりしてはいけません)。すべての数値を検証可能にしてください。インサイトに基づく指標には PostHog の保存済みインサイトへのリンクを付け、アドホッククエリには、そのスキルの「検証可能性」セクションに従って、実行したクエリを正確に表示します。また、 すべてのph呼び出しをproject.capabilitiesで宣言してください(インサイトの短縮 ID はcapabilities.posthog.insightsに、キャプチャしたイベントはcaptureEventsに、アドホッククエリにはinlineQueries: trueを、ph.agent.requestにはagentRequests: trueを指定します)。ホストはこれらを実行時に強制し、宣言されていない呼び出しは検証で拒否されます。 validating-and-publishing-canvasesに従ってください。必要に応じてcanvas-validate-createで検証し、エラー重大度の診断をすべて修正します。- プロジェクトを公開して保存します。公開はデフォルトの動作で、すぐに公開状態になります。
- 初回バージョン(
current_version_idが null):canvas-publish-createを使ってプロジェクト全体を公開し、expected_current_version_id: nullを渡します。 - すでに公開済み(
current_version_idが設定済み):canvas-edit-createを使って変更箇所のみを送信し、ファイル内の変更にはstr_replace操作を使用します。 公開中のcurrent_version_idをexpected_current_version_idとして渡します。 プロジェクト全体を置き換える場合に限り、canvas-publish-createを使ってプロジェクト全体を公開します。 - ユーザーが公開前の下書き、プレビュー、またはレビューの手順を希望した場合に限り、
canvas-draft-createで下書きを作成します。 診断と競合からの復旧については、validating-and-publishing-canvasesスキルに従ってください。
- 初回バージョン(
- ビルドの完了を待ちます。下書きと公開のどちらも、ビルドが 1 件キューに追加されます。公開または編集のレスポンスには
build.build_statusが含まれています。値がreadyまたはfailedの場合は、その値を使用します。それ以外の場合は、ビルドがreadyまたはfailedになるまでcanvas-builds-retrieveを数秒おきに(最長約 2 分間)ポーリングします。failedの場合は、ビルドのエラー診断を読み、プロジェクトを修正して再度保存します。ビルドに失敗した状態でタスクを終了してはいけません。
キャンバスの準備ができたら、依頼された変更ごとに 1 回だけ保存してください。細かな編集のたびに保存する必要はありません。ユーザーが下書きを希望した場合は、下書きのプレビューと公開への昇格が可能であることを返信の最後に伝えてください。下書き → ビルド → プレビュー → 昇格の流れについては、validating-and-publishing-canvases スキルを参照してください。
返信の最後に、キャンバスが属するチャンネル名を記載し、キャンバスツールが返す url フィールドを使ってリンクしてください(canvas-create、canvas-list、公開およびソースのレスポンスに含まれます)。キャンバスへの有効なリンクとして使用できるのは、このフィールドのみです。リンクを独自に作成してはいけません。推測した URL(プロジェクトページやウェブルート)は解決されません。
ランタイムのメモリとアクション
-
ph.state— 永続的なキーと値のメモリです:ph.state.get(key, { scope })、ph.state.set(key, value, { scope })(値を null にするとキーが削除されます)、ph.state.list({ scope })。 スコープ"user"(デフォルト)は各閲覧者専用です。"shared" はキャンバスごとに値が1つで、 チーム全体から参照できます。使用するスコープはcapabilities.posthog.stateで宣言してください。 値は JSON 形式で、シリアライズ後のサイズは最大64 KB、スコープごとのキー数は最大256個です。大きなデータは PostHog(インサイト、データウェアハウス)に保存し、そこを参照してください。シークレットや閲覧者の個人情報を state に保存しないでください。 -
ph.actions.invoke(verb, payload)— 閲覧者として PostHog に書き込みます。すべての verb をcapabilities.posthog.actionsで宣言してください。宣言されていない verb や登録されていない verb は検証に失敗し、 ホストが実行時に拒否します。アクションは明示的なユーザー操作(閲覧者がクリックするボタンなど)に結び付けてください。読み込み時やレンダリング時には実行しないでください。レジストリが信頼できる情報源です。canvases-actions-retrieveツールで一覧表示し、各 verb のusage(ペイロード/結果の形式、 動作、必要な確認メッセージ)に従って組み込んでください。 -
ph.tools.read(tool, args)およびph.tools.call(tool, args):閲覧者として許可リストにある PostHog MCP ツールを実行します。たとえば、機能フラグを読み取り、そのロールアウトを変更できます。すべての ツールをcapabilities.posthog.toolsで宣言してください。readは読み取り専用ツールを受け付けます。callはデータを変更するため、 クリック操作に結び付けてください。ホストは閲覧者に確認を求めます。許可リストと、フラグの書き込みに必要なバージョン処理についてはquerying-canvas-dataを参照してください。 -
ph.connectors.call(provider, tool, args)— 表示時に閲覧者自身の接続を使って、GitHub や任意の MCP ストアサーバーから最新のサードパーティーデータを読み取ります。GitHub、Calendly、その他のサービスを自分で呼び出して、その結果をソースに貼り付けないでください。公開時点でそのスナップショットは古くなり、すべての閲覧者に作成者のデータが表示されます。各プロバイダーとツールをcapabilities.connectorsで宣言してください。canvas-connectors-retrieveツールで確認できます。結果の処理と未接続時の処理についてはquerying-canvas-dataを参照してください。 -
ph.agent.request(prompt)— 閲覧者の承認を得て、キャンバスの作成エージェントに変更を依頼します。capabilities.posthogでagentRequests: trueを宣言してください。直接のクリックまたはフォーム送信からのみ呼び出してください。ホストは正確なプロンプトを表示し、計算リソースを消費する前に閲覧者に承認を求めます。レンダリング中、マウント中、ポーリング中の呼び出しは拒否されます。エージェントは変更を新しいバージョンとして公開します。作成者以外からのリクエストは実行を開始するのではなく、作成タスクのスレッドに記録されます。
ソースプロジェクトの構成
- ソースツールから返されるエントリーシェルとして
index.htmlを維持してください。 src/canvas.tsxは通常の React エントリーコンポーネントとして維持します。ただし、プロジェクト内の追加の相対 TypeScript、TSX、JavaScript、JSON、SVG、CSS、および許可されたアセットファイルをインポートできます。- 自己完結型のモジュールワーカーは
./worker.ts?workerでインポートできます。ワーカーから別のローカルモジュールをインポートすることはできません。 - 画像には上記の公開メディアライブラリのフローを使用してください。その他のバイナリアセットは、許可されたコンテンツタイプの base64 コンテンツとして、プロジェクトの
assetsマップに格納してください。WOFF/WOFF2、WebAssembly、汎用オクテットストリームのアセットに対応しています。 - プラットフォーム依存関係マップは、返された内容をそのまま維持してください。npm パッケージを追加しないでください。相対パスのローカルインポートはプロジェクトファイルを指し、パッケージ名のみのインポートはプラットフォームで固定されたものに限られます。