Skip to content

Latest commit

 

History

History
596 lines (372 loc) · 37.4 KB

File metadata and controls

596 lines (372 loc) · 37.4 KB

生成式 UI 持久化与项目看板

技术实现见 docs/handover/dashboard.md(看板系统)和 docs/handover/generative-ui.md(widget 渲染基础设施)

灵感来源

Moxt 启发。Moxt 定位为 AI-native workspace,核心洞察:

  • AI 应该在原生格式里工作:md/csv/html/代码,而非 PDF/PPT/传统文档
  • 文件系统是 AI 最熟悉的图书馆:层级目录 > 传统知识库的非结构化检索
  • 0 摩擦:AI 处理信息带宽极大,1% 摩擦在 n 次幂后趋近于 0——必须保障每次通信零损耗
  • Less Content is More Context(对组织而言):AI 产出远超人类,需要用 AI 习惯的方式维护内容

Moxt 实践中最具启发性的案例:直接在 Moxt 中用生成式 UI 替代了 Jira 看板——不是用 AI 操控旧看板,而是直接实现看板本身。"同样的信息和数据,你想怎么看就怎么看"。

我们解决的用户问题

生成式 UI 的"一次性浪费"

当前 widget 绑死在聊天消息里。模型花大量 token 生成一个精心设计的图表或流程图,但用户下次需要类似内容时必须重新描述、重新生成。widget 的复用率为零。

项目缺乏"视觉摘要"

打开一个项目,看到的是聊天列表——纯文本、线性、需要翻阅。用户无法一眼看到"这个项目现在什么状态"。对助理工作区尤其明显:memory.md 是纯文本,daily notes 分散在文件里,缺少一个整合的视觉入口。

可视化结果无法分享

生成式 UI 产出的图表和示意图质量很高,但只能在 CodePilot 内部看到。用户想把 AI 的分析结果发到社交媒体或分享给团队时,没有导出途径。

核心设计理念

看板 = AI 对项目的持续理解的视觉化

看板不是"保存的 widget 集合",而是 AI 对项目的理解在视觉维度上的投影。每个卡片背后是一个数据契约——"这个 widget 展示什么数据、数据从哪来"。每次打开或刷新时,AI 读取最新数据重新填入,布局和样式保持不变。

AI-first,不是 UI-first

传统看板的思路:用户手动创建卡片 → 定义字段 → 拖拽排列 → 手动更新数据。

AI-first 的思路:

  1. AI 主动提议初始看板:首次打开时,AI 已经读过项目全部文件,直接提议一版看板。助理工作区 → 日程/待办/记忆摘要;代码项目 → 提交活动/TODO 分布/依赖状态。
  2. AI 自动推断数据契约:用户在聊天里 pin 一个 widget 时,AI 根据上下文自动推断数据来源和刷新方式,用户一键确认。
  3. AI 驱动更新:daily check-in 后 AI 顺便更新看板数据;对话中状态变化时 AI 建议同步到看板。
  4. AI 建议新卡片:用户连续多天提到某个话题,AI 主动提议新增对应卡片。

对话 ↔ 看板飞轮

对话和看板不是割裂的两个界面,而是同一个 AI 理解的两种呈现:

  • 对话 → 看板:好的 widget 一键固定;对话中提到的状态变化反映到看板
  • 看板 → 对话:点击卡片发起相关话题对话;看板状态注入对话 context,AI 知道项目全貌
  • 看板内对话:看板页面底部有输入框,用户可以对着看板说话——"把商单B标记为已签约"、"给我加一个本月支出统计"

数据架构

保存什么

保存的是 widget 代码 + 数据契约 + 数据源定义

  • widget 代码:原始 HTML/JS/CSS(作为"设计参考",保留布局和样式)
  • 数据契约:自然语言描述,说明这个 widget 展示什么数据、如何从原始数据中提取
  • 数据源:结构化定义,可以是文件路径、MCP tool 调用、CLI 命令、或它们的组合

每次刷新时,系统按数据源获取最新数据,把「原始代码 + 最新数据」喂给模型,模型只更新数据部分,保留布局和样式。

不做模板语法——模型天然理解"保持设计,换新数据"。

数据源类型

type DataSource =
  | { type: 'file'; paths: string[]; query?: string }
  | { type: 'mcp_tool'; server: string; tool: string; args: Record<string, unknown> }
  | { type: 'cli'; command: string }
  | { type: 'composite'; sources: DataSource[] }

存储位置

存在项目目录 .codepilot/dashboard/ 下:

  • 跟着项目走,git 可追踪
  • AI 在对话中可直接读写
  • 每个项目天然隔离
  • 符合 Moxt "文件系统是 AI 的图书馆"理念

