CoveBlog
ARCHITECTURE NOTE 01工程方法

Cove Node:把 Agent 放回用户自己的电脑

如果 Cove 只是一段对话,放在哪里都差不多。但当它开始长期保存上下文、连接渠道、处理文件、执行自动化并发布结果,运行位置就会变成产品最重要的决定之一。Cove Node 是我们对这个问题的回答。

01

我们先冻结的不是技术栈,而是产品边界

设计 Node 时,最容易做的事是先画服务图:一个聊天服务、一个文件服务、一个任务服务,再配一个后台。但服务图回答的是代码怎么跑,不回答产品属于谁。我们先定下的事实是:Cove Node 是一个完整的客户机产品,本机使用本身就是一条完整路径。

因此,core/app、core/runtime、core/agent、core/control、core/channels 和桌面壳即使运行在不同进程里,也仍然属于同一个 Node。进程边界服务于稳定性与职责分离,不能反过来制造多个需要用户理解、安装和维护的产品。唯一独立的可选产品是公网传输边界 Edge;不安装它,Node 依然成立。

  • 本机或局域网使用不依赖 Cove Cloud。
  • 一个 Node 对应一份不可变发行版和一套统一生命周期。
  • 内部模块可以独立运行,但不向用户暴露成多个产品。
  • 公网入口是可选传输能力,不是 Agent 能否工作的前提。
留下来的判断

先确定谁拥有产品、断网后还剩下什么,再选择框架和进程。否则架构很容易围着部署便利生长,而不是围着用户所有权生长。

02

一份安装目录,两类完全不同的所有权

Node 安装后只有一个 Cove Home,但里面有一道刻意保留的边界:core 由产品发行版拥有,workspace 由用户拥有。前者必须能够验证、升级和回滚;后者必须能够长期生长,而且不能在升级或卸载时被顺手替换。

这条边界比把数据放进某个隐藏目录更重要。它让我们可以原子切换 current 与 previous,而不用迁移用户的文件、数据库、技能和凭据;也让用户能直接检查自己的 Harness、插件和工作资料,而不是把一切埋进应用内部。

<personal-agent-home>/
├── core/
│   ├── releases/<release-id>/   # 不可变产品
│   ├── current -> releases/...  # 当前版本
│   └── previous -> releases/... # 可回滚版本
└── workspace/
    ├── registry/  skills/  plugins/
    ├── files/  publications/  databases/
    └── config/  secrets/  runtime/  logs/
留下来的判断

升级默认替换产品,不替换用户;卸载默认移除 Core,不删除 workspace。所有权必须能落到目录、发行版和恢复动作上。

03

Next.js 是界面与 BFF,不是 Agent 的大脑

Node 使用 Next.js App Router 统一 Setup Center、对话、动态、邮件、Pages、技能、渠道和更新界面。它负责本地读取、版本化 BFF 与一致的会话边界,但不会承接长生命周期工作。页面请求结束,不应该意味着 Agent、渠道轮询或备份调度也结束。

真正持续运行的工作留在 runtime 与 agent 服务中:前者管理生命周期、本机网关和产品状态,后者管理 Codex 会话、任务、文件、动态、自动化与发布。channels 隔离第三方渠道状态,desktop 只是复用系统 WebView 的轻量窗口。每层都可以失败和恢复,但它们共同组成一个 Node。

LOCAL UI + BFFcore/app

Next.js 页面、认证后的本地读取、版本化 Route Handlers。

LIFECYCLEcore/runtime

安装状态、服务编排、本机网关、更新与恢复边界。

LONG-RUNNING WORKcore/agent

Codex 会话、任务、动态、文件、Pages 与周期自动化。

INTEGRATIONScore/channels + plugins

渠道适配与受清单、权限约束的用户扩展。

OPTIONAL TRANSPORTEdge / Cloud

只提供远程入口和传输,不成为业务数据的家。

04

长期工作的 Agent,不能被压扁成一次页面请求

传统 Web 应用常把用户点击、服务器处理和页面响应看成一次完整事务。Agent 的工作不一样:它可能调用多个工具、等待外部渠道、产生阶段结果、被用户中途修正,并在很久以后由计划任务再次启动。用一个 HTTP 请求包住整个过程,既难恢复,也会把界面与运行历史绑死。

