Anarlog 的无锁定(No-Lock-in)设计:本地优先数据、MCP Agent 访问与结构化导出
【免费下载链接】anarlogOpen source Granola AI Alternative项目地址: https://gitcode.com/GitHub_Trending/hy/anarlog
本文以 Anarlog 企业版规划文档 no-lock-in.md(工单号 ANLG-138)为主体,完整还原其"数据可带走、Agent 访问可控"的设计承诺:笔记以本地 SQLite 为唯一事实源,云端仅存放密文与元数据,MCP 工具、CLI 与结构化导出共用同一套本地 API,客户可以检查、导出、自动化并最终带着全部数据离开。读完本文,你可以理解该设计在仓库中的落地面——MCP 服务实现、E2EE 密钥体系、会话 ingest 信封与远程删除边界,以及 v1 与后续版本的演进路线。
设计承诺:可检查、可导出、可自动化、可离开
原文档 "Promise" 一节给出的核心承诺是:
Customers can inspect, export, automate, and leave with their Anarlog data. Notes are local-first SQLite. Cloud holds ciphertext plus metadata. Agents see only what the user (or workspace policy) grants.
拆成三条硬约束:
- 本地优先(local-first):笔记的规范模型(canonical model)是设备上的 SQLite 数据库。仓库中 crates/db-app 承载应用层数据库与 83 个 SQL 迁移文件,桌面端与 CLI 都直接读写该本地库,而不是把云端数据库当作真身。
- 云端只存密文加元数据:从 crates/e2ee/src/lib.rs 的源码结构看,E2EE 层围绕恢复密钥(
anarlog-e2ee-v1:前缀)、工作区密钥分发(WorkspaceKeyGrant、seal_workspace_key_for_member,见 lib.rs#L6-L13)和设备注册密钥(DeviceEnrollmentKey,X25519 静态密钥对)组织,配合 XChaCha20-Poly1305 认证加密——云端持有的行是密文,服务端不掌握解密能力。 - Agent 权限最小化:Agent 只能看到用户或工作区策略显式授予的内容。仓库中的 crates/agent-access 提供了 agent 访问层,其中
proposals.rs实现了"提案"机制——Agent 的写回不直接落库,而是生成待审提案,与官方文档 MCP for agents 描述的propose_summary_edit/propose_memo_edit/list_proposals/decline_proposal工具链对应。
这一设计在整个企业版路线图中被明确定位为 v1 交付项:owned-stack-roadmap.md 的工单表中将 "No lock-in" 对应工单 ANLG-138,标注为 "CLI/MCP/export v1; public HTTP API later",即 v1 只承诺 CLI、MCP 与导出三条通道,公开的版本化 HTTP API 属于后续版本。
v1 的四条持久接口(Durable surfaces)
原文档列出了 v1 阶段的四条持久接口,这既是当前仓库能力的索引,也是"数据可带走"承诺的具体落点。
1. 桌面端/CLI 直接面向本地 SQLite 规范模型
桌面应用与 apps/cli 中的 CLI 共享同一个本地 SQLite 规范模型,所有检查与导出操作都发生在设备上。这意味着即使断开云服务,CLI 仍可对本地库执行查询与导出——数据的所有权物理上在客户手里,而非托管在厂商服务器中。
2. MCP 工具调用同一套本地/会话 API
"MCP tools that call the same local/session APIs" 的实现在 crates/mcp 中。从源码结构看:
- crates/mcp/src/service.rs 基于
rmcp的 Streamable HTTP 传输构建 MCP 服务,并通过with_allowed_hosts将可接受的 Host 白名单收敛到localhost、127.0.0.1、::1及 Anarlog 的托管域名(见 service.rs#L8-L16)——本地 stdio 与托管两种部署方式共用同一套工具实现; - 官方文档 docs/agents/mcp.mdx 给出两种接入方式:托管 Cloud MCP(
https://api.anarlog.so/mcp,走 OAuth,只读,仅暴露用户已 opt-in 的快照),以及完全本地的 stdio 服务,不监听任何端口、不向 Anarlog 服务器发送任何会议数据。本地 stdio 的配置示例(可直接复制使用):
{ "mcpServers": { "anarlog": { "command": "anarlog", "args": ["mcp"] } } }如需指定数据库路径,可写为"args": ["--db-path", "/path/to/app.db", "mcp"]。文档还明确了工具使用纪律:先用list_meetings拿到id,再用get_meeting;export_meeting仅在任务确实需要完整记录(含转录)时使用;云端 MCP 是只读的,持久化编辑必须走本地 CLI 或本地 MCP 的提案工具。
正是由于 MCP 工具与 CLI 调用同一套本地 API,Agent 获得的视图与人类用户在设备上的视图一致,不会出现"Agent 通过云端接口绕过本地策略"的分叉路径。
3. 客户端侧的结构化导出(Markdown / JSON)
"Structured export of sessions (markdown/JSON) from the client" 指的是导出动作由客户端本地执行,而非请求服务端打包。仓库中对应实现分布在 crates/export-core(核心导出逻辑)与 plugins/export(导出插件,含 4 个字体文件 等资源),支撑会议记录、转录与摘要以 Markdown 或 JSON 形式落盘。export_meetingMCP 工具同样是这一通道的代理入口。
对"无锁定"承诺而言,结构化导出的关键在于格式稳定:Markdown 是人类可读的通用格式,JSON 可被任意下游系统解析,客户离开产品时不需要任何专有格式的转换工具。
4. 来自客户自托管捕获平面的会话 ingest 信封
"Session ingest envelopes from the customer-hosted capture plane" 指企业客户自托管的会议捕获平面(Google Meet 可见机器人、Zoom RTMS worker 等,见 enterprise/zoom-rtms-worker 与 docs/teams-capture.md)把捕获的会话以"信封"(envelope)形式投递给客户端。仓库中 crates/session-ingest 实现了这一协议,模块划分清晰:
protocol.rs/model.rs:信封的协议与数据模型;validate.rs:信封校验(见 crates/session-ingest/src/validate.rs);apply.rs:将校验通过的信封应用到本地规范模型;tests.rs:协议行为的测试用例。
把捕获平面置于客户自托管环境、以可校验的信封协议投递,意味着捕获侧同样不依赖 Anarlog 的托管服务即可工作,与"客户拥有敏感数据平面"的定位一致。
后续演进:HTTP API、工作区级 Agent Token 与离职包(Offboarding Bundle)
原文档 "Later" 一节规划了三项能力:
- 用于自动化的版本化 HTTP API:v1 以本地 CLI/MCP 为自动化入口,后续提供带版本号的公开 HTTP API;
- 工作区范围(workspace-scoped)的 Agent token:Agent 凭据从个人级收敛到工作区策略级,与 crates/api-cloud 等云端凭据层形成对照;
- 含 E2EE 密钥材料的离职包(offboarding bundle):由于云端只有密文,客户在离开时需要带走自己本就持有的 E2EE 密钥材料才能继续解密。crates/e2ee/src/lib.rs 中可见的恢复密钥(
RECOVERY_KEY_PREFIX = "anarlog-e2ee-v1:")、成员身份密钥(MemberIdentityKey)与工作区密钥授权(WorkspaceKeyGrant)正是离职包需要包含的材料形态——可以推断,离职包的设计目标是让"带走数据"在密码学意义上闭环,而不仅是导出明文。
边界:无锁定不等于无边界
原文档 "Boundaries" 一节划定了三条明确边界,这是理解该设计诚意的关键——它不回避技术约束:
- 本地录音与笔记永远不会为了喂给 Agent 而变得服务端可读。即使 Agent 需要某段内容,也通过本地通道或用户显式 opt-in 的快照(密文 + 授权)解决,而不是放宽服务端的可读性。
- 工作区远程删除可丢弃云端密文,但离线设备是公开声明的限制。这与配套的 access-control-remote-deletion.md(ANLG-133)一致:保留任务
enforce_workspace_retention软删过期的session_shares并丢弃快照,CloudSync 随后停止提供这些行,本地镜像在下次同步时删除;"从不过网的设备无法被强制擦除"被 v1 明确声明为已知限制,而不是用 MDM 话术掩盖。 - Agent 写回被限制在与人类编辑器相同的会话文档 schema 内。Agent 不能创造新的文档类型或旁路写入通道;结合前文提到的提案机制(crates/agent-access/src/proposals.rs),Agent 的每次写入都是一条可审查、可拒绝(
decline_proposal)的待审提案,最终状态与人类编辑结果同构。
小结:把"可带走"变成可验证的工程约束
no-lock-in.md 的价值在于它把"反锁定"从营销口号翻译成了四条 v1 持久接口和三条不可逾越的边界,并且每一条都能在当前仓库中找到对应实现或明确的后续工单:
| 承诺/边界 | 仓库中的对应物 |
|---|---|
| 本地 SQLite 规范模型 | crates/db-app、apps/cli |
| MCP 与 CLI 共用本地 API | crates/mcp、docs/agents/mcp.mdx |
| Markdown/JSON 结构化导出 | crates/export-core、plugins/export |
| 客户自托管捕获平面的 ingest 信封 | crates/session-ingest、enterprise/zoom-rtms-worker |
| 云端仅密文 + 元数据 | crates/e2ee |
| 远程删除的离线限制 | access-control-remote-deletion.md |
| 后续 HTTP API / Agent token / 离职包 | ANLG-138(见 owned-stack-roadmap.md) |
适用前提需要说明:本文基于当前仓库状态,v1 的无锁定面是 CLI/MCP/导出三条通道,公开版本化 HTTP API 与离职包属于规划中的后续版本;远程删除对离线设备的限制是产品公开声明的边界,而非待修复的缺陷。
【免费下载链接】anarlogOpen source Granola AI Alternative项目地址: https://gitcode.com/GitHub_Trending/hy/anarlog
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考