刷新策略

用户可配,提供开关:

  • 自动刷新:每次打开看板时调模型更新所有卡片(不在乎 token 的用户)
  • 手动刷新:提供刷新按钮,用户按需触发(在乎 token 的用户)

附加优化:数据源文件 mtime 没变则跳过刷新,用上次缓存结果。

UI 承载方式:右侧面板

看板作为右侧面板,和 Git 面板、文件树面板、预览面板同级。理由:

  • 项目级归属:看板是项目维度的,放在右侧面板天然和当前项目绑定,不需要改动左侧 Chat List 的层级结构
  • 与聊天共存:用户可以边聊天边看看板,符合"对话 ↔ 看板飞轮"的交互模型
  • 复用现有架构:ResizeHandle、PanelContext、TopBar toggle 按钮全部现成

面板宽度参数:

参数
MIN_WIDTH 320px
MAX_WIDTH 800px
DEFAULT_WIDTH 640px

参考:预览面板 320-800px 默认 480px,看板默认值更大因为 widget 内容更丰富。640px 渲染图表和表格完全够用,类似 Claude Artifacts / Gemini 的侧边网页渲染宽度。

Widget 直接在面板内用 iframe 渲染,复用聊天中的 WidgetRenderer 组件。不做摘要模式、不做展开模式——桌面端空间充裕,用户拖窄面板导致样式问题是用户自己的选择,我们只保证默认宽度下体验良好。

生成式 UI 作为系统级渲染层

看板不只是聊天 widget 的持久化。生成式 UI 应该成为 CodePilot 所有子系统的通用可视化出口。

                    ┌─────────────┐
                    │   看板       │ ← 持久化展示层
                    │  Dashboard  │
                    └──────┬──────┘
                           │ pin / render / refresh
                    ┌──────┴──────┐
                    │  生成式 UI   │ ← 通用渲染层
                    │  Widget 系统 │
                    └──────┬──────┘
            ┌──────┬───────┼───────┬──────┐
            │      │       │       │      │
         ┌──┴──┐┌──┴──┐┌──┴──┐┌──┴──┐┌──┴──┐
         │ Chat ││ MCP ││ CLI ││Skill││Bridge│
         └─────┘└─────┘└─────┘└─────┘└─────┘

MCP × 生成式 UI

MCP 工具返回的结构化数据可以直接渲染为 widget。用户配的任何 MCP server(Notion/Linear/数据库等)都自动成为看板的潜在数据源。

场景:用户问"看看 Linear 里这周的 bug 统计" → 模型调 MCP tool → 返回 JSON → 渲染为柱状图 widget → 用户 pin 到看板 → 看板每次刷新时重新调 MCP tool。

生态杠杆巨大——社区几百个 MCP server,每一个都可以成为看板数据提供者。

CLI 工具 × 生成式 UI

CLI 工具的输出天然是结构化数据,适合可视化:

  • git log --stat → 提交活动时间线
  • docker ps → 容器状态卡片
  • npm audit → 依赖安全仪表盘

CLI 数据源的刷新可以不调模型——命令输出格式稳定,首次生成后可以做纯前端解析。

桥接 × 生成式 UI

最有想象力的组合。两个方向:

看板 → IM 推送:每日早上自动刷新看板 → 生成截图 → 通过桥接推送到 Telegram/飞书。从"打开才能看"变成"推到你面前"。这是"导出图片"的自动化版本。

IM → 看板更新:用户在 Telegram 里说"商单B签了" → 桥接收到 → AI 处理 → 更新数据源文件 → 看板状态随之更新。

Skills × 生成式 UI

Skill 变成 widget 工厂

  • /weekly-report → 产出周报 widget(含本周完成事项、关键指标、下周计划),可 pin 可导出
  • /codebase-health → 运行多个 CLI 工具后产出健康度仪表盘 widget

每个 skill 不只输出文字结论,还输出可持久化的视觉组件。

多组件联动(远期)

看板级共享状态

interface DashboardContext {
  selectedDate?: string;
  selectedItem?: { type: string; id: string };
  filters?: Record<string, unknown>;
}

每个 widget 声明 publish(我发布什么事件)和 subscribe(我订阅什么状态),通过 DashboardContext 中转,widget 之间不直接通信。

联动场景举例

  • 助理"我的一周":点日程表某天 → 右侧刷新当天详情 → 点详情某事项 → 下方进度卡片聚焦相关条目
  • 代码"项目健康度":选提交 → 热力图高亮相关文件 → 点文件 → 展开 diff 摘要
  • 内容"排期 + 数据":选已发布内容 → 显示表现数据;选未发布 → 显示草稿 + 优化建议

