Claude Code 是一个强大的本地 AI 编程助手,但它默认只能在终端里使用。如果你人在外面,想让它帮你读一个文件、查一段代码、或者回答关于项目的问题,就得打开电脑才行。
im-claude 解决的就是这个问题。 它是一个网关服务,把 Telegram(或钉钉)变成 Claude Code 的远程操控入口。启动之后,你在手机上给 Telegram Bot 发消息,它就能帮你查文件、读代码、回答问题------全程在你的本地机器上运行,数据不经过任何第三方。
它是怎么工作的
消息流向非常直接:
你的手机 Telegram
↓(互联网)
Telegram 服务器
↓(长轮询)
本地运行的 im-claude
↓
Claude Agent SDK(本地进程)
↓
Claude API(claude-sonnet-4-6)
↓ 返回结果,原路回去
关键点是:Claude Agent SDK 跑在你本地。Claude 拿到的是你本地文件系统的读写权限,不是某个云端沙箱。你告诉它"读取 D:/AI/claude_code 下的测试文件",它就真的去读你本地那个目录。
架构上分四层:
| 层 | 组件 | 职责 |
|---|---|---|
| 接入层 | TelegramAdapter / DingTalkAdapter | 接收/发送 IM 消息 |
| 路由层 | MessageRouter | 权限校验、防并发 |
| 执行层 | ClaudeRunner | 调用 Agent SDK |
| 能力层 | @anthropic-ai/claude-agent-sdk | 完整 Claude Code 工具链 |
五分钟跑起来
前置条件:
-
Node.js 18+
-
Anthropic API Key
-
一个 Telegram Bot Token(去找
@BotFather发/newbot就能拿到)
第一步:克隆并安装
git clone https://github.com/zytc2009/im-claude
cd im-claude
npm install
第二步:配置环境变量
cp .env.example .env
编辑 .env,最少只需要三个值:
ANTHROPIC_API_KEY=sk-ant-xxx
TELEGRAM_BOT_TOKEN=你的Bot Token
ALLOWED_USER_IDS=你的Telegram数字ID
不知道自己的 Telegram ID?在 Telegram 里找 @userinfobot 发一条消息,它会直接告诉你。
第三步:启动
npm run dev
看到 🚀 IM-Claude Bridge 已启动 就说明成功了。去 Telegram 找你的 Bot,发一条 /start,然后直接说话。
会话是持续的
这是 im-claude 一个值得注意的设计:它用 Claude Agent SDK 原生的 session_id 来维持对话上下文,而不是手动拼接历史消息。
第 1 条消息 → query({ prompt }) → SDK 返回 session_id,保存
第 2 条消息 → query({ prompt, resume: sid }) → 续接上文
/clear 命令 → 删除 session_id → 下次开新对话
这意味着你可以在 Telegram 里进行多轮对话,Claude 会记住之前说的内容,就像在终端里连续输入一样。
工具权限控制
im-claude 允许你精确控制 Claude 能做什么,通过 .env 里的一行配置:
# 只读,最安全
ALLOWED_TOOLS=Read,Glob,Grep
# 读写,可以修改文件
ALLOWED_TOOLS=Read,Glob,Grep,Write,Edit
# 完整权限,含 Shell 执行(生产环境谨慎开放)
ALLOWED_TOOLS=Read,Glob,Grep,Write,Edit,Bash
配合 ALLOWED_USER_IDS 白名单,只有你列出来的用户 ID 才能跟 Bot 交互。ALLOWED_USER_IDS 留空表示允许任何人------本地测试可以,暴露到公网绝对不行。
工作目录也可以限制:
WORKING_DIR=D:/AI/claude_code
Claude 的文件操作默认限制在这个目录下,不会跑到你其他地方去。
如果你要同时接钉钉
钉钉配置比 Telegram 麻烦一些,需要在钉钉开放平台创建企业内部应用并拿到三个值:AppKey、AppSecret、AgentId,再加一个 webhook 签名密钥。
本地开发时因为没有公网 IP,可以用 ngrok 临时暴露端口:
ngrok http 3000
# 把 https://xxx.ngrok.io/dingtalk/webhook 填到钉钉消息接收地址
Telegram 和钉钉可以同时运行,在 .env 里把两边参数都填上,服务启动时会自动注册两个适配器。
扩展到其他平台
项目用接口隔离了平台差异。如果你想接入微信、Slack 或者其他 IM,实现 IMAdapter 接口就够了:
export class MyIMAdapter implements IMAdapter {
readonly platform = "myim" as const;
onMessage(handler: MessageHandler): void { /* 注册消息处理器 */ }
async sendMessage(msg: OutgoingMessage): Promise<void> { /* 发送消息 */ }
async start(): Promise<void> { /* 启动 */ }
async stop(): Promise<void> { /* 停止 */ }
}
然后在 src/index.ts 里 router.registerAdapter(new MyIMAdapter(...)) 注册一行,核心逻辑完全不用动。
Docker 部署
如果想让服务一直跑着不依赖本地终端,用 Docker:
docker-compose up -d
Dockerfile 已经做了生产优化:npm ci --omit=dev 只安装运行时依赖,镜像不包含 TypeScript 编译器、测试框架等开发工具。
适合哪些场景
-
外出时临时查代码:让 Claude 帮你检索项目里的某个函数实现
-
私人知识库问答:把工作目录指向你的笔记或文档目录,用自然语言提问
-
轻量远程辅助:给信任的同事加白名单,让他们也能查你本地项目的特定内容
不适合的场景:把 ALLOWED_TOOLS 开到 Bash 然后对外公开------那等于给陌生人开了你电脑的 Shell。