Skip to content
Development
Skill

/building-canvases

Create or edit a PostHog freeform canvas — a sandboxed browser application (data board, document, form, small tool, graphics experiment) stored in PostHog and rendered by the desktop/web app. Use when a task asks to build, generate, update, or fix a standalone canvas app, or

From plugin
posthog
84164 skills1 agent3 commands2 hooks
+1
Install
$ npx -y skills add PostHog/ai-plugin --skill building-canvases --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/building-canvases

Context preview

The summary Claude sees to decide when to auto-load this skill.

Create or edit a PostHog freeform canvas — a sandboxed browser application (data board, document, form, small tool, graphics experiment) stored in PostHog and rendered by the desktop/web app. Use when a task asks to build, generate, update, or fix a standalone canvas app, or

SKILL.md

building-canvases.SKILL.md
name: building-canvases
description: >
  Create or edit a PostHog freeform canvas — a sandboxed browser application (data board, document,
  form, small tool, graphics experiment) stored in PostHog and rendered by the desktop/web app. Use
  when a task asks to build, generate, update, or fix a standalone canvas app, or when a freeform
  canvas id is given as the publish target. For grid/home canvases, widget placements, or reusable
  components, use composing-grid-canvases instead. Covers resolving or creating the target canvas,
  choosing an implementation approach (React + Quill vs plain HTML/browser APIs), the read → edit →
  validate → publish → build loop, and which companion canvas skills to load for the details.

Building canvases

A canvas is a client-side browser application that runs in a sandboxed iframe inside PostHog. Its source lives in PostHog — not in a repository — and you read and write it through the `canvas-*` tools. Never write a canvas to a local file; publishing through the tool is what saves it.

Canvas work can start from any ordinary task. A dedicated canvas mode or pre-created canvas is not required. When the user asks for a board, document, form, visualization, or small app that should live in PostHog, treat that as a canvas request and follow this skill.

This skill owns `freeform` canvases (standalone apps). Two other canvas kinds exist: `grid` canvases (widget grids, including the user's home canvas) and `component` canvases (reusable widgets grids place). When the target is a grid or home canvas, a placement, or a reusable widget/component, load `composing-grid-canvases` instead — it owns the store search → configure → fork → build ladder and the layout patch loop. Authoring a component's source still uses the implementation companions below.

Resolve the target canvas

  • If the task names a canvas id (canvas-initiated tasks do), that is the target. Do not create another.
  • Otherwise the target channel is the one the task was created in — named in the task's context

(the `channel_context` block or the generation instructions). List that channel's canvases with `canvas-list` (scope with `channel`). If one is clearly what the request refers to — an earlier iteration of the same board or tool — build on it instead of creating a near-duplicate, and say so in your reply so the user knows where the result landed.

  • Only when nothing existing fits, create one with `canvas-create` in that same channel, named

with a short descriptive title drawn from the request — never "Untitled canvas".

  • Never survey channels to choose a target yourself: use `channel-list` only to resolve a channel

the USER named to its id. Its listing puts the personal #me channel first, and #me is never a default — a canvas filed there is invisible to everyone else. If the task names neither a canvas nor a channel, ask which channel to use instead of guessing.

Load the companion skills for the implementation

This skill owns canvas selection and the authoring lifecycle. The companion skills hold the implementation contracts. Load every companion that applies before writing source:

  • **`building-react-quill-canvases`** for dashboards, data boards, forms, tools, application-like

state, or anything that should look native to PostHog. It owns allowed imports, Quill composition, theming, charts, loading and error states, and the date picker.

  • **`building-html-canvases`** for documents, articles, focused experiments, generative graphics,

`<canvas>`, or WebGL work where application components add no useful structure. It owns semantic markup, direct browser APIs, animation cleanup, and non-Quill theming.

  • **`querying-canvas-data`** whenever the canvas reads PostHog data, captures events, or navigates.

It owns the `ph` SDK, saved-insight preference, result shapes, variables, date ranges, progressive per-query loading, and declared data capabilities. Load it alongside either implementation skill when data is involved.

  • **`validating-and-publishing-canvases`** for every canvas. It owns project shape, capability

declarations, validation diagnostics, guarded publishes, drafts, builds, and conflict recovery.

Mix implementation approaches when appropriate: React can own application chrome while browser graphics code owns a canvas element, or a mostly static page can mount one interactive island.

This is a judgment call, not a persisted mode — ask the user only when the choice changes a user-visible requirement you cannot infer.

Images

Use public media library URLs for images in a canvas. Call `posthog:media-images-list` with `purpose="canvas"` first and reuse a suitable image when one already exists.

To add a local image:

1. Call `posthog:media-image-upload-start` with the file name and `purpose="canvas"`. 2. From a shell, POST the file to the returned `upload_url` as multipart form data. Include every returned `form_fields` entry and put the file part last. 3. Call `posthog:media-image-upload-complete` with the returned id and use its permanent `url` as the image `src`. 4. Add the URL's exact origin to `project.capabilities.network.origins`. Canvas validation checks this declaration, and the published artifact uses it in its Content Security Policy.

Canvas media URLs are public and do not require authentication. Never upload secrets, credentials, customer data, or sensitive screenshots. Images must be under 4 MB and decode as PNG, JPEG, GIF, WebP, AVIF, or BMP. Never base64-encode image bytes into a tool call.

Common request patterns

Use these as routing examples, not fixed templates:

  • **Product dashboard, web analytics board, or metric explorer:** React + Quill plus data querying.
  • **Checklist, form, or lightweight workflow:** React + Quill, plus data querying for PostHog reads,

event capture, or navigation. For a checklist or runbook specifically, start from the worked example in `building-react-quill-canvases` (`reference

Read more
Ships withposthog

Official PostHog plugin for AI clients. Access PostHog products directly from your AI coding tool.

Get the whole plugin

Other skills on posthog.