对话式看板操控

看板底部输入框,用户对着整个看板说话:

  • "把商单B的状态更新为已签约" → 商单进度 widget 数据更新
  • "这周三的会取消了" → 日程 widget 更新 + 数据源文件同步修改
  • "给我加一个本月支出统计的卡片" → 新 widget 生成并添加

模型知道所有 widget 的数据契约和来源,可以精准修改。

与 Moxt 的差异化定位

维度 Moxt CodePilot 看板
定位 组织级 AI 原生办公室 个人级项目 AI 原生控制台
部署 云端 本地优先
协作 多 AI 同事 + 多人 单人 + 单 AI
上下文深度 广但浅(文档为主) 窄但深(在代码仓库内部,git/文件/运行时全可达)
数据归属 云端 完全本地,不上传
优势场景 组织知识管理、多人协作 深度项目理解、开发者工作流、个人助理

我们不是在做"轻量版 Moxt",而是在做 "每个项目的 AI 原生控制台"

推进优先级

阶段 内容 价值
P0 聊天 → 看板核心链路(pin widget、看板展示、数据刷新) 最小可用
P0 AI 自动推断数据契约 AI-first 体验基础
P1 AI 主动提议初始看板 零配置上手
P1 MCP 数据源支持 生态杠杆,接入外部数据
P1 看板 ↔ 对话双向联动 飞轮效应
P1 导出图片 分享传播
P2 CLI 数据源支持 代码项目杀手功能
P2 看板 → Bridge 推送 被动变主动
P2 widget 间点击联动 体验飞跃
P2 对话式看板操控 终极交互形态
P3 Skill → Widget 工厂 锦上添花
P3 check-in 后自动更新看板 助理深度集成

已知的局限和风险

  1. Token 成本:每次刷新都调模型,看板卡片多时 token 消耗显著。mtime 缓存可缓解但不能消除。
  2. 刷新延迟:模型生成 widget 需要几秒,多个卡片串行刷新体验差。需要并行刷新 + 骨架屏。
  3. 数据契约漂移:数据源文件结构变化后,原有数据契约可能失效。需要错误检测和自动修复机制。
  4. MCP 依赖:外部 MCP server 的稳定性不可控,看板卡片可能因 MCP 故障显示空白。
  5. 第三方 API Provider 限制:同现有 widget 系统——部分三方 provider 不处理 appendSystemPrompt,widget 功能可能不可用。

技术调研:Pretext 文本排版库

项目地址:chenglou/pretext 作者:chenglou(React 核心贡献者、Reason 语言作者)

是什么

纯 JS/TS 的多行文本测量与排版库。核心能力:不触发 DOM reflow 就能精确计算多行文本布局

两阶段架构:

  1. prepare(text, font):一次性分析——文本分段 + Canvas measureText() 测量宽度 + 缓存。500 段文本约 19ms。
  2. layout(prepared, maxWidth, lineHeight):纯算术换行——基于缓存宽度做行折断。500 段文本约 0.09ms。

第二步是纯数学运算,零 DOM 操作,可在 resize/动画/虚拟化场景下高频调用。

语言支持极广:CJK、日文、阿拉伯文、泰文、缅甸文、emoji、混合双向文本,各语言有专门 corpus 测试。渲染目标不绑定 DOM——可渲染到 DOM、Canvas、SVG,计划支持服务端渲染。

对看板和生成式 UI 的价值

1. 高质量图片导出

导出看板为图片(社交媒体分享)时,如果用 Canvas 渲染而非简单截图,文本排版是最大难题。Pretext 让我们在 Canvas 上精确排列多行文本,不需要 DOM。意味着:比截图更高质量的导出、文本位置/换行/对齐完全可控、未来服务端图片生成(定时推送到 IM)不依赖浏览器。

2. Widget 高度预计算(解决高度跳动)

当前最大 UX 痛点之一是 widget 高度跳动——iframe 加载前不知道高度,加载后突然撑开。如果 widget 文本内容已知,Pretext 可以在 iframe 加载前算出预期高度,提前分配空间,彻底消除跳动。

3. 看板布局引擎

看板排列多个 widget 卡片,每个卡片标题/描述文本长度不同。Pretext 可以不渲染就预计算所有卡片高度:无闪烁瀑布流布局、拖拽排序精确占位、响应式重排即时高度计算(0.09ms 级别)。

4. 异形布局 Widget

layoutNextLine() 支持每行不同宽度——文本可环绕图片、沿曲线排列、在不规则形状内流动。对生成式 UI 有价值:文本环绕图表的信息卡片、圆形/多边形内文字排版、瀑布流中的精确文本截断。

5. Widget 内部文本虚拟化

