# 7-47 MNote 公共 capability/plugin 注册表设计 v1

> 状态：process
>
> 目标：把当前分裂的 MNote builtin skill、mnote tool manifest、Hermes plugin、Reasonix wrapper 和 Page AI UI 开关收口为同一个“AI 能力”模型。对用户来说 skill / plugin / tool 都是“授予 AI 的能力”，UI 不应暴露实现层分类；实现层再把一个能力映射到说明书、工具、runtime adapter 和权限策略。本轮只整理 MNote 公共能力；Reasonix / Hermes 自带的 skills/plugins 维持现状，不纳入统一注册表迁移范围。

## 0. 用户口径

用户不需要理解 skill、plugin、tool 的区别。Page AI 设置中统一展示为“AI 能力”：

- `当前页读取`
- `本地索引与证据检索`
- `本地文件编辑`
- `思维导图`
- `ONLYOFFICE 实时编辑`
- `纯聊天`

每个能力只有一个主开关。展开后可以显示该能力包含的工具、上下文要求和读写权限，但这些是高级详情，不是主概念。

实现层映射：

- `skill`：能力说明书，告诉 agent 什么时候用、怎么用。
- `tool`：能力的可执行函数，真正落到 Rust runtime / kernel。
- `plugin / adapter`：把同一套工具暴露给 Hermes ACP、Reasonix ACP 或其它 agent runtime。
- `policy`：决定该能力是否可见、是否启用、是否允许写入。

后续 UI 文案统一使用“能力”，不再把 MNote builtin skill、Hermes skill、Reasonix skill、mnote tool 作为并列用户入口。

## 1. 当前盘点

### 1.1 MNote builtin skills

当前入口：`rust/crates/mnote-web/src/hermes_tools/skill.rs`

现有内置 skill：

- `mnote-current-page`
- `mnote-local-index`
- `mnote-local-file`
- `mnote-onlyoffice-live`
- `mnote-mindmap`
- `mnote-chat-only`

特点：

- skill 是 Rust 静态注册，正文来自 `skills/*/SKILL.md`。
- `/api/hermes/client/skills?runtime=mnote&agentId=...` 通过 `mnote_builtin_skills_payload()` 输出到 UI。
- 每个 skill 现在已经带 `toolNames` 和 `requiresContextRefs`，但这些只是弱引用，不是一个正式 capability/plugin 合同。
- `mnote.skill.read` 能懒加载正文；旧 `mnote-document-evidence` 已作为兼容别名映射到 `mnote-local-index`。

### 1.2 MNote tools

当前入口：`rust/crates/mnote-web/src/hermes_tools/manifest.rs`

现有工具大类：

- skill/context：`mnote.skill.read`、`mnote.context.*`
- evidence/index：`mnote.evidence.*`、`mnote.index.*`
- doc/block/page/artifact：`mnote.doc.*`、`mnote.block.*`、`mnote.page.*`、`mnote.artifact.*`
- mindmap：`mnote.mindmap.*`
- office/onlyoffice：`mnote.office.*`、`mnote.onlyoffice.*`

执行入口：

- `/api/hermes/tools/mnote/manifest`
- `/api/hermes/tools/mnote/call`
- `execute_mnote_tool_call()` 统一做认证、profile 禁用检查、workspace 校验、capabilityScope 校验、写入 guard、audit、idempotency。

问题：

- manifest 只有 plugin 总描述和扁平 tools，没有“哪个 tool 属于哪个公共能力包”的结构。
- `/api/hermes/client/tools?scope=mnote&profile=...` 只展示扁平工具列表。
- tool 开关写入 Hermes profile 的 `mnote.tools.disabled`，skill 开关写入 MNote SQLite user preference，两个开关域不同步。

### 1.3 Hermes plugin

当前本机存在 `/home/lix/.hermes/plugins/mnote/`，包括：

- `plugin.yaml`
- `__init__.py`

现状：

- 这是 Hermes 用户插件，不在 mnote repo 内。
- `plugin.yaml` 只列出旧批次工具：`mnote_page_get/save/update_title/update_options`、`mnote_doc_*`、`mnote_block_*`、artifact 等。
- 没有 `mnote_evidence_*`、`mnote_index_*`、mindmap、onlyoffice live 等新工具。
- `__init__.py` 手写 Python wrapper，把 Hermes tool call 转发到 `/api/hermes/tools/mnote/call`。

