7.6 KiB
架构总览
定位
本项目是纯个人使用、本地优先的开发助手与电脑管家。完整功能范围保持不变,但源码只围绕两个长期边界演化:Kernel 撑起系统,Extensions 增加能力。
架构不追求套用通用框架的模块名。一个概念是否进入 Kernel,只看它是不是所有能力都必须遵守的稳定运行规则;其余需求默认通过 Extension 实现。
系统拓扑与源码架构
系统拓扑描述进程如何连接:
Supervisor ──启动/切换/回退──▶ Runtime
▲
│
CLI / Web / Desktop
Runtime 内部的源码架构只有:
Kernel ◀──── Extensions
Supervisor、Runtime 入口和三个产品入口是部署位置,不是叠在 Kernel 上方的业务架构层。
Kernel
Kernel 负责让系统可靠地运行:
- 启动、停止以及 Extension 生命周期;
- Extension 注册、能力查找和运行事件;
- Space、Conversation、Message 与 Run 的稳定语义;
- Agent 主执行循环、流式输出、取消和错误边界;
- 本地状态、持久化一致性和资源所有权;
- Tool 等副作用能力不可绕过的权限与记录边界;
- 产品输入提交和 Run 事件订阅的统一运行接口。
Kernel 可以认识本项目真正不可缺少的概念,不为了保持“微内核纯度”拆出 Application、Host 或 Client 等中间层。
正常增加产品能力时不修改 Kernel。只有多个 Extension 都缺少同一种通用机制,或某项规则必须由系统统一强制执行时,才扩展 Kernel 的公共接口。
Extensions
Extension 负责让系统具备具体能力,例如模型、Workspace、Shell、Git、计划、多 Agent、记忆、浏览器、自动化、界面和系统控制。
Extension 不需要声明自己属于 Adapter、Tool、Hook、Behavior 或 Profile。一个完整能力可以同时注册可调用实现、订阅事件、维护数据并管理资源。
最小契约只有生命周期:
interface Extension {
readonly id: string;
setup(context: ExtensionSetupContext): void | Promise<void>;
start?(context: ExtensionRuntimeContext): void | Promise<void>;
stop?(context: ExtensionRuntimeContext): void | Promise<void>;
}
setup只注册能力和事件处理器,不开启外部资源;所有 Extension 完成setup后才进入start。start开启终端、网络连接、后台任务等运行资源。stop按安装的逆序关闭资源。
Extension 对象只是安装入口。Kernel 在运行时真正调用的是 Extension 注册的能力;只需响应过程的 Extension 则订阅 Kernel 事件。事实事件只能由拥有该事实的 Kernel 流程发布,ExtensionContext 不提供发布 Kernel 事件的权限。
公共扩展与产品线私有扩展
Extensions 按使用范围组织:
extensions/
├── shared/ # 三条产品线可复用的能力
├── cli/ # CLI 私有输入、展示和终端交互
├── web/ # Web 私有协议、路由和页面
└── desktop/ # Desktop 私有原生集成
公共扩展不认识具体产品界面。产品线私有扩展可以使用 Kernel 和公共能力,但 CLI、Web、Desktop 私有扩展之间不能直接依赖;不再只属于一条产品线的代码应提升到 shared/,不要求三个产品全部使用。
“公共”与“私有”只是源码归属和装配规则。Kernel 不认识这些分类,也不包含 cli | web | desktop 分支。
产品装配
每条产品线只有一份扩展清单:
products/
├── shared.ts
├── cli.ts
├── web.ts
└── desktop.ts
启动入口先安装公共扩展,再安装当前启用产品的私有扩展。装配清单不承载业务逻辑,也不形成新的架构层。
单个 Runtime 可以同时装配三条产品线的接入扩展;也可以在某种安装形态中只启用其中一部分。无论启用哪些产品,Kernel 和公共数据始终只有一套。
系统拓扑图中的 CLI、Web、Desktop 表示用户实际接触的产品入口。产品私有 Extension 运行在适合自己的位置:Web Extension 可以直接在 Runtime 中开启服务;CLI 与 Desktop 可以包含 Runtime 侧接入能力和进程外的轻量启动器。启动器只负责拉起或连接 Runtime、转发输入输出,不保存 Agent 状态,也不复制 Kernel。CLI 启动器退出时,Runtime 中的 Kernel 与已提交 Run 继续运行。
产品入口需要使用的 Kernel 接口不只包含聊天 Run,还包括三类基础操作:
- 创建、读取和修改 Space、Conversation、配置、扩展及审批等产品状态;
- 提交、查询、取消和继续 Run;
- 按连接或 Run 重新订阅实时事件。
这些是同一套运行接口,不要求再建立独立 Client 架构层。具体采用本地 IPC、HTTP、SSE 或其他传输方式,由相应产品 Extension 决定。
首版工作流
第一版先跑通同一条端到端主链路:
产品私有扩展接收输入
↓
Kernel 创建 Run 并保存用户消息
↓
Kernel 调用模型 Extension
↓
模型返回文本增量或 Tool 请求
↓
Kernel 按需调用 Tool Extension,并将结果继续交给模型
↓
Kernel 保存最终消息和 Run 状态
↓
产品私有扩展订阅 Run Event 并展示
CLI 私有 Extension 与轻量启动器把 Run Event 渲染到终端;Web 转换为网络响应和事件流;Desktop 转换为 IPC、窗口或原生通知。产品差异只存在于链路两端,中间的 Run、模型、Tool、记忆和计划能力全部复用。
能力与事件
- 能力是 Kernel 或其他 Extension 需要主动调用并取得结果的实现,例如模型生成、Tool 执行或记忆检索。
- 事件是已经发生的运行事实,例如 Run 开始、文本增量、Tool 完成和 Run 结束。所有监听器相互隔离;监听失败进入诊断记录,不反向改变已经发生的事实或主流程结果。
需要阻止、修改或返回结果的逻辑不能伪装成普通事件监听;真实需求出现时,由 Kernel 提供明确的调用能力或受控执行点。
Extension 的持久化数据统一通过 Kernel Store 写入各自命名空间。Extension 可以拥有自己的数据结构和外部资源,但不能绕过 Kernel 的数据目录、生命周期、权限和清理规则;模型连接、浏览器进程等运行资源在 start/stop 中管理。
依赖规则
main → products → extensions → kernel
shared extensions → kernel
CLI extensions → kernel + shared capabilities
Web extensions → kernel + shared capabilities
Desktop extensions → kernel + shared capabilities
Kernel ✕ 具体 Extension
CLI ✕ Web ✕ Desktop 私有实现
图中的依赖表示源码 import。Extension 之间需要协作时,通过 Kernel 注册和取得公开能力,不直接反向引用另一个 Extension 的内部实现。
目录不是边界本身。判断架构是否成立的标准是:新增具体能力通常只需增加或修改 Extension,而 Kernel 不需要知道它的名字和产品归属。
Supervisor 与自进化
Supervisor 位于当前 Runtime 版本之外,只负责启动、版本切换、健康检查和失败回退。它在 System Evolution 发布闭环出现时实现;此前可由普通启动脚本承担。
Agent 可以在隔离 worktree 中修改 Kernel 或 Extensions、运行测试并展示 Diff。具体功能优先通过 Extension 生长,但 Kernel 并非不可修改;涉及新的全局运行规则时,仍可在验证和回退保护下演化 Kernel。