看板 widget 可能包含大量文本(一周日程、几十条商单)。如果 widget 内需要文本虚拟化(只渲染可见区域),Pretext 可提前算好所有文本行高,不需要把文本真的渲染到 DOM 里去测量。

设计哲学契合

作者在 thoughts.md 中的核心观点:"80% of CSS spec could be avoided if userland had better control over text." 主张把能力下放到 userland 而非无限扩展规范。这与我们的生成式 UI 理念一致——不用预设模板,让 AI 自由生成 HTML/SVG/JS,Pretext 为 AI 生成的代码提供强大的文本排版基础设施。

集成评估

维度 情况
包大小 轻量,纯 TS,零运行时依赖
兼容性 Chrome/Safari/Firefox 全通过精度测试
成熟度 v0.0.2,早期但测试极严格(多语言 corpus + 跨浏览器精度验证)
集成方式 npm install @chenglou/pretext,ESM
风险 版本早期,API 可能变动;核心架构已稳定

引入时机建议

  • P0-P1 不需要引入:看板核心链路用现有 iframe 渲染够用
  • P2 值得引入:导出图片(Canvas + Pretext 高质量生成)、看板布局预计算(消除高度跳动)
  • 远期关键依赖:服务端看板截图(Bridge 定时推送)的非 DOM 渲染方案

实现后复盘

以下是 P0-P2 全部实现完成后的回顾,包含实际踩坑、设计取舍、以及对未来方向的重新审视。

实现状态

阶段 内容 状态 备注
P0 核心 pin → 展示 → 刷新 MCP 统一路径
P0 AI 自动推断数据契约 在对话上下文中推断
P1 MCP 数据源支持 file / mcp_tool / cli 三种
P1 看板 ↔ 对话双向联动 标题点击 + context 注入
P1 导出图片 Electron 隔离窗口截图
P1 AI 主动提议初始看板 ⏸ 暂缓 时机不成熟
P2 CLI 数据源 通过 bash tool 审批执行
P2 widget 间联动 pub/sub via postMessage
P2 对话式看板操控 ✅ → 移除 输入框多余,聊天统一入口
P2 看板 → Bridge 推送 ⏸ 暂缓

最大的教训:不要改 prompt 格式示例

整个开发过程中最严重的回归不是来自代码逻辑,而是来自修改 WIDGET_SYSTEM_PROMPT 中的格式示例。

原始格式块:

{"title":"snake_case_id","widget_code":"<raw HTML/SVG string>"}

我把 title 从 "snake_case_id" 改成 "Short human-readable title in the user's language" ——一个看似无害的改动——直接导致 GLM-5-Turbo 模型开始输出各种非标准 fence 格式(单反引号、分离的 json 代码块等),widget 全部渲染为 JSON 代码。

根因:模型把格式示例当作"应该长这样"的模板来模仿。当模板中的值从短字符串变成长描述性文本,部分模型会把整个格式块理解为"指导说明"而非"严格模板",从而在格式执行上放松。

修复:还原格式示例,把标题指导放到 rules 列表末尾。同时重写了 widget 解析器为 fence-agnostic(用 JSON brace matching 替代固定 regex),作为防御性改进。

教训:对模型行为有影响的 prompt 改动,必须像改数据库 schema 一样谨慎——在目标模型上做 A/B 测试,而不是"看起来合理就改"。

安全层面学到的

  1. "只加 CSP"不等于安全connect-src 'none' 阻断 fetch/XHR/WebSocket,但 img-src * 允许通过图片请求信道泄漏数据,will-navigate 允许通过 top-level 导航泄漏。安全封堵必须覆盖所有出口通道。

  2. auto-approved MCP 工具不能执行 shell 命令。即使是在对话上下文中,如果工具内部直接 execSync(),用户看到的审批界面只有 widgetId,完全不知道自己批准了什么命令。正确做法:MCP 工具返回命令文本,让模型通过 bash tool(有标准审批流程)执行。

  3. 导出 iframe 的 allow-same-origin 是个陷阱。看起来"临时的所以安全",但 widget 脚本在 finalize 阶段执行时就已经拥有了 parent.document 访问权。最终采用 Electron 隔离 BrowserWindow 方案——独立进程、独立 partition、无 preload、导航阻断。

iframe 是一种"接近正确但永远有边界的"隔离