问题：

- Hermes 用户插件和 Rust manifest 已经漂移。
- 新增 Rust tool 后不会自动进入 Hermes plugin。
- 如果继续维护该插件，必须由 Rust manifest 生成 plugin.yaml / Python adapter，不能手写。

### 1.4 Reasonix wrapper

当前入口：`scripts/reasonix-acp-wrapper.mjs`

现状：

- 手写 Reasonix ACP 可见工具名，例如 `mnote_evidence_search`、`mnote_index_status`。
- 手写 `REASONIX_TOOL_TO_MNOTE_TOOL` 映射到 Rust `mnote.*` 工具。
- 手写每个工具的 parameters。

问题：

- 与 Rust manifest 重复。
- 与 Hermes plugin 重复。
- 新增/改名工具必须同步改 wrapper，否则 agent 看得到 skill 也无法调用工具。

### 1.5 Page AI UI

当前入口：

- skills panel：`rust/crates/mnote-web/browser/sidebar-page-ai-skill-runtime.js`
- runtime/tools panel：`rust/crates/mnote-web/browser/sidebar-page-ai-render-runtime.js`
- data load/toggle：`rust/crates/mnote-web/browser/sidebar-page-ai-runtime.js`

现状：

- Skills 页能展示 MNote builtin skills、Reasonix skills、Hermes profile skills。
- Runtime/高级页展示扁平 `mnote tools` 列表。
- MNote skill 开关调用 `/api/hermes/client/skills/toggle`，写 SQLite user preference。
- Tool 开关调用 `/api/hermes/client/tools/toggle`，写 profile YAML `mnote.tools.disabled`。

问题：

- 用户想管理的是“索引能力包”，不是单独 skill 或一堆扁平工具。
- 现在 UI 上 skill 和 tool 分两个地方，不能表达“启用索引 skill，同时启用对应工具”。
- 无法像公共 skill 一样展示 plugin/capability 包的工具内容、权限、启停状态。

## 2. 设计判断

当前应该引入 `MnoteAiCapability` / `MnoteCapabilityPack`，而不是继续把 skill、tool、plugin 分开维护。代码中可叫 capability pack；UI 中只叫“AI 能力”。

定义：

```rust
pub struct MnoteCapabilityPack {
    pub id: &'static str,
    pub title: &'static str,
    pub description: &'static str,
    pub agent_ids: &'static [&'static str],
    pub read_only: bool,
    pub requires_context_refs: &'static [&'static str],
    pub skill_id: &'static str,
    pub skill_content: &'static str,
    pub tool_names: &'static [&'static str],
    pub ui_kind: &'static str,      // capability | chat | compat
    pub category: &'static str,     // mnote, office, resource, chat
    pub public: bool,
}
```

原则：

- 一个公共能力包可以包含一个 skill 和多个 tools。
- UI 主要展示 capability pack，不再让用户先理解 skill/tool/plugin 三套概念。
- agent prompt 仍注入短 skill/capability 摘要，正文仍走 `mnote.skill.read` 懒加载。
- tool manifest 仍是执行真相，但每个 tool 必须能反查所属 capability pack。
- Reasonix wrapper / Hermes plugin 都从同一份 capability/tool manifest 生成或动态注册。

## 3. 目标 API

### 3.1 新增 capability 列表

`GET /api/hermes/client/capabilities?runtime=mnote&agentId=reasonix&profile=...`

返回：

```json
{
  "ok": true,
  "runtime": "mnote",
  "categories": [
    {
      "name": "mnote",
      "title": "MNote",
      "capabilities": [
        {
          "id": "mnote-local-index",
          "title": "MNote local index",
          "description": "Search local documents with evidence locators and manage local index scopes.",
          "enabled": true,
          "toggleable": true,
          "readOnly": false,
          "skillId": "mnote-local-index",
          "toolNames": [
            "mnote.evidence.search",
            "mnote.evidence.read",
            "mnote.evidence.open",
            "mnote.index.status",
            "mnote.index.refresh",
            "mnote.index.update_settings"
          ],
          "tools": [
            {
              "name": "mnote.index.update_settings",
              "kind": "write",
              "status": "available",
              "enabled": true,
              "requiresWritePermission": true
            }
          ],
          "requiresContextRefs": ["folder"],
          "configScope": "user_sqlite+profile_tool_policy"
        }
      ]
    }
  ]
}
```

