tgcc 是一个 Telegram Bot。用户在手机上发送任务,Bot 在电脑上启动 Claude Code,再把执行状态和最终结果发回 Telegram。
项目从 2026 年 2 月开发到 6 月。最终版本有 11016 行源码、15029 行测试代码和 7887 行文档,发布了 5 个 Git tag 和 2 个 PyPI 版本。6 月以后,已停止使用和维护这个项目。
结论
短进程适合 Telegram 这类请求式入口,进程容易启动、终止和清理,缺点是无法打开 Claude Code 的终端选择器。正式版本没有把 /model、/effort 和 /permissions 的交互界面搬进 Telegram,而是在 Bot 中提供对应设置。用户为当前 chat 选择模型、推理强度和权限后,tgcc 保存这些值,后续任务继续使用同一组设置。
tmux 抓屏不能作为可靠的回答数据源。TUI 可能仍在重绘,解析器无法恢复屏幕上尚未出现的数据。能够读取 JSONL transcript 时,应直接消费结构化事件,只在处理终端选择器时抓屏。
自动化代理可以持续发现并修复局部问题,项目范围和停止条件仍需人工控制。四天内产生的 480 个提交通过了各自的检查,最终没有进入发布版本。
测试只能验证预先定义的行为。真实凭据进入测试数据后,覆盖率和通过数量无法发现来源错误。凭据轮换和公开历史清理也不能由代码补丁替代。
tgcc 完成了从 Telegram 调用 Claude Code 的目标。项目没有获得足以支撑长期维护的真实使用反馈,我也转向了其他远程入口,因此在 2026 年 6 月停止开发。
一、从消息转发开始
最初需求只有三个步骤。
Telegram 接收消息
电脑运行 Claude Code
Telegram 返回结果
第一版在一天内完成了包结构、配置、执行器、流式输出、Bot 命令和发布流程。当天首先暴露的是输出缓冲问题。
22:08 stdout buffer 调到 50MB
22:09 stream buffer 调到 2GB
22:11 stream buffer 收回到 100MB
Claude Code 的输出会超过 asyncio 默认的 64KB 流缓冲。缓冲区只是开始,连续对话很快带来了会话和并发问题。
tgcc 保存 Telegram chat 与 Claude session 的对应关系,下一次请求通过 --resume 恢复上下文。同一个 chat 内的任务进入 FIFO 队列,避免两次执行同时修改同一段会话。不同 chat 之间可以并行。
长任务需要持续反馈。Bot 将运行状态与最终答案分开,状态消息显示工具调用、耗时和停止按钮,最终答案单独分页发送。这个结构一直保留到最后一个版本。
项目随后增加多实例配置。每个项目拥有独立的 Bot、环境变量、运行状态和日志。多实例又要求统一处理启动、停止、重启、实例发现和进程冲突。准备公开发布后,项目继续加入群聊权限、日志脱敏、安装诊断、文件权限修复和发布检查。
二、短进程架构的边界
tgcc 每次收到请求都会启动一个新的 claude -p 进程。任务结束后,进程随之退出。
claude -p \
--resume <session_id> \
--output-format stream-json \
--verbose
会话状态由 Claude Code 管理,tgcc 只维护 chat 与 session id 的对应关系。短进程也便于设置超时、终止任务和清理异常。
长驻交互终端需要处理 TTY 状态、ANSI 输出、输入提示、崩溃恢复和进程池。短进程避开了这些问题,同时失去了终端交互能力。
claude -p 运行在 headless 模式。/model、/effort 和 /permissions 等命令依赖终端选择器,无法直接通过 Telegram 使用。为了解决这几个命令,我开始实现 tmux 交互模式。
三、tmux 抓屏为什么失败
交互模式在 tmux 中启动完整的 claude,用 send-keys 输入文字,再用 capture-pane 读取屏幕。
这个方案先后遇到四类问题。
alt-screen 没有完整历史
Claude Code 的 TUI 使用备用屏幕,capture-pane -S - 无法取得完整 scrollback。临时方案是将 pane 高度设为 200 行,尽量让一轮输出留在当前帧中。长输出仍可能被截断。
无法可靠判断任务结束
Claude Code 的 spinner 会显示随机词,固定字符串匹配无法判断运行状态。Crunched for 3s 一类文本在任务结束后仍会留在屏幕上,也不能作为运行标志。最后采用连续两帧完全相同的判定方式。
Markdown 会干扰边界识别
早期解析器使用横线定位输入框。Markdown 分隔线和表格边框也包含横线,回答会被错误截断。解析器后来改用孤立的空 ❯ 作为输入框锚点。
抓到的是渲染中间状态
前三类问题都能通过修改解析器缓解。Markdown 表格暴露了抓屏方案的根本限制。抓取结果有表头、分隔线和底边,中间的数据行却是空的。解析器测试没有发现错误,缺失发生在 capture-pane 之前。
Claude Code 会先绘制表格框架,再填入数据。稳定检测结束时,TUI 可能仍在重绘。capture-pane 读取的是当前屏幕,无法保证它对应完整回答。
后续实现改为读取 Claude Code 的 JSONL transcript。transcript 保存结构化事件和原始 Markdown,不包含终端边框,也不存在表格渲染中间帧。tmux 只负责发送输入,普通回答由 transcript reader 读取。终端选择器等不写入 transcript 的界面继续使用抓屏。
增量读取时,reader 只有在整行 JSON 成功解析后才推进 byte offset。读到尚未写完的行就停止,下一轮从原位置重试。文件被截断且 offset 大于文件大小时,reader 从头读取。
重启又暴露了一个问题。tmux 是独立 daemon,tgcc restart 只重启 Bot,原来的 Claude Code 进程仍然存在。旧实现会生成新的 session id,reader 找不到对应 transcript,随后静默退回抓屏。
修复后,chat 与 interactive session id 被持久化到 status.json。tmux session 存活时复用旧 id,已经退出才创建新 id。这里不能使用 --resume,因为 resume 会派生新的 session id,transcript 路径也会改变。
这条分支最终没有合并。正式版本继续使用短进程,模型、推理强度和权限改由 tgcc 保存每个 chat 的设置。主分支一度保留了 /screen、/key 和 tmux 模式文档,但没有对应代码,发布前已经删除。
四、四天 480 个提交
2026 年 5 月 29 日到 6 月 1 日,项目产生了 480 个提交,四天分别为 66、199、174 和 41 个。
这批工作主要围绕开源发布检查展开。AI 编写检查脚本,扫描密钥、文件权限、配置、文档和发布流程。检查发现问题后,AI 修改代码、补测试、更新报告,再运行下一轮检查。
修改次数最多的文件集中在发布文档和检查工具。
297 次 CHANGELOG.md
281 次 docs/releases/v0.1.0.md
219 次 tests/release_readiness_fixture.py
201 次 scripts/release_readiness_config.py
145 次 scripts/check_release_readiness.py
提交信息记录了约束、否决方案、影响范围、测试结果和未验证项。单个提交大多有明确目标,连续运行却形成了自我扩张的检查循环。检查脚本新增规则,AI 修复对应问题,修复又产生新的检查项。
这 480 个提交中的发布检查和版本文档没有进入最终仓库。项目版本从 0.1 推进到 0.7,也没有对应七轮用户验证。自动化提高了局部任务的完成速度,没有替项目判断继续投入是否有价值。
五、脱敏测试泄漏了真实 Token
2026 年 6 月 2 日,Robin 报告 tests/test_sanitizer.py 中存在一个仍然有效的 Telegram Bot Token。Token 在 5 月 25 日进入公开提交,暴露了八天。
sanitizer.py 用于清理 Claude Code 输出中的 Token、API key 和私钥。测试需要一段符合 Telegram Token 格式的字符串,测试数据却使用了真实 Token。
泄漏发生在标题为 Prevent tgcc instance collisions and secret leakage 的提交中。该提交记录了 245 个测试通过,覆盖率为 86%。现有测试验证了脱敏器能否识别 Token,没有验证测试数据是否来自真实凭据。
代码完成了两项修复。
- 用运行时生成的无效 Token 替换真实值。
- 增加仓库密钥扫描测试。
已经泄漏的 Telegram Token 仍需在 BotFather 中手动轮换,现有记录无法确认这一步是否完成。代码修复也无法删除公开 Git 历史里的旧 Token。
从 Git 历史和 GitHub 创建时间判断,仓库随后被删除并重新创建。当前 GitHub 历史从 Initial release: tgcc v0.8.0 开始,旧提交不再可达。本地保留的旧历史有 598 个提交,重建后的主分支有 54 个提交。
六、项目结束时的状态
仓库重建后,项目继续完成安全加固和重构。
群聊权限改为默认拒绝,恢复的 session id 在进入 claude --resume 参数前必须通过 UUID 校验。脱敏器增加 ANSI、OSC、URL 凭据和 HTTP Basic Auth 的处理。
Executor.run 从 367 行拆到 91 行,并提取 6 个辅助方法。整个 executor.py 从 911 行增加到 1034 行。重构降低了单个方法的复杂度,同时增加了函数边界和文件内跳转。
后续又加入 3 个 Protocol 接口和 ServiceContainer。原计划中的统一配置、状态持久化抽象和命令注册框架没有继续实施。BotCommandHandlers 已经依赖二十多个 TGBot 属性,进一步拆分的收益不足以覆盖新增复杂度。
项目最终规模如下。
| 项目 | 数量 |
|---|---|
| 源码 | 11016 行 |
| 测试代码 | 15029 行 |
| 文档 | 7887 行 |
| 测试函数 | 775 个 |
| Git tag | 5 个 |
| PyPI 版本 | 2 个 |
到 2026 年 9 月 3 日,GitHub 为 0 star、0 fork、0 watcher。两个 PR 均来自 Dependabot,没有真人 issue 或 PR。PyPI 不含镜像的累计下载量为 403 次,其中 251 次集中在两个发布日期。下载数据无法证明有多少真人实际使用。
6 月 9 日,开发记录已经转向调查 Claude Code Agent SDK 等替代方案。tgcc 此后只收到一次 Dependabot 自动提交,项目停止维护。