Claude Code 通常运行在电脑终端里,适合处理代码阅读、文件修改、命令执行、项目重构这类开发任务。问题是,人不一定一直坐在电脑前。如果能在手机微信里给 Claude Code 发消息,电脑上的 Claude Code 负责执行任务,微信负责收发指令,就能把手机变成一个远程开发入口。
关键点不在于“把 Claude Code 塞进微信”,而是写一个桥接进程:
- 本地 Node.js 进程通过 ClawBot 协议连接微信。
- 微信消息通过 HTTP(超文本传输协议)长轮询进入本地进程。
- 本地进程解密消息,交给 Claude Agent SDK(Software Development Kit,软件开发工具包)。
- Claude Code 处理完成后,把回复再发回微信。
开源实现地址:
https://github.com/Wechat-ggGitHub/wechat-claude-code
整体架构
ClawBot 相关包里已经包含一套微信 Bot 协议能力,包括消息接收、AES(Advanced Encryption Standard,高级加密标准)加解密、二维码认证、CDN(内容分发网络)媒体上传下载等。把这些能力单独抽出来,就可以绕开 OpenClaw 的业务处理逻辑,改成对接 Claude Code。
flowchart LR
A[手机微信] --> B[微信 ClawBot 服务]
B -->|HTTP 长轮询| C[本地 Node.js 桥接进程]
C --> D[微信协议层]
D --> D1[AES 解密]
D --> D2[消息解析]
D --> D3[媒体文件处理]
D --> E[会话与命令路由]
E --> F[Claude Agent SDK]
F --> G[Claude Code]
G --> F
F --> E
E --> D
D -->|发送文本或媒体| B
B --> A
这里最重要的设计是:微信协议层和 Agent 执行层要解耦。
微信协议层只负责“怎么和微信通信”,包括登录、收消息、发消息、加解密、媒体文件处理;Claude 适配层只负责“怎么把用户消息变成 Claude Code 能处理的请求”。这样做的好处是,Claude Code 不是唯一选择,后续换成其他 Agent,也只需要替换适配层。
为什么不需要公网地址和域名
很多机器人系统使用 Webhook,也就是平台主动请求开发者提供的服务器地址。这种方式通常要求公网 IP(Internet Protocol,互联网协议)地址、域名和可访问的 HTTPS 服务。
ClawBot 这套思路不一样。它使用的是长轮询:本地进程主动向微信侧发起请求,请求会挂起一段时间;如果期间有新消息,微信侧直接返回;如果超时没有消息,本地进程马上发起下一次请求。
sequenceDiagram
participant Local as 本地 Node.js 进程
participant WeChat as 微信 ClawBot 服务
participant Claude as Claude Code
Local->>WeChat: 发起长轮询请求
WeChat-->>Local: 返回微信消息或超时
Local->>Local: 解密并解析消息
Local->>Claude: 调用 query() 处理任务
Claude-->>Local: 流式返回结果
Local->>WeChat: 发送回复
WeChat-->>Local: 发送成功
Local->>WeChat: 继续下一轮长轮询
因为连接是本地进程主动发起的,所以电脑只要能访问外网就行,不需要让外部访问你的电脑。这也是它适合个人开发环境的原因。
核心模块拆分
一个可维护的微信 Claude Code 桥接项目,至少需要拆成这些模块:
| 模块 | 责任 | 关键点 |
|---|---|---|
| 微信协议客户端 | 负责登录、长轮询、发消息 | 处理超时、重连、消息确认 |
| 加解密模块 | 处理 AES 加密消息 | 密钥不能写死,不能泄露到日志 |
| 媒体模块 | 上传和下载图片、文件、语音等媒体 | 需要接入 CDN 上传下载流程 |
| 消息解析器 | 把微信消息转换成统一格式 | 文本、图片、文件要区分处理 |
| 会话管理 | 维护微信用户和 Claude 会话的关系 | 避免不同用户上下文串在一起 |
| Claude 适配器 | 调用 Claude Agent SDK 的 query() | 支持流式返回、错误处理 |
| 命令路由 | 处理斜杠命令、管理命令、普通对话 | 例如 /help、/reset、/status |
| 权限审批 | 处理 Claude Code 的敏感操作确认 | 用户可以在微信里回复 yes/no |
| 守护进程 | 保证本地进程长期运行 | macOS 可以用 launchd 托管 |
这种拆分方式能让协议、会话、Agent 调用互不干扰。微信协议变了,只改协议客户端;Claude SDK 变了,只改 Claude 适配器。
消息处理流程
一条微信消息进入本地进程后,不应该直接丢给 Claude Code。更稳妥的做法是先经过标准化处理,再判断它属于普通对话、命令还是审批回复。
flowchart TD
A[收到微信消息] --> B{能否解密}
B -->|不能| B1[记录错误并丢弃]
B -->|可以| C[解析消息类型]
C --> D{是否为审批回复}
D -->|是| D1[恢复等待中的 Claude 操作]
D -->|否| E{是否为斜杠命令}
E -->|是| E1[执行本地命令路由]
E -->|否| F[写入会话上下文]
F --> G[调用 Claude Agent SDK query()]
G --> H[接收流式输出]
H --> I[合并或分段回复微信]
核心循环可以抽象成这样:
for await (const packet of wechatClient.poll()) {
const message = cryptoBox.decrypt(packet)
if (approvalGate.resolveIfNeeded(message)) {
continue
}
if (commandRouter.isCommand(message.text)) {
const result = await commandRouter.handle(message)
await wechatClient.sendText(message.from, result)
continue
}
const session = sessionStore.getOrCreate(message.from)
let reply = ""
const stream = claudeAdapter.query({
sessionId: session.claudeSessionId,
prompt: message.text,
})
for await (const event of stream) {
if (event.type === "text_delta") {
reply += event.text
}
}
await wechatClient.sendText(message.from, reply)
}
代码里的 poll()、decrypt()、query() 只是表达核心逻辑,真实项目还要补上异常处理、消息去重、重试、限流和日志。
Claude Agent SDK 的接入方式
Claude Agent SDK 提供的 query() 可以把用户输入交给 Claude Code。桥接进程要做的事情,是把微信里的自然语言消息转换成一次 Agent 请求。
普通对话很简单:
await claudeAdapter.query({
sessionId: "wechat-user-xxx",
prompt: "帮我检查这个项目里的 TypeScript 类型错误",
})
真正复杂的是多轮任务。比如 Claude Code 可能需要读取文件、修改代码、执行命令,某些操作需要用户确认。这时微信端必须能承接“审批”这个状态。
一个可行的状态模型如下:
stateDiagram-v2
[*] --> Idle
Idle --> Running: 收到普通任务
Running --> WaitingApproval: Claude 请求执行敏感操作
WaitingApproval --> Running: 用户回复 yes
WaitingApproval --> Idle: 用户回复 no
Running --> Idle: 任务完成
Running --> Failed: 执行失败
Failed --> Idle: 返回错误信息
如果没有审批状态管理,Claude Code 一旦要求用户确认,整个会话就会卡住。本地桥接进程需要保存“哪一个微信用户、哪一个 Claude 会话、正在等待哪个审批请求”。
用 Superpowers 组织开发流程
Superpowers 是一个面向 Claude Code 等工具的 Skill 框架。它的价值不是让 AI 随便生成代码,而是把开发流程拆成更稳定的几个阶段:先明确方案,再写计划,再并行实现。
适合这类桥接项目的流程可以这样组织:
flowchart LR
A[Brainstorming] --> B[明确协议边界和功能范围]
B --> C[Writing Plans]
C --> D[拆模块、定接口、排依赖]
D --> E[Dispatching Parallel Agents]
E --> F[多个 Agent 并行实现独立模块]
F --> G[集成、编译、测试]
三个阶段各自解决不同问题:
| 阶段 | 目标 | 产物 |
|---|---|---|
| Brainstorming | 明确能不能做、怎么做、边界在哪里 | 协议分析、架构选择、功能取舍 |
| Writing Plans | 把方案拆成可执行任务 | Markdown 计划、模块接口、依赖关系 |
| Dispatching Parallel Agents | 让多个 Agent 同时处理独立模块 | 协议层、SDK 接入、会话管理、命令路由等代码 |
Brainstorming 阶段要重点确认几个问题:
- 是否复用 OpenClaw 相关包里的协议层,还是完全重写协议。
- 是否需要 OpenClaw Gateway(网关)。
- 是否支持斜杠命令。
- Claude Code 请求执行敏感操作时,微信端如何确认。
- 文本、图片、文件等不同消息类型是否都要支持。
- 多个微信会话同时使用时,如何隔离上下文。
Writing Plans 阶段要把这些问题落到接口上。例如微信协议层只暴露 poll()、sendText()、sendMedia(),Claude 适配层只暴露 query(),这样并行开发时不会互相踩代码。
适合和不适合的场景
| 场景 | 是否适合 | 原因 |
|---|---|---|
| 个人在手机上给 Claude Code 分配开发任务 | 适合 | 本地电脑执行任务,微信负责收发指令 |
| 没有公网地址、没有域名的个人机器 | 适合 | 长轮询由本地进程主动发起 |
| 临时查看项目状态、让 Claude Code 跑检查 | 适合 | 微信消息足够表达轻量任务 |
| 面向大量用户的客服机器人 | 不适合 | 会话隔离、稳定性、风控要求更高 |
| 严格企业合规环境 | 不一定适合 | 需要额外审计、权限、数据隔离 |
| 电脑不能长期在线 | 不适合 | 本地进程停止后,微信入口也会失效 |
它更像个人开发者的“移动控制台”,不是直接面向生产环境的大规模机器人平台。
上手流程
项目基于 Node.js,本地需要先准备好 Node.js 环境和 Claude Code 相关认证。
常见启动流程类似这样:
git clone https://github.com/Wechat-ggGitHub/wechat-claude-code.git
cd wechat-claude-code
npm install
# 按仓库里的示例配置 Claude 与微信会话参数
# 如果存在 .env.example,可以复制后再填写
# cp .env.example .env
npm run dev
如果脚本名不同,以 package.json 里的 scripts 为准。第一次启动时,本地进程会进入二维码认证流程。认证完成后,手机微信发来的消息就能进入本地 Node.js 进程,再由 Claude Code 处理。
在 macOS 上长期运行时,可以交给 launchd 管理。核心思路是让系统启动后自动拉起 Node.js 进程,进程退出后再重启。
<plist version="1.0">
<dict>
<key>Label</key>
<string>local.wechat-claude-code</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/node</string>
<string>/path/to/wechat-claude-code/dist/index.js</string>
</array>
<key>WorkingDirectory</key>
<string>/path/to/wechat-claude-code</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
路径要替换成本机真实路径。如果使用 TypeScript 开发模式,也可以让 launchd 执行项目提供的启动脚本,但生产运行更建议先构建再启动。
容易踩的坑
1. 长轮询超时不是异常
长轮询经常会“等一段时间后没有消息返回”,这属于正常情况。处理逻辑应该是:超时后立刻发起下一轮请求,而不是把它当成错误疯狂打印日志。
while (true) {
try {
const messages = await wechatClient.poll({ timeoutMs: 30000 })
await handleMessages(messages)
} catch (error) {
logger.warn(error)
await sleep(1000)
}
}
2. 消息必须去重
网络重试、确认失败、进程重启都可能导致同一条消息被处理多次。每条微信消息最好根据消息 ID 做去重,已经处理过的消息不要再次交给 Claude Code。
3. 流式输出不要每个 token 都发微信
Claude Code 的返回通常是流式的。如果每来一小段就发一次微信,会造成刷屏,也容易触发频率限制。更合理的方式是先缓冲,再按句子、段落或时间窗口合并发送。
4. 授权确认要有明确状态
Claude Code 执行命令、修改文件时,可能需要确认。微信里回复 yes 或 no 时,桥接进程要知道它对应哪一次请求,不能把普通聊天误判成授权。
5. 会话上下文要隔离
同一个桥接进程可能收到多个微信会话的消息。每个用户都应该有独立的 Claude 会话 ID、任务状态和审批状态,否则上下文会混在一起。
6. 密钥和会话文件不能进仓库
微信会话 token、AES 密钥、Claude 认证信息都属于敏感数据。它们应该放在本地配置或受保护的凭据存储里,并加入 .gitignore。
.env
*.token
sessions/
credentials/
关键结论
ClawBot 协议层解决的是微信通信问题,Claude Code 解决的是 Agent 执行问题。把两者用本地 Node.js 进程连接起来,就能得到一个不依赖公网回调的微信入口。
这套结构的核心不是某一个具体实现,而是协议层与 Agent 层的解耦:
flowchart LR
A[微信协议层] --> B[统一消息模型]
B --> C[Agent 适配层]
C --> D[Claude Code]
C -.可替换.-> E[其他 Agent]
只要能处理微信认证、长轮询、AES 加解密和消息发送,后面的 Agent 可以是 Claude Code,也可以是其他代码助手。微信负责输入输出,本地电脑负责执行任务,这就是整个方案最实用的地方。