Skip to main content
Glama
evlon

codebuddy-matrix-channel

by evlon
README.md
# codebuddy-matrix-channel

把 **Matrix** 聊天桥接到 [CodeBuddy Code](https://cnb.cool/codebuddy/codebuddy-code) 本地会话的 **Channel 插件(MCP 服务器)**。

效果等同于 CodeBuddy 内置的 Telegram / Discord / 微信 channel:

- 在 Matrix 房间里发消息 → 通过 **Gateway Protocol**(`POST /api/v1/runs`,`conversation.id = 房间ID`)投到本地 CodeBuddy 服务(`--serve`,默认 9099),目标是让**每个房间在 9099 Web UI 里成为一条独立的会话线程**
- CodeBuddy 的回复从 run 的 SSE 流里抓取(或 Agent 直接调用 `reply` 工具),再发回原 Matrix 房间
- 可选:把 CodeBuddy 的权限请求提示转发到“控制室”,在手机上审批/拒绝工具调用

本插件基于 CodeBuddy 的 **Channel** 扩展机制(见 `docs/cn/cli/channels.md` 与 `channels-reference.md`),**无需修改 CodeBuddy 本体**。

> ### 📌 现状速览(Current Status)
> 本插件已可用于「Matrix ↔ CodeBuddy 数字分身」的**双向桥接**,但部分设计目标受限于当前 serve 版本尚未达成。下面如实区分「已实现」与「受限 / 未实现」:
>
> **✅ 已实现**
> - Matrix 双向桥接:收消息(含 @提及过滤、白名单、加密房间解密)与发回复(文本 / `m.notice` / html)。
> - **Gateway Protocol 投递**:经 `POST /api/v1/runs` 把消息投到本地 `--serve`(9099),取代旧版 `notifications/claude/channel` 注入。
> - **回复取回与去重**:消费 run 的 SSE 流抓取 assistant 文本,并与 Agent 主动调用的 `reply` 工具去重,避免重复投递。
> - **数字分身授权模型**:三层任务状态(`approved` / `pending` / `unauthorized`)、控制室审批(`approve` / `yes <id>` / `no <id>`)、高风险工具硬闸、陌生工作先 `request_approval`。
> - **按房间分日志 + 上下文隔离**:每房间独立历史文件 `matrix-logs/history-<房间>.log`;插件侧维护每房间滚动上下文(`MATRIX_ROOM_CONTEXT_TURNS`,默认 6),转发时注入「本房间历史上下文」块,在**模型有效上下文层面**做到按群隔离,显著降低跨房间串味。
> - **E2EE 支持**(matrix-js-sdk 42.x:Rust crypto wasm + `fake-indexeddb` 内存垫片)。
> - **媒体下载**(`MATRIX_DOWNLOAD_MEDIA`,以 `[file: 路径]` 注入)、**自检**(`npm run doctor` / `health_check` 工具)。
>
> **⚠️ 受限 / 未实现(受 serve 版本约束)**
> - **每个 Matrix 房间 = 一条独立 Web UI 会话线程:当前做不到。** serve 的 `getOrCreateSession(conversationId)` 在已有主会话时直接 `return this.primarySession`,忽略传入的 `conversation.id` / `session.id`,所有 Gateway run 都落入同一个主会话线程。因此 9099「对话」里 Matrix 消息统一在主会话(每条带房间作用域头区分)。详见第 8 节「已知限制」与第 11 节「未来迭代方向(路线 B)」。
> - **E2EE 密钥不落盘**:42.x 下 Rust crypto 走内存垫片,重启需重新协商密钥 / 设备验证。
> - **权限中继**依赖 CodeBuddy 的 `claude/channel/permission` 能力;若版本不支持,核心聊天桥接不受影响。

---

## 1. 工作原理

```
Matrix 房间  ──(matrix-js-sdk 收消息)──▶  matrix-channel (本插件)
                                              │  组装上下文前缀(群名/发信人/成员)
                                              │  Gateway Protocol: POST /api/v1/runs
                                              │    source.conversation.id = 房间ID  ← 目标:每房间独立线程(当前 serve 仍合入主会话,见现状/§8)
                                              ▼
                                        本地 CodeBuddy 服务(--serve, 默认 9099)
                                              │  Agent 处理;回复经 SSE 抓取 / reply 工具
                                              ▼
                                        matrix-channel ──(sendText)──▶ 原 Matrix 房间
```

插件作为子进程由 CodeBuddy 以 stdio 启动,通过 MCP 协议通信;同时把消息以 Gateway Protocol 投到**同一个** CodeBuddy 服务实例(即启用 `--serve` 的进程),从而复用其 Agent 能力并在 Web UI 生成会话线程。

> 前提:CodeBuddy 必须以 `--serve` 模式运行(默认 9099)且网关密码可读(写入 `~/.codebuddy/settings.json` 的 `gateway.password`,或显式用环境变量提供)。详见第 8 节(Gateway / Web UI 会话线程)。

---

## 2. 安装

```bash
cd matrix-channel
npm install
npm run build        # 编译到 dist/(也可直接用 tsx 运行,无需构建)
```

运行时需要 **Node >= 20**。

---

## 2.1 快速开始(数字分身)

1. **安装 / 编译**
   ```bash
   cd matrix-channel && npm install && npm run build
   ```
2. **填 `.env`**(最小可用集,详见第 3 节)
   ```bash
   MATRIX_HOMESERVER=https://im.yiq.pub
   MATRIX_ACCESS_TOKEN=<从 Element:设置 → 帮助 → 高级 → 访问令牌 复制>
   MATRIX_USER_ID=@evlon-ai:im.yiq.pub
   MATRIX_ALLOWLIST=@evlon:im.yiq.pub           # 防 prompt 注入,必填
   MATRIX_OWNER_ID=@evlon:im.yiq.pub            # 分身管理者=你,审批权只认此身份
   MATRIX_CONTROL_ROOM_ID=!<控制室房间ID>:im.yiq.pub
   MATRIX_MENTION_REQUIRED=true                 # 群里只响应 @分身
   # 可选:MATRIX_TRUSTED_SENDERS / MATRIX_TRUSTED_ROOMS / MATRIX_AUTHORIZED_WORK
   ```
3. **自检**(每次改完 `.env` 先跑)
   ```bash
   npm run doctor      # 期望:连接 ✅、账号 ✅、E2EE ✅
   ```
4. **接入 CodeBuddy**:在项目 `.mcp.json` 注册(绝对路径)后启动
   ```bash
   codebuddy --channels server:matrix --dangerously-load-development-channels
   ```
5. **日常使用**
   - 群里 **@分身** 派活 → 可信来源/已授权工作自动执行;陌生工作先出计划、进控制室等你 `approve`。
   - 高风险工具(Bash/写文件等)永远进控制室请示你。
   - 你在控制室下命令(只认 `MATRIX_OWNER_ID`):
     - `approve`(`run` / `go`,可跟房间 ID)→ 授权该房间任务
     - `yes <id>` / `no <id>` → 放行 / 拒绝等待中的高风险权限请求

> 加密群需 `MATRIX_E2EE=true`;`MATRIX_DEVICE_ID` 留空会自动从 `/devices` 选,报错再填「设置 → 设备」里的设备 ID。

---

## 3. 配置

复制 `.env.example` 为 `.env` 并填写:

```bash
cp .env.example .env
```

| 变量 | 说明 |
|------|------|
| `MATRIX_HOMESERVER` | 家庭服务器地址,如 `https://matrix.org`(必填) |
| `MATRIX_ACCESS_TOKEN` | 账号 access_token(推荐;从 Element「设置 → 帮助」复制) |
| `MATRIX_USER_ID` | 可选,用于识别“自己的消息”,如 `@alice:matrix.org` |
| `MATRIX_USER` / `MATRIX_PASSWORD` | 备选鉴权方式,启动时会 `loginWithPassword` 换 token |
| `MATRIX_ALLOWLIST` | 允许发消息的**发送者**用户 ID,逗号分隔(务必配置) |
| `MATRIX_ROOM_ALLOWLIST` | 允许收听的房间 ID,逗号分隔(留空 = 全部) |
| `MATRIX_CONTROL_ROOM_ID` | 权限中继控制室房间 ID(可选,但数字分身模式**必填**) |
| `MATRIX_OWNER_ID` | **分身管理者(owner)的 Matrix 用户 ID(必填)**。审批权只认此身份 |
| `MATRIX_TRUSTED_SENDERS` | 可信同事用户 ID,逗号分隔;来自他们的工作自动执行(安全工具) |
| `MATRIX_TRUSTED_ROOMS` | 可信群 ID,逗号分隔;这些房间里的所有工作自动执行 |
| `MATRIX_AUTHORIZED_WORK` | 已授权常规工作描述(自由文本),供分身判断「常用 vs 陌生」 |
| `MATRIX_MENTION_REQUIRED` | 群内是否仅响应被 @ 提及的消息(默认 true;多分身共存建议开启) |
| `MATRIX_HIGH_RISK_TOOLS` | 高风险工具列表,逗号分隔;默认 `Bash,Write,Edit,MultiEdit,NotebookEdit` |
| `MATRIX_DOWNLOAD_MEDIA` | 是否下载图片/文件到本地并以 `[file: 路径]` 注入(默认 false) |
| `MATRIX_MEDIA_DIR` | 媒体下载目录(默认 `.matrix-media`) |
| `MATRIX_E2EE` | 是否启用端到端加密(默认 false,见下文第 6 节) |
| `MATRIX_CRYPTO_DB` | 在 matrix-js-sdk 42.x **不生效**(见第 6 节):Rust crypto 走 wasm + `fake-indexeddb` 内存垫片,密钥不落盘。留空即可 |
| `MATRIX_STREAM_TIMEOUT_MS` | 抓取 Gateway run 的 SSE 回复的超时(毫秒,默认 `300000`=5 分钟)。超时后停止抓取,已通过 `reply` 工具发出的回复不受影响 |
| `MATRIX_GATEWAY_PORT` | 本地 CodeBuddy 服务端口(默认读 `9099`);与下方 `MATRIX_GATEWAY_URL` 二选一 |
| `MATRIX_GATEWAY_URL` | 本地 CodeBuddy 服务完整地址(如 `http://127.0.0.1:9099`);优先级低于 `MATRIX_GATEWAY_PORT` |
| `MATRIX_GATEWAY_PASSWORD` | 网关密码;缺省自动读取 `~/.codebuddy/settings.json` 的 `gateway.password` |
| `MATRIX_GATEWAY_DEBUG` | 设为 `1` 时把 Gateway SSE 原始事件写入 `matrix-gateway-debug.log`,便于排查回复解析 |

> ⚠️ **安全**:务必配置 `MATRIX_ALLOWLIST`(按**发送者**而非房间校验,避免群聊中任意成员注入会话)。留空表示允许所有人,仅用于本地测试。

---

## 4. 接入 CodeBuddy

### 方式 A:开发期(绕过市场白名单)

把本插件注册到你的 CodeBuddy 项目 `.mcp.json`:

```json
{
  "mcpServers": {
    "matrix": {
      "command": "npx",
      "args": ["tsx", "/绝对路径/matrix-channel/src/index.ts"]
    }
  }
}
```

然后启动 CodeBuddy:

```bash
codebuddy --channels server:matrix --dangerously-load-development-channels
```

> 编译后用 `node` 运行可改为:
> ```json
> "args": ["node", "/绝对路径/matrix-channel/dist/index.js"]
> ```

### 方式 B:打包为插件(提交到官方市场后)

```bash
npm run build
```
再将 `codebuddy-matrix-channel` 作为插件发布,之后用:

```bash
codebuddy --channels plugin:matrix-channel@<你的市场>
```

---

## 5. 使用

1. 启动后(`codebuddy --serve --channels server:matrix --dangerously-load-development-channels`),在允许的 Matrix 房间里发消息,插件会通过 Gateway Protocol 把消息投到本地 CodeBuddy 服务,`conversation.id = 房间ID`。
2. CodeBuddy 处理完成后,回复会抓回并发回**原 Matrix 房间**(若 Agent 已通过 `reply` 工具直接发回,则不会重复发送)。
3. 在 9099 Web UI 的「对话」里,当前所有 Matrix 消息统一落入**同一个主会话线程**(每条消息带 `(消息来源:Matrix 房间「…」…)` 作用域头区分房间;插件侧另通过「本房间历史上下文」块在模型上下文层面做到按群隔离)。真正的按房间独立线程需改 serve(见第 8 / 11 节)。
4. 若配置了 `MATRIX_CONTROL_ROOM_ID`:CodeBuddy 调用需审批的工具(Bash / Write 等)时,控制室会收到提示(以 `m.notice` 系统提示发送,不触发未读/提醒),回复 `yes <id>` 允许 / `no <id>` 拒绝。

### `reply` 工具参数

| 参数 | 说明 |
|------|------|
| `chat_id` | Matrix 房间 ID(取自会话里消息标签的 `chat_id` 属性) |
| `text` | 要发送的文本 |
| `html` | 可选,HTML 正文(与 `text` 同时发送,使用 `org.matrix.custom.html` 格式) |
| `msgtype` | 可选,`m.text`(默认,普通消息)或 `m.notice`(系统提示:不在客户端触发未读/提醒/通知) |

> 例如让 CodeBuddy 用 `m.notice` 回一句状态提示:`reply({ chat_id: "!abc:server", text: "已处理", msgtype: "m.notice" })`。

### `health_check` 工具

可在 CodeBuddy 会话里直接调用,或在 `/mcp` 健康检查中触发,等价于 `npm run doctor` 的连通性/E2EE 部分,返回 JSON:

```json
{ "ok": true, "userId": "@alice:matrix.org", "e2ee": true, "cryptoReady": true }
```

`ok=false` 时附 `error` 字段说明失败原因(连接/鉴权/E2EE 初始化)。

---

## 6. 局限与注意事项

- **端到端加密(E2EE)房间**:默认只支持**未加密**房间。要桥接加密房间,把 `MATRIX_E2EE=true`,插件会复用 **matrix-js-sdk 自带的 Rust crypto**(`initRustCrypto`),由 SDK 自动完成「接收时解密、发送时加密」——无需自己实现加密协议。开启后:
  - 加密消息以 `m.room.encrypted` 到达,SDK 解密完成(`Event.decrypted`)后类型变为真实类型,再由插件推送给会话;
  - 发送到加密房间的回复由 SDK 自动加密;
  - **密钥存储(重要,与版本相关)**:在 **matrix-js-sdk 42.x** 下,Rust crypto 后端只有 **wasm/IndexedDB** 一种实现(`@matrix-org/matrix-sdk-crypto-wasm`),**没有 Node 原生后端**。为了让它在 Node 上跑起来,插件在启动时用 `fake-indexeddb/auto` 给 Node 注入一个全局 `indexedDB` 垫片——该垫片是**纯内存**的,因此:
    - 密钥实际只存在于进程内存,`MATRIX_CRYPTO_DB` 在本版本下**不会**生成真实的 SQLite 落盘文件;重启进程后密钥需重新协商(不影响收发,只是要重新做一次密钥转发/设备验证)。
    - 真正的磁盘持久化需要升级到**自带 `@matrix-org/matrix-sdk-crypto-nodejs` 原生后端的 matrix-js-sdk 版本**,或未来支持 nodejs 入口的版本(届时去掉 `fake-indexeddb` 垫片、改走原生后端即可)。
    - 注意:依赖里已装的 `@matrix-org/matrix-sdk-crypto-nodejs` 在当前 42.2.0 下**不被 SDK 调用**,仅作为未来升级的备选;当前加密核心靠 wasm + `fake-indexeddb` 内存垫片工作。
  - 新设备首次进入加密房间,建议在 Matrix 客户端里**验证本 bot 的设备**(否则对方可能看到“未验证设备”提示,但消息仍可正常收发)。
- **媒体**:默认只把消息文本桥接进会话;开启 `MATRIX_DOWNLOAD_MEDIA` 会把图片/文件下载到本地并以 `[file: 路径]` 注入,便于 Agent 读取。
- **权限中继**依赖 CodeBuddy 的 `claude/channel/permission` 能力;若 CodeBuddy 版本不支持,核心聊天桥接不受影响。

---

## 7. 数字分身:管理者授权模型(核心场景)

把分身当成「群里的同事」,既能被随意 `@` 派活,又**不会在管理者同意前真正改动任何东西**。

### 场景
- 同事建多个群(如 `#项目A`、`#客服`),群里可能同时有多个分身 bot。同事在群里 **@你的分身** 派活;**只在被 @ 时才响应**(直接私聊总响应)。
- 收到派活后:
  - **常用 / 已授权工作**(来自你预设的 `MATRIX_TRUSTED_SENDERS` / `MATRIX_TRUSTED_ROOMS`,或属于 `MATRIX_AUTHORIZED_WORK` 描述的范围)→ **自动执行**(安全工具)。
  - **陌生工作**(不在授权范围)→ 分身**先出计划**,调用 `request_approval` 升级到你的控制室;你回 `approve` 才执行。
  - **高风险操作**(`MATRIX_HIGH_RISK_TOOLS`,如 Bash / 写文件)→ **无论来源,永远请示你**。

### 架构分层
- **MCP 插件 = 安全传输 + 硬闸(代码强制,不信任模型)**:`@` 过滤、权限裁决 `allow`/`deny` 只依据可验证事实(是否 owner、是否可信来源、是否高风险工具)、控制室审批只认 `MATRIX_OWNER_ID`。
- **SKILL = 策略大脑(语义判断,交给 Agent)**:`skills/matrix-avatar/SKILL.md` 指导分身判断「常用 vs 陌生」,陌生时进入计划模式并调 `request_approval`。Agent **只申请审批、从不自放行**;放行只来自「管理者的可信来源预设」或「管理者 `approve`」。

> 插件内置的 channel `instructions` 已内联该策略,因此不额外安装 SKILL 也能工作;`skills/matrix-avatar/SKILL.md` 供你在 CodeBuddy 中复用/微调。

### 三层任务状态(按房间)
| 状态 | 含义 | 安全工具 | 高风险工具 |
|------|------|----------|------------|
| `approved` | 可信来源 / 已 `approve` | 自动执行 | 请示管理者(控制室 `yes`) |
| `pending` | 已升级待审(`request_approval`) | 拦截 | 拦截 |
| `unauthorized` | 陌生来源未授权 | 拦截 | 拦截(并提示 `approve`) |

### 控制室命令(仅管理者 `MATRIX_OWNER_ID` 有效)
- `approve`(或 `run` / `go`,可选跟房间 ID,如 `approve !projectA:server`)→ 授权该房间当前任务,分身开始执行。
- `yes <id>` / `no <id>` → 对等待中的高风险权限请求放行 / 拒绝。
- 其他人的控制室回复一律忽略。

### 配置示例(`.env`)
```bash
MATRIX_OWNER_ID=@you:matrix.org
MATRIX_TRUSTED_SENDERS=@alice:matrix.org,@bob:matrix.org
MATRIX_TRUSTED_ROOMS=!projectA:server
MATRIX_AUTHORIZED_WORK=回答产品问题、总结会议纪要、起草文档
MATRIX_MENTION_REQUIRED=true
MATRIX_HIGH_RISK_TOOLS=Bash,Write,Edit,MultiEdit,NotebookEdit
```

## 8. Gateway Protocol 与 Web UI 会话线程

插件把每条 Matrix 消息投到本地 CodeBuddy 服务(Gateway Protocol),而不是旧的 `notifications/claude/channel` 注入:

- **投递**:`POST /api/v1/runs`,请求体为 Gateway 入站消息格式,`source.conversation.id` 取 **Matrix 房间 ID**,因此同一房间的多条消息落入同一条会话;不同房间各自独立。
- **回复取回**:消费 `GET /api/v1/runs/:runId/stream` 的 SSE,抽取 assistant 文本发回 Matrix。为避免与 Agent 主动调用 `reply` 工具造成**重复投递**,插件用一个 `agentRepliedViaTool` 标记去重:若 Agent 已通过 `reply` 工具把回复发回 Matrix,则不再发送 SSE 抓取到的文本。
- **上下文**:房间可读信息(群名、发信人昵称、群成员)以文本前缀形式写入 `payload.text`,保证 Gateway run 里的 Agent 也能看到原本由 channel `meta` 携带的上下文。
- **鉴权**:请求带 `X-CodeBuddy-Request: 1` 与 `Authorization: Bearer <网关密码>`;密码默认读 `~/.codebuddy/settings.json` 的 `gateway.password`。

> **前提**:必须运行 `codebuddy --serve`(默认 9099)。若服务不可达,插件会向原房间发一条 `⚠️ 无法连接本地 CodeBuddy 服务(9099)` 提示,消息不丢失但本次不处理。
>
> **已知限制(已验证)**:当前 serve 版本中,Gateway run 无论传 `conversation.id` 还是 `session.id`,都会被附加到**已有的主会话(primary session)**,不会按房间生成独立 Web UI 线程。根因在 serve 的 `getOrCreateSession(conversationId)`:只要 `primarySession` 存在就直接 `return this.primarySession`,忽略传入的会话标识。因此「每个 Matrix 房间 = 一条独立 Web UI 会话」在本 serve 版本**无法通过插件侧实现**;Matrix 消息在 9099「对话」里统一落在主会话线程(每条消息带 `(消息来源:Matrix 房间「…」…)` 前缀以区分房间)。
>
> 若要真正的按房间分线程,需二选一:① 推动 serve 在 Gateway run 下尊重 `conversation.id`/`session.id`(改动 `getOrCreateSession` 的 primary 短路逻辑);② 为 Matrix 编写与企微/微信同级的**平台适配器(platform adapter)**,由适配器自行管理按会话的 Web UI 线程(工作量较大,且需 serve 加载)。排查时设 `MATRIX_GATEWAY_DEBUG=1` 看 `matrix-gateway-debug.log`。
>
> **插件侧缓解(已落地)**:尽管 serve 侧无法按房间分线程,插件仍在**模型有效上下文层面**做到按群隔离——每个房间在插件侧维护最近若干轮(用户消息 + 本房间回复)的滚动上下文,转发时注入为「本房间历史上下文」块并明确指示仅依据本房间上下文作答;同时每条入站消息带 `(消息来源:Matrix 房间「…」…)` 作用域头。这样即便 serve 侧历史共享,模型实际看到的仍是按房间裁剪过的上下文,跨房间串味显著降低。轮数用 `MATRIX_ROOM_CONTEXT_TURNS`(默认 6;设 0 关闭)控制;历史另见 `matrix-logs/history-<房间>.log`。

## 9. 自检(doctor)

填好 `.env` 后,可先跑自检确认配置、连通性与 E2EE 状态,再启动 CodeBuddy:

```bash
npm run doctor
```

自检会打印当前配置(token 脱敏)、验证 homeserver 可达与凭证有效,并在 `MATRIX_E2EE=true` 时尝试初始化 Rust crypto。任何一项失败都会给出明确原因并以非 0 退出码结束。

---

## 11. 未来迭代方向(Roadmap)

按影响面 / 优先级排列。其中**路线 B 是真正解决「按房间分线程」的关键**。

### 路线 B(推荐,关键):推动 serve 在 Gateway run 下尊重会话标识 ★
- **根因**:serve 的 `getOrCreateSession(conversationId)` 在已有主会话时直接 `return this.primarySession`,忽略传入的 `conversation.id` / `session.id`。
- **改动**:当 Gateway 入站带会话标识且非显式「主会话」时,按该标识创建 / 复用会话,而非一律塞进 `primarySession`(单函数短路逻辑)。
- **收益**:彻底实现「每个 Matrix 房间 = 一条独立 Web UI 线程」,消除当前插件侧上下文隔离的“权宜”性质,Web UI 可读性与审计大幅提升。
- **风险与状态**:直接改 `dist`(minified)仅本地生效;正式需走 CodeBuddy 主干 PR。尚未执行,待管理者批准。

### 路线 C:为 Matrix 编写平台适配器(platform adapter)
- **思路**:与企微 / 微信同级,由适配器自行管理按会话的 Web UI 线程。
- **现状评估**:serve 的 `LocalGatewayServer.initialize()` 中适配器为**硬编码注册**(`GenericAdapter` / `WecomAdapter` / `WechatKfAdapter`),无外部 / 插件扩展点;且 Webhook 入口同样走 `handleMessage → getOrCreateSession` 那条短路。因此路线 C 不仅工作量大,**同样绕不开路线 B 的短路**,在当前 serve 版本下单独实施收益有限。
- **结论**:优先级低于 B;仅在 serve 开放适配器扩展点后再考虑。

### E2EE 密钥持久化
- 升级到自带 `@matrix-org/matrix-sdk-crypto-nodejs` 原生后端的 matrix-js-sdk 版本(或支持 nodejs 入口的版本),去掉 `fake-indexeddb` 内存垫片,改为 SQLite 落盘,重启无需重新协商密钥。当前依赖里的 `@matrix-org/matrix-sdk-crypto-nodejs` 在 42.2.0 下不被 SDK 调用,作为升级备选已就绪。

### 增强隔离与上下文管理
- `MATRIX_ROOM_CONTEXT_TURNS` 已支持按房间滚动上下文;后续可考量:跨房间「记忆共享」白名单(可信同事房间之间有限共享)、按房间可配置系统提示、长会话摘要压缩以节省 token。

### 健壮性与可观测性
- Gateway 连接失败时指数退避重连;在 `matrix-gateway-debug.log` 之外补充结构化运行指标;多 bot 共存时的身份冲突规避(在 `MATRIX_MENTION_REQUIRED` 基础上进一步按 `user_id` 分流)。

### 打包与分发
- 走「方式 B」发布到官方插件市场,支持 `codebuddy --channels plugin:matrix-channel@<市场>`,免去 `--dangerously-load-development-channels` 开发开关。

---

## 10. 目录结构

```
matrix-channel/
├── src/
│   ├── config.ts     # 环境变量 / 白名单 / 授权配置读取与校验
│   ├── matrix.ts     # Matrix 客户端封装(连接、@提及过滤、收/发、下载媒体、E2EE、自检)
│   ├── index.ts      # MCP 服务:channel 通知、授权硬闸、reply / request_approval 工具、控制室审批
│   └── doctor.ts     # `npm run doctor` 自检入口
├── skills/
│   └── matrix-avatar/
│       └── SKILL.md  # 分身行为策略(语义判断:常用 vs 陌生)
├── package.json
├── tsconfig.json
├── .gitignore
├── .env.example
├── matrix-history.log      # 收发历史(落盘审计,已 gitignore)
├── matrix-gateway-debug.log # Gateway SSE 原始事件(MATRIX_GATEWAY_DEBUG=1 时)
└── README.md
```

TDQS

A4.1/5.0

Scored across 6 tools

Disambiguation4/5

The tools are mostly distinct: reply, health_check, request_approval, list_rooms, room_members, and room_info each target a different action or resource. The only mild overlap is between room_info and room_members, since room_info also includes member names/IDs, but the descriptions are clear enough to guide selection.

Naming Consistency3/5

All names are lowercase snake_case, but the semantic pattern is mixed: reply is a bare verb, list_rooms and request_approval are verb+noun, while room_members and room_info are noun+noun descriptors. This is readable but not consistently a verb_noun convention.

Tool Count5/5

Six tools is a tight, well-scoped set for a Matrix channel bridge. Each tool supports a distinct part of the workflow—responding, verifying health, escalating approval, and discovering rooms and participants—without redundancy or bloat.

Completeness4/5

The set covers the core bot workflow on a Matrix channel: replying, understanding room context, checking connection health, and handling approval escalation. Minor gaps like joining/leaving rooms or reading message history exist, but they are outside the apparent core purpose and do not create dead ends.

Maintenance

ActivityMaintained
ResponsivenessNo issues