这次实现中最花时间的部分不是功能逻辑,而是 iframe 的各种行为边界:

  • 排序:React 重排 keyed 元素会 detach+reattach DOM,对普通 div 无感,但 iframe 会重载。最终用 CSS order 解决。
  • CDN 脚本:inline script 和 CDN script 的执行时序不可预测。模型生成的代码经常不按 guidelines 写 onload。receiver script 的 CDN 处理逻辑迭代了 5 个版本才稳定。
  • 导出:sandbox iframe 不能 contentDocument,加 allow-same-origin 又有安全问题。foreignObject 方案抓不到 canvas 像素。最终转向 Electron native 截图。
  • 高度同步body.scrollHeight 是唯一可靠的高度来源,但固定高度容器 + content-box 会导致内容溢出底部 padding。

每个问题的最终解都不复杂,但找到它们的过程说明:iframe 作为隔离边界是一种妥协——它提供的不是完美的隔离,而是"在可接受的成本下足够好的隔离"

打通以后怎么用

看板的核心价值不在于"展示图表",而在于让 AI 持续了解项目状态。几个高价值场景:

1. 项目健康监控

让 AI 生成一组监控 widget——git 提交热力图、dependency 更新状态、test coverage 趋势——pin 到看板。每次打开项目,AI 通过 <active-dashboard> 知道这些指标,能在对话中主动提醒"你的 test coverage 这周下降了 3%"。

2. 外部数据源集成

配了 Linear/Notion MCP server 的用户可以 pin MCP 数据源 widget。"帮我可视化 Linear 里本周的 bug 统计" → 模型调 Linear MCP tool 获取数据 → 生成图表 → pin 到看板。刷新时模型自动调 MCP tool 获取最新数据。

3. CLI 输出可视化

git log --stat / docker ps / npm audit 这类命令输出变成持久化的可视化卡片。开发者不需要记命令、不需要手动看终端输出——AI 把它变成一目了然的图表。

4. 跨 widget 联动分析

筛选器 widget + 数据列表 widget 组合使用。点击筛选条件,相关数据自动过滤。这不是写死的联动逻辑,而是 AI 在生成 widget 时用 __widgetPublish / widget-filter API 实现的动态联动。

解决问题的方法论

实现过程中总结的几个原则:

  1. 先修根因,再加防御。widget 渲染问题的根因是 prompt 格式示例被改动,但同时也暴露了解析器过于脆弱。两个都修:还原 prompt(修根因)+ fence-agnostic 解析器(加防御)。

  2. 安全是最后验证,不是最后添加。每个涉及代码执行的路径(iframe sandbox、export window、CLI 刷新)都在实现后被审查出安全问题。应该在设计阶段就列出所有出口通道并逐一封堵。

  3. 不要维护两条路径。最初设计了"API 路由 pin + MCP 对话 pin"两条路径。用户正确指出这增加维护成本和出错可能。统一到 MCP 一条路径后,代码量更少、行为更一致。

  4. DOM 操作要考虑 iframe 的特殊性。对普通 div 有效的操作(React key 重排、setState 触发 re-render、DOM clone for screenshot)在 iframe 上都可能失效或产生副作用。

对未来发展的思考

看板是 AI agent 的"工作台",不是用户的"仪表盘"。

传统仪表盘的设计思路是:用户定义指标 → 系统展示数据 → 用户看数据做决策。这是 human-first 的思路。

AI-first 的看板应该是:AI 在工作中产出的视觉工件的展示空间。AI 分析了代码就产出 coverage widget,AI 处理了 issue 就更新 issue 状态 widget,AI 做了 code review 就产出 diff 统计 widget。看板不是用户配置出来的——是 AI 工作过程中自然涌现出来的。

这个方向上还有几个关键的未解问题:

  1. AI 什么时候应该主动更新看板? 对话中提到了相关数据就更新?每次 check-in 后自动更新?还是只在用户明确要求时更新?目前没有自动更新触发机制。

  2. widget 的生命周期管理。看板卡片会越来越多,但没有"这个 widget 已经过时了"的检测。需要一种机制让 AI 或用户能识别和清理不再有价值的卡片。

  3. 多看板 / 看板视图。一个项目可能有多个关注维度——代码健康、产品指标、团队协作。当前是单一看板,未来可能需要分组或分页。

  4. widget 的可编辑性。用户看到 widget 上的数据不对,目前只能在对话中说"帮我改一下"。能否直接在 widget 上双击编辑数值?这涉及到 widget 从"只读展示"变成"可交互表单"的架构转变。

  5. widget 作为 AI 的"视觉记忆"。当 AI 看到看板上有一个"本周计划"widget,它应该能理解这些计划的完成状态,并在后续对话中主动跟进。这需要 <active-dashboard> 注入的内容更丰富——不只是标题和数据契约,可能需要包含 widget 的核心数据摘要。

