# [recycle] 7-6 [done] mnote Hermes plugin tool 合同 v1 > 更新时间:2026-05-14 > > 上位依据:`design/07-ai/done/7-3-page-ai-hermes-panel-and-mnote-plugin-v1.md`、`design/07-ai/done/7-4-page-ai-hermes-panel-execution-checklist-v1.md` > > Hermes Web UI 参考:`packages/client/src/api/hermes/plugins.ts`、`packages/client/src/api/hermes/skills.ts`、`packages/server/src/services/hermes/plugins.ts`、`packages/server/src/services/hermes/chat-run-socket.ts` > > 2026-05-16 口径补充:本文定义的是页面 AI 最小可用工具合同。`mnote.page.save` 只作为页面级兜底写入工具,不再代表长期精确块编辑方案;页面/块级 AI 工具体系路线图已归档到 `design/07-ai/done/7-9-page-block-ai-tooling-roadmap-v1.md`。 > > 2026-05-22 归档治理补充:旧 `7-10` 已移入 `design/old/07-ai/process/7-10-page-block-ai-tooling-execution-checklist-v1.md`,不再作为当前执行验收入口;`7-14` 也已移入 `design/old/07-ai/process/7-14-local-first-ai-markdown-editing-convergence-v1.md`。当前 AI 编辑 active 口径以 `design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md` 为准,MNote 不再提供普通 Markdown 编辑工具。 ## 1. 总边界 - [x] Hermes 看到的工具名必须是 `mnote.*`,不是 `mnote-cli`、Next route 或前端私有函数。 - [x] plugin 内部可以临时调用 `mnote-cli` JSON adapter,但这只是内部 adapter,不是长期 tool 名称。 - [x] Hermes plugin 不直接写 Convex;所有写入必须回到 Rust runtime / kernel。 - [x] mnote 只保存业务事实、audit、artifact、edge、page/body/title/options 结果,不保存 Hermes 聊天历史。 - [x] 所有 tool call 必须携带 `sessionId/runId/toolCallId/traceId` 便于串联 Hermes run 与 Rust command。 ## 2. 统一入参 ```json { "toolName": "mnote.page.get", "workspaceId": "ws_1", "documentId": "doc_1", "actorId": "user_1", "sessionId": "mnote_doc_1_trace_1", "runId": "run_123", "toolCallId": "call_123", "traceId": "trace_1", "idempotencyKey": "idem_123", "dryRun": false, "capabilityScope": ["page.read"], "args": {} } ``` ## 3. 统一出参 ```json { "ok": true, "toolName": "mnote.page.get", "toolCallId": "call_123", "traceId": "trace_1", "result": {}, "audit": { "effect": "read", "commandId": null, "workspaceId": "ws_1", "documentId": "doc_1" }, "error": null } ``` 失败: ```json { "ok": false, "toolName": "mnote.page.save", "toolCallId": "call_123", "traceId": "trace_1", "result": null, "audit": { "effect": "none", "workspaceId": "ws_1", "documentId": "doc_1" }, "error": { "code": "mnote_tool_permission_denied", "message": "当前用户没有页面写权限" } } ``` ## 4. 第一批工具 schema ### `mnote.page.get` 入参: ```json { "type": "object", "required": ["workspaceId", "documentId", "sessionId", "runId", "toolCallId", "traceId"], "properties": { "workspaceId": { "type": "string" }, "documentId": { "type": "string" }, "includeBody": { "type": "boolean", "default": true }, "includeOptions": { "type": "boolean", "default": true }, "includeBlocks": { "type": "boolean", "default": true } } } ``` 成功: ```json { "ok": true, "toolName": "mnote.page.get", "toolCallId": "call_get_1", "traceId": "trace_1", "result": { "documentId": "doc_1", "workspaceId": "ws_1", "title": "项目计划", "bodySummary": "第一段...", "pageOptions": { "wideLayout": true }, "blocks": [{ "id": "heading_1", "type": "heading", "text": "章节一" }] }, "audit": { "effect": "read", "commandId": null } } ``` 失败: ```json { "ok": false, "toolName": "mnote.page.get", "toolCallId": "call_get_1", "traceId": "trace_1", "error": { "code": "mnote_tool_permission_denied", "message": "无页面读取权限" } } ``` ### `mnote.page.save` 入参: ```json { "type": "object", "required": ["workspaceId", "documentId", "sessionId", "runId", "toolCallId", "traceId", "idempotencyKey", "dryRun", "content"], "properties": { "workspaceId": { "type": "string" }, "documentId": { "type": "string" }, "content": { "type": "array" }, "mode": { "type": "string", "enum": ["replace", "append"] }, "idempotencyKey": { "type": "string" }, "dryRun": { "type": "boolean" } } } ``` 成功: ```json { "ok": true, "toolName": "mnote.page.save", "toolCallId": "call_save_1", "traceId": "trace_1", "result": { "commandName": "page.body.save", "revision": 8 }, "audit": { "effect": "write", "commandId": "page_body_save_trace_1" } } ``` dryRun: ```json { "ok": true, "toolName": "mnote.page.save", "toolCallId": "call_save_1", "traceId": "trace_1", "result": { "dryRun": true, "diff": [{ "op": "append", "blocks": 1 }] }, "audit": { "effect": "dry_run", "commandId": null } } ``` 权限失败: ```json { "ok": false, "toolName": "mnote.page.save", "toolCallId": "call_save_1", "traceId": "trace_1", "error": { "code": "mnote_tool_permission_denied", "message": "无页面写权限" } } ``` 业务失败: ```json { "ok": false, "toolName": "mnote.page.save", "toolCallId": "call_save_1", "traceId": "trace_1", "error": { "code": "mnote_tool_conflict", "message": "页面版本冲突,需要刷新后重试" } } ``` ### `mnote.page.update_title` 入参: ```json { "type": "object", "required": ["workspaceId", "documentId", "title", "sessionId", "runId", "toolCallId", "traceId", "idempotencyKey", "dryRun"], "properties": { "workspaceId": { "type": "string" }, "documentId": { "type": "string" }, "title": { "type": "string", "minLength": 1 }, "idempotencyKey": { "type": "string" }, "dryRun": { "type": "boolean" } } } ``` 成功、dryRun、权限失败、业务失败响应形状同 `mnote.page.save`,成功 command 为 `page.head.updateTitle`。 ### `mnote.page.update_options` 入参: ```json { "type": "object", "required": ["workspaceId", "documentId", "options", "sessionId", "runId", "toolCallId", "traceId", "idempotencyKey", "dryRun"], "properties": { "workspaceId": { "type": "string" }, "documentId": { "type": "string" }, "options": { "type": "object", "properties": { "wideLayout": { "type": "boolean" }, "smallText": { "type": "boolean" }, "showToc": { "type": "boolean" }, "protectEditing": { "type": "boolean" } }, "additionalProperties": false }, "idempotencyKey": { "type": "string" }, "dryRun": { "type": "boolean" } } } ``` 成功、dryRun、权限失败、业务失败响应形状同 `mnote.page.save`,成功 command 为 `page.layout.updateOptions`。`runtimeSupport !== "wired"` 的字段必须返回 dryRun 警告或业务失败。 ### `mnote.artifact.create_summary` 入参: ```json { "type": "object", "required": ["workspaceId", "documentId", "summary", "sessionId", "runId", "toolCallId", "traceId", "idempotencyKey", "dryRun"], "properties": { "workspaceId": { "type": "string" }, "documentId": { "type": "string" }, "summary": { "type": "string" }, "idempotencyKey": { "type": "string" }, "dryRun": { "type": "boolean" } } } ``` 成功:创建或更新当前页面唯一 summary node,并创建或确认 reference edge。 失败示例: ```json { "ok": false, "toolName": "mnote.artifact.create_summary", "toolCallId": "call_summary_1", "traceId": "trace_1", "error": { "code": "mnote_tool_idempotency_conflict", "message": "同一幂等键已用于不同 summary 内容" } } ``` ### `mnote.artifact.create_ai_note` 入参: ```json { "type": "object", "required": ["workspaceId", "documentId", "content", "sessionId", "runId", "toolCallId", "traceId", "idempotencyKey", "dryRun"], "properties": { "workspaceId": { "type": "string" }, "documentId": { "type": "string" }, "content": { "type": "string" }, "idempotencyKey": { "type": "string" }, "dryRun": { "type": "boolean" } } } ``` 成功:每次创建独立 ai_note node,并创建 reference edge。 ## 5. 权限、幂等与 dryRun - [x] 权限校验点:登录、workspace member、页面读、页面写、artifact 写。 - [x] 同一 `idempotencyKey` 重试不得重复创建 artifact 或重复写正文。 - [x] `dryRun=true` 只能返回计划和 diff,不得写入。 - [x] 所有失败响应不得泄露无权限页面标题、正文或 artifact 内容。 - [x] 写工具返回的 `audit.commandId` 必须能追踪到 Rust runtime / kernel command。