
这是什么
EverRoom 是一个本地优先的桌面工作区,立在这样一句话上:上下文应当由证据拼装、被限定在某个工作场所之内,并且足够可见,让人能管得住它。文件、仓库、会议录音、一个浏览器扩展,以及飞书、Slack、Notion、Gmail 这类被连接的服务,都从同一条入口进来;每份来源都保留稳定的身份、内容哈希、版本与来源记录,而一条策略快照决定它究竟变成 Room 的 Wiki 页、实体候选、记忆文档,还是仅仅一条链接。工作单位是 Context Room——一个项目、话题、人或一项长期职责——agent 会话拿到的是这个 Room 的工具与文档,而不是一整片语料。文档是有版本、按块操作的,agent 的改稿要先经过操作内核提交,随后才轮到知识或记忆的扇出,于是一个外部服务出错也弄不坏文档。底下是 SQLite 加 Drizzle、FTS5 与按内容寻址的对象库,一个由 Electron 监管的 Fastify 5 网关,一个从 TencentDB-Agent-Memory 分叉来的 MemoryCore 服务负责分层记忆管线,以及一个由文件驱动的、装着十三个子代理的目录。
谁做的一个公司账号而不是个人:仓库全名是 NxcoreAI/EverRoom,元数据里没有所有者资料,735 次提交记在七个贡献者账号名下——21335464876(173 次)、SkylistqAq(159 次)、lzp-plus(128 次)与 Ewan-yuan(112 次)写了其中大部分,Rlacat 有 72 次,ultralan 有 9 次,xgx1124982311-sys 有 2 次,另有八十次提交没有关联到任何账号。提交邮箱指向一个团队而不是陌生人:五个地址挂在 vyitec.com 上,其中一个 xieguoxin@vyitec.com 有 25 次提交,还有二十四次来自 nexcore@nexcoredeMacBook-Pro.local。88 次提交带共同作者尾注,而每一条尾注点的都是 Claude 模型。某条 pull request 里出现的连接器回调域名是 connect.everroom.vyitec.com,主页是 r.nxcore.ai。
它是怎么搭起来的
组成 · 6四层,并且对「哪一层可以换」有明确规定:桌面端掌握生命周期与信任边界,网关掌握持久编排,它下面的引擎——Pi agent 运行时、记忆核心、知识服务、连接器桥——都被当作可替换件,而数据留在设备上的 SQLite 与按内容寻址的对象库里。塑造了其余一切的那个后果是:一份来源只规范化一次,之后被引用而不是被复制——原始文件与它解析出的 Markdown 只有一个存储归属,下游拿着的都是引用、哈希与来源记录,而不是第二份拷贝。这正是为什么摄入是最大的几个模块之一,也是为什么会有策略快照:它就是「这份材料被允许给哪些下游看」的那条记录。后面还跟着三个后果。文档要先经由操作内核与 outbox 提交,之后才开始向知识与记忆扇出,于是外部失败弄不坏权威版本。agent 是被限定范围的:会话先解析出自己所在的 Room,而子代理目录由文件驱动、变更即产生不可变修订,所以定义改动动不了已经在跑的那次调用。最后,每个可选引擎都写了降级态,因为记忆服务、知识服务或模型凭据缺失时,桌面端仍然必须能用。
- apps/gateway/
- 446 个文件、约十兆:
src/modules/下三十个模块,最大的是 148 KB 的知识服务,其次是 85 KB 的create-server.ts、46 KB 的文件服务、46 KB 的文档服务、57 KB 的摄入、58 KB 的记忆、61 KB 的写作风格与 47 KB 的子代理工具面,另有感知、现实、ASR、连接器、本地 agent、调度、通知与运行时配置等较小的模块。drizzle/下是六十三个 SQL 迁移及其快照——编号有重复也有空缺——测试和代码一样重,单是agent-room-selection.test.ts就有 41 KB。 - apps/desktop/
- 693 个文件:Electron 主进程里最大的是 72 KB 的本地数据服务、64 KB 的
saas-client.ts、50 KB 的 preload 索引、26 KB 的私有转写同步与 7 KB 的更新器;其上是渲染层,含 56 KB 的现实页、55 KB 的设置页、40 KB 的来源页,以及一百多个 agent 与 context-room 组件,其中一整套context-room/ported/组件自带编辑器、面板与 hook。 - agents/
- 十三个由文件驱动的子代理,每个是一份
agent.yaml加系统提示,另可带技能与 JSON schema:main、context-room、doc-writer、knowledge、room-corrector、multimodal-document-parser、connector-mapper、transcription-summary、content-analyst、cursor-completion、diary、ingest-filter 与 web-search。每个SKILL.md都必须有 name 与 description 前言,agent 只能通过受限工具读自己的技能快照,而网关会在定义变更时生成不可变修订。 - packages/ 与 submodules/
- 六个工作区包加一个子模块:46 KB 的 agent 契约;47 KB 的 Pi 运行时(它的测试有 41 KB,并持有记忆与知识工具客户端);文档模型;现实契约;一个假运行时和一个未配置运行时适配器;以及连接器子模块——一个约三十个文件的网关模块,按 provider 分出飞书、飞书 Wiki、Gmail、Notion、Google Docs、Google 日历、Outlook 与 webcal 订阅的同步代码。
- docs/
- 35 个文件、656 KB 的规划文档,多数是中文:42 KB 的 Room Wiki 方案、40 KB 的统一摄入方案、43 KB 的 doc-writer 子代理方案、38 KB 的连接器重构方案、37 KB 的写作风格方案、36 KB 的办公套件集成方案与 29 KB 的子代理框架设计;旁边是一份英文的「感知数据进 Wiki」设计,以及一个 62 KB 的来源页 HTML 原型。
- 工具链与交付
.github/下八个工作流共 62 KB,主角是 29 KB 的桌面发版流水线与 11 KB 的定时任务,另有 Codex 审查工作流、一个飞书卡片 action,以及 issue 与 pull request 的通知钩子。patches/里四个补丁分别针对 electron osx-sign、记忆核心、MCP 适配器与 sqlite-vec;打包脚本准备五套随包运行时,其中含一个 Rust 写的表格 sidecar,另有一个 7 KB 的校验脚本在发布前检查 Windows 包。
取舍,以及它替代了什么
把上下文限定在一个 Room 里,而不是交出一整片语料 替代 让 agent 读取工作区摄入的一切
README 把它当成产品命题写下来:知识工具在读 Wiki 页、来源或材料之前先解析出当前 Room 或会话,agent「默认拿不到一片无界的全局语料」;同一份文档还把「有界上下文窗口而非提示词倾倒」写成 Room 保护的东西。
一份来源只规范化一次,之后被引用 替代 让 Wiki、记忆层与文档索引各留一份拷贝
原文写的是「一份资产,多处引用」:原始文件与解析出的 Markdown 只有一个存储归属,下游保留稳定的引用、哈希与来源记录,而不是把同一份来源复制进几个库。摄入设计把同一条规则用到录音上,幂等键就是源标识加内容哈希。
先提交文档,再谈副作用 替代 在同一次写入里把文档版本推给知识与记忆
这是一条顺序规则:文档改动先经事务化的提交内核与 outbox,向知识与记忆的扇出只在权威版本提交之后发生,于是外部服务失败弄不坏文档。同一个模块还留着一台操作状态机,让一次改稿成为可被查看的东西,而不是一次副作用。
给 agent 的删除工具加上强制确认 替代 相信模型只在被要求时才删
pull request 257 新增
context_room_document_delete,凡是confirm参数不为真的调用一律拒绝,返回一个可重试、下一步是「问用户」的错误;提示词守则把该工具限制在明确要求之下,禁止顺手或批量删除;删除本身是可恢复的回收站动作,并且刻意不发永久删除事件,因为否则渲染端会连回收站列表一起清掉。nightly 交给机器,stable 交给人手 替代 只要有功能提交就升一个正式版
pull request 261 删掉定时升版,记下 0.1.9 正是被它误升到 stable 的,并把渠道按 tag 烙进包内,使一个 nightly 构建无法给自己推正式更新。pull request 249、250、253 里那三次改版本号与一次回退,就是在为同一个决定付账。
给每个可选引擎都写一个降级态 替代 把记忆、知识与连接器服务当成必需件
README 把它写成规则——假 agent 运行时、被关闭的记忆核心、连不上的连接器、模型失败,各自都有明确的兜底状态——理由是缺少一个可选服务不该让本地文档变得打不开;而 pull request 263 里的故障注入,用一条内联错误条加一个重试按钮,测的正是这同一件事可见的那一半。
依据docs/reality-wiki-ingest-design.md——报告唯一全文打印的架构文档,1,786 字符——加上 README(23,065 字符,报告只打印了前 6,000,其余部分于 2026-10-01 从 raw.githubusercontent.com 取回)、README 自己的仓库结构与技术选型表、三十条 issue 与 pull request 正文及其评论串,以及完整的 1,386 个文件树及其体积和两级目录汇总。
制作过程
6 个阶段- 01
七周、735 次提交,以及从群聊里进来的 bug 报告
仓库建于 2026-08-14,比它最早的一次提交——「feat: scaffold NexCore CE desktop app」,时间戳 2026-08-12T03:49:30Z——晚两天;735 次提交之后,它站在 3,069 个星、322 个 fork、219 个 watcher 的位置上。曲线的形状更像公司冲刺而不是个人长跑:八月剩下的日子里 561 次,九月 174 次,其中最新的一次是 2026-09-20 合并 pull request 239,而仓库记录的最后一次 push 是 2026-09-30,中间隔了十天。735 次提交里有 655 次关联到账号,而最忙的四个账号就写了 572 次。88 次提交带共同作者尾注,88 条全部指向 Claude 模型:31 条只写「Claude」,20 条 Fable 5,12 条 Opus 5,11 条 Opus 4.8,7 条带百万上下文的 Opus 4.8,5 条「Claude Code」,2 条 Opus 4.6。社区是从聊天客户端进来的而不是 issue 列表:三十条 issue 与 pull request 里有三条由
github-actions[bot]代开,带着<!-- feishu-request:... -->标记;仓库里留着四个通知工作流和一个可复用的feishu-cardaction,还有一条 issue 的全部内容就是指向本仓库的一个网址。 - 02
nightly 当流水线,stable 靠手打,以及一个被回退的版本号
材料里列了二十个 release,最早的一个 nightly 发布于 2026-09-08,最晚的是 2026-09-30 发布的
desktop-v0.1.9-nightly.20261001.81;其中十八个是 nightly,命名为desktop-v<版本>-nightly.<日期>.<序号>,例外只有desktop-v0.1.7与desktop-v0.1.8。pull request 261 是定下这套规则并给出理由的那份文件:自动升正式版被删掉了——那大约四十行会扫feat提交并把某个构建提上 stable 渠道,0.1.9 就是这样被误升的;渠道改为在构建时按 tag 通过NXCORE_UPDATE_CHANNEL烙进包内;nightly 渠道打开allowDowngrade,因为在 semver 里X.Y.Z到X.Y.Z-nightly.N属于降级;stable 则继续禁止降级,因为真的降级必须挡住。同一份 pull request 还提醒:SaaS 侧有一条配套改动必须同批合并,否则窗口期里 nightly 设备会查到一个空渠道。版本线上留着这次错误的代价:0.1.8 曾为了热更新链路被升成 0.2.0 当基线,又升到 0.2.1 当更新目标,而 pull request 253 把两者一起回退到 0.1.9,称它们是「误定的跳跃版本号」,并请求在当晚零点前合并,免得定时任务从错误的版本序列切出 nightly。 - 03
来源是一条台账记录,不是一段摘要
摄入设计用一句话把机制说清:同一份内容靠
sourceId + contentHash被认出,命中摄入台账后直接返回,不会再解析、再扇出一次。一条被记录下来的策略快照决定这份材料能到达哪些下游系统——示例里的策略是meeting-minutes,默认同时打开 Room、Wiki 与 Memory 三条链路——而转换出的 Markdown 落进parsed_contents,ingest_events则留着源版本、内容指纹、策略快照与路由任务。围绕它的规则都是在把半成品挡在外面:转写还处在pending_confirmation时根本不写 Wiki;已确认的录音异步投递,不把确认接口按住不放;不改动 Wiki 正文的元数据更新不触发任何东西;自动投递失败只记日志,不回滚用户已经确认录音这件事。人工补投有自己的端点POST /v1/reality/events/:id/knowledge-ingest,且只接受完成态事件。同一份文档还画了边界:感知模块只决定何时投递、并持有源 ID,它从不引用知识服务,而 bootstrap 注入的适配器让这三个模块不至于形成环依赖。 - 04
与本档案已有的三个记忆项目相比,它不同在哪
本档案已经收了三个给 agent 用的记忆层,差别在于记忆从哪来。OKF Agent Memory 把一包 Markdown 形式的 OKF bundle 留在仓库里,用进程内 BM25 检索,于是记忆能出现在
git diff里;agent-memory 让一个文件就是一条记忆,用有效期区间替代状态字段,并让一个独立的睡眠期层按自己的时钟新增与更新;Memmy 则跑一个本地服务,供十个不同的宿主读写。EverRoom 不是这几种形状里的任何一种。它是一个自带入口的应用,记忆是派生物而不是主要产物:来源先被规范化一次,然后才由一条被记录的策略决定有没有东西变成知识或记忆——这和「让 agent 往一个库里写」正好相反。它的存储是迁移线里六十三个 SQL 文件建起来的 SQLite,不是仓库里的 Markdown;做判断的是项目自带的 Pi 运行时,不是用户本来开着的那个宿主工具。这个项目给自己找的对照物是聊天客户端和一层薄薄的检索界面,而不是某个记忆库;而它的 README 同时列出了还没做完的东西:冲突展示、来源导航、手工挂接与回退、来源级诊断,以及更完整的带引用 agent 流程,都还是路线图条目而非已交付行为。记忆管线本身是借来的——MemoryCore 打包自 TencentDB-Agent-Memory 的一个分叉,而仓库里四个补丁中的一个补的就是这个依赖。 - 05
pull request 本身就是说明书
这个仓库的写作发生在 pull request 正文里,其中几条比它们承载的改动更值钱。273 号是一次两个平台同时挂掉的 nightly:某个依赖在构建期去取
https://oomol.com/en/apps/catalog.json,而那个网址在站点改版后开始返回 404;作者拿锁文件 SHA 和上一次成功构建对比,证明变数不在依赖本身,指出上游项目自 2026-08-03 起没有任何提交,最后顺着仓库既有的补丁链加了一层 try-catch。271 号是一行改动,把lib/commands/test.js从随包内置的 npm 运行时里排除掉——此前发版审计因为一个违禁文件把包拦了下来。268 号是两处测试断言,因为新增一个 agent 工具改变了预期的工具清单,作者还写明这条分支在改动之前就是红的。262 号最锋利:总结区域被逐字稿本身占满,修法是先剥掉时间戳与说话人标记,再到原文里找八个互不重叠的 64 字探针,命中过半就判为回显。还有两条 pull request 从两端追同一个偶发 500——263 号让网关把笼统的内部错误换成带重试提示的具名 503,267 号则在桌面端的桥里加静默重试,先等一秒再等三秒,只针对打开 Room 的那两个只读请求。 - 06
作者写明不做的东西
README 在介绍功能之前先划边界:第一个版本不做持续录屏、不做自主的多 agent 集群、不做企业管理、也不要求云端同步,理由是这一版要做的是可信的本地上下文。同样的克制出现在发版工程里。macOS 是写明的开发目标,Windows 安装包没有签名,于是 README 直说 SmartScreen 会警告。九月的更新链路调试发现:打包出来的应用里根本没有
app-update.yml——那是 electron-updater 在能下载任何东西之前必须先读的文件,缺它是因为构建配置里没有 publish;而手动检查更新只要versionInfo存在就报「发现新版本」,可这个字段永远存在,于是判据改成isUpdateAvailable。一个 490 MB 的更新包下了二十多分钟、界面上连百分比都没有,这才有了进度广播与多段并发下载,理由是差量下载才是让这个体积活下去的东西。站在别人代码上的代价写在树里:patches/下四个补丁——electron osx-sign、记忆核心、MCP 适配器与 sqlite-vec;也写在某个早晨:工作流锁定的下载工具版本被 CDN 下架,于是一次 nightly 只建出了 GitHub release,既没有分发也没有登记。
相关档案
全部档案 →第 113 号
Chat On Steroids
一个给 ChatGPT 装上本地工具的桌面工作台。它用 MCP 提供文件、shell、终端和整个桌面,再用一个 Chrome 扩展通过隧道驱动用户自己那一个 ChatGPT 对话页面:模型因此能改真实项目,而 app 记录每一次工具调用,并在旧对话装不下时把会话搬进一个新对话。
第 109 号
Whiteboard
一个桌面应用,让 agent 和人共用同一块画布。agent 把审查画出来——时序图、实体关系图、钉在某次提交上的代码引用——而画布上的每个形状都能跳回它被画出来时所指的那段代码。
第 105 号
OpenBot
CopilotKit 开源的一套 AI 同事平台:每个同事分到一台自己的电脑——一个装着 Chromium、一块工作区卷、一套自己的登录态的容器。同事可以是任何说 AG-UI 的端点;而它对浏览器、文件、MCP 或 shell 做的每一次动作,都要先经过同一个网关——按 CEL 策略裁决、写下一行审计、然后才真的执行,或者拒绝并说出是哪条规则拦下的。