Files
mnote/rust/design/core/02-command-query-tool-protocol-v0.md
T

12 KiB
Raw Blame History

02. Command / Query / Tool Protocol v0

更新时间:2026-04-11 适用范围:/mnt/Data1T/mnote-rust


1. 目标

本文件定义 mnote-rust 的统一协议面。

目标只有一个:

让 Web、Desktop、CLI、Agent、批处理任务都通过同一套正式入口操作系统。

它要解决的问题:

  • 怎样避免“每个页面、每个组件、每个 API route 都有自己的写法”
  • 怎样让 AI 不依赖 UI 模拟,而能直接操作笔记软件
  • 怎样保证命令可审计、可回放、可测试、可维护

2. 基本原则

2.1 写与读必须分离

  • Command:会改变事实层
  • Query:只读,不改变事实层
  • Tool:面向 AI / CLI 的能力暴露层,内部映射到 Command / Query / Job

2.2 Tool 不是第三套业务逻辑

禁止出现:

  • Web 走一套逻辑
  • CLI 走一套逻辑
  • AI Tool 再写一套逻辑

正确关系:

Tool -> Command / Query / Job -> Domain + Storage + EventLog

2.3 每条写命令都要可审计

至少要记录:

  • 谁发起
  • 从哪里发起
  • 改了什么
  • 为什么改
  • 影响了哪些对象
  • 是否成功

2.4 AI 默认只能调用系统工具

AI 不应默认获得:

  • 任意 SQL
  • 任意文件写入
  • 任意 UI 按钮点击
  • 任意内部未定型方法

AI 应调用:

  • 稳定的 Tool API
  • 明确的参数模型
  • 明确的权限模型

3. 三层协议面

Human UI / CLI / Agent Runtime
            │
            ▼
         Tool API
            │
    ┌───────┴────────┐
    ▼                ▼
 Query API        Command API
    │                │
    └───────┬────────┘
            ▼
      Job / Workflow API
            │
            ▼
     Rust Note Core

说明:

  • Tool API 是面向使用者的稳定能力面
  • Command / Query API 是内核的正式操作面
  • Job / Workflow API 负责长任务、异步流程、外部能力编排

4. Actor 模型

所有命令、查询、工具调用都应带 actor

建议结构:

{
  "actor": {
    "type": "human",
    "id": "user_123",
    "session_id": "ui_session_xxx"
  }
}

或:

{
  "actor": {
    "type": "agent",
    "id": "agent_session_456",
    "provider": "openai",
    "model": "gpt-5.4-mini"
  }
}

或:

{
  "actor": {
    "type": "system",
    "id": "job_runner"
  }
}

用途:

  • 审计
  • 权限判断
  • 限流
  • 错误追踪

5. Command API

5.1 通用结构

建议所有命令统一壳:

{
  "command": "insert_block",
  "command_id": "cmd_01",
  "idempotency_key": "idem_01",
  "actor": {
    "type": "agent",
    "id": "agent_session_1"
  },
  "source": {
    "channel": "tool",
    "client": "mcp"
  },
  "target": {
    "workspace_id": "ws_1",
    "page_id": "page_1"
  },
  "payload": {},
  "reason": "补充总结段落",
  "refs": ["ref_1"],
  "dry_run": false,
  "validate_only": false,
  "requested_at": "2026-04-11T12:00:00Z"
}

5.2 通用返回

{
  "ok": true,
  "command_id": "cmd_01",
  "event_ids": ["evt_1", "evt_2"],
  "affected_objects": [
    { "type": "block", "id": "block_123" }
  ],
  "revision": {
    "workspace_id": "ws_1",
    "page_id": "page_1",
    "value": 42
  },
  "warnings": [],
  "rollback_hint": {
    "kind": "compensating_command",
    "command": "delete_block",
    "target_id": "block_123"
  }
}

5.4 观测字段约束

从 task-034 开始,所有正式 Command / Query / Tool / Job 面都要默认带上并统一解释下面这些字段:

  • request_id:一次入口请求级别的稳定编号,用于串起 route、runtime、日志和回查接口
  • trace_id:一次完整调用链的稳定编号,用于跨 query / command / tool / job 串联同一条执行路径
  • command_id:写命令的唯一编号,也是 command_log_idevent_id 推导的基础
  • idempotency_key:CLI、AI、Web 共享的幂等语义主键,不能三端各自解释
  • command_log_id / event_id:进入审计与回放链后的稳定对象编号,供 request/trace/command 回查与恢复命令复用