最终愿景:打开一个项目,看板上已经有 AI 根据项目特征自动生成的卡片。开始工作后,AI 在对话中产出的分析自然沉淀到看板。一天结束时,看板是 AI 今天帮你做了什么的视觉记录。第二天打开,AI 看着看板说:"昨天你要做的三件事还有一件没完成,要现在继续吗?"

这就是"AI 原生项目控制台"的含义——不是人配置给 AI 看的,是 AI 工作给人看的。

CodePilot 生态联动:从功能堆叠到有机系统

回顾 CodePilot 目前的能力拼图——聊天、MCP 工具生态、CLI 工具库、素材库、远程桥接、Skills、助理工作区、生成式 UI、看板——每一个功能独立看都有价值,但真正的力量在于它们开始互相连接

看板的实现让我看到了这种连接的具体形态:

MCP 是血管。用户装一个 Linear MCP server,它不只是"对话中能查 issue"——它同时成为看板的数据源、widget 的数据提供者、bridge 推送的内容来源。一个 MCP 接入点辐射到整个系统。社区有几百个 MCP server,每个都是 CodePilot 生态的潜在新器官。

生成式 UI 是眼睛。在这之前,AI 的所有产出都是文字——用户需要用自己的脑子去"可视化"一段 JSON 或一份日志。widget 让 AI 有了"画出来给你看"的能力。这不是锦上添花——这是一种新的表达维度。一个 AI agent 如果只能说话不能画图,就像一个人只能打字不能画白板。

Bridge 是嘴巴。看板生成的可视化结果,通过 bridge 推到 Telegram/飞书,AI 的工作成果就从"打开才能看"变成了"推到你面前"。这关联到一个更大的问题:AI 的产出不应该被困在一个应用窗口里。

Skills 是手。每个 skill 不只是一段提示词模板——当 skill 可以产出 widget、widget 可以 pin 到看板、看板可以推到 IM,一个 skill 就变成了一条完整的自动化管线。/weekly-report 不只是生成一段文字,而是生成可视化周报 → pin 到看板 → 每周一自动推到团队群。

这些连接目前大部分还是潜在的——bridge 推送还没做,skill 产出 widget 还需要约定协议。但架构上的可能性已经打开了。CodePilot 不是一堆功能的集合,而是一个有循环的有机系统。

Widget 对 AI 交互方式的影响

做完整个看板系统后,我对"AI 应该怎么和人交互"有了一些新的认识。

文字对话是必要的,但不充分。

当前 AI 产品的主流交互是对话——用户问,AI 答。这对"解答问题"足够了,但对"持续协作"远远不够。持续协作需要共享工作空间——双方都能看到、都能修改、状态持续保持的东西。传统软件用文档、看板、代码仓库来做这件事。AI 时代,这个共享工作空间应该是什么?

我认为生成式 UI 给出了一个方向:AI 产出的、人类可理解的、可持久化的视觉工件。不是文档(太重)、不是代码(人类不可直接理解)、不是纯文字(没有结构)——而是一个图表、一张卡片、一个交互式组件。

"同样的数据,你想怎么看就怎么看"

这是 Moxt 的核心理念,也是生成式 UI 最深刻的启示。传统 BI 工具的做法是:系统预定义 10 种图表类型,用户从中选一种,把数据拖进去。生成式 UI 的做法是:你用自然语言描述你想怎么看,AI 当场画出来。

这意味着展示层完全由用户定义。用户说"用环形图"就是环形图,说"用时间线"就是时间线,说"加一个筛选器"就加一个筛选器。开发者不需要预先实现各种图表组件——AI 生成 HTML/JS/CSS 就是最灵活的"组件库"。

一个激进的想法:上下文即应用

做完看板后,我开始想一个更大的问题:如果我们把上下文搞对,是不是根本不需要预设的 UI?

想象一下:CodePilot 没有预先写死的"看板面板"、"Git 面板"、"文件树面板"。它只有一个空白的右侧区域和一个对话框。用户说"我想看 Git 状态",AI 生成一个 Git diff 可视化 widget。用户说"我想管理我的 TODO",AI 生成一个交互式 TODO list widget。用户说"帮我监控 Docker 容器",AI 生成一个实时状态面板。

每个"面板"都不是开发者预先实现的——而是 AI 根据用户需求实时生成的。开发者只需要保证三件事:

  1. 上下文完整:AI 能访问文件系统、Git、终端、MCP 工具、网络——所有它需要的数据源。
  2. 渲染能力完整:生成式 UI 能渲染任何 HTML/JS/CSS,包括图表、表格、表单、动画。
  3. 持久化能力完整:用户觉得好的 widget 能保存,下次打开还在。

其他一切——布局、样式、交互逻辑、数据展示方式——全部由 AI 根据用户的自然语言描述生成。

