
PostHog Canvas 自由画布开发指南从解析目标到受保护发布与构建的完整工作流【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog本篇指南基于 PostHog 仓库中 Canvas 产品的building-canvases技能文档系统讲解如何为 PostHog 创建或编辑freeform自由画布——一种运行在沙箱 iframe 中的独立浏览器应用数据看板、文档、表单、小工具、图形实验。读完你可以掌握如何解析或创建目标画布、如何在 React Quill 与纯 HTML 两种实现路线间选型、图片资源的标准处理流程、读 → 改 → 校验 → 发布 → 等构建的迭代闭环以及ph.state、ph.actions、ph.connectors、ph.agent.request四个运行时桥接 API 的声明规则并进一步结合后端模型与校验源码理解平台契约固定依赖、能力声明、CSP 沙箱的落地机制。画布是什么源码存在 PostHog 里的浏览器应用Canvas画布是一个客户端浏览器应用运行在 PostHog 内部的沙箱 iframe中。与常规前端工程最本质的区别是它的源码存放在 PostHog 里而不是代码仓库中。你通过canvas-*系列工具读写它通过工具发布才算保存——永远不要把画布写到本地文件。画布工作可以从任何普通任务发起不要求存在专门的画布模式或预先创建的画布。只要用户要求一个应该住在 PostHog 里的看板、文档、表单、可视化或小应用就应当按画布请求处理。PostHog 中画布分为三种类型对应后端模型Canvas.kind字段的三个取值见 models.py类型含义由哪个技能负责freeform独立应用源项目编译为单个制品building-canvases本文主体grid组件网格包括用户的首页画布composing-grid-canvasescomponent可复用组件widget被 grid 画布放置composing-grid-canvasesbuilding-canvases技能只拥有freeform画布。当目标是 grid 或首页画布、某个 placement 布局、或可复用组件时应改加载 composing-grid-canvases——它拥有商店搜索 → 配置 → fork → 构建的阶梯与布局补丁循环。但注意编写组件的源码仍然使用本文所述的实现类伴随技能。从源码结构看这一划分与后端模型注释完全一致grid的源码是布局文档发布时校验并版本化布局而不排队构建component与freeform共用同一套源码/构建管线额外携带配置 schema 与网格尺寸契约。第一步解析目标画布在动笔写任何代码之前先确定写给哪个画布。规则按优先级排列任务指定了 canvas id画布发起的任务都会带上那就是目标不要再创建新的。否则目标频道是任务创建时所在的频道——任务上下文channel_context块或生成指令中会写明频道名。用canvas-list工具以channel参数限定范围列出该频道的画布。如果其中有一个明显是所指对象同一看板的早期迭代、同一工具的前身就在其上继续构建而不是创建一个近似的重复品并在回复中说明结果落在哪里。只有当现有画布都不匹配时才用canvas-create在同一频道创建新画布名字取请求中简短的描述性标题——绝不能用 Untitled canvas。永远不要自行浏览频道来挑选目标channel-list只用于把用户点名的频道解析为 id。它的列表会把个人频道#me排在最前而#me永远不应作为默认值——放在那里的画布对其他人不可见。如果任务既没有点名画布也没有点名频道直接询问用户用哪个频道而不是猜测。canvas-create支持kind参数freeform独立应用默认、component可复用组件其已发布项目必须声明component放置契约、grid组件组合通过canvas-layout-patch编辑。工具定义见 mcp/tools.yaml。选择实现路线加载伴随技能building-canvases拥有画布选择 创作生命周期而实现契约放在四个伴随技能中。在写源码之前先加载所有适用的伴随技能building-react-quill-canvases——用于看板、数据板、表单、工具、应用式状态或任何希望看起来原生于 PostHog 的场景。它拥有允许导入清单、Quill 组件组合、主题化、图表、加载/错误状态与日期选择器。building-html-canvases——用于文档、文章、聚焦实验、生成式图形、canvas或 WebGL即应用组件不带来任何有用结构的场合。它拥有语义化标记、直接浏览器 API、动画清理与非 Quill 主题化。querying-canvas-data——只要画布要读 PostHog 数据、埋点或导航就必须加载。它拥有phSDK、优先用已保存 insight的数据层级、结果形状、变量、日期范围、按查询渐进加载与声明数据能力。涉及数据时与任一实现技能一起加载。validating-and-publishing-canvases——每个画布都要加载。它拥有项目形状、能力声明、校验诊断、受保护发布、草稿、构建与冲突恢复。实现方式可以混搭React 可以拥有应用外壳而浏览器图形代码拥有画布元素或一个基本静态的页面挂载一个交互式岛屿。这是一个判断决策而不是持久化模式——只有当选择改变了一个你无法推断的用户可见需求时才向用户提问。从源码结构看两种路线共享同一入口约束building-html-canvases 明确要求所有画布都保留src/canvas.tsx作为被挂载的 React 入口组件默认导出、无 propsReact 层保持薄壳体验写在其中的 HTML/CSS/浏览器 API 里——纯 HTML 路线的文档就是效果上是语义化 HTML 的 JSX。图片资源走公共媒体库不要 base64画布中的图片使用公共媒体库 URL。标准流程先调用posthog:media-images-list带purposecanvas已有合适的图片就直接复用。要添加本地图片时调用posthog:media-image-upload-start传文件名字段和purposecanvas。在 shell 中把文件以 multipart 表单数据 POST 到返回的upload_url。包含所有返回的form_fields条目并把文件部分放在最后。调用posthog:media-image-upload-complete传回返回的 id用其永久url作为图片src。把该 URL 的精确 origin 加入project.capabilities.network.origins。画布校验会检查这个声明已发布制品会在其 Content Security Policy 中使用它。约束与安全边界画布媒体 URL 是公开的、不需要认证。绝不要上传秘密、凭证、客户数据或敏感截图。图片必须小于 4 MB且可解码为 PNG、JPEG、GIF、WebP、AVIF 或 BMP。绝不把图片字节 base64 编码进工具调用。从后端实现看第 5 步之所以强制是因为声明的 origin 会被直接拼进入口制品的 CSPcontract.py 中artifact_csp()把通过canonical_network_origin()校验的 origin 注入connect-src、style-src、img-src、font-src、media-src、frame-src指令。而canonical_network_origin()本身是一道安全闸只接受精确 HTTPS origin无路径、无凭证、无查询/片段、无通配符并且主机必须是公共的——回环地址、私有 IP、单标签域名如intranet、以及.local/.localhost/.internal/.home.arpa后缀全部被拒绝。因此像https://localhost:8010这样的本地开发主机会以invalid_network_origin诊断失败校验。常见请求模式路由示例而非固定模板这些模式用于把请求路由到实现方案不是必须套用的模板产品看板、Web 分析板、指标浏览器React Quill 数据查询querying-canvas-data。清单、表单、轻量工作流React Quill如需 PostHog 读取、埋点或导航再加数据查询。对于清单或 runbook从building-react-quill-canvases的实例 references/checklist-example.md 起步——通过每步一个ph.state键实现团队共享进度。不要暗示现有 API 并不提供的持久化。文档或叙述式报告HTML 提供基本静态的阅读体验需要 PostHog 实时数据、过滤器或应用式交互时改用 React Quill 数据查询。生成式图形或动画HTML 浏览器图形 API只有当 React 能实质简化应用状态或外壳时才加入 React。如果任务携带诸如dashboard或web-analytics之类的遗留请求模式应用上面匹配的形态。模式只是提示用户的实际请求始终是权威。迭代循环读 → 改 → 校验 → 发布 → 等构建这是整个技能的操作核心。完整循环如下1. 读取当前源码与版本指针用canvas-source-retrieve读取当前源码与版本指针记住current_version_id——你的发布必须用它做守卫。返回的项目形状为schemaVersion1、files路径 → 内容、entryHtmlindex.html、dependencies平台固定精确版本、canvasSdkVersion、capabilities。从未发布过的画布current_version_id为null首次发布时原样传null。2. 按选定的实现技能编辑项目文件对画布展示的任何 PostHog 数据遵循querying-canvas-data技能数据只走ph桥已保存 insight 通过phSDK 加载——绝不自行fetch或自带 PostHog 客户端且让每个数字可验证insight 支撑的指标通过ph.openExternal链接其已保存 insightad-hoc 查询在卡片旁展示实际执行的精确查询。同时在project.capabilities中声明每一个ph调用insight 短 id 进capabilities.posthog.insights埋点事件名进capabilities.posthog.captureEventsad-hoc 查询置inlineQueries: trueph.agent.request置agentRequests: true。宿主在运行时强制这些声明校验拒绝未声明的调用。校验逻辑在 source.py 中可以逐条对照_validate_capabilities()用正则扫描源码中的ph.loadInsight/ph.query/ph.capture/ph.state/ph.actions.invoke/ph.agent.request/ph.connectors.call调用点与声明清单比对后产出capability_missing_insight、capability_missing_inline_queries、capability_missing_capture_event、capability_missing_state、capability_missing_action、capability_missing_agent_requests、capability_missing_connector等 error 级诊断。3. 校验直到干净canvas-validate-create无副作用可以随需随调修复所有 error 级诊断后才能发布。诊断条目带severity、稳定的code、message以及文件级问题的path与line。常见 errorimport_not_allowed裸导入被限制在源项目返回的依赖集内、forbidden_dynamic_import/forbidden_require/forbidden_inline_script、invalid_path、各类capability_missing_*、dependency_not_admitted/dependency_version_mismatch、platform_token_redeclared声明了与 Quill 平台 token 同名的 CSS 变量——平台样式表把--background、--border、--muted、--primary等设置在每个元素上:root或html.dark里同名声明永远到不了任何元素导致文字颜色失效自己的变量必须加前缀以及路径/尺寸越限。warning 级如network_fetch/network_xhr不阻断但意味着代码在直接伸手网络应声明精确 origin 或改用ph桥。4. 受保护地发布publish 即保存默认且立即生效发布是保存变更的默认方式首次版本与后续编辑一视同仁且立即生效首版current_version_id为 null用canvas-publish-create发布完整项目传expected_current_version_id: null。已上线current_version_id已设置用canvas-edit-create按文件发布变更每个 operation 设置某文件的完整内容content: null表示删除或用canvas-publish-create发布完整项目——都把当前current_version_id作为expected_current_version_id传入。canvas-edit-create的守卫是强制的因为 diff 的语义依赖其基线。草稿canvas-draft-create仅在用户要求草稿、预览或上线前评审时暂存。草稿是一个真实的、可构建的版本但永远不会成为 head在线画布继续渲染当前版本直到有人 promote 它。草稿响应会返回capability_widening——草稿相对 live 版本新增声明的 insights、埋点事件、内联查询与网络 origin应在 promote 前向用户明示这是变更将新授予的访问面。这个能力扩张信号由后端 capabilities.py 的capability_widening()计算按after 相对 before 新增了哪些声明结构化输出。发布约定一次请求变更只发布一次用户在之后要求再改时重新读取源码head 可能已移动再发布——不要把无关变更打进同一版本也不要在每次微编辑后发布半成品。429 表示团队构建容量暂时耗尽等待约 30 秒后重试同一发布此时尚未保存任何东西。发布响应返回新的current_version_id。版本语义每次发布向 append-only 的版本序列追加一个完整源版本并移动 head 指针CanvasSourceVersion行只增不改内容存对象存储行上记录 SHA-256source_hash、能力清单快照与任务归属见 models.py。用户可以在应用里回退到旧版本回退会重新发布并重新构建。守卫的意义正在于此基于你实际读到的版本来发布才能避免用户的回退、其他 agent 的发布和你的编辑互相静默抹除。409 version_conflict 的恢复流程409 意味着画布已越过你的基线并发发布或回退响应里包含 livecurrent_version_id。绝不无守卫重试硬推重新canvas-source-retrieve读取源码 → 在新鲜源码上重新应用你的编辑新 head 可能含他人变更必须保留→ 用新的current_version_id重新发布。5. 等待构建完成草稿和发布一样都会排队一个服务端构建。轮询canvas-builds-retrieve每几秒一次最长约 2 分钟直到你的构建进入终态queued/building——进行中稍后再轮询ready——画布的published_build_id前移到该构建除非更新的发布已抢先取代它画布工作完成failed——读取构建的错误诊断修复项目再次保存。不要带着失败的构建结束任务。从后端模型看为什么失败的构建不会顶掉旧版CanvasBuild注释明确写了——失败构建只记录诊断永远不取代画布最后已知良好的制品live 指针Canvas.published_build只在构建完成且其源版本仍是当前 head时才前移。这意味着如果你在这里收工用户拿到的是陈旧画布加一次静默失败。另有一条经验规则运行时错误报告渲染中画布抛错时上报到创作任务会注明其来源构建 id。来自旧构建 id的报告是历史不是你当前代码的证据——特别地某个已文档化的phAPI 未定义如ph.state意味着该制品由旧宿主运行时打包重新发布让当前构建替换它即可永远不要通过删掉该 API 或其能力声明来修复。运行时桥接状态、动作、连接器与 agent 请求自由画布通过宿主注入的ph桥与 PostHog 交互。以下四组 API 各有声明要求未声明者校验失败、宿主运行时拒绝。ph.state —— 持久键值记忆APIph.state.get(key, { scope })、ph.state.set(key, value, { scope })值为 null 删除键、ph.state.list({ scope })。作用域user默认对每位查看者私有shared每画布一个值、团队可见。使用的 scope 必须声明在capabilities.posthog.state。约束值是 JSON序列化上限64 KB、每 scope 最多256 个键。大数据应存进 PostHoginsight、warehouse再引用state 里绝不放秘密或查看者 PII。这两个数字不是文档随口说的它们就是平台契约 manifest.json 中limits.maxStateValueBytes: 65536与maxStateKeysPerScope: 256的落地后端CanvasState模型在写入时执行边界约束使每次访问都是点查、表增长以画布数为上限。ph.actions.invoke(verb, payload) —— 以查看者身份写 PostHog每个 verb 必须声明在capabilities.posthog.actions未声明或未注册的 verb 校验失败宿主运行时也拒绝。只把动作接到显式用户手势查看者点击的按钮绝不接到 load 或 render。动作注册表是唯一事实来源用canvases-actions-retrieve工具列出它接线前遵循每个 verb 的usagepayload/结果形状、行为、它配什么样的确认文案。ph.connectors.call(provider, tool, args) —— 读取实时第三方数据用查看者本人的连接GitHub或任意 MCP 商店服务器在查看时读取数据。绝不要自己调用 GitHub、Calendly 或别的再把结果粘进源码那样的快照在发布时就已陈旧且会把作者的数据展示给每个查看者。每个 provider 与 tool 声明在capabilities.connectors用canvas-connectors-retrieve工具发现它们。校验侧_validate_connector_declarations/_validate_connector_callsprovider 必须是原生 id如github或mcp:server host形式未知 provider、未注册的原生工具、私有 MCP 主机都会失败校验每个声明的工具在目录中必须is_read_only: true。带 connectors 的画布不能声明 shared state对应诊断connector_results_in_shared_state。ph.agent.request(prompt) —— 向创作 agent 请求变更声明capabilities.posthog.agentRequests: true。只能从直接点击或表单提交调用——宿主会展示精确 prompt 并要求查看者接受后才消耗算力渲染、挂载或轮询期间发起的调用会被拒绝。agent 以新版本发布该变更非创建者的请求会被归档到创作任务线程而不是直接启动运行。源项目形状与平台契约源码项目本身受一组平台契约约束其单一事实来源是 canvas_builder/manifest.json——它同时被 Node 构建器、Python 校验器source.py与制品源的 CSP 加载桌面端应用还会在契约测试中用它断言自己的副本防止固定依赖或限制漂移。项目结构约定来自building-canvases的 Source-project shape 节保留index.html作为源工具返回的入口 shellentryHtml必须是index.html校验代码invalid_entry/missing_entry强制这一点。src/canvas.tsx是约定的 React 入口组件但它可以从项目内导入额外的相对 TypeScript、TSX、JavaScript、JSON、SVG、CSS 与已接纳的资产文件。自包含的模块 worker 可用./worker.ts?worker导入worker 不得再导入其他本地模块。图片走上述媒体库流程其他二进制资产放入项目的assets映射以 base64 内容 已接纳的 content type 表示。WOFF/WOFF2、WebAssembly 与通用 octet-stream 资产受支持。平台依赖映射必须原样保留不得添加 npm 包相对导入是项目文件裸导入被限制在平台固定集合内。允许导入的裸模块allowedImportSpecifiersposthog/canvas-sdk、react、react-dom、react-dom/client、posthog/quill、recharts、lucide-react、dayjs、d3、three、framer-motion、zod、tanstack/react-table、tanstack/react-virtual、react-hook-form、lodash-es、react-markdown、papaparse。固定版本包括 react 19.0.0、posthog/quill 0.3.0-beta.18、recharts 2.15.0 等依赖缺失报dependency_not_admitted版本漂移报dependency_version_mismatch。源码体量限制limits校验器逐条强制执行限制值对应诊断maxSourceFiles64 个文件too_many_filesmaxSourceFileBytes512 KB / 文件file_too_largemaxSourceTotalBytes2 MBfiles assets 及规范化 JSON 双重计量file_too_large/project_too_largemaxStateValueBytes64 KB / state 值写入时边界maxStateKeysPerScope256 键 / scope写入时边界运行时安全规则校验器中的禁止模式全部 error 级动态import()报forbidden_dynamic_importrequire()报forbidden_requireimportScripts()报forbidden_import_scripts内联script报forbidden_inline_script。路径必须相对、非空、正斜杠段字符集限字母数字. _ -禁止.、..段invalid_path。远端脚本与动态导入被彻底封死——沙箱 CSP 本身就包含script-src self、default-src none、connect-src none声明 origin 后才有条件放开。收尾链接与交付约定每次请求变更保存一次画布就绪时——不是在每次微编辑后。用户要草稿时结尾说明草稿已就绪可预览并 promote草稿 → 构建 → 预览 → promote 流程由validating-and-publishing-canvases覆盖。回复结尾必须给出画布所在频道并附上链接——使用画布工具返回的url字段canvas-create、canvas-list与发布/源响应都携带它。该字段是画布唯一合法链接永远不要自行构造猜测的 URL项目页、web 路由无法解析。小结building-canvases技能把自由画布开发压缩成一条可验证的闭环解析目标不猜测频道、不造重复品→ 按请求形态加载实现与校验技能 → 以平台契约约束的项目形状编写源码 → 用无副作用的canvas-validate-create洗掉全部 error 诊断 → 用expected_current_version_id守卫发布或按需暂存草稿→ 轮询构建到终态。其背后是一套相当严格的平台工程append-only 的源版本序列与 last-good 构建指针保证失败发布不污染在线画布能力声明 运行时强制 CSP 注入构成最小权限边界64 KB / 256 键的 state 限制与 64 文件 / 2 MB 的源码限制让每次访问保持点查、每次构建保持有界。理解这条文档规则—校验诊断—后端模型三层一致的链条是可靠地为 PostHog 构建、更新和修复独立画布应用的关键。【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考