claude-mem 自定义模式 Telegram 通知接入指南:Bot 配置、触发规则与安全边界
本指南面向在 claude-mem 中以「mode-creator」技能创建自定义模式(mode)并启用实时告警的场景,完整讲解 Telegram 通知系统的设置读取、触发匹配机制、Bot 创建到安全配置助手的全链路操作,以及常见故障的排查路径。读完你将掌握 claude-mem 的 Telegram 通知五个核心环境变量、OR 触发语义、消息格式与隐私边界,并能独立完成「新建 Bot → 安全录入凭据 → 配置触发条件 → 验证告警送达」的完整闭环。本文是 mode-creator 技能内置的 telegram.md 参考文档的技术展开,辅以仓库内通知器源码、默认设置管理与集成测试作为实现佐证。
前置条件与适用语境
claude-mem 把 Telegram 告警设计为「用户明确选择启用(opt in)」的增强能力,而不是默认行为。在 mode-creator 的交互流程中,只有当用户在第 4 步明确要求「记录到某些类型或标签时收到 Telegram 通知」,技能才会引导进入本文所讲的配置流程;如果用户拒绝,则所有 Telegram 设置保持原样、不做任何改动(见 SKILL.md)。因此 telegram.md 参考文档本身的语义是"用户同意后才会被读取"——它并不是一个随时需要执行的通用指南。
从依赖环境看,完整接入 Telegram 需要同时具备:
- 本地已安装并运行 claude-mem worker(注意:若
CLAUDE_MEM_RUNTIME为server,mode-creator 会因无法为共享服务器安全安装单用户模式而在写入前停止,Telegram 配置同样不适用); - Node.js 20+(configure-telegram.mjs 依赖原生
fetch); - 可用的交互式终端(凭据输入要求 TTY)与联网环境;
- 一个你自己的 Telegram 账号。
通知器如何读取设置:settings.json 的五个配置项
claude-mem 的 Telegram 通知器不读取命令行参数,也不读取项目级配置,而是从 claude-mem 数据目录下的 settings.json 中读取五个与 Telegram 相关的设置项。配置文件默认位于 ~/.claude-mem/settings.json,也可通过环境变量 CLAUDE_MEM_DATA_DIR 或 settings.json 中 env.CLAUDE_MEM_DATA_DIR 字段指定其他数据目录(路径解析逻辑见 configure-telegram.mjs)。
| 配置项 | 含义 | 取值说明 |
|---|---|---|
CLAUDE_MEM_TELEGRAM_ENABLED |
通知总开关 | 字符串 "true" 表示启用;通知器在读到非 "true" 值时直接返回 |
CLAUDE_MEM_TELEGRAM_BOT_TOKEN |
Bot 鉴权令牌 | BotFather 下发,等同密码,务必以 0600 权限保存 |
CLAUDE_MEM_TELEGRAM_CHAT_ID |
消息接收方 | 私聊/用户为正整数;群组通常为负数;也接受 @channel_username |
CLAUDE_MEM_TELEGRAM_TRIGGER_TYPES |
触发用观察类型(逗号分隔) | 与 observation 的 type 精确匹配,匹配即告警 |
CLAUDE_MEM_TELEGRAM_TRIGGER_CONCEPTS |
触发用概念标签(逗号分隔) | 与 observation 携带的任一 concept 精确匹配即告警 |
其中类型与概念列表均以小写 ID 形式存储与匹配——这一点在排查「测试成功却不告警」时尤为关键(见下文故障排查)。类型与概念的区别:一条 observation 有且仅有一个 type(互斥的种类),但可以携带多个 concept(可复用的跨领域标签)。mode-creator 在收集用户偏好时正是按此模型与用户确认分类法。
从源码看,上述字段在 SettingsDefaultsManager.ts 中声明为设置接口的一部分,并给出了出厂默认值:CLAUDE_MEM_TELEGRAM_ENABLED: 'true'、BOT_TOKEN 与 CHAT_ID 均为空串、TRIGGER_TYPES 默认 'security_alert,sensitive'(见 SettingsDefaultsManager.ts)。也就是说,即使总开关默认开启,只要 Bot 凭据尚未配置,通知器也不会发送任何消息;一旦完成凭据配置,默认就会对 security_alert(安全告警)与 sensitive(敏感)两类观察发出提醒,直到你主动改写 TRIGGER_TYPES。同时该类还内置了旧版兼容迁移:当读到历史遗留值 security_alert 时会将其升级为当前默认触发集(见 SettingsDefaultsManager.ts)。
触发匹配语义:type 与 concept 的 OR 逻辑
触发规则是本文档最核心的语义,一句话概括为:
一条 observation 在其唯一类型命中任一配置的触发类型,或者其任一概念命中任一配置的触发概念时,即触发通知。两种触发列表都为空时,不发送任何消息。
匹配是同一条 observation 内部的 OR 关系,而不是多字段 AND。在通知器实现 TelegramNotifier.ts 中可以看到完整判定:
const matchesType = triggerTypes.includes(obs.type);
const matchesConcept = obs.concepts.some(c => triggerConcepts.includes(c));
if (!matchesType && !matchesConcept) continue; // 不命中则跳过
这段代码意味着:一个类型为 experiment_outcome、携带 security 标签的观察,只要配置了 TRIGGER_CONCEPTS=security 就会告警;同理,一个类型命中但没有任何命中概念也会告警。mode-creator 在询问用户时也明确提示「matching is OR: any selected type or any selected concept sends an alert」(见 SKILL.md),避免用户误以为必须类型与标签同时命中。
通知器还有一个"前置闸门"式的三段防御(见 TelegramNotifier.ts):ENABLED !== 'true' 直接返回 → Bot token 或 Chat ID 缺失直接返回 → 两种触发列表同时为空直接返回。只有三道检查全部通过后,才会逐条遍历 observation 做匹配,因此未配置触发列表时绝不会产生任何消息或 API 调用。
通知内容与隐私边界:只发摘要、不发正文
告警消息不包含 observation 的完整叙事(narrative)或事实清单(facts),而是由四个字段拼成一行紧凑摘要。以源码 TelegramNotifier.ts 为准,实际发送格式为:
{emoji} *{type}* — {title}
{subtitle}
Project: `{project}` · obs \#{observationId}
对应到 Telegram 渲染层:通知器使用 parse_mode: MarkdownV2 发送,并在拼装前对 type/title/subtitle/project 中所有 MarkdownV2 保留字符(_*[]()~>#+-=|{}.! 等)做转义,防止特殊字符破坏消息排版(见 [TelegramNotifier.ts](https://gitcode.com/GitHub_Trending/cl/claude-mem/blob/be44b6c8e238a7e2bc5b3403c05afac071a59ead/src/services/integrations/TelegramNotifier.ts?utm_source=gitcode_repo_files#L14-L25))。消息开头的 emoji 依类型区分:security_alert 用 🚨、security_note 用 🔐、sensitive` 用 🤫,其余类型统一用 🔔(见 TelegramNotifier.ts)。
隐私边界必须在使用前向用户讲透:虽然正文(facts)不进消息,但 title 与 subtitle 本身完全可能包含敏感信息——例如「客户 A 的合同泄露事件」「某位患者的诊断结论」。因此在选择触发类型/标签时,应主动避开那些标题极易沾染敏感内容的类别。mode-creator 的技能开场白与第 4 步提问中都复述了这一提示:「Alerts include the observation type, title, subtitle, project, and observation ID, so avoid selecting categories that may expose sensitive material」(见 SKILL.md)。同时参考文档要求:配置前必须向用户明确说明这一隐私取舍,而不是默认用户知情。
通知在何处触发:worker 会话压缩后的回执
从集成位置看,Telegram 通知并非实时随转录逐条发送,而是在 worker 完成一次会话压缩、产出结构化 observations 之后统一发送。在 ResponseProcessor.ts 中,notifyTelegram 在确认已声明消息、触发压缩事件上报之后、syncAndBroadcastObservations 同步广播之前被调用,入参是一次压缩产出的全部 observations、对应的 observationIds、project 与 memorySessionId。因此:
- 通知的粒度是"每条被 AI 压缩为 observation 的记忆";
- 通知发生的时机是压缩批次处理完毕之时;
- 若某类型此刻尚未生成任何 observation,自然不会触发消息——这能解释「测试消息到了、但某类观察从不提醒」的现象(多半是该类型从未被记录,而不是通知器故障)。
单条发送失败不会中断整个批次:postOne 抛错后由通知器捕获并写入 logger.warn('TELEGRAM', ...) 日志(见 TelegramNotifier.ts),随后继续处理下一条 observation。
从零创建一个可用的 Telegram Bot
参照官方 Bot 生态约定,接入前需要先建立 Bot 并取得凭据。完整步骤:
- 在 Telegram 中打开官方 @BotFather(Telegram 机器人管理与 Bot API 的官方起点)。
- 发送
/newbot,依次指定一个展示名称,再指定一个以bot结尾的唯一用户名(如claude_mem_alerts_bot)。 - BotFather 会返回一个 HTTP API 鉴权 token。把它当作密码对待——任何持有该 token 的人都能完全控制这个 Bot,可向你的会话发消息、读取由 getUpdates 暴露的更新。
- 打开刚创建的新 Bot,点击 Start,并主动给它发一条消息。Telegram 的规则是 Bot 在用户主动联系之前不能发起私聊,所以"先打招呼"这一步是后续自动发现 chat ID 的前提。
- 在获得用户明确同意后,运行本技能目录下的安全配置助手
configure-telegram.mjs(用法见下一节)。它会以隐藏终端输入收集 token、用getMe校验、尽量用getUpdates自动发现最近会话、用sendMessage发送连通测试,最终以仅属主可读(owner-only)的权限把结果写入配置。
需要留意的是:步骤 1~4 属于必须由真人账号在 Telegram 内完成的手工动作,Agent 无法代办。mode-creator 明确划分了这条人工边界:如果 Agent 运行环境无法把交互式终端交给用户,就只展示确切的助手命令并暂停等待用户在本地执行,绝不要求用户把 token 粘回聊天里作为一种变通方案(见 SKILL.md)。
使用 configure-telegram.mjs 安全写入凭据
技能目录下的 configure-telegram.mjs 是唯一推荐的凭据录入路径。其命令行接口支持两个可选参数,用于在写入设置的同时合并触发条件:
node <skill-directory>/scripts/configure-telegram.mjs [--types <csv>] [--concepts <csv>]
其中 <skill-directory> 指向 mode-creator 技能所在目录(即本仓库 plugin/skills/mode-creator);--types/--concepts 为逗号分隔的类型与概念清单,会与已存在的触发配置去重合并而非覆盖(mergeCsv 基于 Set 实现,见 configure-telegram.mjs)。该助手执行的核心流程逐段拆解如下:
- 解析数据目录:优先读取
CLAUDE_MEM_DATA_DIR,否则读取~/.claude-mem/settings.json中的env.CLAUDE_MEM_DATA_DIR覆盖项,默认落到~/.claude-mem。 - 优先复用已保存凭据:若环境变量
CLAUDE_MEM_TELEGRAM_BOT_TOKEN或既有设置中已存在 token,会以[Y/n]交互征询是否沿用,避免重复粘贴。 - 隐藏输入收集 token:token 通过开启 raw-mode 的终端逐字读取,屏幕只回显
•占位符(支持退格与 Ctrl-C 取消),保证 token 不进入 transcripts、shell 历史或聊天记录(见 configure-telegram.mjs)。 - getMe 校验:调用 Telegram Bot API 的
getMe确认 token 有效,并回显形如Authenticated as @xxx.的 Bot 用户名(用户名本身可安全显示)。 - Chat ID 自动发现:在引导用户给 Bot 发消息后,通过
getUpdates收集最近聊天;解析范围覆盖普通消息、已编辑消息、频道帖文与回调查询等 update 形态(见 configure-telegram.mjs)。单个聊天直接询问是否采用,多个则列出候选。发现失败(常见于 webhook 占用 updates)时允许手动输入;数值必须是纯整数(群组通常为负),也允许@channel用户名。 - sendMessage 连通测试:向目标会话发送
✅ claude-mem Telegram notifications are connected.,在写入配置前先验证整条链路可用。 - 原子写入与备份:对既有
settings.json先生成带时间戳的.backup-<ISO 时间>备份并chmod 0600,随后将五个设置(含合并后的触发列表)以0600权限原子写入(临时文件 +rename,见 configure-telegram.mjs),最后输出机器可读 JSON 结果,报告ok、Bot 用户名、chat ID、生效的触发类型/概念、settings 路径与备份路径。
如果你更希望触发条件在模式安装阶段就一次到位,mode-creator 还提供了另一条入口:使用 install-mode.mjs 的 --telegram-types 与 --telegram-concepts 参数,在安装并激活自定义模式的同时合并通知触发条件(两者都是逗号分隔、与既有触发去重合并,见 SKILL.md)。若用户谢绝告警,则省略这两个参数即可,安装器不会改动任何 Telegram 设置。两条路径的落点一致:都写在数据目录 settings.json 中,且都采用"先备份、后原子写入"的防损坏策略。
必须遵守的安全规则
Telegram token 在本项目中被视为与密码等价的敏感凭据,参考文档与技能"Ground rules"共同构成了以下硬性约束(对应实现可回看 configure-telegram.mjs 的隐藏输入与 TelegramNotifier.ts 的设置读取方式):
- 永不通过普通聊天回复或交互式提问索取 token——这类回答会被转录进会话记录;
- 永不把 token 放进打印到终端的 URL、shell 命令、聊天中展示的环境变量赋值或命令行参数;
- 配置完成后不得整体打印
settings.json; - 允许向用户安全报告的仅是:token 是否已存在(布尔结论)、
getMe返回的 Bot 用户名、选定的 chat ID; settings.json及其备份文件权限必须为0600,数据目录为0700(实现中atomicWriteJson已强制这两档权限);- 一旦发现 token 可能已泄露,应引导用户到 BotFather 执行
/revoke(或重新生成)再继续配置,而不是继续沿用旧 token。
mode-creator 的 Ground rules 同样要求 Agent 不得在聊天、命令参数、日志或工具输出中暴露 token,也不得编辑插件缓存或内置模式——自定义内容一律安装到解析出的数据目录的 modes/ 下(见 SKILL.md)。
告警配置后的重启与验证
完成配置 ≠ 立即生效。按 mode-creator 第 7 步要求,settings 变更后必须重启 worker 再验证,否则新配置不会被正在运行的通知链路加载:
npx claude-mem restart
npx claude-mem status
若 CLI shim 不可用,可用已安装插件的 scripts/worker-service.cjs restart(以 Bun 运行)作为备选重启路径。重启后建议核验以下事项(摘自 SKILL.md):
- 重启返回新健康 worker 且退出码正常;
- 模式文件存在于解析出的数据目录;
settings.json中CLAUDE_MEM_MODE指向预期的模式 ID(且不暴露任何密钥);- 有 MCP 时用
session_start_context拉取完整启动上下文,否则调用本地 worker 的/api/context/inject?project=mode-creator-verification&full=true; - 启动上下文中出现
Mode: <mode name> (<mode id>); - 若配置了 Telegram,确认连通测试消息已到达。
若 worker 意外回退到内置 code 模式,应查看 worker 日志中的模式校验/查找错误并修复模式,再重复上述重启;不要把回退当成激活成功。整个 mode-creator 流程结束后的交接清单里,Telegram 部分只需汇报"触发类型/概念(或 unchanged)"与测试消息送达情况,永远不包含 token。
故障排查速查表
参考文档给出了经过实战检验的六类典型问题,结合源码可将现象、原因与处置一一对应:
| 现象 | 原因 | 处置 |
|---|---|---|
getMe failed: Unauthorized |
token 错误或已被撤销 | 在 BotFather 生成新 token 后重试 |
| 找不到任何聊天(No chats found) | 用户尚未与 Bot 建立会话 | 用户需对 Bot 按 Start 并发一条消息后重试 |
getUpdates 提示有 webhook 正在接管 |
webhook 占用 updates 时无法自动发现聊天 | 手动输入数字 chat ID;未经明确许可不得删除他人 webhook |
sendMessage 提示 chat not found |
chat ID 有误,或 Bot 未被 start / 未加入群组 | 核对 chat ID;确保私聊已启动、群组中已添加 Bot |
| 群组告警不生效 | 群组 ID 或成员关系问题 | 把 Bot 加入群组、发送一条 Bot 可接收的消息,并使用负数群组 ID |
| 测试消息成功但观察从不告警 | 触发列表与真实 observation 不一致 | 核对生成的 observation 的 type/concepts 是否与配置的小写 ID 精确一致;settings 变更后重启 worker |
最后一个问题在实现层面有两点直接佐证:触发判定是严格的大小写敏感字符串 includes(见 TelegramNotifier.ts),且通知发生在会话压缩批次之后而非转录即时(见上文"通知在何处触发"小节)。因此排查时既要点检 ID 拼写与大小写,也要确认该类别确实产生了 observation——此外,若你想立刻验证而非等待真实记录,配置助手内置的 sendMessage 测试消息就是最直接的链路探针。
结语
claude-mem 的 Telegram 通知是一条精心收敛的"摘要级"告警通道:设置收敛在数据目录 settings.json 的五个键中,触发语义是"单类型命中 OR 单概念命中",消息只携带类型、标题、副标题、项目与观察 ID,发送发生在 worker 会话压缩之后。接入的安全重心在于把 token 视为密码——只经由隐藏终端输入、只写入 0600 配置、绝不进入任何可被转录或打印的位置。配合 mode-creator 技能的交互式引导,你可以把自定义模式中最关心的观察类型与概念标签映射为实时的 Telegram 提醒,从而在重要记忆落库的第一时间感知到它。
如需深入实现细节,建议继续阅读:通知器实现 src/services/integrations/TelegramNotifier.ts、默认设置与迁移 src/shared/SettingsDefaultsManager.ts、触发调用点 src/services/worker/agents/ResponseProcessor.ts、安全配置助手 plugin/skills/mode-creator/scripts/configure-telegram.mjs,以及针对本技能的测试用例 tests/utils/mode-creator-skill.test.ts 与 tests/shared/settings-defaults-manager.test.ts。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00