这当然是一个极端的设想。现实中预设 UI 仍然有价值——启动速度快、行为可预期、不消耗 token。但这个思考方向揭示了一个趋势:AI 应用的 UI 层会越来越薄,上下文层会越来越厚

传统应用:厚 UI + 薄上下文(CRUD 界面 + 数据库查询) AI 应用:薄 UI + 厚上下文(渲染容器 + AI 生成内容 + 丰富的数据访问)

CodePilot 正在走这条路。聊天区是一个通用的文字渲染容器,WidgetRenderer 是一个通用的 HTML 渲染容器,看板是一个通用的持久化展示容器。它们不关心"展示什么"——这由 AI 决定。它们只关心"怎么安全地渲染和持久化"。

最后的反思

做这个项目让我重新理解了一件事:基础设施的价值不在于它能做什么,而在于它让什么成为可能

一个 iframe sandbox + postMessage 通信协议,让任意 AI 生成的代码能在用户面前安全执行。 一个 MCP 工具注册 + 关键词门控机制,让 AI 在对话中按需获得新能力。 一个 JSON 文件 + 数据契约,让一次性的对话产物变成持久化的项目工件。

每一层都很简单。但堆叠起来,它们创造了一种新的人机协作模式——AI 不只是回答问题的工具,而是一个有视觉表达能力、有持久记忆、能接入外部世界的协作伙伴。

这只是开始。


全局视角:CodePilot 作为 AI-Native 操作系统

以下是跳出看板功能本身,站在 CodePilot 整体产品的视角来看这一切意味着什么。

一条隐含的主线

回头看 CodePilot 已经实现的所有子系统,表面上是独立的功能模块,但它们其实在回答同一个问题:怎样让 AI 成为一个完整的工作伙伴,而不是一个问答机器?

子系统 解决的问题 AI 获得的能力
CLI 工具库 AI 知道要用工具但装不了 发现、安装、执行系统级工具
MCP 生态 AI 只能操作本地文件 接入任意外部服务(Linear、Notion、数据库…)
助理工作区 对话结束 AI 就失忆 持久人格、长期记忆、每日复盘
素材库 AI 生成的图片/音频散落各处 统一媒体管理、跨会话复用
生成式 UI AI 只能用文字解释 用图表、流程图、交互组件"画"出来
看板 对话中的好东西是一次性的 持久化视觉工件、持续追踪项目状态
远程桥接 用户必须坐在电脑前 通过 Telegram/飞书/Discord 远程指挥 AI
Skills 重复的工作流每次都要重新描述 封装成可复用的"技能包",一键触发

把这张表竖着看:AI 获得了工具使用能力、外部世界连接能力、记忆能力、视觉表达能力、持久化能力、远程通信能力、程序化工作流能力。

这不是一个"聊天应用加了很多功能"。这是一个 AI agent 的运行时环境——和操作系统为程序提供的能力类似,CodePilot 为 AI 提供了感知、记忆、行动、表达的完整能力栈。

MCP 是这一切的枢纽

在所有子系统中,MCP 扮演着特殊角色。它不是一个"功能"——它是一个能力扩展协议

CLI 工具库通过 MCP 暴露工具管理能力。看板通过 MCP 暴露 pin/refresh/update 能力。素材库通过 MCP 暴露图片生成和导入能力。Widget 系统通过 MCP 暴露设计指南加载能力。

这意味着每新增一个 MCP server,AI 同时获得了在对话中使用它、在看板中展示它的数据、通过 bridge 远程触发它的能力。能力不是线性增长的——是组合增长的。

社区有几百个 MCP server。一个 Linear MCP server 接入 CodePilot 后,AI 可以:

  • 在对话中查询 issue(MCP 基本能力)
  • 生成 issue 统计图表(生成式 UI)
  • 把图表 pin 到看板持续追踪(看板 MCP)
  • 定期刷新数据(看板刷新机制)
  • 在飞书群里推送周报图表(Bridge + 导出)
  • 一键触发完整流程(Skills 封装)

一个 MCP 接入点,六个价值输出通道。这才是"生态杠杆"的含义。

从"聊天界面"到"任务环境"

传统 AI 聊天产品的心智模型是:用户发问 → AI 回答 → 对话结束。CodePilot 正在变成另一种东西:用户描述意图 → AI 在一个持久环境中持续工作

这个"持久环境"包含:

  • 工作空间:文件系统、Git 仓库、CLI 工具——AI 的操作对象
  • 记忆:助理工作区的 soul/user/memory 文件——AI 知道"我是谁、用户是谁、我们在做什么"
  • 视觉空间:看板上的 widget——AI 的工作成果可视化
  • 外部连接:MCP server + Bridge——AI 能触达的外部世界

