A2APP / 专为 AGENT 构建的语言

输入意图。输出工作流。

让 Agent 组合工具、数据与原生界面的精巧 DSL。以 Makepad Splash 为基础,提供有界工作流运行时,以及从像素到可检查组件的 A2App 路径。

开源 · Rust 宿主 · Makepad Splash VM

tool_workflow.octoscript源码示例
use mod.tool

let task = "prepare release notes"
let result = tool.call("text.echo", task)
result
01 / SOURCE描述工作
02 / HOST调用工具
03 / RESULT返回数据
预期输出 · TEXT.ECHO
"prepare release notes"
由宿主授权工具访问本地运行
LLM 生成源码宿主控制执行按需呈现原生 UI
01 / 为何需要 DSL?

为模型设计语言。 让宿主掌握边界。

LLM 需要容易生成、检查与修正的语言;应用需要知道生成的程序究竟能做什么。Octoscript 把两者放进同一份明确的约定。

01

缩小模型的生成目标

规范语法、版本化 profile 与结构化诊断,让 Agent 围绕明确的语言表面完成生成、检查和修正。

生成 → 检查 → 修正
02

把执行权留给宿主

注册工具、数据约定与逐步授权共同定义允许的副作用。源码语法正确,也不能自行获得执行权。

审查 → 授权 → 执行
03

为嵌入应用而设计

共享 Rust VM、明确的资源上限与宿主驱动的延迟执行,让工作流融入应用生命周期和 UI 事件循环。

小巧 → 有界 → 可嵌入

为何不直接让模型写 Python / JavaScript?

通用语言擅长利用成熟生态。Octoscript 选择为嵌入应用的生成程序设计更小的执行约定:让模型专注表达工作,让宿主检查并控制每一步。

设计问题Python / JavaScriptOctoscript
生成目标通用语法与大型生态,应用另行约束可用范围。明确的规范语法 + profile + 工具目录。
执行权由嵌入方式、隔离环境与 API 共同决定。默认无工具权限;宿主逐步签发能力。
运行成本按所选运行时补齐限制与应用集成。指令、时间、内存等显式上限;宿主驱动让出与恢复。

小巧和高效是设计目标;安全与可靠来自具体的检查、授权、执行预算和宿主隔离。这里不宣称未经测量的性能优势。

阅读完整设计动机与安全模型
02 / 为何从 SPLASH 出发?

演进语言基础。 复用 UI 生态。

Splash 已有 Rust VM、对象组合与实时 UI 语言。Octoscript 在此基础上加入有界工作流约定和受控执行,VM 加固维护在共享 Makepad fork,UI 继续复用 Splash 组件生态。

为何 fork,哪些能力继续共享?
工作流宿主

Octoscript

工具 · 数据 · 执行
UI 宿主

Makepad UI

组件 DSL · 原生渲染
共享 VMMakepad Splash

共享实现 · 各宿主按需创建 VM 实例与绑定

03 / MEET SPLASH

一种语言,连接 界面、行为与绘制。

认识 Rik Arends 与 Makepad 项目中的 Splash:可实时编辑的 UI 语言,也是 Octoscript 的 VM 基础。

component.splashUI HOST
View {
    width: Fill
    height: Fit
    flow: Down
    spacing: 12

    title := Label {
        text: "Ready to build"
    }
    launch := Button {
        text: "Run workflow"
    }
}
:=命名子组件:设置属性{ }组合实例

UI 片段:需要已注册 Label、Button 等组件的宿主。

  1. 01

    对象组合

    Type { … } 实例化定义,name := 命名组件;让界面结构可复用、可定位。

  2. 02

    类型与样式

    +: 合并继承的属性,主题与 kit 共享默认值;改一处,复用到多处。

  3. 03

    行为与 Rust

    函数与回调表达交互;Rust 注册组件、持有状态、执行真正的应用服务。

  4. 04

    绘制与动画

    shader、instance、uniform 与 Animator 支持自定义 GPU 视觉和状态过渡。

  5. 05

    实时迭代

    UI 宿主可重新挂载或更新 Splash,结合组件检查和画面反馈完成修正。

UI 复用 Splash,工作流有自己的边界。

直接编写 Splash,或先把 L0 / L1 实例化为卡片树,再经 kit 转换和求值得到渲染器 UiNode,最后生成组件源码。共享 makepad-script 实现,不等于共享宿主能力。

