mcpField
B
building-canvases

building-canvases

github.com/posthog开发95109 次安装今天更新
代码仓库

关于 building-canvases

面向在 PostHog 中创建独立应用的技能,指导选择、编辑和发布运行于沙盒 iframe 的 freeform canvas。它还规定何时加载 React、HTML、数据查询和发布验证等配套技能。

主要功能

  1. 01按请求定位或创建 canvas
  2. 02通过工具读取和编辑 canvas 源码
  3. 03根据任务选择 React 或 HTML 实现
  4. 04为可编辑组件配置参数
  5. 05验证、发布并处理构建结果

适用场景

  1. 01在 PostHog 中创建数据看板或分析工具
  2. 02制作表单、清单或轻量工作流
  3. 03编写文档或叙述式报告
  4. 04构建生成图形或动画

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/posthog/ai-plugin --skill building-canvases

安装后在 Claude Code 中输入/building-canvases确认已加载。

附带文件references/blocks.md

详细介绍

构建画布

画布是在 PostHog 内部沙盒化 iframe 中运行的客户端浏览器应用。 其源代码存放在 PostHog 中,而非代码仓库里;你需要通过 canvas-* 工具读取和写入。切勿将画布写入本地文件;通过工具发布才会保存内容。

画布任务可以从任何常规任务开始。不需要专门的画布模式或预先创建画布。当用户要求创建 一个要放在 PostHog 中的看板、文档、表单、可视化内容或小型应用时,应将其视为画布请求并遵循 本技能。

本技能负责 freeform 画布(独立应用)。另外还有两种画布类型:grid 画布(小组件网格,包括用户的主页画布)和 component 画布(可供网格放置的可复用小组件)。 如果目标是网格或主页画布、放置操作,或可复用小组件/组件,请改为加载 composing-grid-canvases; 它负责管理从搜索资源库 → 配置 → 分叉 → 构建的流程,以及布局补丁循环。编写组件源代码仍需使用下面的实现配套技能。

确定目标画布

  • 如果任务指定了画布 ID(由画布发起的任务会指定),则该画布就是目标。不要另建画布。
  • 否则,目标频道就是创建任务时所在的频道——任务上下文(channel_context 块或生成指令)中会注明。 使用 canvas-list 列出该频道的画布(通过 channel 指定范围)。如果其中有一个明显符合请求——例如同一看板或工具的早期版本—— 就在其基础上构建,而不是创建一个近似重复项;并在回复中说明这一点,让用户知道结果保存在哪里。
  • 只有在没有合适的现有画布时,才在同一频道中使用 canvas-create 创建一个,并根据请求取一个简短且有描述性的标题——切勿使用“未命名画布”。
  • 切勿自行遍历频道来选择目标:仅当用户指定了频道、需要将其解析为 ID 时,才使用 channel-list。其列表会将个人 #me 频道排在首位,而 #me 绝不是默认选项——保存在此处的画布对其他人不可见。如果任务既未指定画布,也未指定频道,请询问应使用哪个频道,而不要猜测。

加载实现所需的配套技能

本技能负责画布选择和编写生命周期。配套技能包含实现规范。编写源代码前,加载所有适用的配套技能:

  • building-react-quill-canvases 用于仪表板、数据看板、表单、工具、带有应用状态的内容,或任何应采用 PostHog 原生外观的内容。它负责管理允许导入的内容、Quill 组合、主题、图表、加载和错误状态,以及日期选择器。
  • building-html-canvases 用于文档、文章、专注型实验、生成式图形、<canvas> 或 WebGL 工作,适用于应用组件无法提供有用结构的场景。它负责管理语义化标记、直接浏览器 API、动画清理和非 Quill 主题。
  • querying-canvas-data 适用于任何读取 PostHog 数据、捕获事件或进行导航的画布。它负责管理 ph SDK、已保存洞察的优先使用、结果形状、变量、日期范围、逐查询渐进式加载,以及已声明的数据功能。涉及数据时,应与任一实现技能一同加载。
  • validating-and-publishing-canvases 适用于所有画布。它负责管理项目结构、功能声明、验证诊断、受保护的发布、草稿、构建和冲突恢复。

