[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-posthog-composing-grid-canvases":3,"mdc-7gkeus-key":48,"related-org-posthog-composing-grid-canvases":1399,"related-repo-posthog-composing-grid-canvases":1574},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":23,"repoUrl":24,"updatedAt":25,"license":26,"forks":27,"topics":28,"repo":43,"sourceUrl":46,"mdContent":47},"composing-grid-canvases","compose PostHog grid canvases","Compose PostHog grid canvases — widget grids (including the user's home canvas) built from reusable component canvases. Use when a task asks to add, fill, move, resize, or remove a widget on a grid or home canvas, to compose a whole canvas of widgets from one ask, to build a reusable widget\u002Fcomponent, or when a placement id or grid canvas id is the target. Covers the component store search → configure → fork → build ladder, the component placement contract (size, configSchema), the placement lifecycle (pending\u002Fgenerating\u002Flive\u002Ffailed), the guarded layout patch loop, and reading the canvas's comment threads.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"posthog","PostHog","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fposthog.png",[12,16,17,20],{"name":13,"slug":14,"type":15},"Dashboards","dashboards","tag",{"name":9,"slug":8,"type":15},{"name":18,"slug":19,"type":15},"Analytics","analytics",{"name":21,"slug":22,"type":15},"UI Components","ui-components",35568,"https:\u002F\u002Fgithub.com\u002FPostHog\u002Fposthog","2026-08-19T03:59:25.879116",null,2977,[29,30,19,31,32,33,34,35,36,37,38,39,40,41,42],"ab-testing","ai-analytics","cdp","data-warehouse","experiments","feature-flags","javascript","product-analytics","python","react","session-replay","surveys","typescript","web-analytics",{"repoUrl":24,"stars":23,"forks":27,"topics":44,"description":45},[29,30,19,31,32,33,34,35,36,37,38,39,40,41,42],"🦔 PostHog is an all-in-one developer platform for building successful products. We offer product analytics, web analytics, session replay, error tracking, feature flags, experimentation, surveys, data warehouse, a CDP, and an AI product assistant to help debug your code, ship features faster, and keep all your usage and customer data in one stack.","https:\u002F\u002Fgithub.com\u002FPostHog\u002Fposthog\u002Ftree\u002FHEAD\u002Fproducts\u002Fcanvas\u002Fskills\u002Fcomposing-grid-canvases","---\nname: composing-grid-canvases\ndescription: >\n  Compose PostHog grid canvases — widget grids (including the user's home canvas) built from\n  reusable component canvases. Use when a task asks to add, fill, move, resize, or remove a widget\n  on a grid or home canvas, to compose a whole canvas of widgets from one ask, to build a reusable\n  widget\u002Fcomponent, or when a placement id or grid canvas id is the target. Covers the component\n  store search → configure → fork → build ladder, the component placement contract (size,\n  configSchema), the placement lifecycle (pending\u002Fgenerating\u002Flive\u002Ffailed), the guarded layout\n  patch loop, and reading the canvas's comment threads.\n---\n\n# Composing grid canvases\n\nA grid canvas is a composition, not an app: a grid of placements, each rendering a **component\ncanvas** (a reusable widget with its own source, build, and placement contract). The user's home\ncanvas is an ordinary grid canvas in their personal channel. Layout is data — publishing or\npatching one is live immediately, with no build.\n\nThree canvas kinds share one lifecycle:\n\n- `freeform` — a standalone app (the `building-canvases` skill owns these).\n- `component` — a reusable widget. Same source\u002Fbuild pipeline as freeform, plus a placement\n  contract. Visibility rides its channel: personal channel = private, team channel = shared.\n- `grid` — a layout of placements referencing components. No file source; layout only.\n\n## The resolution ladder: configure, fork, build\n\nWhen a grid placement needs content (\"a weather widget here\", \"a kanban of my tasks\"), resolve in\nthis order — placing an existing component beats authoring a duplicate:\n\n1. **Search the store**: `canvas-list` with `kind=component` and `search=\u003Cwhat the widget shows>`.\n   A component is placeable when both `component_meta` and `published_build_id` are set. If its\n   `configSchema` can express the request (\"weather for Lisbon\" → existing weather component with\n   `config: {\"location\": \"Lisbon\"}`), place and configure it — write no code.\n2. **Fork** when a component is close but its config cannot express the ask: read its source\n   (`canvas-source-retrieve`), create a new component (`canvas-create` with `kind=component`),\n   adapt, publish. Name the difference in the new component's description.\n3. **Build new** when nothing fits — see \"Building a component\" below.\n\nNew components land in the channel you create them in. Create them in the same channel as the grid\nthey serve unless the user asks to share them more widely.\n\n## Building a component\n\nA component is authored exactly like a freeform canvas — load `building-react-quill-canvases` (or\n`building-html-canvases`) plus `querying-canvas-data` and `validating-and-publishing-canvases` —\nwith three additions.\nStart from the complete, buildable project in [references\u002Fcomponent-example.md](references\u002Fcomponent-example.md); its envelope, placement contract, capability declarations, and defensive `ph.state` access are the parts that break when improvised.\n\n- **Create with `kind=component`** and a `description` written for store search: say what the\n  widget shows and what its config controls. Future placements are found by this text.\n- **Declare the placement contract** in the project's top-level `component` key:\n\n  ```json\n  {\n    \"component\": {\n      \"size\": { \"defaultW\": 2, \"defaultH\": 1, \"minW\": 1, \"minH\": 1, \"maxW\": 4 },\n      \"configSchema\": {\n        \"type\": \"object\",\n        \"properties\": { \"location\": { \"type\": \"string\", \"description\": \"City to show weather for\" } }\n      }\n    }\n  }\n  ```\n\n  Size is in grid units (widths 1–12, heights 1–40); `minW \u003C= defaultW \u003C= maxW`. The range is\n  advisory: users may resize a placement to any size, so it informs defaults and warnings, never\n  rejections. The config schema\n  vocabulary is an allowlist — `type`, `title`, `description`, `default`, `properties`, `required`,\n  `additionalProperties`, `items`, `enum`, `const`, `minimum`, `maximum`, `minLength`, `maxLength`,\n  `minItems`, `maxItems`, `format`. No `$ref`, no `pattern` — validation rejects them.\n\n- **Design responsively.** Fill 100% of the box's width and height, and adapt the layout to any\n  size the user drags: a 2×1 placement is a glanceable tile; a 6×4 is a full app surface. Render\n  usefully at `minW`×`minH`, and treat `config` as the only per-placement input.\n\nPublish and wait for the build like any canvas — a component with no ready build cannot go live on\na grid.\n\n## Composing a whole canvas\n\nA whole-canvas ask (\"a home canvas that summarizes my work in progress\") usually means several widgets, not one.\nPlan the full set first — one placement per concern — then resolve each with the ladder above.\nLay them out together: no overlaps, sizes matched to what each widget shows, the grid filled deliberately rather than tiles scattered in a corner.\nBatch the layout writes (one publish for an initial layout, surgical patches after) instead of one write per widget, and finish with every placement live or failed — never generating.\n\n## Canvas comments\n\nUsers leave feedback as comment threads on the canvas, anchored to its conversation task.\nList them with the task comment tools (`tasks-comments-list`, `tasks-comments-retrieve`) on your task before and after changing the canvas, and address the open ones — a comment naming a broken widget is your brief for fixing it.\n\n## Editing a grid\n\nThe loop is read → patch, guarded exactly as `validating-and-publishing-canvases` describes for\nsource publishes — with `canvas-layout-get` in place of `canvas-source-retrieve`, and\n`canvas-layout-patch` (surgical ops, guard required) or `canvas-layout-publish` (complete\ndocument, for an initial layout or full restructure) as the write. On a 409, re-read the layout,\nre-apply your change, and patch again.\n\nOperations:\n\n- `add_placement` — a new box: `{id, status, x, y, w, h, ...}`. Placements must not overlap or\n  extend past `grid.columns`.\n- `update_placement` — merge `changes` into the placement with `id`. Filling a drawn box is\n  `{\"op\": \"update_placement\", \"id\": \"p1\", \"changes\": {\"status\": \"live\", \"component\": \"\u003Ccomponent\ncanvas id>\", \"config\": {...}}}`.\n- `remove_placement`, `set_grid`.\n\n## The placement lifecycle\n\nA placement's `status` tells the renderer what to show:\n\n- `pending` — the user drew a box but hasn't described it (or the prompt awaits dispatch).\n- `generating` — an agent task is filling it; `generationTaskId` links the task and `prompt`\n  records the ask. Set this when you start working on a placement from a task.\n- `live` — renders its `component` at `version` (`\"latest\"` by default; a pinned version id is\n  allowed). Requires the component to be published and visible to the acting user.\n- `failed` — generation failed; keep the `prompt` so the user can retry or re-describe.\n\nWhen a task asks you to fill a placement, its prompt and the box's size are your brief: honor the\ndrawn `w`×`h` and keep the placement's `prompt`\nintact for provenance.\n\n## Validation you will hit\n\nLayout publishes validate atomically; every error names its placement. The common ones:\n\n- `component_not_found` — the id is wrong, deleted, not a component, or not visible to the acting\n  user (a component in someone else's personal channel is not placeable).\n- `component_not_published` — the component has never published a placement contract.\n- `placement_config_invalid` — `config` does not match the component's `configSchema`.\n- `placement_size_out_of_contract` — a warning, not an error: the box's `w`\u002F`h` is outside the\n  component's suggested range. The publish still succeeds; the component must render responsively.\n- `placements_overlap` \u002F `invalid_placement` — geometry; fix coordinates rather than removing the\n  other widget.\n\nEnd your reply by linking the grid canvas with the `url` field the canvas tools return — never\nconstruct a canvas URL yourself.\n",{"data":49,"body":50},{"name":4,"description":6},{"type":51,"children":52},"root",[53,61,75,80,127,134,139,250,255,261,313,960,965,971,976,982,1002,1008,1051,1056,1137,1143,1156,1249,1276,1282,1287,1380,1393],{"type":54,"tag":55,"props":56,"children":57},"element","h1",{"id":4},[58],{"type":59,"value":60},"text","Composing grid canvases",{"type":54,"tag":62,"props":63,"children":64},"p",{},[65,67,73],{"type":59,"value":66},"A grid canvas is a composition, not an app: a grid of placements, each rendering a ",{"type":54,"tag":68,"props":69,"children":70},"strong",{},[71],{"type":59,"value":72},"component\ncanvas",{"type":59,"value":74}," (a reusable widget with its own source, build, and placement contract). The user's home\ncanvas is an ordinary grid canvas in their personal channel. Layout is data — publishing or\npatching one is live immediately, with no build.",{"type":54,"tag":62,"props":76,"children":77},{},[78],{"type":59,"value":79},"Three canvas kinds share one lifecycle:",{"type":54,"tag":81,"props":82,"children":83},"ul",{},[84,105,116],{"type":54,"tag":85,"props":86,"children":87},"li",{},[88,95,97,103],{"type":54,"tag":89,"props":90,"children":92},"code",{"className":91},[],[93],{"type":59,"value":94},"freeform",{"type":59,"value":96}," — a standalone app (the ",{"type":54,"tag":89,"props":98,"children":100},{"className":99},[],[101],{"type":59,"value":102},"building-canvases",{"type":59,"value":104}," skill owns these).",{"type":54,"tag":85,"props":106,"children":107},{},[108,114],{"type":54,"tag":89,"props":109,"children":111},{"className":110},[],[112],{"type":59,"value":113},"component",{"type":59,"value":115}," — a reusable widget. Same source\u002Fbuild pipeline as freeform, plus a placement\ncontract. Visibility rides its channel: personal channel = private, team channel = shared.",{"type":54,"tag":85,"props":117,"children":118},{},[119,125],{"type":54,"tag":89,"props":120,"children":122},{"className":121},[],[123],{"type":59,"value":124},"grid",{"type":59,"value":126}," — a layout of placements referencing components. No file source; layout only.",{"type":54,"tag":128,"props":129,"children":131},"h2",{"id":130},"the-resolution-ladder-configure-fork-build",[132],{"type":59,"value":133},"The resolution ladder: configure, fork, build",{"type":54,"tag":62,"props":135,"children":136},{},[137],{"type":59,"value":138},"When a grid placement needs content (\"a weather widget here\", \"a kanban of my tasks\"), resolve in\nthis order — placing an existing component beats authoring a duplicate:",{"type":54,"tag":140,"props":141,"children":142},"ol",{},[143,208,240],{"type":54,"tag":85,"props":144,"children":145},{},[146,151,153,159,161,167,169,175,177,183,184,190,192,198,200,206],{"type":54,"tag":68,"props":147,"children":148},{},[149],{"type":59,"value":150},"Search the store",{"type":59,"value":152},": ",{"type":54,"tag":89,"props":154,"children":156},{"className":155},[],[157],{"type":59,"value":158},"canvas-list",{"type":59,"value":160}," with ",{"type":54,"tag":89,"props":162,"children":164},{"className":163},[],[165],{"type":59,"value":166},"kind=component",{"type":59,"value":168}," and ",{"type":54,"tag":89,"props":170,"children":172},{"className":171},[],[173],{"type":59,"value":174},"search=\u003Cwhat the widget shows>",{"type":59,"value":176},".\nA component is placeable when both ",{"type":54,"tag":89,"props":178,"children":180},{"className":179},[],[181],{"type":59,"value":182},"component_meta",{"type":59,"value":168},{"type":54,"tag":89,"props":185,"children":187},{"className":186},[],[188],{"type":59,"value":189},"published_build_id",{"type":59,"value":191}," are set. If its\n",{"type":54,"tag":89,"props":193,"children":195},{"className":194},[],[196],{"type":59,"value":197},"configSchema",{"type":59,"value":199}," can express the request (\"weather for Lisbon\" → existing weather component with\n",{"type":54,"tag":89,"props":201,"children":203},{"className":202},[],[204],{"type":59,"value":205},"config: {\"location\": \"Lisbon\"}",{"type":59,"value":207},"), place and configure it — write no code.",{"type":54,"tag":85,"props":209,"children":210},{},[211,216,218,224,226,232,233,238],{"type":54,"tag":68,"props":212,"children":213},{},[214],{"type":59,"value":215},"Fork",{"type":59,"value":217}," when a component is close but its config cannot express the ask: read its source\n(",{"type":54,"tag":89,"props":219,"children":221},{"className":220},[],[222],{"type":59,"value":223},"canvas-source-retrieve",{"type":59,"value":225},"), create a new component (",{"type":54,"tag":89,"props":227,"children":229},{"className":228},[],[230],{"type":59,"value":231},"canvas-create",{"type":59,"value":160},{"type":54,"tag":89,"props":234,"children":236},{"className":235},[],[237],{"type":59,"value":166},{"type":59,"value":239},"),\nadapt, publish. Name the difference in the new component's description.",{"type":54,"tag":85,"props":241,"children":242},{},[243,248],{"type":54,"tag":68,"props":244,"children":245},{},[246],{"type":59,"value":247},"Build new",{"type":59,"value":249}," when nothing fits — see \"Building a component\" below.",{"type":54,"tag":62,"props":251,"children":252},{},[253],{"type":59,"value":254},"New components land in the channel you create them in. Create them in the same channel as the grid\nthey serve unless the user asks to share them more widely.",{"type":54,"tag":128,"props":256,"children":258},{"id":257},"building-a-component",[259],{"type":59,"value":260},"Building a component",{"type":54,"tag":62,"props":262,"children":263},{},[264,266,272,274,280,282,288,289,295,297,303,305,311],{"type":59,"value":265},"A component is authored exactly like a freeform canvas — load ",{"type":54,"tag":89,"props":267,"children":269},{"className":268},[],[270],{"type":59,"value":271},"building-react-quill-canvases",{"type":59,"value":273}," (or\n",{"type":54,"tag":89,"props":275,"children":277},{"className":276},[],[278],{"type":59,"value":279},"building-html-canvases",{"type":59,"value":281},") plus ",{"type":54,"tag":89,"props":283,"children":285},{"className":284},[],[286],{"type":59,"value":287},"querying-canvas-data",{"type":59,"value":168},{"type":54,"tag":89,"props":290,"children":292},{"className":291},[],[293],{"type":59,"value":294},"validating-and-publishing-canvases",{"type":59,"value":296}," —\nwith three additions.\nStart from the complete, buildable project in ",{"type":54,"tag":298,"props":299,"children":301},"a",{"href":300},"references\u002Fcomponent-example.md",[302],{"type":59,"value":300},{"type":59,"value":304},"; its envelope, placement contract, capability declarations, and defensive ",{"type":54,"tag":89,"props":306,"children":308},{"className":307},[],[309],{"type":59,"value":310},"ph.state",{"type":59,"value":312}," access are the parts that break when improvised.",{"type":54,"tag":81,"props":314,"children":315},{},[316,339,928],{"type":54,"tag":85,"props":317,"children":318},{},[319,329,331,337],{"type":54,"tag":68,"props":320,"children":321},{},[322,324],{"type":59,"value":323},"Create with ",{"type":54,"tag":89,"props":325,"children":327},{"className":326},[],[328],{"type":59,"value":166},{"type":59,"value":330}," and a ",{"type":54,"tag":89,"props":332,"children":334},{"className":333},[],[335],{"type":59,"value":336},"description",{"type":59,"value":338}," written for store search: say what the\nwidget shows and what its config controls. Future placements are found by this text.",{"type":54,"tag":85,"props":340,"children":341},{},[342,347,349,354,356,780,784,786,792,794,799,801,807,808,813,814,820,821,826,827,833,834,840,841,847,848,854,855,861,862,868,869,875,876,882,883,889,890,896,897,903,904,910,912,918,920,926],{"type":54,"tag":68,"props":343,"children":344},{},[345],{"type":59,"value":346},"Declare the placement contract",{"type":59,"value":348}," in the project's top-level ",{"type":54,"tag":89,"props":350,"children":352},{"className":351},[],[353],{"type":59,"value":113},{"type":59,"value":355}," key:",{"type":54,"tag":357,"props":358,"children":363},"pre",{"className":359,"code":360,"language":361,"meta":362,"style":362},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"component\": {\n    \"size\": { \"defaultW\": 2, \"defaultH\": 1, \"minW\": 1, \"minH\": 1, \"maxW\": 4 },\n    \"configSchema\": {\n      \"type\": \"object\",\n      \"properties\": { \"location\": { \"type\": \"string\", \"description\": \"City to show weather for\" } }\n    }\n  }\n}\n","json","",[364],{"type":54,"tag":89,"props":365,"children":366},{"__ignoreMap":362},[367,379,408,568,592,633,753,762,771],{"type":54,"tag":368,"props":369,"children":372},"span",{"class":370,"line":371},"line",1,[373],{"type":54,"tag":368,"props":374,"children":376},{"style":375},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[377],{"type":59,"value":378},"{\n",{"type":54,"tag":368,"props":380,"children":382},{"class":370,"line":381},2,[383,388,393,398,403],{"type":54,"tag":368,"props":384,"children":385},{"style":375},[386],{"type":59,"value":387},"  \"",{"type":54,"tag":368,"props":389,"children":391},{"style":390},"--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA",[392],{"type":59,"value":113},{"type":54,"tag":368,"props":394,"children":395},{"style":375},[396],{"type":59,"value":397},"\"",{"type":54,"tag":368,"props":399,"children":400},{"style":375},[401],{"type":59,"value":402},":",{"type":54,"tag":368,"props":404,"children":405},{"style":375},[406],{"type":59,"value":407}," {\n",{"type":54,"tag":368,"props":409,"children":411},{"class":370,"line":410},3,[412,417,423,427,431,436,441,447,451,455,460,465,469,474,478,482,487,491,495,500,504,508,512,516,520,525,529,533,537,541,545,550,554,558,563],{"type":54,"tag":368,"props":413,"children":414},{"style":375},[415],{"type":59,"value":416},"    \"",{"type":54,"tag":368,"props":418,"children":420},{"style":419},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[421],{"type":59,"value":422},"size",{"type":54,"tag":368,"props":424,"children":425},{"style":375},[426],{"type":59,"value":397},{"type":54,"tag":368,"props":428,"children":429},{"style":375},[430],{"type":59,"value":402},{"type":54,"tag":368,"props":432,"children":433},{"style":375},[434],{"type":59,"value":435}," {",{"type":54,"tag":368,"props":437,"children":438},{"style":375},[439],{"type":59,"value":440}," \"",{"type":54,"tag":368,"props":442,"children":444},{"style":443},"--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C",[445],{"type":59,"value":446},"defaultW",{"type":54,"tag":368,"props":448,"children":449},{"style":375},[450],{"type":59,"value":397},{"type":54,"tag":368,"props":452,"children":453},{"style":375},[454],{"type":59,"value":402},{"type":54,"tag":368,"props":456,"children":457},{"style":443},[458],{"type":59,"value":459}," 2",{"type":54,"tag":368,"props":461,"children":462},{"style":375},[463],{"type":59,"value":464},",",{"type":54,"tag":368,"props":466,"children":467},{"style":375},[468],{"type":59,"value":440},{"type":54,"tag":368,"props":470,"children":471},{"style":443},[472],{"type":59,"value":473},"defaultH",{"type":54,"tag":368,"props":475,"children":476},{"style":375},[477],{"type":59,"value":397},{"type":54,"tag":368,"props":479,"children":480},{"style":375},[481],{"type":59,"value":402},{"type":54,"tag":368,"props":483,"children":484},{"style":443},[485],{"type":59,"value":486}," 1",{"type":54,"tag":368,"props":488,"children":489},{"style":375},[490],{"type":59,"value":464},{"type":54,"tag":368,"props":492,"children":493},{"style":375},[494],{"type":59,"value":440},{"type":54,"tag":368,"props":496,"children":497},{"style":443},[498],{"type":59,"value":499},"minW",{"type":54,"tag":368,"props":501,"children":502},{"style":375},[503],{"type":59,"value":397},{"type":54,"tag":368,"props":505,"children":506},{"style":375},[507],{"type":59,"value":402},{"type":54,"tag":368,"props":509,"children":510},{"style":443},[511],{"type":59,"value":486},{"type":54,"tag":368,"props":513,"children":514},{"style":375},[515],{"type":59,"value":464},{"type":54,"tag":368,"props":517,"children":518},{"style":375},[519],{"type":59,"value":440},{"type":54,"tag":368,"props":521,"children":522},{"style":443},[523],{"type":59,"value":524},"minH",{"type":54,"tag":368,"props":526,"children":527},{"style":375},[528],{"type":59,"value":397},{"type":54,"tag":368,"props":530,"children":531},{"style":375},[532],{"type":59,"value":402},{"type":54,"tag":368,"props":534,"children":535},{"style":443},[536],{"type":59,"value":486},{"type":54,"tag":368,"props":538,"children":539},{"style":375},[540],{"type":59,"value":464},{"type":54,"tag":368,"props":542,"children":543},{"style":375},[544],{"type":59,"value":440},{"type":54,"tag":368,"props":546,"children":547},{"style":443},[548],{"type":59,"value":549},"maxW",{"type":54,"tag":368,"props":551,"children":552},{"style":375},[553],{"type":59,"value":397},{"type":54,"tag":368,"props":555,"children":556},{"style":375},[557],{"type":59,"value":402},{"type":54,"tag":368,"props":559,"children":560},{"style":443},[561],{"type":59,"value":562}," 4",{"type":54,"tag":368,"props":564,"children":565},{"style":375},[566],{"type":59,"value":567}," },\n",{"type":54,"tag":368,"props":569,"children":571},{"class":370,"line":570},4,[572,576,580,584,588],{"type":54,"tag":368,"props":573,"children":574},{"style":375},[575],{"type":59,"value":416},{"type":54,"tag":368,"props":577,"children":578},{"style":419},[579],{"type":59,"value":197},{"type":54,"tag":368,"props":581,"children":582},{"style":375},[583],{"type":59,"value":397},{"type":54,"tag":368,"props":585,"children":586},{"style":375},[587],{"type":59,"value":402},{"type":54,"tag":368,"props":589,"children":590},{"style":375},[591],{"type":59,"value":407},{"type":54,"tag":368,"props":593,"children":595},{"class":370,"line":594},5,[596,601,606,610,614,618,624,628],{"type":54,"tag":368,"props":597,"children":598},{"style":375},[599],{"type":59,"value":600},"      \"",{"type":54,"tag":368,"props":602,"children":603},{"style":443},[604],{"type":59,"value":605},"type",{"type":54,"tag":368,"props":607,"children":608},{"style":375},[609],{"type":59,"value":397},{"type":54,"tag":368,"props":611,"children":612},{"style":375},[613],{"type":59,"value":402},{"type":54,"tag":368,"props":615,"children":616},{"style":375},[617],{"type":59,"value":440},{"type":54,"tag":368,"props":619,"children":621},{"style":620},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[622],{"type":59,"value":623},"object",{"type":54,"tag":368,"props":625,"children":626},{"style":375},[627],{"type":59,"value":397},{"type":54,"tag":368,"props":629,"children":630},{"style":375},[631],{"type":59,"value":632},",\n",{"type":54,"tag":368,"props":634,"children":636},{"class":370,"line":635},6,[637,641,646,650,654,658,662,668,672,676,680,684,689,693,697,701,706,710,714,718,722,726,730,734,739,743,748],{"type":54,"tag":368,"props":638,"children":639},{"style":375},[640],{"type":59,"value":600},{"type":54,"tag":368,"props":642,"children":643},{"style":443},[644],{"type":59,"value":645},"properties",{"type":54,"tag":368,"props":647,"children":648},{"style":375},[649],{"type":59,"value":397},{"type":54,"tag":368,"props":651,"children":652},{"style":375},[653],{"type":59,"value":402},{"type":54,"tag":368,"props":655,"children":656},{"style":375},[657],{"type":59,"value":435},{"type":54,"tag":368,"props":659,"children":660},{"style":375},[661],{"type":59,"value":440},{"type":54,"tag":368,"props":663,"children":665},{"style":664},"--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178",[666],{"type":59,"value":667},"location",{"type":54,"tag":368,"props":669,"children":670},{"style":375},[671],{"type":59,"value":397},{"type":54,"tag":368,"props":673,"children":674},{"style":375},[675],{"type":59,"value":402},{"type":54,"tag":368,"props":677,"children":678},{"style":375},[679],{"type":59,"value":435},{"type":54,"tag":368,"props":681,"children":682},{"style":375},[683],{"type":59,"value":440},{"type":54,"tag":368,"props":685,"children":687},{"style":686},"--shiki-light:#916B53;--shiki-default:#916B53;--shiki-dark:#916B53",[688],{"type":59,"value":605},{"type":54,"tag":368,"props":690,"children":691},{"style":375},[692],{"type":59,"value":397},{"type":54,"tag":368,"props":694,"children":695},{"style":375},[696],{"type":59,"value":402},{"type":54,"tag":368,"props":698,"children":699},{"style":375},[700],{"type":59,"value":440},{"type":54,"tag":368,"props":702,"children":703},{"style":620},[704],{"type":59,"value":705},"string",{"type":54,"tag":368,"props":707,"children":708},{"style":375},[709],{"type":59,"value":397},{"type":54,"tag":368,"props":711,"children":712},{"style":375},[713],{"type":59,"value":464},{"type":54,"tag":368,"props":715,"children":716},{"style":375},[717],{"type":59,"value":440},{"type":54,"tag":368,"props":719,"children":720},{"style":686},[721],{"type":59,"value":336},{"type":54,"tag":368,"props":723,"children":724},{"style":375},[725],{"type":59,"value":397},{"type":54,"tag":368,"props":727,"children":728},{"style":375},[729],{"type":59,"value":402},{"type":54,"tag":368,"props":731,"children":732},{"style":375},[733],{"type":59,"value":440},{"type":54,"tag":368,"props":735,"children":736},{"style":620},[737],{"type":59,"value":738},"City to show weather for",{"type":54,"tag":368,"props":740,"children":741},{"style":375},[742],{"type":59,"value":397},{"type":54,"tag":368,"props":744,"children":745},{"style":375},[746],{"type":59,"value":747}," }",{"type":54,"tag":368,"props":749,"children":750},{"style":375},[751],{"type":59,"value":752}," }\n",{"type":54,"tag":368,"props":754,"children":756},{"class":370,"line":755},7,[757],{"type":54,"tag":368,"props":758,"children":759},{"style":375},[760],{"type":59,"value":761},"    }\n",{"type":54,"tag":368,"props":763,"children":765},{"class":370,"line":764},8,[766],{"type":54,"tag":368,"props":767,"children":768},{"style":375},[769],{"type":59,"value":770},"  }\n",{"type":54,"tag":368,"props":772,"children":774},{"class":370,"line":773},9,[775],{"type":54,"tag":368,"props":776,"children":777},{"style":375},[778],{"type":59,"value":779},"}\n",{"type":54,"tag":781,"props":782,"children":783},"br",{},[],{"type":59,"value":785},"Size is in grid units (widths 1–12, heights 1–40); ",{"type":54,"tag":89,"props":787,"children":789},{"className":788},[],[790],{"type":59,"value":791},"minW \u003C= defaultW \u003C= maxW",{"type":59,"value":793},". The range is\nadvisory: users may resize a placement to any size, so it informs defaults and warnings, never\nrejections. The config schema\nvocabulary is an allowlist — ",{"type":54,"tag":89,"props":795,"children":797},{"className":796},[],[798],{"type":59,"value":605},{"type":59,"value":800},", ",{"type":54,"tag":89,"props":802,"children":804},{"className":803},[],[805],{"type":59,"value":806},"title",{"type":59,"value":800},{"type":54,"tag":89,"props":809,"children":811},{"className":810},[],[812],{"type":59,"value":336},{"type":59,"value":800},{"type":54,"tag":89,"props":815,"children":817},{"className":816},[],[818],{"type":59,"value":819},"default",{"type":59,"value":800},{"type":54,"tag":89,"props":822,"children":824},{"className":823},[],[825],{"type":59,"value":645},{"type":59,"value":800},{"type":54,"tag":89,"props":828,"children":830},{"className":829},[],[831],{"type":59,"value":832},"required",{"type":59,"value":632},{"type":54,"tag":89,"props":835,"children":837},{"className":836},[],[838],{"type":59,"value":839},"additionalProperties",{"type":59,"value":800},{"type":54,"tag":89,"props":842,"children":844},{"className":843},[],[845],{"type":59,"value":846},"items",{"type":59,"value":800},{"type":54,"tag":89,"props":849,"children":851},{"className":850},[],[852],{"type":59,"value":853},"enum",{"type":59,"value":800},{"type":54,"tag":89,"props":856,"children":858},{"className":857},[],[859],{"type":59,"value":860},"const",{"type":59,"value":800},{"type":54,"tag":89,"props":863,"children":865},{"className":864},[],[866],{"type":59,"value":867},"minimum",{"type":59,"value":800},{"type":54,"tag":89,"props":870,"children":872},{"className":871},[],[873],{"type":59,"value":874},"maximum",{"type":59,"value":800},{"type":54,"tag":89,"props":877,"children":879},{"className":878},[],[880],{"type":59,"value":881},"minLength",{"type":59,"value":800},{"type":54,"tag":89,"props":884,"children":886},{"className":885},[],[887],{"type":59,"value":888},"maxLength",{"type":59,"value":632},{"type":54,"tag":89,"props":891,"children":893},{"className":892},[],[894],{"type":59,"value":895},"minItems",{"type":59,"value":800},{"type":54,"tag":89,"props":898,"children":900},{"className":899},[],[901],{"type":59,"value":902},"maxItems",{"type":59,"value":800},{"type":54,"tag":89,"props":905,"children":907},{"className":906},[],[908],{"type":59,"value":909},"format",{"type":59,"value":911},". No ",{"type":54,"tag":89,"props":913,"children":915},{"className":914},[],[916],{"type":59,"value":917},"$ref",{"type":59,"value":919},", no ",{"type":54,"tag":89,"props":921,"children":923},{"className":922},[],[924],{"type":59,"value":925},"pattern",{"type":59,"value":927}," — validation rejects them.",{"type":54,"tag":85,"props":929,"children":930},{},[931,936,938,943,945,950,952,958],{"type":54,"tag":68,"props":932,"children":933},{},[934],{"type":59,"value":935},"Design responsively.",{"type":59,"value":937}," Fill 100% of the box's width and height, and adapt the layout to any\nsize the user drags: a 2×1 placement is a glanceable tile; a 6×4 is a full app surface. Render\nusefully at ",{"type":54,"tag":89,"props":939,"children":941},{"className":940},[],[942],{"type":59,"value":499},{"type":59,"value":944},"×",{"type":54,"tag":89,"props":946,"children":948},{"className":947},[],[949],{"type":59,"value":524},{"type":59,"value":951},", and treat ",{"type":54,"tag":89,"props":953,"children":955},{"className":954},[],[956],{"type":59,"value":957},"config",{"type":59,"value":959}," as the only per-placement input.",{"type":54,"tag":62,"props":961,"children":962},{},[963],{"type":59,"value":964},"Publish and wait for the build like any canvas — a component with no ready build cannot go live on\na grid.",{"type":54,"tag":128,"props":966,"children":968},{"id":967},"composing-a-whole-canvas",[969],{"type":59,"value":970},"Composing a whole canvas",{"type":54,"tag":62,"props":972,"children":973},{},[974],{"type":59,"value":975},"A whole-canvas ask (\"a home canvas that summarizes my work in progress\") usually means several widgets, not one.\nPlan the full set first — one placement per concern — then resolve each with the ladder above.\nLay them out together: no overlaps, sizes matched to what each widget shows, the grid filled deliberately rather than tiles scattered in a corner.\nBatch the layout writes (one publish for an initial layout, surgical patches after) instead of one write per widget, and finish with every placement live or failed — never generating.",{"type":54,"tag":128,"props":977,"children":979},{"id":978},"canvas-comments",[980],{"type":59,"value":981},"Canvas comments",{"type":54,"tag":62,"props":983,"children":984},{},[985,987,993,994,1000],{"type":59,"value":986},"Users leave feedback as comment threads on the canvas, anchored to its conversation task.\nList them with the task comment tools (",{"type":54,"tag":89,"props":988,"children":990},{"className":989},[],[991],{"type":59,"value":992},"tasks-comments-list",{"type":59,"value":800},{"type":54,"tag":89,"props":995,"children":997},{"className":996},[],[998],{"type":59,"value":999},"tasks-comments-retrieve",{"type":59,"value":1001},") on your task before and after changing the canvas, and address the open ones — a comment naming a broken widget is your brief for fixing it.",{"type":54,"tag":128,"props":1003,"children":1005},{"id":1004},"editing-a-grid",[1006],{"type":59,"value":1007},"Editing a grid",{"type":54,"tag":62,"props":1009,"children":1010},{},[1011,1013,1018,1020,1026,1028,1033,1035,1041,1043,1049],{"type":59,"value":1012},"The loop is read → patch, guarded exactly as ",{"type":54,"tag":89,"props":1014,"children":1016},{"className":1015},[],[1017],{"type":59,"value":294},{"type":59,"value":1019}," describes for\nsource publishes — with ",{"type":54,"tag":89,"props":1021,"children":1023},{"className":1022},[],[1024],{"type":59,"value":1025},"canvas-layout-get",{"type":59,"value":1027}," in place of ",{"type":54,"tag":89,"props":1029,"children":1031},{"className":1030},[],[1032],{"type":59,"value":223},{"type":59,"value":1034},", and\n",{"type":54,"tag":89,"props":1036,"children":1038},{"className":1037},[],[1039],{"type":59,"value":1040},"canvas-layout-patch",{"type":59,"value":1042}," (surgical ops, guard required) or ",{"type":54,"tag":89,"props":1044,"children":1046},{"className":1045},[],[1047],{"type":59,"value":1048},"canvas-layout-publish",{"type":59,"value":1050}," (complete\ndocument, for an initial layout or full restructure) as the write. On a 409, re-read the layout,\nre-apply your change, and patch again.",{"type":54,"tag":62,"props":1052,"children":1053},{},[1054],{"type":59,"value":1055},"Operations:",{"type":54,"tag":81,"props":1057,"children":1058},{},[1059,1086,1120],{"type":54,"tag":85,"props":1060,"children":1061},{},[1062,1068,1070,1076,1078,1084],{"type":54,"tag":89,"props":1063,"children":1065},{"className":1064},[],[1066],{"type":59,"value":1067},"add_placement",{"type":59,"value":1069}," — a new box: ",{"type":54,"tag":89,"props":1071,"children":1073},{"className":1072},[],[1074],{"type":59,"value":1075},"{id, status, x, y, w, h, ...}",{"type":59,"value":1077},". Placements must not overlap or\nextend past ",{"type":54,"tag":89,"props":1079,"children":1081},{"className":1080},[],[1082],{"type":59,"value":1083},"grid.columns",{"type":59,"value":1085},".",{"type":54,"tag":85,"props":1087,"children":1088},{},[1089,1095,1097,1103,1105,1111,1113,1119],{"type":54,"tag":89,"props":1090,"children":1092},{"className":1091},[],[1093],{"type":59,"value":1094},"update_placement",{"type":59,"value":1096}," — merge ",{"type":54,"tag":89,"props":1098,"children":1100},{"className":1099},[],[1101],{"type":59,"value":1102},"changes",{"type":59,"value":1104}," into the placement with ",{"type":54,"tag":89,"props":1106,"children":1108},{"className":1107},[],[1109],{"type":59,"value":1110},"id",{"type":59,"value":1112},". Filling a drawn box is\n",{"type":54,"tag":89,"props":1114,"children":1116},{"className":1115},[],[1117],{"type":59,"value":1118},"{\"op\": \"update_placement\", \"id\": \"p1\", \"changes\": {\"status\": \"live\", \"component\": \"\u003Ccomponent canvas id>\", \"config\": {...}}}",{"type":59,"value":1085},{"type":54,"tag":85,"props":1121,"children":1122},{},[1123,1129,1130,1136],{"type":54,"tag":89,"props":1124,"children":1126},{"className":1125},[],[1127],{"type":59,"value":1128},"remove_placement",{"type":59,"value":800},{"type":54,"tag":89,"props":1131,"children":1133},{"className":1132},[],[1134],{"type":59,"value":1135},"set_grid",{"type":59,"value":1085},{"type":54,"tag":128,"props":1138,"children":1140},{"id":1139},"the-placement-lifecycle",[1141],{"type":59,"value":1142},"The placement lifecycle",{"type":54,"tag":62,"props":1144,"children":1145},{},[1146,1148,1154],{"type":59,"value":1147},"A placement's ",{"type":54,"tag":89,"props":1149,"children":1151},{"className":1150},[],[1152],{"type":59,"value":1153},"status",{"type":59,"value":1155}," tells the renderer what to show:",{"type":54,"tag":81,"props":1157,"children":1158},{},[1159,1170,1197,1231],{"type":54,"tag":85,"props":1160,"children":1161},{},[1162,1168],{"type":54,"tag":89,"props":1163,"children":1165},{"className":1164},[],[1166],{"type":59,"value":1167},"pending",{"type":59,"value":1169}," — the user drew a box but hasn't described it (or the prompt awaits dispatch).",{"type":54,"tag":85,"props":1171,"children":1172},{},[1173,1179,1181,1187,1189,1195],{"type":54,"tag":89,"props":1174,"children":1176},{"className":1175},[],[1177],{"type":59,"value":1178},"generating",{"type":59,"value":1180}," — an agent task is filling it; ",{"type":54,"tag":89,"props":1182,"children":1184},{"className":1183},[],[1185],{"type":59,"value":1186},"generationTaskId",{"type":59,"value":1188}," links the task and ",{"type":54,"tag":89,"props":1190,"children":1192},{"className":1191},[],[1193],{"type":59,"value":1194},"prompt",{"type":59,"value":1196},"\nrecords the ask. Set this when you start working on a placement from a task.",{"type":54,"tag":85,"props":1198,"children":1199},{},[1200,1206,1208,1213,1215,1221,1223,1229],{"type":54,"tag":89,"props":1201,"children":1203},{"className":1202},[],[1204],{"type":59,"value":1205},"live",{"type":59,"value":1207}," — renders its ",{"type":54,"tag":89,"props":1209,"children":1211},{"className":1210},[],[1212],{"type":59,"value":113},{"type":59,"value":1214}," at ",{"type":54,"tag":89,"props":1216,"children":1218},{"className":1217},[],[1219],{"type":59,"value":1220},"version",{"type":59,"value":1222}," (",{"type":54,"tag":89,"props":1224,"children":1226},{"className":1225},[],[1227],{"type":59,"value":1228},"\"latest\"",{"type":59,"value":1230}," by default; a pinned version id is\nallowed). Requires the component to be published and visible to the acting user.",{"type":54,"tag":85,"props":1232,"children":1233},{},[1234,1240,1242,1247],{"type":54,"tag":89,"props":1235,"children":1237},{"className":1236},[],[1238],{"type":59,"value":1239},"failed",{"type":59,"value":1241}," — generation failed; keep the ",{"type":54,"tag":89,"props":1243,"children":1245},{"className":1244},[],[1246],{"type":59,"value":1194},{"type":59,"value":1248}," so the user can retry or re-describe.",{"type":54,"tag":62,"props":1250,"children":1251},{},[1252,1254,1260,1261,1267,1269,1274],{"type":59,"value":1253},"When a task asks you to fill a placement, its prompt and the box's size are your brief: honor the\ndrawn ",{"type":54,"tag":89,"props":1255,"children":1257},{"className":1256},[],[1258],{"type":59,"value":1259},"w",{"type":59,"value":944},{"type":54,"tag":89,"props":1262,"children":1264},{"className":1263},[],[1265],{"type":59,"value":1266},"h",{"type":59,"value":1268}," and keep the placement's ",{"type":54,"tag":89,"props":1270,"children":1272},{"className":1271},[],[1273],{"type":59,"value":1194},{"type":59,"value":1275},"\nintact for provenance.",{"type":54,"tag":128,"props":1277,"children":1279},{"id":1278},"validation-you-will-hit",[1280],{"type":59,"value":1281},"Validation you will hit",{"type":54,"tag":62,"props":1283,"children":1284},{},[1285],{"type":59,"value":1286},"Layout publishes validate atomically; every error names its placement. The common ones:",{"type":54,"tag":81,"props":1288,"children":1289},{},[1290,1301,1312,1336,1361],{"type":54,"tag":85,"props":1291,"children":1292},{},[1293,1299],{"type":54,"tag":89,"props":1294,"children":1296},{"className":1295},[],[1297],{"type":59,"value":1298},"component_not_found",{"type":59,"value":1300}," — the id is wrong, deleted, not a component, or not visible to the acting\nuser (a component in someone else's personal channel is not placeable).",{"type":54,"tag":85,"props":1302,"children":1303},{},[1304,1310],{"type":54,"tag":89,"props":1305,"children":1307},{"className":1306},[],[1308],{"type":59,"value":1309},"component_not_published",{"type":59,"value":1311}," — the component has never published a placement contract.",{"type":54,"tag":85,"props":1313,"children":1314},{},[1315,1321,1323,1328,1330,1335],{"type":54,"tag":89,"props":1316,"children":1318},{"className":1317},[],[1319],{"type":59,"value":1320},"placement_config_invalid",{"type":59,"value":1322}," — ",{"type":54,"tag":89,"props":1324,"children":1326},{"className":1325},[],[1327],{"type":59,"value":957},{"type":59,"value":1329}," does not match the component's ",{"type":54,"tag":89,"props":1331,"children":1333},{"className":1332},[],[1334],{"type":59,"value":197},{"type":59,"value":1085},{"type":54,"tag":85,"props":1337,"children":1338},{},[1339,1345,1347,1352,1354,1359],{"type":54,"tag":89,"props":1340,"children":1342},{"className":1341},[],[1343],{"type":59,"value":1344},"placement_size_out_of_contract",{"type":59,"value":1346}," — a warning, not an error: the box's ",{"type":54,"tag":89,"props":1348,"children":1350},{"className":1349},[],[1351],{"type":59,"value":1259},{"type":59,"value":1353},"\u002F",{"type":54,"tag":89,"props":1355,"children":1357},{"className":1356},[],[1358],{"type":59,"value":1266},{"type":59,"value":1360}," is outside the\ncomponent's suggested range. The publish still succeeds; the component must render responsively.",{"type":54,"tag":85,"props":1362,"children":1363},{},[1364,1370,1372,1378],{"type":54,"tag":89,"props":1365,"children":1367},{"className":1366},[],[1368],{"type":59,"value":1369},"placements_overlap",{"type":59,"value":1371}," \u002F ",{"type":54,"tag":89,"props":1373,"children":1375},{"className":1374},[],[1376],{"type":59,"value":1377},"invalid_placement",{"type":59,"value":1379}," — geometry; fix coordinates rather than removing the\nother widget.",{"type":54,"tag":62,"props":1381,"children":1382},{},[1383,1385,1391],{"type":59,"value":1384},"End your reply by linking the grid canvas with the ",{"type":54,"tag":89,"props":1386,"children":1388},{"className":1387},[],[1389],{"type":59,"value":1390},"url",{"type":59,"value":1392}," field the canvas tools return — never\nconstruct a canvas URL yourself.",{"type":54,"tag":1394,"props":1395,"children":1396},"style",{},[1397],{"type":59,"value":1398},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":1400,"total":1573},[1401,1416,1428,1440,1453,1469,1484,1500,1516,1533,1546,1561],{"slug":1402,"name":1402,"fn":1403,"description":1404,"org":1405,"tags":1406,"stars":23,"repoUrl":24,"updatedAt":1415},"analyzing-expensive-users","analyze expensive users in AI observability","Analyze the most expensive users in AI observability and explain why they cost so much. Use when the user asks about top spenders, expensive users, per-user LLM cost, user-level cost drivers, or patterns behind high AI observability spend.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1407,1408,1411,1414],{"name":18,"slug":19,"type":15},{"name":1409,"slug":1410,"type":15},"Cost Optimization","cost-optimization",{"name":1412,"slug":1413,"type":15},"Observability","observability",{"name":9,"slug":8,"type":15},"2026-08-13T04:28:38.012786",{"slug":1417,"name":1417,"fn":1418,"description":1419,"org":1420,"tags":1421,"stars":23,"repoUrl":24,"updatedAt":1427},"auditing-endpoints","audit PostHog project endpoints","Audit every endpoint in a PostHog project for staleness, failed materialisations, and unused materialised versions. Use when the user asks \"what endpoints can I clean up?\", \"are any of my endpoints broken?\", \"which materialised versions are still being called?\", or wants a one-shot cleanup pass over the Endpoints product. Produces a prioritised report grouped by issue type, with recommended actions but does not modify anything without explicit confirmation.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1422,1423,1426],{"name":18,"slug":19,"type":15},{"name":1424,"slug":1425,"type":15},"Audit","audit",{"name":9,"slug":8,"type":15},"2026-06-08T08:08:33.693989",{"slug":1429,"name":1429,"fn":1430,"description":1431,"org":1432,"tags":1433,"stars":23,"repoUrl":24,"updatedAt":1439},"auditing-warehouse-source-health","audit PostHog data warehouse source health","Audit the health of a PostHog project's data warehouse sources and syncs — find every broken or degraded source connection, sync schema, and webhook channel. Use when the user asks \"why are my imports failing?\", \"what's broken with my sources?\", \"why is my warehouse data stale?\", or wants a one-shot triage of source\u002Fsync health before deciding where to dig in. Produces a prioritized report grouped by severity, with recommended next steps. For materialized-view health use `auditing-warehouse-view-health`; for a single failing sync use `diagnosing-failed-warehouse-syncs`.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1434,1435,1437,1438],{"name":1424,"slug":1425,"type":15},{"name":1436,"slug":32,"type":15},"Data Warehouse",{"name":1412,"slug":1413,"type":15},{"name":9,"slug":8,"type":15},"2026-06-18T08:22:57.67984",{"slug":1441,"name":1441,"fn":1442,"description":1443,"org":1444,"tags":1445,"stars":23,"repoUrl":24,"updatedAt":1452},"auditing-warehouse-view-health","audit PostHog materialized view health","Audit the health of a PostHog project's materialized views (saved queries) — find every failed materialization and flag unused or stale materialized views that cost storage and compute. Use when the user asks \"which of my views are broken?\", \"why is this materialized view failing?\", \"are any of my views wasting compute?\", or wants a one-shot triage of view health. For source\u002Fsync health use `auditing-warehouse-source-health`.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1446,1447,1448,1451],{"name":1424,"slug":1425,"type":15},{"name":1436,"slug":32,"type":15},{"name":1449,"slug":1450,"type":15},"Performance","performance",{"name":9,"slug":8,"type":15},"2026-06-18T08:25:10.936787",{"slug":1454,"name":1454,"fn":1455,"description":1456,"org":1457,"tags":1458,"stars":23,"repoUrl":24,"updatedAt":1468},"authoring-data-quality-checks","author data quality checks for warehouse tables","Adds and runs data quality checks (dbt-test style assertions) on a project's warehouse tables and saved-query views: not-null, uniqueness, accepted values, referential integrity, row-count bounds, freshness, and custom HogQL. Use when asked to test a model, validate a view, check for nulls or duplicates, add data quality checks, find out why a number looks wrong, or judge whether a warehouse table is trustworthy before using it in an analysis. To describe what data *means* (metrics, certifications, joins), see setting-up-data-catalog instead. Trigger terms: data quality, data test, dbt test, not null check, uniqueness check, freshness check, referential integrity, row count check, validate model, is this table trustworthy.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1459,1460,1463,1466],{"name":18,"slug":19,"type":15},{"name":1461,"slug":1462,"type":15},"Data Engineering","data-engineering",{"name":1464,"slug":1465,"type":15},"Data Quality","data-quality",{"name":1467,"slug":1467,"type":15},"dbt","2026-08-19T03:59:25.329274",{"slug":1470,"name":1470,"fn":1471,"description":1472,"org":1473,"tags":1474,"stars":23,"repoUrl":24,"updatedAt":1483},"authoring-error-tracking-alerts","author PostHog error tracking alerts","Author error tracking alerts that fire when an issue is created, reopened, or starts spiking. Use when the user asks to set up error notifications, route exceptions to Slack\u002Fwebhook\u002FLinear, or evaluate which error events are worth alerting on. Covers trigger-event selection, integration choice, dedup against existing alerts, and shipping with the canonical message body shape.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1475,1478,1481,1482],{"name":1476,"slug":1477,"type":15},"Alerting","alerting",{"name":1479,"slug":1480,"type":15},"Debugging","debugging",{"name":1412,"slug":1413,"type":15},{"name":9,"slug":8,"type":15},"2026-08-13T04:28:36.025103",{"slug":1485,"name":1485,"fn":1486,"description":1487,"org":1488,"tags":1489,"stars":23,"repoUrl":24,"updatedAt":1499},"authoring-log-alerts","author log alerts in PostHog","Author useful, low-noise log alerts on services in a PostHog project. Use when the user asks to set up alerts for their logs, suggest alerts they should add, or evaluate whether a service is worth monitoring. Covers service triage, baseline characterisation, threshold drafting, back-testing via simulate, and shipping with a notification destination.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1490,1491,1494,1495,1498],{"name":18,"slug":19,"type":15},{"name":1492,"slug":1493,"type":15},"Monitoring","monitoring",{"name":1412,"slug":1413,"type":15},{"name":1496,"slug":1497,"type":15},"Operations","operations",{"name":9,"slug":8,"type":15},"2026-08-13T04:28:20.051489",{"slug":102,"name":102,"fn":1501,"description":1502,"org":1503,"tags":1504,"stars":23,"repoUrl":24,"updatedAt":1515},"create and edit PostHog 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\u002Fweb 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\u002Fhome 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\u002Fbrowser APIs), the read → edit → validate → publish → build loop, and which companion canvas skills to load for the details.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1505,1508,1511,1512],{"name":1506,"slug":1507,"type":15},"Automation","automation",{"name":1509,"slug":1510,"type":15},"Design","design",{"name":9,"slug":8,"type":15},{"name":1513,"slug":1514,"type":15},"Prototyping","prototyping","2026-08-19T03:27:38.215922",{"slug":279,"name":279,"fn":1517,"description":1518,"org":1519,"tags":1520,"stars":23,"repoUrl":24,"updatedAt":1532},"author HTML and CSS PostHog canvases","Author a PostHog canvas with semantic HTML, CSS, and direct browser APIs — documents, articles, generative graphics, 2D canvas and WebGL experiences, and focused experiments where React components add no useful structure. Use after building-canvases has routed a canvas request to a plain-HTML\u002Fbrowser-API implementation. Covers the thin component wrapper the current runtime requires, styling and theming without Quill, drawing surfaces, and animation\u002Fcleanup patterns.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1521,1524,1525,1528,1531],{"name":1522,"slug":1523,"type":15},"CSS","css",{"name":1509,"slug":1510,"type":15},{"name":1526,"slug":1527,"type":15},"Graphics","graphics",{"name":1529,"slug":1530,"type":15},"HTML","html",{"name":9,"slug":8,"type":15},"2026-08-06T06:09:30.313848",{"slug":271,"name":271,"fn":1534,"description":1535,"org":1536,"tags":1537,"stars":23,"repoUrl":24,"updatedAt":1545},"build React and Quill canvases","Author the React + Quill implementation of a PostHog canvas: the single-component contract, the allowed imports, Quill (PostHog's design system) component and composition rules, theme-aware design tokens, loading skeletons, and the in-canvas date picker. Use after building-canvases has routed a canvas request to a React implementation — dashboards, data boards, forms, tools, or any canvas that should look native to PostHog.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1538,1539,1542,1544],{"name":1509,"slug":1510,"type":15},{"name":1540,"slug":1541,"type":15},"Frontend","frontend",{"name":1543,"slug":38,"type":15},"React",{"name":21,"slug":22,"type":15},"2026-08-19T03:27:37.227731",{"slug":1547,"name":1547,"fn":1548,"description":1549,"org":1550,"tags":1551,"stars":23,"repoUrl":24,"updatedAt":1560},"building-workflows","build and edit PostHog workflows","Build, edit, test, enable, and monitor PostHog workflows over MCP. Author the action\u002Fedge graph so it runs and opens cleanly in the visual editor, then change drafts surgically with patch operations. Use when asked to build, set up, automate, change, fix, or debug a workflow, campaign, broadcast, drip sequence, or event-triggered automation in the workflows product.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1552,1553,1556,1557],{"name":1506,"slug":1507,"type":15},{"name":1554,"slug":1555,"type":15},"MCP","mcp",{"name":9,"slug":8,"type":15},{"name":1558,"slug":1559,"type":15},"Workflow Automation","workflow-automation","2026-08-10T04:16:26.294119",{"slug":1562,"name":1562,"fn":1563,"description":1564,"org":1565,"tags":1566,"stars":23,"repoUrl":24,"updatedAt":1572},"check-posthog-loading","inspect PostHog SDK loading across URLs","Inspect how the PostHog JavaScript SDK is loaded across a list of URLs. Use to confirm consistent installation across pages, find pages missing the snippet, detect mismatched API keys or hosts between pages, and verify the load method (head snippet vs deferred vs array.js).\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1567,1568,1569,1570,1571],{"name":18,"slug":19,"type":15},{"name":1479,"slug":1480,"type":15},{"name":1540,"slug":1541,"type":15},{"name":1412,"slug":1413,"type":15},{"name":9,"slug":8,"type":15},"2026-05-07T05:56:19.828048",251,{"items":1575,"total":1625},[1576,1583,1589,1596,1603,1610,1617],{"slug":1402,"name":1402,"fn":1403,"description":1404,"org":1577,"tags":1578,"stars":23,"repoUrl":24,"updatedAt":1415},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1579,1580,1581,1582],{"name":18,"slug":19,"type":15},{"name":1409,"slug":1410,"type":15},{"name":1412,"slug":1413,"type":15},{"name":9,"slug":8,"type":15},{"slug":1417,"name":1417,"fn":1418,"description":1419,"org":1584,"tags":1585,"stars":23,"repoUrl":24,"updatedAt":1427},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1586,1587,1588],{"name":18,"slug":19,"type":15},{"name":1424,"slug":1425,"type":15},{"name":9,"slug":8,"type":15},{"slug":1429,"name":1429,"fn":1430,"description":1431,"org":1590,"tags":1591,"stars":23,"repoUrl":24,"updatedAt":1439},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1592,1593,1594,1595],{"name":1424,"slug":1425,"type":15},{"name":1436,"slug":32,"type":15},{"name":1412,"slug":1413,"type":15},{"name":9,"slug":8,"type":15},{"slug":1441,"name":1441,"fn":1442,"description":1443,"org":1597,"tags":1598,"stars":23,"repoUrl":24,"updatedAt":1452},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1599,1600,1601,1602],{"name":1424,"slug":1425,"type":15},{"name":1436,"slug":32,"type":15},{"name":1449,"slug":1450,"type":15},{"name":9,"slug":8,"type":15},{"slug":1454,"name":1454,"fn":1455,"description":1456,"org":1604,"tags":1605,"stars":23,"repoUrl":24,"updatedAt":1468},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1606,1607,1608,1609],{"name":18,"slug":19,"type":15},{"name":1461,"slug":1462,"type":15},{"name":1464,"slug":1465,"type":15},{"name":1467,"slug":1467,"type":15},{"slug":1470,"name":1470,"fn":1471,"description":1472,"org":1611,"tags":1612,"stars":23,"repoUrl":24,"updatedAt":1483},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1613,1614,1615,1616],{"name":1476,"slug":1477,"type":15},{"name":1479,"slug":1480,"type":15},{"name":1412,"slug":1413,"type":15},{"name":9,"slug":8,"type":15},{"slug":1485,"name":1485,"fn":1486,"description":1487,"org":1618,"tags":1619,"stars":23,"repoUrl":24,"updatedAt":1499},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[1620,1621,1622,1623,1624],{"name":18,"slug":19,"type":15},{"name":1492,"slug":1493,"type":15},{"name":1412,"slug":1413,"type":15},{"name":1496,"slug":1497,"type":15},{"name":9,"slug":8,"type":15},78]