如果某条能力不能带出这组字段,它就还不能算“可供 CLI 与 AI 稳定运行的正式协议面”。

5.3 命令分类

页面类

  • create_page
  • rename_page
  • move_page
  • archive_page
  • restore_page
  • set_page_property

块类

  • insert_block
  • update_block
  • delete_block
  • move_block
  • batch_apply_block_ops
  • replace_block_content

引用类

  • create_reference
  • remove_reference
  • rebind_reference_anchor

资产类

  • attach_asset
  • replace_asset_version
  • set_asset_metadata
  • extract_asset_outline

工作区 / 系统类

  • create_task
  • cancel_task
  • rebuild_search_index
  • run_import_job
  • run_export_job

6. Command 设计约束

6.1 命令应小而明确

优先:

  • insert_block
  • move_block
  • set_page_property

避免:

  • save_everything
  • update_editor_state
  • mutate_page_with_ui_payload

6.2 支持幂等键

AI 可能重试、网络可能重放,因此:

  • 所有外部写命令建议支持 idempotency_key
  • 同一作用域内重复提交应可去重

6.3 支持 dry-run / validate-only

这样 AI 可以先问:

  • 这个操作是否合法?
  • 会影响哪些对象?
  • 是否需要确认?

这对 Agent 很重要。

6.4 支持批量 ops,但要有边界

对于 Mindmap、结构调整、导入转换,可以提供:

  • batch_apply_block_ops
  • apply_mindmap_ops
  • apply_document_transform_ops

但要求:

  • ops 必须结构化
  • 单条失败策略明确
  • 返回逐条结果

7. Query API

7.1 通用结构

{
  "query": "page.get",
  "actor": {
    "type": "human",
    "id": "user_1"
  },
  "scope": {
    "workspace_id": "ws_1"
  },
  "params": {
    "page_id": "page_1"
  }
}

7.2 查询分类

页面与块

  • page.get
  • page.tree
  • page.list_children
  • block.get
  • block.subtree

检索

  • search.text
  • search.reference
  • search.asset
  • search.page_by_title

资产

  • asset.get
  • asset.list_versions
  • asset.resolve_anchor

日志与会话

  • command_log.list
  • command_log.get
  • event.list
  • agent_session.get
  • task.list

7.3 输出要求

  • 输出稳定、字段可预期
  • 支持分页、游标、过滤
  • 避免直接返回前端组件所需临时形态
  • 对大型对象支持摘要与展开模式

8. Tool API

8.1 Tool API 的职责

Tool API 是给:

  • AI Agent
  • CLI
  • 自动化脚本
  • 外部集成方

用的能力层。

它的原则是:

  • 工具名清晰
  • 参数结构明确
  • 返回格式稳定
  • 明确确认策略与权限策略

8.2 工具命名风格

建议按领域分组:

  • note.read_page
  • note.list_children
  • note.insert_block
  • note.update_block
  • note.move_block
  • note.search
  • asset.attach_file
  • asset.extract_outline
  • office.get_selection
  • office.replace_selection
  • mindmap.apply_ops
  • system.get_recent_commands

也可以对外映射为 MCP 风格扁平命名,但内核层建议保留层级语义。

8.3 Tool 与 Command/Query 的映射

例如:

  • note.read_page -> page.get
  • note.insert_block -> insert_block
  • note.search -> search.text
  • asset.attach_file -> attach_asset
  • mindmap.apply_ops -> apply_mindmap_ops

8.4 Tool 返回

建议统一包含:

  • ok
  • data
  • warnings
  • requires_confirmation
  • confirmation_reason
  • next_actions

例如:

{
  "ok": true,
  "data": {
    "page_id": "page_1",
    "title": "项目计划"
  },
  "warnings": [],
  "requires_confirmation": false,
  "next_actions": []
}

9. Job / Workflow API

有些操作不是同步命令,而是长任务。

例如:

  • 导入大型 PDF
  • OCR
  • 构建索引
  • 批量转换文档
  • Office 文件解析
  • 全库引用修复
  • AI 长链路整理

因此需要 Job API

9.1 Job 通用结构

{
  "job": "import_document",
  "job_id": "job_1",
  "actor": { "type": "agent", "id": "agent_1" },
  "input": {
    "asset_id": "asset_1"
  }
}

9.2 Job 状态

  • queued
  • running
  • waiting_confirmation
  • succeeded
  • failed
  • cancelled

9.3 Job 输出

  • 结果对象
  • 生成的 page / asset / reference
  • 日志摘要
  • 错误详情

10. Confirmation Policy

