Official agent skill

Canvas Templates

by PostHog in PostHog/code

How PostHog "canvas" dashboards work end-to-end — the two rendering tiers (json-render vs freeform React-in-iframe), the agent system prompts that steer each, and the RIGHT way to fetch PostHog data…

OfficialMITAuto-check passedAI & LLM Engineering

Install Canvas Templates

skills CLI
$ npx skills add PostHog/code --skill canvas-templates -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install PostHog/code canvas-templates --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/PostHog/code.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/canvas-templates .claude/skills/canvas-templates && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
canvas-templates
GitHub stars
179
Token cost
~2.2k tokens
SKILL.md length
910 words
Files
1
Skills in repo
10
Repo updated
First seen
Licence
MIT

At a glance

How PostHog "canvas" dashboards work end-to-end — the two rendering tiers (json-render vs freeform React-in-iframe), the agent system prompts that steer each, and the RIGHT way to fetch PostHog data…

  • Changing canvas templates
  • SKILL.md covers The two tiers, Data: the RIGHT way (read this…, Dates and Styling (freeform sandbox), plus 2 more sections
  • Calls pnpm and npx
  • The freeform sandbox

What it does

Canvas Templates is an agent skill from PostHog/code, published by the product's own GitHub organization. How PostHog "canvas" dashboards work end-to-end — the two rendering tiers (json-render vs freeform React-in-iframe), the agent system prompts that steer each, and the RIGHT way to fetch PostHog data (typed query nodes through ph.query, not hand-rolled HogQL). Use when changing canvas templates, the freeform sandbox, the ph. data shim, canvas data fetching, or the agent prompts that build dashboards / web-analytics boards.

Its SKILL.md is about 2.2k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in AI & LLM Engineering, covering Prompt engineering and End-to-end testing. It works with PostHog and React. The repository describes itself as: The era of self-driving development is here. The licence is MIT.

When your agent uses it

  • Changing canvas templates
  • The freeform sandbox

Example prompts

  • “canvas”
  • “/canvas-templates”

Requirements

  • Node.js

What it can do on your machine

Read from SKILL.md and the folder at commit a4c32df. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • pnpm
    • npx

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use pnpm and npx, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Canvas Templates loads about 2.2k tokens when it runs. Until then it costs about 111 tokens; SKILL.md has 910 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~111
When it runs · the whole SKILL.md, loaded when a task matches
~2.2k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from PostHog/code at commit a4c32df, republished under its MIT licence (© PostHog). 910 words, ~2,176 tokens.

Download SKILL.mdSave it as .claude/skills/canvas-templates/SKILL.md (or your agent's skills folder).
name
canvas-templates
description
How PostHog "canvas" dashboards work end-to-end — the two rendering tiers (json-render vs freeform React-in-iframe), the agent system prompts that steer each, and the RIGHT way to fetch PostHog data (typed query nodes through ph.query, not hand-rolled HogQL). Use when changing canvas templates, the freeform sandbox, the ph.* data shim, canvas data fetching, or the agent prompts that build dashboards / web-analytics boards.

Canvas templates & data

PostHog "canvases" are agent-built dashboards/apps. There are two rendering tiers and a strict data path. Get the tier and the data path right and most canvas work is straightforward; get them wrong and you ship correctness bugs.

The two tiers

A canvas's kind (set at create time, persisted in file meta) decides everything:

TierkindWhat the agent writesRendererData path
json-render"json-render"JSONL patches against a component catalogViewRenderer (Quill component tree)state.queries HogQL, re-run by dashboardsService on refresh
freeform / React"freeform"a single-file React appsandboxed <iframe> (FreeformCanvas)the ph.* shim → host → PostHog

Which template maps to which tier: REACT_TIER_TEMPLATE_IDS in packages/core/src/canvas/freeformSchemas.ts. Today dashboard, web-analytics, and the generic freeform template render React; everything else is json-render. Legacy canvases created before a template moved tiers keep their stored kind — there is no migration, so both renderers must keep working.

Key files:

  • packages/core/src/canvas/canvasTemplates.ts — the agent system prompts + per-template rules. This is where you steer agent behavior. Two prompt families:
    • BASE_RULES + DASHBOARD_RULES / WEB_ANALYTICS_RULES → json-render (catalog-built).
    • FREEFORM_BASE + buildFreeformPrompt(...) → React tier. freeformSystemPromptFor(id) picks the prompt for a kind:"freeform" canvas by templateId.
  • packages/core/src/canvas/canvasDataService.ts — host-side ph.query / ph.capture.
  • packages/ui/src/features/canvas/freeform/ — the iframe: FreeformCanvas.tsx (postMessage broker), sandboxRuntime.ts (the iframe HTML + the ph shim), freeformDataBridge.ts (routes a ph.* call to the host tRPC).

Data: the RIGHT way (read this before touching queries)

Reuse PostHog's query runners; don't reinvent metrics in SQL.

The freeform app talks to PostHog ONLY through the injected ph global — the host holds the token, the iframe never sees it. The one call that matters:

js
const { columns, results } = await ph.query(arg)

arg is either a typed query node or an inline HogQL string:

  • PREFERRED — a typed query node: ph.query({ kind: "TrendsQuery", series: [...], dateRange: {...} }). The product's OWN query runners compute it, so the numbers match the PostHog UI exactly (sessionization, unique users, breakdowns, math, bounce rate) and the node's dateRange handles the window. The agent gets the node by creating/ opening an insight via the PostHog MCP tools and copying its query node.
  • ESCAPE HATCH — inline HogQL: ph.query("SELECT …"). Only for shapes a typed node can't express. The agent owns the SQL and its correctness.

Why this split exists: hand-rolled HogQL for standard metrics (especially web analytics — bounce rate, channel attribution, sessionization) subtly diverges from the product's numbers. Typed nodes are the same wheel the UI uses; don't re-cut it.

⚠️ The result SHAPE differs by kind — get it wrong and every value reads 0.

  • HogQL → { columns: string[], results: rows[][] } (read results[row][col]).
  • Typed node (TrendsQuery/etc.) → results is an array of series objects ({ data: number[], days: string[], count, aggregated_value, compare_label, … }), NOT rows. KPI total = results[0].count/.aggregated_value; series = results[0].data; the compareFilter previous period is a second series (match compare_label === "previous", don't assume index order). CanvasDataService.query passes typed-node results through untouched and only row-coerces HogQL — see the isTyped branch. The first build of this missed it and rendered all-zeros despite the query running fine.
Show full SKILL.md (441 more words)Show less
The data path end-to-end
ph.query(arg)                                   iframe  (sandboxRuntime.ts shim)
  └─ postMessage "data-request"
       └─ FreeformCanvas route()                 ui      (FreeformCanvas.tsx)
            └─ handleFreeformDataRequest("query") ui      (freeformDataBridge.ts)
                 └─ tRPC canvasData.query         host    (canvas-data.router.ts)
                      └─ CanvasDataService.query   core    (canvasDataService.ts)
                           └─ runQuery(node)        core   (posthogApi.ts)
                                └─ POST /api/projects/<id>/query/
                                     { query: <node>, refresh: "blocking" }
  • runQuery(authService, node, { refresh }) is the one place that POSTs to the query endpoint. runHogQLQuery(...) is a thin wrapper that boxes a string into { kind: "HogQLQuery", query }. Both live in posthogApi.ts.
  • refresh: "blocking" = the cached avenue (serve a fresh cached result, else compute). Same cache insights use — so typed nodes are cached, not recomputed.
  • canvasDataQueryInput (freeformSchemas.ts) accepts { query?, hogql?, params? } and refines that exactly one of query / hogql is present.

To add a new ph.* capability: add the method to the shim (sandboxRuntime.ts window.ph), route it in freeformDataBridge.ts, add a tRPC procedure (canvas-data.router.ts) backed by a CanvasDataService method. Never let the iframe hold a token — it posts a request; the host runs the authenticated call.

ph.run(insightShortId) is stubbed (freeformDataBridge.ts throws). It's the view/published tier's model: a shared canvas can't ship inline queries to anonymous viewers, so publish converts validated query nodes → saved insights + an allowlist and the canvas references them by id. Implement it there, not in edit.

Dates

The freeform app owns its date control (the toolbar picker is hidden for freeform — it drove json-render state.queries, see WebsiteLayout.tsx). The agent renders Quill's DateTimePicker and feeds the window into the typed node's dateRange ({ date_from, date_to }) — the runner handles timezone/bucketing/half-open.

DateTimePicker must be compact in the canvas. Without the compact prop it auto-detects layout via useMediaQuery('(min-width: 64rem)') against the iframe viewport — which is full-width, so it picks the wide dual-calendar layout and overflows the popover it's anchored in. The prompt forces compact. The inline-HogQL fallback must use half-open timestamp >= toDateTime(fromUnix) AND timestamp < toDateTime(toUnix) (integer unix = UTC), never now() / INTERVAL / inclusive <= to. These rules live in FREEFORM_DATE_CONTROL_RULES.

Styling (freeform sandbox)

The iframe loads Quill's compiled CSS + tokens AND the Tailwind Play CDN (sandboxRuntime.ts), with Preflight disabled (its unlayered form reset overrode Quill's @layer components styles). So in a freeform canvas: build from @posthog/quill components, Tailwind utilities work, and you do NOT restyle Quill components. Allowed imports are the FREEFORM_WHITELIST (freeformWhitelist.ts); the Quill version is QUILL_VERSION there (must match the CSS <link> URLs).

Editing the agent prompts

  • Steer the React data templates by editing the rule arrays in canvasTemplates.ts (FREEFORM_QUILL_RULES, FREEFORM_DATE_CONTROL_RULES, FREEFORM_DASHBOARD_RULES, FREEFORM_WEB_ANALYTICS_RULES). Generic freeform stays rule-free ("anything goes").
  • The agent can't WebFetch at runtime (denied tool) — prompt rules must be self-contained; URLs are knowledge pointers only.
  • Prompt strings are plain TS array entries; biome lints the file. Avoid ${...} inside a normal string literal (biome flags it as a template placeholder).

Checks after any change

bash
pnpm --filter @posthog/core typecheck && pnpm --filter @posthog/core test -- --run
pnpm --filter @posthog/ui typecheck
npx biome lint packages/core/src/canvas packages/ui/src/features/canvas

Then verify in the running app — most of this tier (sandbox styling, the data path, the date picker, refresh) is not covered by unit tests. Use the test-electron-app skill to drive a real canvas over CDP.

© PostHog, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .claude/skills/canvas-templates of PostHog/code.

Open the folder on GitHubat commit a4c32df

Compare with similar skills

Canvas Templates next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Canvas Templates compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Canvas Templates this skillPostHog/code179—~2.2kAutomated safety check: PassMIT
Thought Based ReasoningNeoLabHQ/context-engineering-kit1.7k1 repos~5.5kAutomated safety check: PassGPL-3.0
Building Agent Systemstelagod/code-abyss243—~691Automated safety check: PassMIT
Prompt Engineermajiayu000/claude-skill-registry6661 repos~794Automated safety check: PassMIT
Prompt Engineering Patternslamm-mit/scienceclaw244—~522Automated safety check: PassApache-2.0
Dspymagnus919/agent-skills113—~2kAutomated safety check: PassMIT

Similar skills

  • Thought Based Reasoning

    NeoLabHQ/context-engineering-kit

    A skill your agent uses when tackling complex reasoning tasks requiring step-by-step logic, multi-step arithmetic, commonsense reasoning, symbolic manipulation, or problems where simple prompting…

    1.7k GitHub starsUsed in 1 repo~5.5k tokens
    AI & LLM EngineeringAuto-check passed
  • Building Agent Systems

    telagod/code-abyss

    AI agent and LLM system engineering reference covering single-agent dev (ReAct, tool calling, plan-execute), multi-agent coordination (swarm, role decomposition, file locking), LLM security (prompt…

    243 GitHub stars~691 tokensUpdated 2 mo ago
    AI & LLM EngineeringAuto-check passed
  • Prompt Engineer

    majiayu000/claude-skill-registry

    Expert in designing, optimizing, and evaluating prompts for Large Language Models.

    666 GitHub starsUsed in 1 repo~794 tokens
    AI & LLM EngineeringAuto-check passed
  • Prompt Engineering Patterns

    lamm-mit/scienceclaw

    Generate optimized LLM prompts using chain-of-thought, ReAct, and other scientific reasoning patterns

    244 GitHub stars~522 tokensUpdated 1 mo ago
    AI & LLM EngineeringAuto-check passed
  • Dspy

    magnus919/agent-skills

    Optimize and build programmatic prompt systems with Stanford DSPy.

    113 GitHub stars~2k tokensUpdated 2 days ago
    AI & LLM EngineeringAuto-check passed
  • Create Task

    melandlabs/openloomi

    Create an end-to-end Continual Learning Bench task. An agent skill from melandlabs/openloomi.

    1k GitHub stars~4.6k tokensUpdated 15 days ago
    Testing & QAAuto-check passed

More from PostHog/code

All 10 skills in this repo
  • Dynamic Workflows

    PostHog/code

    Official

    How to write JavaScript workflow scripts for the workflow tool - fanning work out across many isolated subagents with agent(), parallel(), and pipeline(), then synthesizing one result.

    179 GitHub stars~2.3k tokensUpdated 2 mo ago
    Auto-check passed
  • MCP Servers

    PostHog/code

    Official

    Install, configure, authenticate, and troubleshoot MCP (Model Context Protocol) servers for this agent.

    179 GitHub stars~1.9k tokensUpdated 2 mo ago
    Auto-check passed
  • Merging PRs

    PostHog/code

    Official

    Merge a PR into main through the Trunk merge queue and babysit it until it lands.

    179 GitHub stars~1.3k tokensUpdated 2 mo ago
    Auto-check passed
  • Onboarding Videos

    PostHog/code

    Official

    Add, replace, and optimize the looping demo videos in the onboarding "welcome" bento grid (packages/ui/src/features/onboarding).

    179 GitHub stars~1.7k tokensUpdated 2 mo ago
    Auto-check passed
  • Quill Code

    PostHog/code

    Official

    Edit the @posthog/quill design system locally and consume the change in this repo (posthog-code) before it is published to npm.

    179 GitHub stars~1.1k tokensUpdated 2 mo ago
    Auto-check passed
  • Storybook Stories

    PostHog/code

    Official

    Write Storybook stories for PostHog UI components. An agent skill from PostHog/code.

    179 GitHub stars~929 tokensUpdated 2 mo ago
    Auto-check passed

Works with

Questions about Canvas Templates

What does Canvas Templates do?

How PostHog "canvas" dashboards work end-to-end — the two rendering tiers (json-render vs freeform React-in-iframe), the agent system prompts that steer each, and the RIGHT way to fetch PostHog data…. Canvas Templates is an agent skill from PostHog/code, published by the product's own GitHub organization.query, not hand-rolled HogQL).

When should I use Canvas Templates?

Canvas Templates fits situations like: changing canvas templates; the freeform sandbox.

How do I install Canvas Templates in Claude Code?

Run `npx skills add PostHog/code --skill canvas-templates -a claude-code`. Or copy the skill folder (.claude/skills/canvas-templates in PostHog/code) into .claude/skills/canvas-templates in your project. Claude Code loads it when a task matches its description.

How do I install Canvas Templates in Codex?

Run `npx skills add PostHog/code --skill canvas-templates -a codex`. Or copy the skill folder (.claude/skills/canvas-templates in PostHog/code) into .agents/skills/canvas-templates in your project. Codex loads it when a task matches its description.

Can I use Canvas Templates in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add PostHog/code --skill canvas-templates -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/canvas-templates, .gemini/skills/canvas-templates, .github/skills/canvas-templates and .opencode/skills/canvas-templates in your project.

What does Canvas Templates need to run?

Going by SKILL.md and its folder, Canvas Templates needs the command-line tools its instructions call (pnpm and npx). Our summary lists: Node.js.

Does Canvas Templates access the network?

SKILL.md contains no URLs. Its commands use npx, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is Canvas Templates safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Canvas Templates use?

Canvas Templates is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Canvas Templates use?

About 2.2k tokens (SKILL.md is roughly 8.7k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Canvas Templates?

Skills that share tags, products or a category with Canvas Templates: Thought Based Reasoning (NeoLabHQ/context-engineering-kit, 1.7k stars), Building Agent Systems (telagod/code-abyss, 243 stars), Prompt Engineer (majiayu000/claude-skill-registry, 666 stars) and Prompt Engineering Patterns (lamm-mit/scienceclaw, 244 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Canvas Templates?

PostHog (a GitHub organization, an official publisher) maintains it in PostHog/code, which has 179 GitHub stars. The repository holds 10 skills in this directory. The repository was last updated on August 5, 2026.

Source: PostHog/code on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.