首页
/ claude-mem 自定义模式 Telegram 通知接入指南:Bot 配置、触发规则与安全边界

claude-mem 自定义模式 Telegram 通知接入指南:Bot 配置、触发规则与安全边界

2026-09-06 18:34:34作者:韦蓉瑛

本指南面向在 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_RUNTIMEserver,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_DIRsettings.jsonenv.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_TOKENCHAT_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、对应的 observationIdsprojectmemorySessionId。因此:

  • 通知的粒度是"每条被 AI 压缩为 observation 的记忆";
  • 通知发生的时机是压缩批次处理完毕之时;
  • 若某类型此刻尚未生成任何 observation,自然不会触发消息——这能解释「测试消息到了、但某类观察从不提醒」的现象(多半是该类型从未被记录,而不是通知器故障)。

单条发送失败不会中断整个批次:postOne 抛错后由通知器捕获并写入 logger.warn('TELEGRAM', ...) 日志(见 TelegramNotifier.ts),随后继续处理下一条 observation。

从零创建一个可用的 Telegram Bot

参照官方 Bot 生态约定,接入前需要先建立 Bot 并取得凭据。完整步骤:

  1. 在 Telegram 中打开官方 @BotFather(Telegram 机器人管理与 Bot API 的官方起点)。
  2. 发送 /newbot,依次指定一个展示名称,再指定一个bot 结尾的唯一用户名(如 claude_mem_alerts_bot)。
  3. BotFather 会返回一个 HTTP API 鉴权 token。把它当作密码对待——任何持有该 token 的人都能完全控制这个 Bot,可向你的会话发消息、读取由 getUpdates 暴露的更新。
  4. 打开刚创建的新 Bot,点击 Start,并主动给它发一条消息。Telegram 的规则是 Bot 在用户主动联系之前不能发起私聊,所以"先打招呼"这一步是后续自动发现 chat ID 的前提。
  5. 在获得用户明确同意后,运行本技能目录下的安全配置助手 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)。该助手执行的核心流程逐段拆解如下:

  1. 解析数据目录:优先读取 CLAUDE_MEM_DATA_DIR,否则读取 ~/.claude-mem/settings.json 中的 env.CLAUDE_MEM_DATA_DIR 覆盖项,默认落到 ~/.claude-mem
  2. 优先复用已保存凭据:若环境变量 CLAUDE_MEM_TELEGRAM_BOT_TOKEN 或既有设置中已存在 token,会以 [Y/n] 交互征询是否沿用,避免重复粘贴。
  3. 隐藏输入收集 token:token 通过开启 raw-mode 的终端逐字读取,屏幕只回显 占位符(支持退格与 Ctrl-C 取消),保证 token 不进入 transcripts、shell 历史或聊天记录(见 configure-telegram.mjs)。
  4. getMe 校验:调用 Telegram Bot API 的 getMe 确认 token 有效,并回显形如 Authenticated as @xxx. 的 Bot 用户名(用户名本身可安全显示)。
  5. Chat ID 自动发现:在引导用户给 Bot 发消息后,通过 getUpdates 收集最近聊天;解析范围覆盖普通消息、已编辑消息、频道帖文与回调查询等 update 形态(见 configure-telegram.mjs)。单个聊天直接询问是否采用,多个则列出候选。发现失败(常见于 webhook 占用 updates)时允许手动输入;数值必须是纯整数(群组通常为负),也允许 @channel 用户名。
  6. sendMessage 连通测试:向目标会话发送 ✅ claude-mem Telegram notifications are connected.,在写入配置前先验证整条链路可用。
  7. 原子写入与备份:对既有 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):

  1. 重启返回新健康 worker 且退出码正常;
  2. 模式文件存在于解析出的数据目录;
  3. settings.jsonCLAUDE_MEM_MODE 指向预期的模式 ID(且不暴露任何密钥);
  4. 有 MCP 时用 session_start_context 拉取完整启动上下文,否则调用本地 worker 的 /api/context/inject?project=mode-creator-verification&full=true
  5. 启动上下文中出现 Mode: <mode name> (<mode id>)
  6. 若配置了 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.tstests/shared/settings-defaults-manager.test.ts

登录后查看全文
热门项目推荐
相关项目推荐