不是所有工具都应直接执行。

建议分级:

10.1 无需确认

  • 只读查询
  • 本地摘要生成
  • 小范围插入草稿块

10.2 建议确认

  • 批量删除
  • 批量重排
  • 覆盖资产版本
  • 导出到外部位置

10.3 强制确认

  • 大范围页面删除
  • 全库重建/迁移
  • 覆盖性导入
  • 对外同步/发布

确认策略应由内核或 policy 层判断,不能完全由前端决定。


11. Error Model

错误必须结构化。

建议格式:

{
  "ok": false,
  "error": {
    "code": "BLOCK_NOT_FOUND",
    "message": "目标块不存在",
    "details": {
      "block_id": "block_xxx"
    },
    "retryable": false,
    "suggested_action": "请先刷新页面树或重新读取块子树"
  }
}

分类建议:

  • VALIDATION_ERROR
  • PERMISSION_DENIED
  • NOT_FOUND
  • CONFLICT
  • STALE_REVISION
  • RATE_LIMITED
  • EXTERNAL_ADAPTER_ERROR
  • INTERNAL_ERROR

这样 AI 才能根据错误做下一步,而不是只看到一段字符串。


12. Revision / Concurrency

12.1 为什么必须有 revision

AI 与人可能同时修改。

如果没有 revision

  • 很容易覆盖彼此内容
  • 工具重试会写乱
  • 无法做冲突判断

12.2 建议

  • Page 级 revision
  • Block 级 revision
  • AssetVersion 级 version_no

命令可支持:

  • expected_revision
  • on_conflict 策略(fail / merge_if_possible / create_patch

13. OnlyOffice 协议边界

OnlyOffice 不应直接暴露为“让 AI 操控 iframe”。

建议拆成两层:

13.1 Office Adapter Query

  • office.get_active_asset
  • office.get_selection
  • office.get_current_page
  • office.list_bookmarks

13.2 Office Adapter Command

  • office.insert_text
  • office.replace_selection
  • office.insert_comment
  • office.save_as_new_version
  • office.extract_outline

原则:

  • Tool 面暴露的是“Office 文档能力”
  • 不是浏览器点击坐标或 iframe DOM
  • 若插件不可用,应返回结构化不可用错误

14. Mindmap 协议边界

继续保留既有设计里最有价值的部分:ops

建议:

  • mindmap.get
  • mindmap.apply_ops
  • mindmap.expand_node
  • mindmap.attach_refs

其中 mindmap.apply_ops 入参可以继续沿用:

  • addChild
  • addSiblingAfter
  • updateText
  • setHyperlink
  • setRefs
  • appendNote
  • deleteNode

但要求:

  • 所有调用都写入统一命令日志
  • mindmap 不再走单独一套野生落盘体系

15. CLI 协议面

CLI 不是开发附属品,而是系统正式壳层。

建议 CLI 优先覆盖:

  • mnote page get <page-id>
  • mnote page tree
  • mnote block insert
  • mnote block move
  • mnote search text
  • mnote asset attach
  • mnote office selection
  • mnote job run import-document
  • mnote log recent

CLI 应满足:

  • 输出 JSON 模式
  • 退出码稳定
  • 适合 shell / AI / 自动化脚本调用

16. MCP / Agent Runtime 暴露面

如果后续提供 MCP

  • MCP 工具层应直接包装 Tool API
  • 不应重新发明一套独立业务逻辑
  • 返回值尽量和 CLI JSON 输出接近

这样好处是:

  • Web agent、桌面 agent、本地 Hermes/Codex 都共用一套系统能力
  • 文档里只需维护一份工具协议

17. 最小 v0 清单

建议 v0 最先固化以下协议:

Command

  • create_page
  • rename_page
  • insert_block
  • update_block
  • delete_block
  • move_block
  • attach_asset
  • create_reference

Query

  • page.get
  • page.tree
  • block.subtree
  • search.text
  • asset.get
  • command_log.list

Tool

  • note.read_page
  • note.insert_block
  • note.update_block
  • note.move_block
  • note.search
  • asset.attach_file
  • system.get_recent_commands

这套足以先打通:

  • 人类基础编辑
  • CLI 基础操作
  • AI 基础介入
  • 审计与回放链路

18. 一句话结论

mnote-rust 的协议设计应坚持:

Command 负责改,Query 负责读,Tool 负责给 AI/CLI 用,Job 负责长流程;所有入口最终收敛到同一 Rust 内核,不再允许页面私有接口、编辑器私有接口、临时胶水接口长期并存。