### 3.2 新增 capability toggle

`PUT /api/hermes/client/capabilities/toggle`

入参：

```json
{
  "runtime": "mnote",
  "profile": "reasonix",
  "id": "mnote-local-index",
  "enabled": true
}
```

行为：

- 写入 MNote SQLite user preference：`ai.agent.mnote_builtin.skill.{id}.enabled`
- 对包内 tools 批量更新 profile `mnote.tools.disabled`
- 保留单 tool 开关作为高级功能，但 UI 默认展示包开关。

### 3.3 manifest 扩展

`/api/hermes/tools/mnote/manifest` 增加：

```json
{
  "capabilities": [
    {
      "id": "mnote-local-index",
      "skillId": "mnote-local-index",
      "toolNames": ["mnote.evidence.search", "mnote.index.status"]
    }
  ],
  "tools": [
    {
      "name": "mnote.index.status",
      "capabilityId": "mnote-local-index",
      "capabilityScope": ["index.read", "evidence.read"]
    }
  ]
}
```

## 4. UI 设计

### 4.1 Skills 页改为 AI 能力页

在 Page AI 的 Skills 页中，用户看到的是统一“AI 能力”列表，不再分 skill / plugin / tool：

- 行标题：`MNote local index`
- 副标题：`索引 / 证据检索 · 6 tools · 需要 folder`
- 状态 chip：`只读` / `可写` / `部分工具关闭` / `只读上下文不可写`
- 主开关：启用/关闭整个能力包
- 展开项：列出 tools，显示 read/write、enabled、status

不新增单独 landing/settings 页；沿用当前 Skills 页即可，避免再散一处入口。

页面标题建议从 `Skills` 改为 `能力`；内部 source filter 可以保留 `MNote / Hermes / Reasonix`，但展示为能力来源，不作为用户要理解的能力类型。

### 4.2 Runtime 高级页保留扁平工具

Runtime 页继续保留 `mnote tools`，但作为高级调试面：

- 默认按 capability 分组，而不是纯扁平列表。
- 单 tool 开关仍保留，用于排查或临时禁用某个写工具。
- 若 capability 关闭，包内工具显示 `disabled_by_capability`。

### 4.3 索引面板与能力包关系

Sidebar 的“索引设置”仍是用户直接管理索引范围的产品 UI；Page AI 的 `mnote-local-index` capability 是 agent 能力开关。

两者职责不同：

- 索引设置面板：用户手动新增/删除/刷新索引范围。
- MNote local index capability：允许 agent 使用工具帮用户查看、新增、刷新、删除索引范围。

## 5. Runtime 适配

### 5.1 Reasonix

短期：

- 保留 `scripts/reasonix-acp-wrapper.mjs`。
- 但 wrapper 启动时请求 `/api/hermes/tools/mnote/manifest`，按 manifest 自动注册工具。
- 保留手写 fallback，避免 mnote-web 未启动时 wrapper 不能初始化。

中期：

- 删除 `REASONIX_TOOL_TO_MNOTE_TOOL` 手写表。
- 工具名转换统一由函数生成：
  - `mnote.index.status` -> `mnote_index_status`
  - `mnote.evidence.search` -> `mnote_evidence_search`

### 5.2 Hermes ACP

短期：

- MNote 继续通过 `AcpMnoteToolContext` 把 `availableSkills` 和 capability policy 交给 Hermes ACP。
- 如果 Hermes ACP 原生不能消费 Rust manifest 注册工具，则仍依赖 `/home/lix/.hermes/plugins/mnote`。

中期：

- 用 Rust manifest 生成 `/home/lix/.hermes/plugins/mnote/plugin.yaml` 和 Python adapter。
- 生成内容覆盖当前手写旧插件，确保 Hermes plugin tools 与 Rust manifest 一致。

长期：

- Hermes ACP 若支持从 host 动态接收 tools，则不再需要本机 Python plugin，只保留 Rust manifest。

## 6. 迁移方案

### Phase A：只加 registry，不改 UI 行为