所以页面只发起和观察工作,Agent 服务保存可恢复的会话与任务状态。面向用户的动态和任务进展也不是把底层日志原样抛给前端,而是由主 Agent 维护一份可读的展示事实。调试记录服务于诊断,用户记录服务于理解;两者目标不同,读取路径也应不同。

  • 页面负责意图提交、状态读取和明确批准,不充当后台任务系统。
  • WebSocket、渠道轮询、Worker、备份与计划任务由长期服务拥有。
  • 主 Agent 维护用户可见动态,原始工具噪声不直接进入产品页面。
  • 失败恢复围绕任务与发行版边界设计,而不是依赖浏览器仍然在线。
05

连接、模型和扩展,是三条彼此独立的轴

很多 Agent 产品把远程访问、模型供应商和账号体系绑在一起:换模型会影响登录,断开 Cloud 会失去历史,安装扩展又要求把数据交给平台。Node 刻意拆开这三件事。

访问可以是 local-only、自托管 Relay 或 Cove Cloud;模型可以使用 BYOK,也可以连接 OpenAI-compatible Token 网关;能力则通过 Skills、Plugins 和渠道适配器组合。改变其中一条轴,不应该迫使另外两条一起迁移。

ACCESS三种连接模式

本机/LAN、自托管 Edge、可选 Managed Cloud。

MODELProvider 自由

BYOK 与兼容网关独立于访问方式。

CAPABILITY可检查的扩展

Skills、Plugins、Channels 各自声明能力与权限。

留下来的判断

Cloud 应该像门牌,模型应该像引擎,扩展应该像工具。它们都很重要,但任何一个都不该取得用户工作空间的所有权。

06

Harness 不是开发脚手架,而是用户能检查的合同

Node 把一套完整 Harness 放进 workspace:AGENTS.md 说明本地所有权与安全约束,registry 声明项目、能力、路由、命令和扩展,skills 与 workflows 说明 Agent 可以怎样工作。它们不是只在源码仓库里有用的开发提示,而是安装后仍然存在、能被用户阅读和扩展的运行合同。

注册表还有一个经常被忽略的作用:区分 implemented、preview 与 planned。界面、CLI 和文档只能把已经落地的能力当作事实。我们宁愿在注册表里明确写出未完成,也不希望一张漂亮的架构图提前替产品做出承诺。

  • 用户扩展写入 workspace,不修改不可变 Core。
  • 插件通过 manifest 声明版本、能力、权限和贡献点。
  • 固定认证、Setup、更新与内部路由不能被插件覆盖。
  • 高风险变更继续经过可追踪的 R0–R3 风险与审批模型。
07

“本地优先”必须能被安全边界证明

把服务监听在 127.0.0.1 并不自动等于本地优先。真正的边界要覆盖凭据写到哪里、谁能发起高风险操作、远程入口能看到什么,以及升级失败时能否回到上一版。

Node 的凭据、数据库、日志和可变状态只进入 workspace;高风险动作使用带摘要、有效期和本机确认的两阶段批准;Edge 只处理 TLS、路由和传输,不持有对话正文、文件、渠道凭据或业务数据库;发行版携带校验、SBOM、provenance,并保留 previous 作为明确回滚点。

  • 秘密固定进入 workspace/secrets,不进入源码或发行版。
  • 远程访问失败或配额用尽,不影响本机 Console 与 Agent。
  • 自托管 Relay 只保存连接密钥摘要,Node 主动建立出站连接。
  • 更新与回滚操作围绕不可变制品执行,不在生产目录原地改代码。
留下来的判断

隐私承诺只有在断网、升级、恢复和远程访问这几个压力场景里仍然成立,才算架构事实。

08

这套设计并不免费,它把复杂度放回了正确的位置

本地优先意味着我们必须面对跨平台安装、服务恢复、数据迁移、备份和原生发行;不可变 Core 意味着每次更新都要构建、验证并保留回滚证据;受约束插件意味着扩展不能随意把服务端 React 代码塞进受信任进程。相比一个集中托管的聊天网站,这些工作显然更重。

但这些复杂度换来的是可替换性:Cloud 可以断开,模型可以更换,公网入口可以自建,产品仍能继续工作。用户不需要因为某个供应商、域名或订阅变化,搬走自己的长期上下文。我们把运维复杂度留给产品,把退出自由留给用户。

留下来的判断

Cove Node 最终要守住的不是“所有东西都在本机”这句口号,而是用户始终拥有自己的数据、工作空间、运行入口和离开某个供应商的能力。

END OF CURRENT LOG返回博客主页,等待下一篇实践记录。