适当时可以混合使用不同的实现方式:由 React 负责应用框架,由浏览器图形代码负责画布元素;或者在基本静态的页面中挂载一个交互式区域。

这是一个判断问题,而不是持久化模式——只有当选项会影响你无法推断的用户可见要求时,才向用户询问。

区块

画布可以包含预制区块:数字、目标、趋势、排行榜、漏斗、留存、已保存的洞察、实时事件流、SQL 表格、筛选器、比较和刷新控件,以及标注。 它们是 src/blocks/ 中的 React 组件,用户可以在桌面应用中将其拖入画布,因此也是你源码的一部分。 更改含有 src/blocks/runtime.tsx 的画布前,请先阅读 references/blocks.md。

参数

将用户可能想要更改的值公开为参数。这样,他们就能在桌面编辑器中更改这些值,而无需创建新任务。 参数是可选的,但请为每个包含值得更改的值的面板、卡片或工具添加参数:标题、文案、事件、属性、阈值、限制、颜色。 参数需要 React 组件。纯 HTML 画布没有参数。

编辑器如何使用 editable()

在桌面编辑器中,用户可以选择画布上的任意元素:标题、段落、区块。他们可以移动、复制或删除元素,也可以双击文本进行修改。无需调用 editable() 即可实现这些操作。

editable() 会将组件设为一个区块。编辑器随后会将该区块视为一个整体:

  • 单击会选中整个区块,而非区块内的元素。
  • 移动、复制和删除操作会作用于整个区块。
  • 侧边栏会将区块的参数显示为字段。更改后,新值会写入源码中该区块的 props。
  • 要访问区块内的元素,用户可以双击区块将其打开。

因此,请在用户认为是一个整体、并会作为一个整体进行配置的部分上使用 editable():例如卡片、图表、表格、表单。周围的页面布局则保留为普通 JSX。这样,用户既可以将卡片作为区块选中,也可以直接选中页面标题或区块。如果包含整个页面的组件使用了 editable(),整个页面就会成为一个区块,每次单击都会选中整个页面。

