Skip to content
Development
Skill

/validating-and-publishing-canvases

Validate and publish a canvas source project safely: the source-project shape, declared capabilities, reading the current version pointer, iterating on validation diagnostics, guarded publishing with expected_current_version_id, staging a draft build and promoting it, waiting

From plugin
ai-plugin
95180 skills1 agent3 commands3 hooks
+1

Claude Code

$ npx -y skills add PostHog/ai-plugin --skill validating-and-publishing-canvases --agent claude-code

SKILL.md

validating-and-publishing-canvases.SKILL.md
name: validating-and-publishing-canvases
description: >
  Validate and publish a canvas source project safely: the source-project shape, declared
  capabilities, reading the current version pointer, iterating on validation diagnostics, guarded
  publishing with expected_current_version_id, staging a draft build and promoting it, waiting out
  the queued build, and recovering from a 409 version_conflict or a 429 capacity limit without
  overwriting concurrent work. Use whenever a canvas edit is ready to save, a draft build is wanted,
  a canvas publish or build returns diagnostics or a conflict, or a task needs to understand canvas
  version history.

Validating and publishing canvases

A canvas's source lives in PostHog, versioned per publish. Publishing is guarded: every edit is based on a specific version, and the server refuses to overwrite newer work. Every publish queues a server-side build, and the canvas renders the last successful build.

The source project

`canvas-source-retrieve` returns:

  • `project` — `schemaVersion` (1), `files` (path → content), `entryHtml` (`"index.html"`),

`dependencies` (exact platform-pinned versions), `canvasSdkVersion`, `capabilities`.

  • `current_version_id` — the version your edits are based on. Keep it; the publish needs it.

It is `null` for a canvas that has never been published — pass that `null` on the first publish.

Keep `index.html` and `dependencies` exactly as returned. You may add relative source files and admitted assets to the project. Use `?worker` for a self-contained module worker and represent binary assets as base64 entries in `assets`; new npm dependencies or dependency-version drift fail validation.

Declare capabilities

The host enforces `project.capabilities` at runtime, so an undeclared `ph` call builds fine and then dies in the rendered canvas. Declare:

  • `capabilities.posthog.insights` — every insight short id the canvas passes to `ph.loadInsight`.
  • `capabilities.posthog.captureEvents` — every event name it passes to `ph.capture`.
  • `capabilities.posthog.inlineQueries: true` — when it calls `ph.query` at all.
  • `capabilities.posthog.agentRequests: true` — when it calls `ph.agent.request`.
  • `capabilities.connectors` — one `{ "provider", "tools" }` entry per third-party provider the

canvas reads through `ph.connectors.call`, listing every tool it calls on that provider. A provider is a native id (`github`) or `mcp:<server host>` (`mcp:mcp.calendly.com`). Unknown providers, unregistered native tools, and private MCP hosts fail validation; every declared tool must have `is_read_only: true` in the catalog. An upstream hint alone does not grant access. A canvas with connectors cannot declare shared state.

  • `capabilities.network.origins` — each exact HTTPS origin used by `fetch`, `XMLHttpRequest`, or an

external stylesheet, image, font, media file, or frame. Remote scripts remain blocked. Do not include paths, credentials, queries, fragments, or wildcards. The host must be public: loopback and private IPs, single-label names like `intranet`, and the `.local`, `.localhost`, `.internal`, and `.home.arpa` suffixes are all rejected, so a local dev host such as `https://localhost:8010` fails validation with an `invalid_network_origin` error. Data sent to a declared origin leaves PostHog and appears in the capability review before promotion.

Before validation, inventory every literal external URL in every source file. Classify navigation links and `ph.openExternal()` URLs as navigation; they do not need a network origin. For every request or resource URL, declare its scheme + host + optional port only. Include every origin a request redirects to and every secondary origin a stylesheet references for fonts or images. Never infer that one CDN hostname covers another.

Validation rejects undeclared literal calls and resource URLs (`capability_missing_*` diagnostics) so you can fix them before publishing. Dynamic URLs and redirect destinations cannot be inferred, so the inventory is still required even when validation is clean.

Validate until clean

`canvas-validate-create` is side-effect free; call it as often as needed. Diagnostics carry `severity`, a stable `code`, a `message`, and (for file-specific problems) `path` and `line`:

  • `error` diagnostics block publishing — fix all of them. Common ones: `import_not_allowed`

(bare imports are limited to the dependencies returned in the source project), `forbidden_dynamic_import` / `forbidden_require` / `forbidden_inline_script`, `invalid_path`, `capability_missing_insight` / `capability_missing_capture_event` / `capability_missing_inline_queries` / `capability_missing_agent_requests` / `capability_missing_network_origin`, `dependency_not_admitted` / `dependency_version_mismatch`, `platform_token_redeclared` (a CSS variable named like a Quill token that the platform stylesheet sets on every element, so the value never applies; prefix your own variables), and path/size violations.

  • `warning` diagnostics don't block, but heed them: `network_fetch` / `network_xhr` mean the code

reaches for the network directly. Declare the exact HTTPS origin or use the `ph` bridge.

Publish guarded

Publishing goes live immediately and is the default way to save a change, for a canvas's first version and for every follow-up edit. Every version records who published it and which task did the work, so the history stays reviewable after the fact. Stage a draft instead only when the user asked for a draft, a preview, or a review step — see "Draft, then promote" below.

Two ways to publish, both guarded:

  • **Edits** — `canvas-edit-create` with `operations`. This is the default for any change to a canvas that already has source.

The guard is mandatory here because an edit's meaning depends on its base.

  • **Whole project** — `canvas-publish-create` with the complete `project`, for a first version or to replace everything.

For an edit with `canva

Read more
@posthog
Ships withai-plugin

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

95180 skills1 agent1 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
95
Star history of PostHog/ai-plugin on GitHub, a chart by star-history.com

Other skills on ai-plugin.

analyzing-ai-citations

analyzing-ai-citations

Answer AI citation and answer engine optimization (AEO) questions in PostHog: whether AI answer engines (ChatGPT, Claude, and an…

@posthog@posthogInstall Skill

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills10d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc12d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react1d252k
@facebook@facebookInstall Skill

Questions about validating-and-publishing-canvases.

Which coding agents can use validating-and-publishing-canvases?
validating-and-publishing-canvases installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.