# Agent-Ops-WeCom-Bridge
**Repository Path**: LY115LY/Agent-Ops-WeCom-Bridge
## Basic Information
- **Project Name**: Agent-Ops-WeCom-Bridge
- **Description**: 基于多平台(企微等)打造的重算力 Agent 控制面(Control Plane)。将 IM 化作“一人公司”驾驶舱,远程调度 Claude Code 等本地 Agent,并可通过 MQTT 联动物理端侧设备。Apache-2.0 开源的人机协同范式。
- **Primary Language**: Python
- **License**: Apache-2.0
- **Default Branch**: main
- **Homepage**: https://github.com/Ly-FirmwareLab/Agent-Ops-WeCom-Bridge
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-10-30
- **Last Updated**: 2026-11-15
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Agent-Ops-WeCom-Bridge
**为多平台打造的重算力 Agent 控制台与运维网关**
同一份内核已在**飞书**与 **Slack** 上真机打通 —— **平台是入口,不是身份。**
> 🔗 **三件套** · [🧠 控制面(本仓)](https://github.com/Ly-Systems-Lab/Agent-Ops-WeCom-Bridge) · [🔌 数据面 · Edge-Hub](https://github.com/Ly-Systems-Lab/Agent-Ops-Edge-Hub) · [🔭 总蓝图 · Architecture](https://github.com/Ly-Systems-Lab/Agent-Ops-Architecture)
>
> 企业微信(推荐)可作为你的调度台:Claude Code 等重算力 Agent 在这里被指挥、被看见、被拦下
> (流式进度、打断、权限拦截),原生打通 MQTT 还能直接触达物理世界。
>
> 它是 **Agent Ops 三件套里的「控制面」**:
>
> | 仓 | 角色 | 状态 |
> |---|---|---|
> | **本仓** · [`Agent-Ops-WeCom-Bridge`](https://github.com/Ly-Systems-Lab/Agent-Ops-WeCom-Bridge) | 控制面 · 人 ⇄ Agent | 已公开 |
> | [`Agent-Ops-Edge-Hub`](https://github.com/Ly-Systems-Lab/Agent-Ops-Edge-Hub) | 数据面 · Agent ⇄ 物理世界(MQTT / 端侧设备) | 已公开 |
> | [`Agent-Ops-Architecture`](https://github.com/Ly-Systems-Lab/Agent-Ops-Architecture) | 总蓝图 · 《协同宣言》与全景架构(只有文档,不含代码) | 已公开 |
>
> 🔌 **它同时是「联邦式中枢」的插座**:入口可以是企微 / 飞书 / Slack,
> 执行面可以是本机 / 设备 / 钉钉 / 飞书 —— 官方能力当插件,本项目只做那层闸门。
> 见下方「**插座与插件**」一节。
## 🎬 演示
| 看什么 | 视频 |
|---|---|
| **总览** · 一个群里的多个 Agent(Claude Code / Codex / OpenCode / DSH …),外加一个纯模型答疑位(DeepSeek),跨企微与飞书 | [▶ 观看](https://www.bilibili.com/video/BV1LBW167Epz) |
| **交互基准** · 手机上发指令,结果落在 Windows 本地;任务卡片(允许 / 拒绝 / 实时进度 / 上下文余量)与 `/stop` 即刻停止 | [▶ 观看](https://www.bilibili.com/video/BV1nY4w6kEiy) |
| **幽灵漫游** · 三平台互相热切换(企微 / 飞书 / Slack)+ 联邦式中枢 | [▶ 观看](https://www.bilibili.com/video/BV1U7WB6mEVD) |
| **识图与主动推送** · DSH 与 CC 的对话记录(含它自己整理的企微官方能力表) | [▶ 观看](https://www.bilibili.com/video/BV1MgWo6KEzF) |
🖼️ **[实拍图集 →](https://github.com/Ly-Systems-Lab/Agent-Ops-Architecture/blob/main/docs/showcase/README.md)** · 手机端下指令、Windows 本地干活、Agent 自动修 Bug、读者自己搭的一份
💬 **[真实用户反馈 →](docs/feedback/README.md)** · 真实不定用户提交的“作业” —— 评论区原话 + 他自己的运行截图(含一位自述 **macOS** 上成功的)
## 🧩 一份内核,不同的聊天平台
这里要解决的问题从来不是「企业微信」这四个字,而是:
> **人不在电脑前的时候,怎么找到并驱动那台机器上的 Agent。**
企业微信只是跑得最远的那个入口。**同一份内核已经接上了形态很不一样的飞书和 Slack** ——
长连接换成官方 SDK / Socket Mode,消息模型、卡片回调、字节上限、推送频率全都不一样,
而「交互基准」那五条,一条都没改。
| 平台 | 作为入口 | 状态 |
|---|---|---|
| 企业微信 | ✅ | **参考实现** · 真机验收 + 两次外部 Agent 独立复现 |
| 飞书 | ✅ | **真机验收** · 五项交互 + 连续在线 24 小时 + 断网自愈 |
| Slack | ✅ | **真机验收** · 24 小时连续运行(进程零重启) |
| 钉钉 | — | 官方 `dws` 已覆盖通道层,本项目**只把它当执行面**,不重复造入口 |
👉 想换入口,从 [`platforms/`](platforms/README.md) 开始;想把官方 CLI 当"手"接进来,看 [`interop/`](interop/README.md)。
## 👻 控制面无状态热漂移:「幽灵漫游」
> **一句话**:换个平台不用换 Agent、不用改配置、不用重装 —— 在聊天里说一句,
> 它就从另一扇门进来,**原来那个窗口的进度还在**。
「平台是入口,不是身份」的操作版就是这一条:`/platform wecom` · `/platform feishu` · `/platform slack`。
换的是"从哪扇门进来",不是内核、不是工作区、不是记忆。
🎬 **[三平台互相热切换的完整演示](https://www.bilibili.com/video/BV1U7WB6mEVD)**
**实测(2026-11-13,三个平台互切)**:切走再切回,问一句「我刚刚说了什么?」——
它答的正是切换前那个窗口里的对话。因为会话本来就**不属于平台**,只属于「哪个窗口 + 谁」。
**为什么值得单独说**:入口只是"人能找到 Agent 的那扇门"。门可以换、可以被关上,
Agent 不会跟着消失 —— 它也**没有把"自己是谁"押在某一家平台上**。某个入口不可用了
(关停、限流、政策),换一扇门就行,代价是一分钟的重启,不是重做一遍。
展开:它和总蓝图是什么关系(为什么叫"幽灵")
- **数据面**:Agent 可以附着在接入的**端侧设备**上(P4 面板、C3 小电视、具身小车)——
设备只管执行,不持有智能。
- **控制面**:Agent 可以附着在接入的**任何平台**上 —— 平台只管"找到人",也不持有智能。
- 同一个模式:**附着点决定"从哪儿被找到",但 Agent 不属于任何一个附着点。**
- 「任何」是目标(**生态中的生态 · 一切皆插件**);企微 / 飞书 / Slack 是这条路的
**最小闭环验证** —— 三个形态完全不同的入口(自建长连接 / 官方 SDK / Socket Mode)都接上了,
**一切皆插件**,这套约定不是围着某一家写的,也不是给某一家开的特例。
> ⚠️ **两条诚实的限制,切换前先看一眼**
>
> 1. **切换会终止正在跑的任务**(进程要换)。先让它答完,或者先 `/stop`。
> 2. **各平台的窗口是各自独立的会话** —— 这既是"进度不丢"的原因,也是它的边界:
> 别指望在企微说的上下文,切到 Slack 还接着用。Agent 的记忆(工作区里的文件、笔记)
> 在哪儿都在;**当前这轮对话**只在它自己的窗口里。
> 如果你自己把它们配成了「同一个窗口」,那两次切换之间就是在同一份上下文上来回挪,
> **进度漂移的风险依然存在** ⇒ **切换前先记录好自己的进度**。
## 🌌 The Manifesto | 我们的协同宣言
**在这个模型狂飙的时代,我们拒绝“许愿式”的 AI 幻想。**
展开完整宣言
我们坚信,**AI 时代不是工具的替代,而是智慧的共存。**
**我们鼓励勇敢闯入“未至之境”**,别因底层知识的壁垒而不敢迈出第一步;但我们也必须保持工程师的严谨——**绝不不懂装懂,永远敬畏物理世界的客观规律。**
面对浩瀚的复杂术语与专业名词,大模型(军师)可作为我们最好的破壁机;
面对真实的业务逻辑与物理设备,Agent(将领)可作为我们最得力的执行官。
**让人类负责意图、决策与底线,让 AI 负责算力、检索与执行。**
敢用、会用、用好,这就是我们定义下一代人机协同的“基本标准”。
—— 献给所有敢于在 AI 时代重构自身工作流的探索者
## 🎣 这个仓真正想给的:授人以渔,而非死板代码
**代码只是参考实现(reference implementation)。** 换台机器、换个 Agent,下面这套东西照样成立 ——
这才是我们想留给读者的部分。
**五条约定**
1. 💬 **入口是聊天** —— 你在哪,工作台就在哪。不需要公网 IP、不需要服务器。
2. 🎯 **`@` 是路由,人是唯一的调度者** —— Agent 之间不直接通信(防打架、防串通)。
3. 🧠 **一个 Agent = 一个工作区 + 一份记忆 + 一个大脑**,换个窗口进来还是同一个 Agent。
4. 🧩 **能力分层,别重复造轮子** —— 官方已经有的一律用官方的,官方没覆盖的才自己补。
5. 🧾 **每个动作留痕** —— 谁点的、跑了什么、上下文还剩多少,都看得见。
**一个任务从「收到」到「干完」该长什么样**,这就是我们说的**交互基准**:
| 环节 | 应有的样子 |
|---|---|
| 收到 | 先回执,且和正文**共用同一个气泡**(不新开一条"处理中") |
| 执行 | 气泡里给**真进度**:第几步、正在读哪个文件 —— 不是定时器编的"已跑 N 秒" |
| 打断 | 任何时候都能 `/stop`,而且杀的是**进程树** |
| 有副作用 | 危险动作先问「允许 / 拒绝」,**否决权在 hook 自己手里**(不在 harness) |
| 收尾 | 结果、拒绝、错误**一律如实回报**;超长才切片,每片等回执 |
> ⚠️ **能"直接抄"的只有这一段**:`Windows + Claude Code` 的最小闭环,就是本仓这份代码。
> 换成 macOS、换成 Codex、DeepSeek Harness 或任何能跑命令的 Agent,
> **约定照用,接入步骤要照官方教程重走一遍** —— 我们只写了官方没覆盖的入站与交互这一段。
>
> 🐧 **Linux 这条也要说清楚**:同一套最小闭环在**树莓派**上同样跑通了(连开机自启),
> 只是那边用的是另一套 Agent 实现与系统服务自启,不是本仓的 Windows 脚本。
> 平台相关的那几处(自启、单实例、进程树)按你的系统替换即可 ——
> **而且可以直接让 Agent 陪你搭**:把这份约定交给它,它会照着你的系统补。
>
> 🍎 **macOS 也有回执了**:一位用户在评论区自述「**mac 大成功**」,并附了自己的运行截图。
> 原话直出 —— 这是**使用者反馈**,不是我们的实测:[真实用户反馈](docs/feedback/README.md)。
>
> **换 harness 到底要重写哪几处?** 教程 [§8 的「6 个适配点」表](docs/claude-code-wecom-guide.md)
> 把通用契约和运行器适配点分开列了:通用部分照抄,这 6 处按你的 Agent 自己回答。
>
> 📄 **已经有人照着接过了**:[外部接入记录](docs/field-reports/README.md) ——
> OpenCode、Codex、DeepSeek Harness 三个 Agent 各按同一份文档从零接入,
> 附它们自己的评价与踩坑(含原图);其中 DSH 接入之后**又把新版收回去了一次**,
> 自己那半边一处没丢(见该页「回灌」一节)。
>
> 🧬 **为什么这个仓可以被「取长补短」**:[锚点与增量](docs/anchor-and-delta.md) 讲分发模型
> (为什么要留那条缝、它已经有哪些证据、我们对下游的义务);
> 具体怎么吸收一次新版:[升级与取长补短](docs/UPGRADING.md)。
>
> 🖼️ **图片总览**:[docs/field-reports/assets/](docs/field-reports/assets/) ——
> 各份接入记录的原始截图都在这个目录里,点进去就能看全。
>
> 目标很简单:**让更多人照着这套约定,更好、更便捷地人机协同学习、工作等**,
> 而不是又多一个“更先进的工具”。
📊 换一个 harness 到底要改多少?(DSH 自己统计的表)

> 「新增代码约 1000 行,改动既有代码 5 处。这个比例就是它帮助多大的直接证据 ——
> **换掉一个『大脑』,身体一行没动。**」
## 👥 一个群,几种成员
我们自己的群里现在就是这么用的。下面写的是**角色**,不是某个具体的人:
| 成员 | 谁在跑 | 干什么 |
|---|---|---|
| **你** | 人 | 唯一的路由器,也是唯一的共享上下文 —— `@` 谁谁干活 |
| **CC(本项目)** | 你的电脑 | **动手**:读代码、改文件、跑命令,结果回到同一个气泡 |
| **官方云端大模型机器人** | 企微官方(**普通模式,免费**) | **答疑**:名词解释、代码讲解、思路讨论 —— 不动手,也不碰你的机器 |
| 其它 Agent 终端 | 树莓派 / 另一台电脑 / Codex… | 各自的工作区,各自闭环 |
| **端侧设备机器人** | P4 面板 / C3 小电视 | **物理世界**:显示、播放、采集 —— 而且它们也在群里、也能被 `@` |
> 关键点:这些机器人**互相看不见对方**(平台只把 `@` 自己的消息推给谁)。
> 所以"一个群里好几个 AI"不会变成"AI 互相打架",也不会背着你串通 ——
> 这是**协议层隔离**,不是配置出来的。
```
【组织层】企微群 = 入口 / 会议室 / 审计记录 ← 你是唯一的路由器
你 ──@──▶ CC(本机 Claude Code) ← 动手
──@──▶ 官方云端大模型机器人 ← 答疑(免费)
──@──▶ 其它 Agent 终端(树莓派 / Codex / …)
──@──▶ 设备机器人(P4 面板 / C3 小电视)
【设备层】MQTT / HTTP = 设备总线
Agent ──▶ 端侧设备(它们同时也在群里,可以被 @)
```
**为什么不是一个"全能大管家"**:一个 Agent = 一个「工作区 + 记忆 + 大脑」,跑在某台设备上;
企微群、私聊、直接开终端,默认是**同一个 Agent 的不同窗口**,换个窗口进来接着做,上下文不丢
(把私聊用 `CC_CWD_DM` 指到另一个工作区时,它就变成另一个 Agent 的窗口——这是可选项,见教程 §6.11)。
各 Agent 之间**不能直接通信是故意的**:能互通就会冒出"谁听谁的"和"私下串通"两件事 ——
前者还能用权限压住,后者压不住。不通信,这两件事就都不存在。
⇒ 于是**人既是唯一的路由器,也是唯一的共享上下文**,层级活在「人的判断 + 群聊 `@`」里。
## 🚀 快速开始
**接入指南(人 + AI Agent 双读者)见 [`docs/claude-code-wecom-guide.md`](docs/claude-code-wecom-guide.md)**
—— 开头那节「开始之前」就是安装,跳过它通常会卡在第一步。
```bash
python -m venv .venv
.venv\Scripts\activate # macOS/Linux: source .venv/bin/activate
pip install -r requirements.txt # requests + websocket-client + pycryptodome
cp .env.example .env # 填 Bot ID/Secret、你自己的 userid、ANTHROPIC_*
.venv\Scripts\python.exe -X utf8 app\bridge.py
```
- 依赖只有三个第三方包(`pycryptodome` 只用来解**加密的图片**;不装它文本照常,图片会明确报错)。
其余全是标准库。**Windows 实测**;Linux 树莓派上同一套控制面闭环
也已跑通(自启用的是系统服务,不是本仓脚本);macOS 协议层同样通用,自启需自己换一套 ——
已有用户自述在 macOS 上接入成功([反馈原文](docs/feedback/README.md))。
- **默认是只读档**(`dontAsk`):能问答、能读代码,**不会动你的机器**。
要让 Agent 真干活,显式改 `CC_PERMISSION_MODE` —— 见「[权限](#权限三种形态一个开关)」。
- 可选:让它常驻(登录自启、单实例、看门狗自愈、日志保留 14 天、运行期间不睡眠)
```bash
.venv\Scripts\python.exe -X utf8 app\bridge.py --install-autostart # 装(不需要管理员)
.venv\Scripts\python.exe -X utf8 app\bridge.py --autostart-status # 看
.venv\Scripts\python.exe -X utf8 app\bridge.py --uninstall-autostart # 卸
```
**一台机器跑多套桥**(换一个 Agent 就行):各自在 `.env` 里设 `BRIDGE_INSTANCE`(如 `dsh`)。
它**只**改两个系统级名字的后缀 —— 单实例互斥量和计划任务名;留空就等于上游行为。
不设的后果是静默的:第二套**起不来**,而装自启会把第一套的任务**覆盖**掉。
## 🧰 它现在能做什么
**群聊 + 私聊都通**;流式气泡、模板卡片、审批卡片都已**真机验收**;
[`tools/test_phase1.py`](tools/test_phase1.py) 里 339 项检查(含会真调一次模型的那几项)全过 —— 你可以自己复跑。
| 能力 | 说明 |
|---|---|
| 长连接 | 主动外连 `wss://openws.work.weixin.qq.com`;30s 心跳;断线指数退避(3s→30s,连上即重置) |
| 鉴权 | `from.userid` **白名单**是唯一真正的鉴权;群里的 `@` 只是消息路由。**留空即拒绝启动**(fail-closed) |
| 群聊 / 私聊 | 群里 `@` 它、私聊直接发;两条路径**各自独立上下文**,默认共用一个 `cwd`,也可用 `CC_CWD_DM` 分开(见教程 §6.11) |
| 会话 | 每个 `(会话, 用户)` 一份 session,跨消息续接;`/new` 清上下文 |
| 控制指令 | `/status` `/new` `/stop` `/model` `/platform` —— **忙碌时也即时可用**(`/status` 是按钮卡) |
| **模型热切换** | 聊天里 `/model` 看列表、`/model <编号\|名字>` 切换、`/model reset` 回默认。**下一条消息生效,不用重启**;切换前先真调一次验证,通过才写进 `data/model.json`;**全局**(群聊 + 私聊一起变)。⚠️ **切到/切离「有自己的工作目录」的模型(例如本地模型)会自动新开会话**(主动设计,见下方第 4 条) |
| **平台切换**
「幽灵漫游」 | 聊天里 `/platform` 看当前值、`/platform <平台>` 切换。⚠️ 平台是"进程的形状",所以这是**重启**(约 1~2 分钟不可用)而不是热切换:预检 → 写 `data/platform.json` → 拉起新进程 → 看守(软窗口 25s / 硬上限 120s)→ 才停旧;**起不来自动回滚,并先把没就绪的新进程收掉**。也能用控制目录(`data/control/`,任何 Agent 会写文件就能用)或 `tools/bridgectl.py` 驱动。见本页「幽灵漫游」一节、[联邦式中枢](docs/federation.md) 与教程 §6.12 |
| 忙碌语义 | 处理中再发 → 回「忙碌中…本条已忽略」,**丢弃不排队**(防输入轰炸) |
| 长回答 | 先整条发;只有被平台 `40058` 拒了才切片(每片等回执,失败会明说哪段没送到) |
| **图片** | 发图片给它 → 解出直链、落盘 → 提示模型用**你自己的读图工具**打开(Claude Code 里是 `Read`)。**能不能"看见"取决于所接模型是否支持图像输入**:图存在系统临时目录,下一轮说"刚才那张图"还在。⚠️ 企微的图是**加密**的(AES-256-CBC、**填充块 32 字节**),解密需要 `pycryptodome` |
| 上下文余量 | 每条回复尾部 `📊 上下文 x% (m/n)`:分母取 `modelUsage.contextWindow`,分子取**本轮最后一次 assistant 调用的 usage**(不是累计值) |
| **真进度** | 气泡显示「正在跑(12s · 第 3 步)+ 当前工具」;**变化才推**,附 60s 兜底心跳 |
| **模板卡片** | `/status` = 刷新 / 清空 / 停止。⚠️ 按钮文字**只有 2 个字的余量**:4 个字会被截成「清...」 |
| **审批卡片** | `Bash`/`Write`/`Edit` 先发「允许 / 拒绝」,点了才执行;只读直放。**仅全自动档位下有效**;开启后群聊 + 私聊都挂卡,**免不免卡按发消息的人**(`CC_APPROVAL_AUTO_USERS`) |
| 常驻 | 登录自启、单实例、看门狗自愈、日志保留 14 天、运行期间不睡眠 |
| 企业能力 | 邮件 / 文档 / 表格 / 日程 / 会议 / 待办 / 微盘 / 通讯录 / 读 7 天群历史 —— **由官方 `wecom-cli` 提供**,本仓零代码接入 |
| 设备总线 | MQTT / HTTP 控端侧设备 —— **在数据面那个仓**([`Agent-Ops-Edge-Hub`](https://github.com/Ly-Systems-Lab/Agent-Ops-Edge-Hub)),不在本仓库 |
| 多 Agent 同群 | 多个机器人同处一群、`@` 谁谁干活、互不串台 —— **形态成立**(已在同一群里用过) |
**关于「物理世界」这一半**:端侧设备(C3 小电视、P4 触控面板、具身小车)已经接在同一条设备总线上,
它们**本身就是群成员、可以被 `@`**。接法与实测数据在数据面那个仓的
[企微接入教程](https://github.com/Ly-Systems-Lab/Agent-Ops-Edge-Hub/blob/main/ai-agent-wecom/README.md) 里 ——
那是**架构思路**,不是另一份接入流程。**MQTT 数据层底座已经公开**([`Agent-Ops-Edge-Hub`](https://github.com/Ly-Systems-Lab/Agent-Ops-Edge-Hub));
两个仓合起来,才是完整的「**人 ⇄ Agent ⇄ 物理世界**」这条路。
> 🎬 **[看实拍:一句话驱动三台端侧设备(36 秒)](https://www.bilibili.com/video/BV18Zx86KEDT/)** ——
> C3 小电视 → P4 触控面板 → 具身智能小车,由 Agent 依次执行。
## 🏛️ 和官方是什么关系:站在官方肩膀上
**先去看官方。** 这一页就是入口:**[企业微信 · AI 开放能力](https://work.weixin.qq.com/nl/index/aicli)**
(以下按该页 2026-10-29 的内容整理,**以官方当时的版本为准**;本文不复制、不改写它的教程)。
它当前列出 **6 个 Agent 工具**(WorkBuddy、DeepSeek Harness、MiniMax Code、Kimi Work、Codex、
企业自研智能体)、**11 项核心开放能力**、**CLI 与 MCP 两种调用方式**,FAQ 里还有
**「如何通过长连接模式访问机器人?」**—— 也就是本项目的入口。
⚠️ 这份名单里**没有 Claude Code**(另有 OpenClaw 这类工具由官方单独提供文档)。
不是官方漏了什么,各家路径本来就不同 —— 我们只是把 **Windows + Claude Code** 这一条的坑写下来。
| | 官方 aicli(`wecom-cli`) | 本项目 |
|---|---|---|
| 定位 | **Agent 的「手」**:发邮件、建文档、排日程、查通讯录 | **Agent 的「耳朵和嘴」**:收实时消息、把结果回到同一个气泡 |
| 入站 | ✅ 有,但是**轮询**:以**授权真人**身份拉最近 **7 天**的会话历史 | ✅ **事件驱动**:长连接回调,机器人只看得见 **@ 自己**的 |
| 出站 | 11 项核心能力(`wecom-cli schema list` 实测列出 **15 个服务**) | 回复同一个气泡(流式)+ 模板卡片(按钮可点) |
| 身份 | 你本人(能看到你这个人能看到的) | 机器人(只看得到 @ 它的) |
| 需要什么 | 装 CLI + `auth init` 授权 | 一个 Bot ID / Secret |
| 能否同时用 | ✅ 可以,而且**建议一起用** | ✅ 可以 |
**两者是叠加关系,不是替代关系。** 官方补的是"Agent 会使用企微的业务能力";本项目补的是
"**人不在电脑前的时候,怎么找到并驱动那个 Agent**"—— 官方入口是命令行 / API 调用,
**没有常驻监听**;要"手机发一句话、电脑里的 Agent 立刻收到并回话",得有人把长连接一直维持着。
> 我们不说"官方不行"。官方把地基、协议、教程都做好了,
> **这个项目只是在它没走到的地方,多修了一小段路。**
⚠️ **装了官方 CLI 也不等于能用**:默认档位 `dontAsk` 下模型跑不了 `Bash(wecom-cli:*)`
(实测 `--allowedTools` 也放不进来,2026-10-29)。要用企业能力,得开全自动或「逐次询问」。
## 🔌 插座与插件:一个 Agent,多个入口,多个执行面
**入口**负责"人跟 Agent 说话",**执行面**负责"事情真正落地"。两者不必是同一家公司。
```text
在企微说一句话 → Agent 判断该用哪只手 → 到钉钉查待办 / 到飞书改文档 / 在本机改代码
↓
结果回到企微同一个气泡
```
**官方能力是插件,我们是插座。** `dws`(钉钉)、`lark-cli`(飞书)、`wecom-cli`(企微)
已经把"给 Agent 用的结构化命令 + Skills"做完了 —— 我们**直接引用,不包装、不复刻**;
本项目只补它们没有的那一层:**审批闸门、身份边界、会话与模型的路由**。
| 我们要保证的 | 落在哪 |
|---|---|
| 接得进来 | Skills 装到 `~/.claude/skills/`,一次安装,所有入口通用 |
| 看得见 | 审批卡写清「平台 / 目标 / 动作 / 以谁的身份」 |
| 拦得住 | 策略表外按写处理;跨平台写操作**默认全部弹卡** |
| 换得掉 | 内核不认识任何平台 —— 换执行面不改代码 |
接入方法、四个平台的差异、每一步的验收判据:[**`interop/`**](interop/README.md);
为什么这么设计:[**联邦式中枢**](docs/federation.md)。
展开:为什么不是「再写一条钉钉通道」,也不是「包成 MCP Server」
- **再写一条通道**:官方 `dws dev connect` 已经覆盖"群 @ → 本机 AI"(多轮、`/new`、白名单、限流)。
再写一遍,收益只剩"工具级审批 + 聊天里切模型"两项,维护成本却要自己扛。
- **包成 MCP Server**:多一层进程、多一套协议。官方 CLI 本身就是结构化命令 + `SKILL.md`,
Agent 会 Bash 就能用 —— 包装只会让我们替官方背升级。
- **直接用官方 CLI**:零适配层,升级跟着官方走,坏了拆掉即可。
⚠️ **身份要说清楚**:`dws` / `lark-cli` 用的是**你本人的 OAuth**。
Agent 在钉钉里发的一条消息,**同事看到的是你发的,不是机器人**。
这是"借力"的代价,也是它的价值 —— 所以写操作上,闸门必须做实。
## 🔐 权限:三种形态,一个开关
**怎么切换:改 `.env`,然后重启桥。** 聊天里**没有**切换指令 ——
`/status` 卡片上的「档位」一行只负责**显示**,三个按钮(刷新 / 清空 / 停止)里没有切换。
这是有意的:档位是"这台机器交给谁"的边界,不该能被聊天里的任何一句话改掉。
| 形态 | 配置 | 实际效果 |
|---|---|---|
| **只读**(默认) | `CC_PERMISSION_MODE=dontAsk` | 能问答、能读代码;**执行命令 / 写文件一律被拒**,拒绝原因如实回到聊天里 |
| **全自动** | `CC_PERMISSION_MODE=bypassPermissions` | 模型直接在你机器上执行命令、改文件,不弹任何确认 |
| **逐次询问** | `bypassPermissions` + `CC_APPROVAL=1` | 有副作用的调用(`Bash`/`Write`/`Edit`/`WebFetch`)先发「允许 / 拒绝」卡;只读工具(`Read`/`Grep`/`Glob`/`TodoWrite`)直放 |
**谁要弹卡,按发消息的人分**:审批一旦开启(`CC_APPROVAL=1`),群聊和私聊都会走闸门;
列进 `CC_APPROVAL_AUTO_USERS` 的 userid 全自动,其余人一律弹卡。
留空 = 谁都要卡。旧开关 `CC_APPROVAL_DM`(私聊全自动)已废弃。
工作区也可以分开(`CC_CWD` / `CC_CWD_DM`)—— 完整教程见
[§6.11](docs/claude-code-wecom-guide.md)。
三条必须知道的事实(都是实测,细节见教程
[§3.5](docs/claude-code-wecom-guide.md) / [§6.10](docs/claude-code-wecom-guide.md)):
1. **「逐次询问」不是第四个档位**,它是全自动档位**之上**加的一道闸。`--permission-mode`
只有 `acceptEdits / auto / bypassPermissions / manual / dontAsk / plan` 六个合法值(**没有 `default`**)。
2. 🚨 **审批卡片不替代 `dontAsk`**:PreToolUse hook **不能越过权限档位** —— `dontAsk` 下
就算你点了「允许」,命令照样不执行。它是"已经决定全自动之后"的第二道闸,不是"让全自动变安全"的东西。
3. **改配置要重启 —— 但模型例外**:`.env` 只在进程启动时读一次,运行期不会重读
⇒ 改了不重启 = 没改(常驻实例按 PID 停掉再拉起,或等任务计划程序的下一次兜底;
桥是登录自启的,直接重启电脑同样生效)。
**换 API key / 服务商 / 工作区属于这一类** —— 改完 `ANTHROPIC_*` 必须重启桥。
**模型不用重启**:它是运行时状态,聊天里 `/model` 改完下一条消息就生效(见下)。
> 想确认**当前真的在跑哪一档**:聊天里发 `/status`,卡片「档位」一行就是实际生效的那个值。
**模型(本地 / 云端)怎么切**(不用碰 `.env`,也不用重启)—— 展开看用法与设计选择:
展开:/model 用法与四条设计选择
```
/model 列出候选 + 当前值
/model 2 按编号切
/model glm-5.2 按名字切(任意名字都行,会先验证)
/model reset 回到 .env 里 CC_MODEL 的默认值
```
四条设计选择,都是有意的:
- **切换前先真调一次**。端点不提供模型枚举(实测 `GET /v1/models` 回 `404`),
名字对不对只有调一次才知道 ⇒ 探测通过才写进 `data/model.json`,
错的模型**永远进不了真源**。失败的原文会压成一句人能读的话。
- **模型是全局的**,群聊和私聊一起变;**正在跑的任务不受影响**(它启动时就定了)。
- **真源坏了不会哑**:`data/model.json` 读不出来 ⇒ 报警并用 `last_good`;
整份文件坏 ⇒ 退到 `.env` 的 `CC_MODEL`(两个文件不会一起坏);都不行才不传 `--model`。
- ⚠️ **切到「有自己的工作目录」的模型会自动新开会话 —— 这是主动设计,不是会话丢了。**
不同模型的上下文窗口能差一个数量级(本地 9B 只有 32K,云端是 1M),
把旧会话硬续上去会直接撑爆;而且撑爆是**静默**的:模型突然不会用工具了,不报错。
所以换工作目录 = 新开会话,**下一条消息就稳稳落在新模型上**。
**本地与云端模型切换:新开会话,上下文不互通。** 切换前请确认没有正在进行的工作。
**云端模型之间互切(同一个工作目录)不新开会话**,上下文照常延续,方便接着干活。
## 🛡️ 安全边界
- `from.userid` **白名单**是唯一真正的鉴权;群里 `@` 只是消息路由。
**留空 ⇒ 拒绝启动**;要开放全部必须显式 `WECOM_ALLOW_ANYONE=1`。
- 想要全自动就把 `CC_PERMISSION_MODE` 改成 `bypassPermissions` —— 那是**一次有意识的选择**。
⚠️ 别以为 `acceptEdits` 更安全:实测在 headless 下它**照样执行 Bash**,与全自动无区别。
- **审批整体默认关(`CC_APPROVAL=0`)**;一旦开启(`CC_APPROVAL=1`),群聊 + 私聊都走闸门、**谁能免卡按发消息的人**(`CC_APPROVAL_AUTO_USERS`),而且**不替代 `dontAsk`**。它的否决权握在
[`tools/approval_hook.py`](tools/approval_hook.py) 自己手里:harness 超时/崩溃一律**放行**,
所以 hook 自己 120 秒到点主动拒绝,harness 的 300 秒只是兜底。
开了它但**自检不过就拒绝启动**(不再静默降级成全自动)—— 自检查两件事:Claude 真的会加载
这个 hook(`settings.json` 注册 + `--setting-sources` 含 `project`),以及 hook 脚本真的跑得起来。
群聊 / 私聊用不同工作区时,**每个会挂卡的工作区各查一遍**,任一不过就拒绝启动。
- **凭证不进代码、不进文档、不进日志**:`bot_secret`、`ANTHROPIC_AUTH_TOKEN` 只从 `.env` 读,
日志里最多出现键名和长度,不出现值。
- **但运行日志**会**记 `userid` / `chatid`,以及消息正文的前 80 个字符** —— 排查"谁发的、
为什么被拒"离不开它。这些日志只写本机 `logs/bridge-YYYYMMDD.log`(已 gitignore、保留 14 天、
不外发);要把日志贴给别人,请先自己脱敏。
- `permission_denials` 与 `is_error` **一律回报**,不许假装成功。
- 杀进程要杀**进程树**(`taskkill /PID /T /F`),并且**看结果** —— 没确认退出就不能说"已清理"。
- 本项目涉及本地算力调度与物理硬件控制,**请务必在人类监督下使用**。因 AI 幻觉或网络延迟导致的设备损坏或数据泄露,**概不负责**。
## 📚 继续往下读
| 想知道什么 | 去哪 |
|---|---|
| **从零安装、建机器人、填 `.env`、首次自检** | [`docs/`](docs/claude-code-wecom-guide.md) 开头「开始之前」+ §2 |
| Claude Code 侧的**实测事实**(`is_error`、`stream-json`、权限档位矩阵…) | [`docs/`](docs/claude-code-wecom-guide.md) §3 |
| 企微长连接的**真实协议形状**(字段、三条回复通道、20480 上限) | [`docs/`](docs/claude-code-wecom-guide.md) §4 |
| **必须自己实现的 10 个机制**(每条附"不这么做会怎样") | [`docs/`](docs/claude-code-wecom-guide.md) §6 |
| 让**另一个 AI Agent** 照着实现 | [`docs/`](docs/claude-code-wecom-guide.md) §8(自包含契约,可整段丢给它) |
| **换一个聊天平台**(飞书 / 钉钉 / Slack) | [`platforms/`](platforms/README.md):同一套约定,四个平台各答一遍 |
| **把官方 CLI 接进来当执行面**(钉钉 `dws` / 飞书 `lark-cli`) | [`interop/`](interop/README.md):四个平台的差异 + 接入六步 + 验收判据 |
| **在它上面改出自己的版本,之后怎么跟进上游** | [`docs/UPGRADING.md`](docs/UPGRADING.md):哈希树对比 → 只看删除行 → 整份替换 vs 定点合并 → 验证 → 回归 |
| **这套「锚点 + 增量」的分发模型本身**(为什么、证据、我们对下游的义务) | [`docs/anchor-and-delta.md`](docs/anchor-and-delta.md) |
| **验收清单** / 发布前红线 | [`docs/`](docs/claude-code-wecom-guide.md) §9 / §10 |
| 代码在哪 | 见下表「目录」 |
## 📁 目录
| 路径 | 内容 |
|---|---|
| [`app/bridge.py`](app/bridge.py) | 桥本体(单文件) |
| [`tools/approval_hook.py`](tools/approval_hook.py) | 审批卡片的 `PreToolUse` hook(独立进程,**否决权在这里**) |
| [`tools/verify_headless.py`](tools/verify_headless.py) | 首次自检①:依赖 + 认证 + headless 行为矩阵(会真调一次模型) |
| [`tools/env_from_settings.py`](tools/env_from_settings.py) | 把 `~/.claude/settings.json` 里 `ANTHROPIC*` 搬到 `.env`(只打键名和长度,不回显 token) |
| [`tools/test_phase1.py`](tools/test_phase1.py) | 单元测试(`--skip-llm` 只跑离线部分) |
| [`.claude/settings.json`](.claude/settings.json) | 注册 `approval_hook.py`;`CC_APPROVAL=0` 时它是空壳 |
| [`docs/`](docs/claude-code-wecom-guide.md) | 接入教程(人 + AI Agent 双读者);[锚点与增量](docs/anchor-and-delta.md) / [升级](docs/UPGRADING.md) / [联邦式中枢](docs/federation.md) |
| [`platforms/`](platforms/README.md) | 平台适配:契约 + 企业微信 / 飞书 / 钉钉 / Slack 各自的答案 |
| [`interop/`](interop/README.md) | 生态互联:官方 CLI 怎么当执行面接进来,四个平台差在哪 |
| [`LICENSE`](LICENSE) [`NOTICE`](NOTICE) | Apache-2.0 全文与版权声明(都在仓库根目录) |
| `logs/` `data/` `.env` | 运行产物与凭证,**不入库** |
> 开发侧的探针脚本(`probe_permission_modes.py` / `probe_hooks.py` 等)与台账(`notes/`)
> **不随公开仓发布** —— 它们是给我们自己复现结论用的,带着本机路径和实验痕迹。
## 🤝 贡献与支持
欢迎提交 Issue 或 PR。如果你觉得这个架构对你有启发,请点个 Star ⭐!
## 📜 许可
**Apache License 2.0** —— 全文见 [`LICENSE`](LICENSE),版权声明见 [`NOTICE`](NOTICE)。
我们坚信开源与共享的力量。在遵守许可证条款的前提下,你可以自由地使用、修改、分发本项目(包括商业用途),甚至将其闭源集成到你的商业产品中。我们唯一的期望是:**保留原作者的版权声明(NOTICE 文件)。**
**开源不仅是给人看,更是给 AI 学习。我们希望这套架构理念能成为未来人机协同的基石。**