深入了解 Splash 语法、Rust 与 UI 宿主
04 / 生成式 UI 约定

声明界面。 交给宿主渲染。

UI 生成有独立约定:声明式 L0,以及受限的 L1 算术扩展。下面分别解释语言能力与四层实现链路。

L0
声明式 UI

组合所需的一切

组件、数据绑定、带键集合、状态与事件转换。节点树的实例化过程无需 VM。

组件数据绑定状态
L1
有界表达式

加一点计算能力

在 L0 基础上增加有界的纯算术表达式,计算界面需要的派生值。

L0 + 算术纯表达式
从声明到渲染
  1. UiNode
  2. 主题/组件 kit
  3. Splash DSL
  4. 原生组件

L0–L3:一条可验证的组件实现链路

这里的四层描述“怎么把卡片变成可操作的界面”。它们与上方卡片头部的语言能力等级是两个独立维度。

  1. L0

    检查与展开

    卡片 + 宿主数据 → UI 树

    验证数据来源、状态、key 与展开预算。

  2. L1

    组件库映射

    UI 树 + kit → 组件调用

    保留角色、参数、主题和来源 ID。

  3. L2

    VM 与节点翻译

    组件调用 → UiNode → Splash

    源码求值得到 UiNode,再由 Rust 生成组件描述。

  4. L3

    挂载与交互

    组件描述 → 像素 + 事件

    实际布局、绘制、点击与状态回传。

能力等级的当前边界:UI L0 已实现;UI L1 仅开放受限的纯算术表达式。UI L2 尚未实现,检查器在解析前拒绝;不存在可用的 UI L3 profile。实现链路的 L3 不是一张执行权限通行证。

查看语法、完整例子与等级判定 →
05 / ONE LOGIC, MULTIPLE HOSTS

共享 Rust 逻辑。 选择界面的呈现方式。

Makepad 绘制组件与平台系统控件都可以成为 UI 的目标,也可以在同一页面内组合。语言、逻辑和渲染宿主各司其职。

跨平台组件

Makepad

Rust + GPU 后端,复用布局、绘制、组件和交互,覆盖原生与 WebAssembly。

平台系统控件

Android

Rust 求值树 → JNI → Java builder → Android / Material View。

平台系统控件

OpenHarmony

Rust → ArkUI C API → 原生节点;外壳与特定平台交接保留在 ArkTS。

后端与接入点

iOS

Makepad iOS 后端已有原生视图接入;完整 UIKit 控件树仍需专门适配器。

一个页面,一致的交互。

宿主协调布局矩形、裁剪、层级、焦点、键盘与生命周期。例如让原生预览负责相机画面,Makepad 负责自定义覆盖层,平台控件提供系统输入体验。

历史例证:相机的两个宿主。

开发分支中的 camera/native 和 camera/oh 都依赖 octosense-camera-logic;这不是当前 Camera 应用包的架构。状态机与场景生成共享,前者使用 Makepad kit,后者通过 ArkUI C API 创建系统节点。

查看共享逻辑与双宿主实现

Makepad 原生绘制组件与平台系统控件是两种后端;同页组合需要具体适配,并不自动将任意 shader 转成系统控件。

查看平台映射与原生组合细节
06 / THE APP IS THE WORKBENCH

把开发工具放进应用。 让 Agent 直接参与。

从面向人类的 Studio,到应用内可通过 socket 访问的检查和控制原语。Agent 无需操作 IDE 窗口,就能理解和驱动正在运行的 UI。

app --remote127.0.0.1:PORT / HTTP
  1. 01

    观察

    读取组件 ID、类型、文字、状态和当前矩形。

    /snap?q=Button
  2. 02

    操作

    按最新边界点击、拖动、滚动、按键和输入。

    /click · /m · /k · /t
  3. 03

    验证

    等待实际帧,检查应用画面和行为日志。

    /g · /gseq · /log
  4. 04

    修正

    检查反射属性、试改样式,再把变更写回源码。

    /tweak/state · /tweak/apply

开发实例显式启用仪器。这里的 headless 指不依赖 Studio GUI,视觉验证仍使用真实 GPU;各平台的检查与采集能力以宿主实现为准。

