【无标题】
把 Claude Code 接进微信:一个周末搓出来的 wxcc 桥
把 Claude Code 接进微信:躺在沙发上让 AI 帮我改服务器

图:wxcc 桥接微信与 Claude Code,实现远程服务器管理
起因
Claude Code 很好用,但它有个"缺点":必须坐在电脑前开着终端才能使唤它。
有天我在刷 NousResearch/hermes-agent 的源码,发现它有一个微信通信渠道——走的是腾讯官方的 iLink Bot API(个人微信机器人接口,不是 hook 也不是协议逆向)。我突然想到:能不能把这层微信接入抽出来,后端换成 Claude Code?
这样我就可以在公交车上发一条微信:“帮我看看服务器上那个定时任务为什么没跑”,回家的时候问题已经修好了。
于是有了 wxcc:github.com/noobprogrammewhy/wxcc
整体架构
两头各用一个官方接口,中间自己写胶水:
| 层 | 用什么 | 职责 |
|---|---|---|
| 微信接入 | iLink Bot API(从 hermes-agent 抽取,MIT) | 扫码登录、35s 长轮询收消息、AES-128 加密的 CDN 媒体收发 |
| 桥接 | 自己写的 bridge.py |
访问控制、按会话串行、! 命令拦截、媒体桥接 |
| Agent | 官方 claude-agent-sdk |
每个微信会话对应一个可 resume 的 Claude Code 会话 |
消息进来 → Claude Code 带着完整工具权限干活 → 结果切段发回微信。Claude 想发文件给我,只要在回复里写一行 MEDIA:/绝对路径,桥接层就会把文件原生发过来。
几个关键设计
常驻客户端,而不是每条消息起一个进程
最初的版本每收到一条微信消息就 query() 一次——等于每次冷启动一个 claude 子进程。实测下来一句"你好"要等十几秒,体验很差。
改成每个会话持有一个常驻的 ClaudeSDKClient:
class ChatSession:
async def ask(self, prompt):
await self._ensure_connected() # 首条消息时 connect,之后复用
await self._client.query(prompt)
return await self._drain() # 收 AssistantMessage 直到 ResultMessage
子进程只在第一条消息时启动,之后的每一轮都是热的。进程挂了就重连一次,用记下来的 session id resume,上下文不丢。
会话要能"切回去"
Claude Code 本身支持按 session id 恢复会话。我把这个能力做成了微信里的 !resume 命令:每个逻辑对话在本地记一条历史(标题就是这个对话的第一句话),随时列出、随时切回:
!resume
历史会话(新→旧):
1. 帮我把服务器上的定时任务修一下 · 2026-07-03 09:1 ←当前
2. 写一个爬虫抓豆瓣书评 · 2026-07-02 22:40
用法: !resume <编号> 切回该会话
有个小细节:同一个对话每聊一轮 session id 都会变。如果傻乎乎地每轮记一条历史,列表马上就被刷爆。所以记录时先查"上一个 id 是不是已有条目",是就原地更新——一个逻辑对话永远只占一条。
没有终端,命令怎么办
/model、/compact 这些是交互式 CLI 的内建命令,Agent SDK 这条路走不通。所以在桥接层拦一套 ! 命令,微信里直接发:
| 命令 | 作用 |
|---|---|
!model sonnet |
切模型(丢掉热进程,带新模型重连并 resume,上下文保留) |
!compact 保留部署步骤 |
压缩上下文,回报前后占用百分比 |
!context |
上下文窗口占用(SDK 的 get_context_usage(),带进度条) |
!usage |
本会话花费、token、轮次 |
!cwd / !perm |
切工作目录 / 权限模式 |
!stop |
打断正在跑的回复 |
切模型不丢上下文的原理和断线重连是同一套:把热进程丢掉,下次连接时带上新参数 + resume=当前会话id。
踩过的三个坑
坑一:GBK 控制台打不出二维码
扫码登录要在终端渲染 ASCII 二维码。Windows 控制台默认 GBK 编码,qrcode 库输出里有 \xa0 字符,直接 UnicodeEncodeError 崩掉。
解法:先渲染到 StringIO,再以 UTF-8 字节写 sys.stdout.buffer,同时无条件保存一份 qr.png 兜底——终端花了没关系,扫图片文件一样能登录。
坑二:start.bat 双击闪退
写启动脚本时文件是 LF 换行。Windows 批处理文件必须 CRLF,否则 cmd.exe 解析错乱,窗口一闪就没。这种坑排查起来最费劲,因为文件内容看起来完全正常。
发布到 GitHub 时顺手加了一行 .gitattributes 防止别人 clone 下来复现这个坑:
*.bat text eol=crlf
坑三:延迟高得离谱,原来是代理
联调时总觉得消息一来一回慢得不正常。查了半天发现:机器上配置了系统代理(环境变量 HTTP_PROXY),而 aiohttp 建会话时写了 trust_env=True——腾讯国内的接口流量也被塞进了翻墙隧道。
实测对比(curl 直连 vs 走代理访问 iLink 接口):
| 路径 | 耗时 |
|---|---|
| 直连 | 约 0.1s |
| 走代理 | 约 2.1s |
慢 20 倍,而且发消息、"正在输入"状态、媒体传输、长轮询重建,每次请求都在付这 2 秒。
修复很简单但要想清楚边界:iLink 会话改 trust_env=False 永远直连;Claude 子进程的代理必须保留——它连的是 api.anthropic.com,在国内没代理反而不通。两条链路各走各路。
安全:这等于把 shell 交给微信
必须想清楚:任何能给这个机器人发消息的人,等于拿到了你机器上一个带完整工具权限的 Claude Code。所以访问控制是硬需求,不是可选项:
- 默认策略
first:绑定后第一个私聊的人成为持久 owner,其他人的消息一律忽略——绑完自己先发一条消息把位置占了; - 更严格可以配白名单;
open模式(谁都能用)只适合演示,真实环境别碰。
另外登录产物(二维码图片、含账号 id 的日志)一定要进 .gitignore,发布前用关键字全库扫一遍敏感信息,这个习惯救过我一次。
效果
现在的日常是这样的:手机上发一条微信,Claude Code 在家里的机器上翻代码、跑命令、把结果(包括截图和文件)发回来。配合 !resume 切换话题、!compact 压上下文,一个微信号就是一个随身终端。

代码全部开源(MIT):github.com/noobprogrammewhy/wxcc
如果你也想搭一个,README 里有完整步骤,大概十分钟:装依赖 → wxcc login 扫码 → wxcc run → 给机器人发第一条消息锁定 owner,完事。
唯一的硬性要求:需要一个独立的微信号给机器人用(iLink 的 token 同一账号只允许一个轮询者),别拿大号试。
微信 iLink 协议实现改编自 NousResearch/hermes-agent1(MIT License);Agent 能力来自官方 Claude Agent SDK2。
更多推荐

所有评论(0)