在这个环境中,"对话"只是 AI 和人类之间的通信通道之一,不是唯一通道。AI 还可以通过看板展示、Bridge 消息推送、文件系统修改来和用户"沟通"。

CLI 趋势对我们的启示

insights/cli-tools.md 提到了一个关键趋势:CLI 正在成为 AI Agent 时代的标准接口。ElevenLabs、Stripe、网易云音乐都在做 Agent-first 的 CLI。

这意味着未来的软件服务会越来越多地提供 CLI/MCP 接口,而非(或不仅仅是)GUI。对 CodePilot 来说,这是巨大的利好——每个新的 CLI 工具和 MCP server 都自动扩展了 AI 的能力范围,而 CodePilot 已经有了完整的基础设施来消费这些能力。

CLI 工具的 Agent 兼容度评分系统(5D:Agent 原生设计 / JSON 输出 / Schema 自省 / Dry Run / 上下文友好)本质上是在回答:这个工具对 AI 来说有多"好用"? 随着更多工具为 AI 优化,CodePilot 作为 AI 的"工作台"价值会不断放大。

Widget 是 AI 时代的"应用"

传统软件生态:开发者写应用 → 用户安装使用 → 应用有固定的 UI 和功能

AI 时代的新模式:用户描述需求 → AI 生成 widget → widget 就是"应用"

一个 widget 可以是一个待办清单、一个项目监控面板、一个数据分析报表、一个交互式筛选器。它由 AI 根据上下文实时生成,天然适配用户的具体需求。不需要去应用商店搜索,不需要学习新软件——用自然语言描述你要什么,AI 当场造出来。

看板让这些"AI 造的应用"有了持久化的生命:它们不再是对话中一闪而过的气泡,而是项目工作空间的一部分,每天都在那里,随数据更新。

这其实是一种新的软件分发方式:不是下载安装,而是描述生成

给用户的真正可能性

把所有这些连在一起看,CodePilot 给用户开启了一种全新的工作方式:

独立开发者 / 创作者

  • 打开项目 → 看板上是 AI 自动维护的项目健康度、依赖状态、TODO 追踪
  • 在飞书/Telegram 上说"看看今天的 issue 情况" → AI 生成图表推送过来
  • 写代码时遇到问题 → 对话中 AI 直接画出架构图帮你理解
  • 做完一天的工作 → AI 自动更新看板上的进度,写入每日记忆

小团队

  • 看板作为团队共享的项目状态面板(.codepilot/dashboard 可以 git 追踪)
  • 每个人的 CodePilot 看到的是同一份看板数据
  • AI 根据不同人的角色(soul.md)以不同方式解读同一份数据

个人助理场景

  • 助理工作区 + 看板 = AI 原生的个人管理系统
  • "帮我做一个本月商单进度看板" → AI 读取你的文件,生成追踪面板
  • "商单 B 签了" → AI 更新数据源文件 → 看板自动刷新

核心价值主张不是"我们有 N 个功能",而是"你用自然语言描述你想要什么样的工作环境,AI 帮你构建出来"。

搞定上下文,让用户定义一切

回到那个激进的问题:是不是只要搞定上下文,所有的设置和展示方式都可以由用户自己定义?

答案比"是"或"否"更微妙。

用户不想"配置"——他们想"描述"。"帮我做一个看板,追踪我的 GitHub stars 和 issue 数量"和"在设置页面创建一个新面板,添加两个数据源,选择图表类型,配置刷新频率"——同一个目标,前者是自然语言描述,后者是传统配置界面。

CodePilot 的架构已经在朝这个方向走了:

  • 生成式 UI 让"展示方式"由用户用自然语言定义
  • MCP 让"数据来源"由用户用自然语言指定
  • 看板让"持久化什么"由用户用自然语言决定
  • Skills 让"工作流程"由用户用自然语言封装

还缺什么?缺的是上下文的深度和广度

  • AI 还不够了解项目的全部状态(只有 working_directory 下的文件)
  • AI 还不够了解用户的完整意图(只有当前对话 + 助理记忆)
  • AI 还不能持续观察变化(只有手动触发的刷新,没有事件驱动的自动感知)

当这些上下文补齐,真正的"用户定义一切"才会实现。到那时,CodePilot 不再是一个"有很多功能的 AI 聊天工具"——它是一个AI 原生操作系统,用户用自然语言"编程"它要做什么、监控什么、展示什么、推送什么。

开发者的工作不再是写"功能",而是写"能力基础设施"——更好的上下文获取、更安全的代码执行、更可靠的持久化、更丰富的渲染。功能本身,由 AI 和用户在对话中共同创造。