这里的 Agent 帮助开发和测试应用。运行时应用 Agent 则由 OctoSense 和 octos 管理,使用用户允许的账户工作区、工具与对话路由。独立 card-host 没有注册 Agent 服务。

探索交互式应用与 Agent 架构图阅读语言、仪器与 A2App 的完整关系
07 / PIXELS → COMPONENTS → APP

让每一个像素, 找到它的组件。

两条流程保留来源与运行时的对应关系,让 Agent 能从设计进入源码,再回到真实组件与交互中验证。

image-to-card

一次设计一组相关页面,把视觉、数据和动作一起组织为真实的服务体验。

GitHub
  1. 01

    测量来源

    保留 prompt、图集、页面裁切与坐标变换。

  2. 02

    映射语义

    把文字、控件、数值图表与图片分别映射到组件。

  3. 03

    连接服务

    提取服务卡片,绑定 reducer、状态、授权与操作。

  4. 04

    验证与发布

    检查组件和实际画面,再输出原生或 WASM 包。

AIRCON / SCENE 05

例证:送达后的安装邀约

点选一个来源元素,查看它在原生界面中的组件类型与服务事件。

SOURCE ID
choose_time
WIDGET
KitButton
EVENT
installation.open_slots

来源按钮成为 KitButton,独立保留控件与文字;动作交给安装服务处理。

01 / 设计参考
空调安装邀约的原始设计参考,包含文字、产品照片和选择时间按钮
02 / 原生组件渲染
同一安装邀约的实际 Makepad 原生渲染,文字与按钮是独立组件

归档原生渲染与源图对照;高亮按来源映射区域定位。这一轮仍有字体、图标和阴影差异。检查器展示记录的映射,不会调用安装服务。

RUST → WASM → MAKEPAD

设计可以直接运行。

在浏览器里体验 Material 组件与 Flutter 示例设计。控件由真实 Makepad 渲染器绘制。

WebAssembly / WebGL

选择配送方式、点击 Gift wrap、勾选 Send updates,再点 Confirm selection。下方状态来自 WASM 内部的真实 slot。

运行状态
尚未启动
最近的动作
—
组件节点
—
启动后显示状态

按需加载。状态仅在当前实例中保留。Flutter 设计由 Octoscript 重建,部分节点只提供展示或导航;设备能力不在网页中模拟。

Makepad component lab

启动后,在这里直接操作。

MATERIAL 3 · FLUTTER DESIGNS

浏览器需要支持 WebAssembly 与 WebGL。组件目录与说明可直接阅读;canvas 控件的辅助技术支持不同于网页表单。 完整组件库与支持范围 →

08 / 人的确认

从源码 到人的决策。

工作流可以无界面运行。需要用户参与时,App Card 呈现数据、上下文和下一步操作。

  1. 01
    接收事件

    让原始消息与提议的操作保持关联。

  2. 02
    组合界面

    通过原生组件呈现结构化数据。

  3. 03
    审查下一步

    由用户确认或忽略提议。

组件目录与实际体验
从事件到 APP CARD
林老师 · 青禾学校周五家校活动的时间调整
01
octoscript
理解→组合→确认
日历卡片等待你确认

家校活动,有了新时间

学校邮件提出了新的活动时间,在这里确认日历调整。

9 月 18 日 · 周五下午 3:30
学校花园
查看原始邮件
林老师 · 青禾学校

Alex,你好!家校活动调整到 9 月 18 日周五下午 3:30,请到学校花园集合。期待见面!—— 林老师

每个操作,都能追溯原始信息

交互概念演示 · 示例数据 · 不执行外部操作

09 / 第一个工作流

几行代码 开始运行

校验源码,注册本地演示工具,运行工作流。然后,用你的应用服务替换演示工具。

  1. 01
    获取源码

    克隆 Octoscript 仓库。

  2. 02
    校验并运行

    执行前,先通过校验器检查源码。

  3. 03
    连接你的工具

    在嵌入宿主中注册应用工具。

宿主工具目录
tool_workflow.octoscript
use mod.tool

let task = "prepare release notes"
let result = tool.call("text.echo", task)
result
预期输出: text.echo → "prepare release notes"
需要 Rust 和 Cargo · 在仓库根目录执行
10 / 开发文档

下一步,清晰可见

先了解架构,再按需深入。