- 新增 `hermes_tools/capability.rs`。
- 将当前 `SKILLS` 迁到 `CAPABILITY_PACKS`，`skill_summaries_for_agent()` 从 pack 派生。
- `manifest()` 给每个 tool 增加 `capabilityId`，并输出 `capabilities`。
- 保持 `/client/skills`、`/client/tools` 响应兼容。

验收：

- `mnote-local-index` 在 `/client/skills?runtime=mnote` 可见。
- `/api/hermes/tools/mnote/manifest` 可看到 `capabilities[]`。
- 旧 `mnote.skill.read` 不破。

### Phase B：UI 展示 capability pack

- 新增 `/api/hermes/client/capabilities`。
- Skills 页对 `runtime=mnote` 优先消费 capabilities。
- 能力包行展示 tools 数、read/write、contextRefs。
- Runtime 页 tools 按 capability 分组。

验收：

- Page AI Skills 页中 `MNote local index` 像公共 skill 一样可见。
- 展开能看到 `mnote.evidence.*` 和 `mnote.index.*`。
- 开关 capability 后，下一次 run 的 `skillPreferences.mnote` 同步变化。

### Phase C：能力包开关驱动工具开关

- 新增 `/api/hermes/client/capabilities/toggle`。
- 开关包时同步 skill preference 和 profile tool disabled 列表。
- `page_ai_capability_policy()` 过滤 disabled capability，且 `execute_mnote_tool_call()` 对 disabled tool 继续硬拒绝。

验收：

- 关闭 `mnote-local-index` 后 agent 不再看到该 skill 摘要。
- 关闭后直接调用 `mnote.index.status` 返回 `mnote_tool_disabled` 或 capability disabled。
- 再打开后恢复。

### Phase D：生成 Reasonix/Hermes adapters

- Reasonix wrapper 从 manifest 自动注册工具。
- Hermes plugin 从 manifest 生成或在启动时同步。
- 删除手写工具表漂移。

验收：

- 新增 Rust tool 后，只改 Rust manifest/capability pack，Reasonix/Hermes UI 与 runtime 均自动出现。
- `node scripts/reasonix-acp-wrapper.mjs` selftest 覆盖 manifest 动态注册。
- `hermes plugins list` / Hermes tool list 显示与 Rust manifest 一致。

## 7. 对 mnote-local-index 的落地形态

`mnote-local-index` 是第一批公共能力包试点：

- skill：`skills/mnote-local-index/SKILL.md`
- tools：
  - `mnote.evidence.search`
  - `mnote.evidence.read`
  - `mnote.evidence.open`
  - `mnote.index.status`
  - `mnote.index.refresh`
  - `mnote.index.update_settings`
- requiresContextRefs：`folder`
- readOnly：`false`
- write guard：只 `mnote.index.update_settings` 写设置；必须 `dryRun/idempotencyKey`；共享只读禁止写。
- UI 文案：`索引 / 证据检索 · 可管理索引范围`

## 8. 非目标

- 不把索引设置面板挪进 Page AI。
- 不让 agent 直接读写 `.mnote/index` 文件。
- 不让 Hermes plugin 直接写 Convex 或绕过 Rust runtime。
- 不在前端手写工具 schema。
- 不把 Reasonix wrapper 作为长期 tool registry 真相。

## 9. 风险

- Hermes Python plugin 当前在 `/home/lix/.hermes/plugins/mnote`，不在 repo，自动生成前仍会漂移。
- tool 开关现在是 profile 级，skill 开关是用户级；能力包 toggle 需要明确优先级。
- `mnote-local-file` 是 agent 原生文件能力指导，当前没有对应 MNote 写工具，放入 capability pack 时需要标记为 `native_agent_tools`，避免误以为 MNote 提供文件 patch tool。
- `mnote-chat-only` 不是业务能力包，应保留为 agent mode skill，不参与 tools。

## 10. 建议执行顺序

1. 先做 Phase A：Rust `MnoteCapabilityPack` registry，完全兼容现有接口。
2. 再做 Phase B：UI 展示 capability pack，保留旧 skills/tools fallback。
3. 再做 Phase C：能力包 toggle 批量控制 skill + tools。
4. 最后做 Phase D：Reasonix/Hermes adapter 从 manifest 自动生成。
