21 KiB
LineUp App 架构设计
状态: 当前权威设计基线
更新日期: 2026-08-04
适用实现: Tauri 2 Desktop Host 与同代码 Web Reference Host
本文取代: DESIGN.md、M4_COMPATIBILITY_AND_RELEASE.md、TECHNOLOGY_SELECTION.md
1. 设计结论
LineUp 是用户安装和使用的主应用;LineUp Runtime 是 LineUp App 内部提供给小程序的核心 运行环境。 Runtime 不是与小程序平级的产品 App,也不是一个独立客户端。
LineUp App
│
├── App Shell / Host
│ ├── 当前前台小程序的挂载与切换
│ ├── 连接状态、通知和安全恢复入口
│ └── Tauri / Web Host Provider
│
├── LineUp Runtime
│ ├── AppServer / Remote Agent 通信
│ ├── Conversation、Store、sync loop、outbox
│ ├── MiniApp Registry、Instance、Focus、Lifecycle
│ ├── Tool Router、Inbox、Inventory
│ ├── Surface、Capability、Artifact、Audit
│ └── LineUp MiniApp SDK
│
└── MiniApps
├── Interact(系统内建:IM / Audio / Video)
├── Task Dashboard(参考 / 已安装小程序)
├── Whiteboard(参考 / 已安装小程序)
├── Draw-and-Guess(参考 / 已安装小程序)
└── 未来第三方小程序
任何 MiniApp 都必须通过 Runtime SDK 使用通信、Tool、生命周期、Surface 和系统能力;不得 建立独立 Agent 通信链路,或直接访问 Host 特权、Store、认证信息及其他 MiniApp 数据。
2. 产品边界与术语
| 术语 | 含义 | 不能做什么 |
|---|---|---|
| LineUp App | 用户实际使用的主应用、产品容器和交付单位。 | 不能把业务规则重新堆进 Shell。 |
| App Shell / Host | Tauri 或 Web 中的挂载、切换、通知、恢复和受限 Host Provider。 | 不解释 Agent 协议,不决定 Tool/App 路由。 |
| LineUp Runtime | App 内部的长期协调环境;唯一拥有通信、可靠性、MiniApp 调度与安全决策。 | 不负责任意 MiniApp 的具体 DOM 或业务 UX。 |
| MiniApp | 运行在 Runtime 上的功能单元。 | 不直连 Agent/AppServer,不直写 Runtime 状态。 |
| System MiniApp | 随 LineUp 发布、代码可信的内建 MiniApp,如 Interact。 | 仍不能绕过 Runtime 调度或 Capability Policy。 |
| Installed MiniApp | 经验证后在受限 Surface 中运行的小程序。 | 不访问 Host DOM、Tauri invoke、token、任意网络或其他 MiniApp。 |
| MiniApp SDK | Runtime 向 MiniApp 开放的受控能力集合。 | 不是通用 Web、Tauri 或 Agent SDK。 |
| Tool | Agent 通过 Runtime 调用的、Manifest 已声明的 MiniApp 功能。 | 不是 App 内部任意函数。 |
| Capability | Runtime/Host 保管的录音、文件、通知等系统能力。 | 不是 MiniApp 自动拥有的权限。 |
| Surface | 复杂交互使用的受限 UI 容器。 | 不承载未验证远端脚本或 Host 特权。 |
2.1 Interact MiniApp
Interact 是第一个系统级 MiniApp,也是用户与 Agent 的默认交互入口:
Interact MiniApp
├── IM Mode:文字、图片、短消息、任务和结果投影
├── Audio Mode:实时语音(后续)
├── Video Mode:实时视频(后续)
└── IM 标准交互的默认 Renderer Provider:notice / choice / confirm / input
当前实现仍保留兼容名称:
产品概念:Interact MiniApp
当前 app_scope:chat
当前目录:tauri/src/core-apps/chat/
目录和作用域改名属于独立迁移任务,不能和 Runtime/MiniApp SDK 重构混在一起。
Interact 是可信内建代码,因此可以使用 LineUp 的可信 DOM 组件;但它和所有 MiniApp 一样, 必须经 SDK 请求 Runtime 行为,不能直接访问 Transport、Conversation Store、焦点栈、App Registry、原始 Agent Envelope 或系统能力。
3. 当前技术与 Host 基线
唯一客户端实现与验收基线是:
Tauri 2 Desktop Host + Web Reference Host
它们运行同一份 TypeScript Runtime 与 MiniApp 代码,并不是两个客户端:
- Web Reference Host:浏览器开发、Tailscale 联调和自动化验证入口;只能提供可安全降级 的浏览器能力。
- Tauri Desktop Host:正式桌面交付;只在 Runtime 授权后提供文件、通知、媒体等 Host Provider 能力。
不规划独立 Android/Kotlin 客户端,也不规划 Wails Host。已退役的 Android/Wails Spike 只保留 在 Git 历史中,不能作为架构、协议、目录或验收依据。
开发命令:
cd lineup-app/tauri
npm run web:dev # Web / Tailscale Reference Host
npm run desktop:dev # Tauri Desktop Host
npm test -- --run # Runtime、MiniApp 与 Host 回归
npm run build # TypeScript 检查与 Web production build
Web Host 与 AppServer 的地址必须按访问位置匹配:同机浏览器使用 127.0.0.1,Tailscale 浏览器
使用受信任的 Tailscale 地址。0.0.0.0 仅是服务器监听地址,不能作为浏览器 API 目标。
4. Runtime 的唯一所有权
Runtime 是以下对象的唯一所有者:
Transport
Conversation Store
sync loop
outbox
协议兼容与原始 Envelope 校验
作用域筛选与 message_id 去重
MiniApp Inbox 与 ACK
MiniApp Registry、Instance、Focus、Lifecycle
Tool Router、Inventory、Capability、Surface、审计与恢复
当前消息路径必须保持单向:
AppServer / Remote Agent
→ LineUp Runtime
→ 协议、scope、权限、去重和持久化
→ MiniApp SDK Inbox / Tool Call
→ MiniApp UX
→ SDK Result / Progress / Lifecycle Request
→ Runtime 校验、审计、outbox
→ AppServer / Remote Agent
禁止项:
MiniApp 直接 fetch AppServer 或 Agent
MiniApp 直接读写 Conversation Store、sync cursor 或 outbox
MiniApp 构造或发送原始 Agent Envelope
MiniApp 直接切换其他 MiniApp、改写 focus stack 或 Registry
MiniApp 直接调用 Tauri invoke、Host DOM 根节点或系统能力
Surface 从消息 payload 直接加载 URL、HTML、CSS、JS、Bundle 或 source
5. MiniApp 信任模型与 SDK 权限视图
所有 MiniApp 共享 Runtime 的协议语义,但按来源获得不同的 SDK 视图。
| 能力 | Interact / System MiniApp | Installed MiniApp |
|---|---|---|
| 接收自身 Inbox、ACK | 可以 | 可以 |
| 接收 Runtime Tool Call | 可以 | 可以 |
| 上报 progress / result / error | 可以 | 可以 |
| 请求前台、后台、关闭 | 可以,由 Runtime 决定 | 可以,由 Runtime 决定 |
| 请求 Surface | 可以,经 Runtime Policy | 可以,经 Runtime Policy |
| 请求 Capability | 可以,经 Runtime Policy | 可以,经 Runtime Policy |
| 可信内建 DOM 组件 | 可以 | 不可以 |
| 隔离 iframe / Surface Bridge | 可选 | 必须 |
| 直连 Transport、Store、Agent | 不可以 | 不可以 |
| 直接 Host / Tauri / OS 调用 | 不可以 | 不可以 |
| 读取其他 MiniApp 数据 | 不可以 | 不可以 |
系统内建不等于绕过 Runtime:可信来源只决定代码的发布与 UI 执行方式,不改变 Runtime 的 通信、焦点、Tool、权限和审计边界。
6. MiniApp 实例、焦点与恢复
MiniApp Registry 管理“有哪些小程序”,Instance Manager 管理“哪些实例正在运行”。二者不能 混为一个状态。
type MiniAppInstanceRecord = {
instance_id: string;
app_scope: string;
conversation_id?: string;
state:
| "starting"
| "foreground"
| "background"
| "suspended"
| "stopping"
| "stopped"
| "failed";
parent_instance_id?: string;
started_at: string;
stopped_at?: string;
error?: string;
};
Runtime 保存焦点栈,不以单个 MiniApp 自己的布尔状态作为事实来源:
focus stack:
chat:audio-001
draw-and-guess:game-001
foreground:
draw-and-guess:game-001
background:
chat:audio-001
当扩展 MiniApp 关闭或失败时,Runtime 必须恢复焦点栈中的前一有效实例。重启后,Runtime
恢复有界的实例与焦点状态;starting 或 stopping 中断的实例必须安全降级为 suspended,
不得伪装为已完成的 Host 操作。
7. MiniApp SDK v1
下一阶段的核心交付是 LineUp MiniApp SDK v1。SDK 不是万能 API,而是 Runtime 根据 Manifest、实例状态、权限和 Policy 开放的最小请求集合。
interface LineUpMiniAppSDK {
readonly context: MiniAppContext;
inbox: MiniAppInboxAPI;
tools: MiniAppToolAPI;
ui: StandardInteractionAPI;
lifecycle: MiniAppLifecycleAPI;
surfaces: MiniAppSurfaceAPI;
capabilities: MiniAppCapabilityRequestAPI;
}
type MiniAppContext = {
app_scope: string;
instance_id: string;
conversation_id: string;
app_version: string;
state: "starting" | "foreground" | "background" | "suspended";
};
7.1 Inbox
interface MiniAppInboxAPI {
list(after_message_id?: string): readonly MiniAppMessage[];
subscribe(listener: (message: MiniAppMessage) => void): Unsubscribe;
acknowledge(message_id: string): boolean;
}
Runtime 在投递前校验 Envelope、scope、目标 MiniApp、实例状态和去重;消息先持久化,再由 MiniApp ACK。后台化、刷新、Surface 重载或 Runtime 重启不能丢失未处理消息。
7.2 Tool
interface MiniAppToolAPI {
subscribe(listener: (call: MiniAppToolCall) => void): Unsubscribe;
get(call_id: string): MiniAppToolCall | undefined;
reportProgress(call_id: string, progress: MiniAppToolProgress): Promise<CommandReceipt>;
complete(call_id: string, result: JsonObject): Promise<CommandReceipt>;
fail(call_id: string, failure: MiniAppToolFailure): Promise<CommandReceipt>;
cancel(call_id: string, reason?: string): Promise<CommandReceipt>;
}
complete、fail、cancel 都是对 Runtime 的请求,不是直接网络发送。Runtime 必须验证
call_id 的实例归属、合法状态迁移、输入/输出 schema、幂等性和权限,然后持久化、审计并
写入 outbox。
7.3 标准交互、Lifecycle、Surface 与 Capability
Runtime 通过 sdk.ui 提供 notice、choice、confirm、input 四种标准交互原语。这是由
Runtime 统一拥有的标准输入输出库:Runtime 创建和持久化交互记录,注入 owner、校验请求/结果、
负责恢复、审计与路由,并依照 Shell Policy 决定呈现位置。
owner 不属于 SDK 调用参数。Runtime 仅从 SDK 已绑定的 MiniAppContext 注入
app_scope、instance_id、conversation_id,并可带有已验证的 parent_call_id、surface_id 与
来源;MiniApp 不可伪造、覆盖或访问其他 owner 的交互。presentation 只能作为 inline、modal
或默认形式的偏好,最终仍由 Runtime/Shell 决定。
Runtime 内部至少持久化以下归属信息:
type StandardInteractionOwner = {
app_scope: string;
instance_id: string;
conversation_id: string;
parent_call_id?: string;
surface_id?: string;
source: "agent_tool" | "miniapp_tool" | "runtime_policy";
};
Agent 在 IM 中的提问由 Interact 作为默认可信 Renderer Provider 呈现在 IM 时间线/卡片内。前台 MiniApp 自己请求的低复杂度事务提示,可在该 MiniApp 的有效容器或 Surface 中以 Runtime 批准的 标准 modal、sheet 或 card 呈现,不能因此强制切换到 Interact。结果始终先返回 Runtime,再仅投递 给 owner MiniApp;MiniApp 不可自行创建 Host 弹窗或直接将结果发送给 Agent。
复杂、高频或私有的业务 UI(例如 Whiteboard 画布文字编辑、画笔、颜色选择、拖放和工具栏)留在
MiniApp 自己的 Surface 内,不使用标准交互库。系统权限确认(文件、麦克风、通知等)则属于
Runtime/Host Capability Gateway,而不是普通 confirm。
interface MiniAppLifecycleAPI {
requestForeground(): Promise<CommandReceipt>;
requestBackground(): Promise<CommandReceipt>;
requestClose(reason?: string): Promise<CommandReceipt>;
}
MiniApp 只能请求生命周期变化;Runtime 决定是否允许,处理 pending Tool/Surface,并负责 焦点恢复。
Surface 与 Capability 也只能请求:
MiniApp requestOpenSurface / requestCapability
→ Runtime 校验 Manifest、Policy、实例状态和用户确认要求
→ Host Provider 执行受限操作
→ Runtime 记录审计并返回受控结果
不应在 SDK v1 提供 fetch、任意网络、任意文件系统、剪贴板、麦克风、摄像头或 Tauri
直接调用。高风险能力以后通过 Capability Request 按需开放。
8. Tool Contract 与 Inventory
MiniApp 只能在 Manifest 中声明 Tool;Agent 只能调用当前 Runtime 已公布 Inventory 中的 Tool。
type ToolDescriptor = {
id: string; // 例如 task-dashboard.open
version: 1;
handling: "direct" | "interactive" | "launch" | "foreground" | "operation";
target: {
app_scope: string;
requires_foreground: boolean;
restore_previous_focus: boolean;
};
input_schema: JsonSchema;
output_schema: JsonSchema;
permissions?: readonly string[];
timeout_ms?: number;
};
统一调度路径:
Agent Tool Invoke
→ Runtime 校验 Envelope、Inventory revision、Tool Descriptor、参数、scope、App 状态和权限
→ 创建可持久化 Tool Call / 审计记录
→ Tool Router 判定 direct / interactive / launch / foreground / operation
→ 投递到目标 MiniApp instance
→ MiniApp SDK 报告 progress / result / error
→ Runtime 校验输出 schema、持久化、更新焦点、写 outbox
→ Agent 收到可靠结果
notice、choice、confirm、input 是 Runtime 的统一 interactive Tool/交互记录能力。
Interact 提供 Agent/IM 场景的默认 Renderer,而不拥有记录或绕过统一 Tool Call、持久化和结果路径;
其他 MiniApp 只能通过 sdk.ui 在自身有效容器使用 Runtime 批准的标准 Renderer。
建议稳定拒绝码至少包括:
inventory_revision_mismatch
tool_not_advertised
tool_input_invalid
tool_output_invalid
app_disabled
app_instance_not_found
app_scope_mismatch
lifecycle_denied
capability_denied
call_already_final
9. Surface、Bundle、Capability 与发布安全
复杂 UI 只能运行在受限 Surface 中。Installed MiniApp 的生产 Bundle 必须满足:
签名 Manifest
→ 精确 byte size 校验
→ SHA-256 校验
→ 原子写入已验证 cache
→ app_id + exact version 解析
→ sandbox="allow-scripts" 的隔离 Surface
9.1 Host 兼容矩阵
| 情况 | Host 必须行为 | 禁止行为 | 观测信号 |
|---|---|---|---|
旧 Client 收到未知 lineup.v1.* |
安全 fallback,不执行 | 将 payload 当 HTML/能力执行 | unsupported_type / unsupported_version |
| 新 Client 收到旧 plain text | 仅作为 Markdown 显示 | 赋予交互或能力 | legacy markdown renderer |
| 不支持目标 Surface version | 不挂载,显示安全提示 | 自动前移到相邻版本 | surface_unavailable |
| 收到生产 Surface | 仅在签名、长度、SHA-256 成功后挂载已验证 bytes | 接收 URL、HTML、JS、Bundle/source | install disposition |
| 候选 Bundle 验证失败 | 保留当前 active 已验证版本 | 覆盖 active bytes 或执行候选 | signature_invalid 等 |
| active Bundle 被撤销 | 原子回滚到已验证 predecessor;没有则不可用 | 回退到未验证缓存/远端 URL | rolled_back / unavailable |
| Bridge 收到非当前 iframe 消息 | 丢弃 | 仅相信 origin 字符串或调用 Host API | bridge rejection counter |
| Capability Catalog 变化 | 发布最小新 Inventory | 用过期 Inventory 自动执行 | catalog revision |
9.2 生产发布序列
- 发布方创建不可变 artifact 与生产 Manifest:
app_id、精确版本、artifact ID、长度、 SHA-256、最小 Host 版本、权限、可信key_id、Ed25519 签名。 - Manifest 与 Bundle 部署在 Host 配置的 HTTPS artifact 服务;Manifest 不携带 URL、HTML、 CSS、JS 或 source。
- Host 在临时内存中验证签名、精确长度与 SHA-256;失败不写 cache。
- 验证成功后原子安装,并只解析精确
app_id + version;不得自动前移版本。 - 仅向满足最小 Host 版本且已启用目标版本的 Client 灰度发布。
- 监控签名、摘要、下载、Bridge 与 Capability 状态;安全事件发生时只回滚到已验证的 predecessor。
- 回滚后保留审计元数据,但不记录 artifact 内容、URL、token、文件路径或 Capability 参数; 新 artifact 必须使用新版本号。
正式 HTTPS Host 才可被标记为 production-capable。HTTP LAN 开发 Host 在浏览器 WebCrypto 受限时必须安全拒绝验签,不能为了联调放宽该规则。
10. 当前实现状态
10.1 已完成:历史安全基础
历史 M0~M4 已完成并沉淀在当前代码中;它们不是新的平行排期:
| 历史阶段 | 保留能力 |
|---|---|
| M0 | HTTP Transport、Conversation Store、协议解码、Markdown、安全 fallback、基础回归 |
| M1 | Tool Call、Task、可靠交互结果、执行摘要、可信 choice/confirm/input |
| M2 | Surface Registry、实例生命周期、隔离 iframe 与恢复 |
| M3 | Capability Registry、用户确认、审计与受限 Host 执行 |
| M4 | 签名 Manifest、Bundle 校验/缓存/回滚、golden fixture |
10.2 已完成:第二次升级
00.base
→ Runtime 托管 Interact IM(当前兼容名 chat)的稳定基线
01.kernel
→ MiniApp Instance / Focus / Lifecycle、Tool Router、App Orchestrator、
Extension SDK 雏形、Workspace 持久化和恢复
当前实现已验证登录、同步、本地回显、Markdown、安全渲染、Tool Call、Task、Surface、
Capability、App Inbox、outbox、实例焦点恢复和生产构建。自动化回归当前为 23 个测试文件、
99 个测试;npm run build 通过。
Runtime 的关键结构位于:
tauri/src/runtime/app-management/
tauri/src/runtime/coordination/
tauri/src/runtime/persistence/
tauri/src/runtime/protocol/
tauri/src/runtime/surfaces/
tauri/src/runtime/capabilities/
tauri/src/core-apps/chat/
10.3 下一阶段:03.sdk_and_coreapp
下一阶段不是应用市场,也不是立即建设服务端下载目录。目标见 03.sdk_and_coreapp.md:定义并验证 MiniApp SDK v1:
冻结 AppManifest、ToolDescriptor、Tool Call、App Context、Result/Progress/Error 和错误码
→ Runtime 实现通用 SDK 请求路由、schema 校验、审计、恢复和 revisioned Inventory
→ Interact 适配为第一个 System MiniApp SDK 样本
→ Task Dashboard 作为第一个参考 MiniApp 验证 Tool、progress、result、focus 与恢复
→ Whiteboard 验证受限 Surface、状态 patch、Artifact 与 Capability 请求
参考 MiniApp 在此阶段可以是 bundled-development:随开发 Host 内置、有 Manifest 和 Runtime
注册记录,但不依赖服务端 Catalog、远程下载或第三方发布。
10.4 后续阶段
MiniApp SDK 与参考实现稳定后,再按顺序推进:
03.reference-miniapps
→ 完成 Task Dashboard / Whiteboard 的端到端参考实现
04.app-delivery-registry
→ Catalog Entry、Manifest/Bundle 下载、验签、安装、启用、禁用、更新、回滚、移除
05.catalog-and-market(按产品需要)
→ 搜索、分类、发布者、安装 UX、组织分发与可能的商业能力
“市场”属于最后的产品分发层,不能反向决定 Runtime、SDK、Tool 或安全模型。
11. 验收与发布门槛
每次 Runtime、MiniApp SDK 或 Host 改动至少满足:
npm test -- --run
npm run build
对于 SDK/参考 MiniApp,还必须有以下证据:
- 合法与非法 Manifest、Inventory revision、Tool 输入/输出 schema 的自动化测试;
- Tool 启动 MiniApp、前后台切换、结果回传、失败回焦和重启恢复的场景测试;
- Interact 的
notice / choice / confirm / inputIM 呈现不退化,且覆盖 owner 自动注入、跨 owner 访问/提交拒绝、owner 结果回路与 MiniApp 容器内呈现的测试; - Installed MiniApp 无法取得 Host DOM、Tauri invoke、token、任意网络或其他 MiniApp 数据;
- 有头浏览器验证登录、同步、本地回显和代表性 MiniApp 路径;
- 对生产 Bundle,验证签名
open → patch → close → rollback、隔离 Bridge 和 Capability 拒绝路径; git diff --check无格式错误,日志不得包含身份、会话、消息正文、Tool 参数、token 或 artifact 内容。
12. 相关文档与源码导航
- 迭代/00.base.md:Runtime 托管 Interact IM 的稳定基线。
- 迭代/01.kernel.md:Runtime Kernel 与 MiniApp 编排目标和验收。
- tauri/src/README.md:当前源码目录和依赖方向。
- tauri/README.md:Tauri/Web Host 的运行、回归与历史实施细节。
- 程序文件清单与功能说明.md:实现文件和功能说明。
- LineUp App 最终设计方案:跨文档详细契约来源; 若与本文的产品术语或当前迭代顺序冲突,以本文为准并同步更新上游方案。