添加参数
  1. 将每个面板放在单独的组件中。组件通过 props 接收这些值,并为其设置默认值。
  2. 在组件的根元素上展开来自 @posthog/canvas-sdk 的 editable(name, props, params)。name 是组件名称。params 将每个 prop 名称映射到对应字段。
  3. 使用带字面量 props 的组件,例如 <SignupFunnel blockId="b-k3m9x2" title="Signup" windowDays={14} />。编辑器会将更改写入这些 props,因此不要在行内计算它们。
  4. 为每次使用提供唯一的 blockId prop,例如 <SignupFunnel blockId="b-k3m9x2" … />,这样用户就能指定某张卡片让 Agent 进行操作。只能使用字母、数字、_、-、. 和 :,否则编辑器会忽略该 ID。在列表中,根据条目的稳定键生成 ID:``blockId={kpi-${item.id}}`。
import { editable } from '@posthog/canvas-sdk'

export function SignupFunnel(props: { blockId?: string; title?: string; steps?: string[]; windowDays?: number }) {
  const { title = 'Signup funnel', steps = ['$pageview', 'signed_up'], windowDays = 14 } = props
  return (
    <Card
      {...editable('SignupFunnel', props, {
        title: { type: 'text', label: 'Title', default: 'Signup funnel' },
        steps: { type: 'events', label: 'Steps', default: ['$pageview', 'signed_up'] },
        windowDays: { type: 'number', label: 'Conversion window (days)', min: 1, max: 90, default: 14 },
      })}
    >
      …
    </Card>
  )
}

字段类型:text、longtext、number(min、max、step;同时设置 min 和 max 时,编辑器会显示滑块)、boolean、select(options:字符串或 { value, label })、event、events、property、insight(已保存洞察的短 ID)、color。每个字段还可以包含 description。 为每个字段设置与其 prop 默认值相同的 default,例如 { type: "boolean", label: "Show legend", default: true }。未设置 prop 时,编辑器会显示 default。 color 参数的默认值是 var(--primary) 之类的主题令牌,因此在用户于编辑器中选择十六进制颜色之前,画布会自动适配浅色和深色模式。 通过参数只传递 JSON 值(字符串、数字、布尔值、字符串数组)。不要将函数和查询结果放入其中。

图像

在画布中使用公开的媒体库 URL。先调用 posthog:media-images-list,并将 purpose="canvas" 作为参数;如果已有合适的图像,请重复使用。

添加本地图像:

  1. 调用 posthog:media-image-upload-start,并提供文件名和 purpose="canvas"。
  2. 在 shell 中,以 multipart 表单数据的形式将文件 POST 到返回的 upload_url。包含所有 返回的 form_fields 条目,并将文件部分放在最后。
  3. 调用 posthog:media-image-upload-complete,并提供返回的 id;然后使用其永久 url 作为图像的 src。
  4. 将 URL 的确切源添加到 project.capabilities.network.origins。画布验证会检查此声明,发布后的产物会在其内容安全策略中使用此声明。

画布媒体 URL 是公开的,无需身份验证。切勿上传密钥、凭据、客户数据或敏感截图。图像必须小于 4 MB,且可解码为 PNG、JPEG、GIF、WebP、AVIF 或 BMP。切勿将图像字节编码为 base64 后放入工具调用中。

常见请求模式

将这些模式用作路由示例,而非固定模板:

  • 产品仪表板、Web 分析看板或指标浏览器: React + Quill,加上数据查询。
  • 清单、表单或轻量级工作流: React + Quill;如果需要读取 PostHog 数据、捕获事件或导航,再加上数据查询。对于清单或运行手册,请从 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——发布时必须以它为依据进行保护。
  2. 使用上文选定的实现伴侣编辑项目文件。对于画布中显示的任何 PostHog 数据, 请遵循 querying-canvas-data(通过 ph SDK 加载已保存的洞察——绝不自行获取数据或使用自己的 PostHog 客户端),确保每个数据都可验证——由洞察支持的指标需链接到 PostHog 中已保存的洞察,临时查询需显示实际运行的确切查询,具体遵循该技能的“可验证性”部分——并且 在 project.capabilities 中声明每次 ph 调用(洞察短 ID 放在 capabilities.posthog.insights 中,捕获的事件放在 captureEvents 中,临时查询需设置 inlineQueries: true,ph.agent.request 需设置 agentRequests: true)——宿主会在运行时强制执行这些要求,验证也会拒绝未声明的调用。
  3. 遵循 validating-and-publishing-canvases:根据需要多次使用 canvas-validate-create 进行验证,并修复所有错误级别的诊断。
  4. 通过发布来保存项目——发布是默认操作,会立即上线:
    • 首个版本(current_version_id 为 null):使用 canvas-publish-create 发布完整项目,并传入 expected_current_version_id: null。
    • 已上线(current_version_id 已设置):仅使用 canvas-edit-create 提交编辑;对于文件内的更改,使用 str_replace 操作。 将当前已上线的 current_version_id 作为 expected_current_version_id 传入。 只有在要替换整个项目时,才使用 canvas-publish-create 发布完整项目。
    • 仅当用户要求草稿、预览,或要求先审核再上线时,才使用 canvas-draft-create 暂存草稿。 遵循 validating-and-publishing-canvases 技能处理诊断和冲突恢复。
  5. 等待构建完成——草稿和发布都会排入一个构建。发布或编辑响应中已包含 build.build_status;如果状态为 ready 或 failed,请直接使用。否则,每隔几秒轮询一次 canvas-builds-retrieve(最多约 2 分钟),直到构建状态为 ready 或 failed。如果状态为 failed,请读取构建的错误诊断,修复项目并再次保存——不要以构建失败结束任务。

每次用户要求的更改只保存一次,待画布就绪后再保存——不要每次微小编辑后都保存。用户要求草稿时,请在回复结尾说明草稿已就绪,可以预览并升级;validating-and-publishing-canvases 技能介绍了草稿 → 构建 → 预览 → 升级流程。

回复结尾需指出画布所在的频道,并使用画布工具返回的 url 字段创建链接(canvas-create、canvas-list 以及发布/源文件响应都包含该字段)。该字段是画布唯一有效的链接——切勿自行构造链接;猜测的 URL(项目页面、网页路由)无法正常访问。

运行时记忆与操作

  • ph.state — 持久键值记忆:ph.state.get(key, { scope })、 ph.state.set(key, value, { scope })(null 值会删除该键)、ph.state.list({ scope })。 作用域 "user"(默认值)对每位查看者都是私有的;"shared" 则为每个画布保存一个值, 整个团队均可查看。请在 capabilities.posthog.state 中声明所用的作用域。 值为 JSON,序列化后上限为 64 KB,每个作用域最多 256 个键——请将大数据存储在 PostHog(洞察、数据仓库)中,并在此引用。切勿在状态中存放机密或查看者个人身份信息。

  • ph.actions.invoke(verb, payload) — 以查看者身份向 PostHog 写入数据。请在 capabilities.posthog.actions 中声明每个 verb;未声明或未注册的 verb 无法通过验证, 主机也会在运行时拒绝执行。请将操作绑定到明确的用户手势(查看者点击按钮),切勿在加载或渲染时触发。 注册表是唯一事实来源:使用 canvases-actions-retrieve 工具列出操作,并遵循每个 verb 的 usage(载荷/结果格式、行为以及相应的确认文案),再进行绑定。

  • ph.tools.read(tool, args) 和 ph.tools.call(tool, args):以查看者身份运行允许列表中的 PostHog MCP 工具,例如读取功能标志并更改其推出比例。请在 capabilities.posthog.tools 中声明每个 工具。read 接受只读工具;call 会更改数据,因此请将其绑定到点击操作,主机会要求查看者确认。 有关允许列表以及写入标志所需的版本处理,请参阅 querying-canvas-data。

  • ph.connectors.call(provider, tool, args) — 在查看时使用查看者自己的连接读取第三方实时数据 (GitHub 或任何 MCP 存储服务器)。切勿自行调用 GitHub、Calendly 或其他服务,再将结果粘贴到源代码中: 发布时该快照会过时,而且所有查看者都会看到作者的数据。请在 capabilities.connectors 中声明每个 provider 和工具;使用 canvas-connectors-retrieve 工具发现它们。有关结果和未连接时的处理,请参阅 querying-canvas-data。

  • ph.agent.request(prompt) — 在查看者批准后,请画布的创作 Agent 进行更改。请在 capabilities.posthog 中声明 agentRequests: true。仅在直接点击或提交表单时调用——主机会显示 完整提示词,并在消耗计算资源前征求查看者同意;渲染、挂载或轮询期间发起的调用会被拒绝。Agent 会将更改 发布为新版本;非创建者的请求会提交到创作任务的讨论串中,而不会启动一次运行。

源项目结构

  • 保留 index.html,将其作为源工具返回的入口外壳。
  • src/canvas.tsx 仍是常规的 React 入口组件,但可以从项目中导入其他相对路径的 TypeScript、TSX、JavaScript、JSON、SVG、CSS 和已准入的资源文件。
  • 可以使用 ./worker.ts?worker 导入独立模块 Worker。Worker 不得导入其他本地模块。
  • 图片请使用上文所述的公共媒体库流程。其他二进制资源应以 base64 内容和已准入的内容类型放在项目的 assets 映射中。支持 WOFF/WOFF2、WebAssembly 和通用 octet-stream 资源。
  • 请完整保留平台依赖映射,不要添加 npm 包;本地相对路径导入对应项目文件,而裸导入仍仅限于平台固定的集合。

评论

支持 Markdown