# 架构总览 ## 定位 本项目是纯个人使用、本地优先的开发助手与电脑管家。完整功能范围保持不变,但源码只围绕两个长期边界演化:`Kernel` 撑起系统,`Extensions` 增加能力。 架构不追求套用通用框架的模块名。一个概念是否进入 Kernel,只看它是不是所有能力都必须遵守的稳定运行规则;其余需求默认通过 Extension 实现。 ## 系统拓扑与源码架构 系统拓扑描述进程如何连接: ```text Supervisor ──启动/切换/回退──▶ Runtime ▲ │ CLI / Web / Desktop ``` Runtime 内部的源码架构只有: ```text 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。一个完整能力可以同时注册可调用实现、订阅事件、维护数据并管理资源。 最小契约只有生命周期: ```ts interface Extension { readonly id: string; setup(context: ExtensionSetupContext): void | Promise; start?(context: ExtensionRuntimeContext): void | Promise; stop?(context: ExtensionRuntimeContext): void | Promise; } ``` - `setup` 只注册能力和事件处理器,不开启外部资源;所有 Extension 完成 `setup` 后才进入 `start`。 - `start` 开启终端、网络连接、后台任务等运行资源。 - `stop` 按安装的逆序关闭资源。 Extension 对象只是安装入口。Kernel 在运行时真正调用的是 Extension 注册的能力;只需响应过程的 Extension 则订阅 Kernel 事件。事实事件只能由拥有该事实的 Kernel 流程发布,ExtensionContext 不提供发布 Kernel 事件的权限。 ## 公共扩展与产品线私有扩展 Extensions 按使用范围组织: ```text extensions/ ├── shared/ # 三条产品线可复用的能力 ├── cli/ # CLI 私有输入、展示和终端交互 ├── web/ # Web 私有协议、路由和页面 └── desktop/ # Desktop 私有原生集成 ``` 公共扩展不认识具体产品界面。产品线私有扩展可以使用 Kernel 和公共能力,但 CLI、Web、Desktop 私有扩展之间不能直接依赖;不再只属于一条产品线的代码应提升到 `shared/`,不要求三个产品全部使用。 “公共”与“私有”只是源码归属和装配规则。Kernel 不认识这些分类,也不包含 `cli | web | desktop` 分支。 ## 产品装配 每条产品线只有一份扩展清单: ```text 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 决定。 ## 首版工作流 第一版先跑通同一条端到端主链路: ```text 产品私有扩展接收输入 ↓ 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` 中管理。 ## 依赖规则 ```text 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。