OmX(oh-my-codex)Discord 集成实战:Webhook 与 Bot Token 的选型、配置与回复监听
导读:本指南围绕 OmX(oh-my-codex)的 Discord 通知体系展开,完整说明两条彼此独立的 Discord 通知通道——入站 Webhook URL 与 Discord Bot Token——的适用场景、创建步骤、最小权限与配置文件写法。读完本文,你将掌握在 .omx-config.json 或环境变量中配置 Webhook 单向通知、Bot 双向回复监听(status 会话状态查询)以及混合模式(Hybrid)的具体方法,并能依据仓库源码理解每条配置项背后的生效逻辑与常见故障根因。
两个 Discord 概念,两条独立的 OMX 配置通道
Discord 本身提供两种截然不同的集成身份,OMX 为它们分别设计了独立的配置键,互不混用:
- Incoming Webhook URL:一个 HTTPS 端点,只负责向单个频道推送出站通知。它不需要以 Discord Bot 用户身份登录,配置简单、作用域限定在频道内。
- Bot Token:Discord Developer Portal 中某个应用/机器人持有的密钥。通过它,OMX 可以调用 Discord Bot API 完成"以 Bot 身份发送"以及需要读取频道消息、做消息关联的**回复/状态(reply/status)**工作流。
从类型定义可以确认这两条通道在 OMX 中是完全独立的第一方平台:NotificationPlatform 将 discord(Webhook)与 discord-bot(Bot)并列,并分别定义了 DiscordNotificationConfig(webhookUrl) 与 DiscordBotNotificationConfig(botToken + channelId) 两种结构。
无论使用哪种凭据,都必须保持私密:不要在公开 issue、日志、截图或共享配置中粘贴 Webhook URL 或 Bot Token。
我应该用哪种凭据?
| OMX 模式 / 目标 | 需要的 Discord 凭据 | OMX 配置平台键 | 常用环境变量 |
|---|---|---|---|
| 仅 Webhook 出站通知 | 一个 Incoming Webhook URL | notifications.discord |
OMX_DISCORD_WEBHOOK_URL |
| 仅 Bot 出站通知 | Bot Token + 目标频道 ID | notifications["discord-bot"] |
OMX_DISCORD_NOTIFIER_BOT_TOKEN、OMX_DISCORD_NOTIFIER_CHANNEL |
回复监听 / 对被跟踪 OMX 通知的 status 回复 |
Bot Token + 目标频道 ID + 被授权的 Discord 用户 ID,并开启回复 | notifications["discord-bot"] 加 notifications.reply |
OMX_DISCORD_NOTIFIER_BOT_TOKEN、OMX_DISCORD_NOTIFIER_CHANNEL、OMX_REPLY_ENABLED、OMX_REPLY_DISCORD_USER_IDS |
| Webhook + Bot 混合(Hybrid) | 一个 Webhook URL、一个 Bot Token、一个目标频道 ID | 同时配置 notifications.discord 与 notifications["discord-bot"] |
以上 Webhook 与 Bot 的环境变量全部设置 |
简单选型原则:只需要 OMX 单向推送通知,用 Webhook 就够了;需要 Discord API 能力(Bot 身份投递、回复关联、reply/status 监听)时,再上 Bot 模式。
从源码看,两条通道的开关逻辑是并列的:buildConfigFromEnv 中 Bot 通道要求 OMX_DISCORD_NOTIFIER_BOT_TOKEN 与 OMX_DISCORD_NOTIFIER_CHANNEL 同时存在才会启用,而 Webhook 通道只要 OMX_DISCORD_WEBHOOK_URL 存在即启用(src/notifications/config.ts);事件派发时 getEnabledPlatforms 会同时检查 discord 与 discord-bot(src/notifications/config.ts)。
为什么混合模式只需要一个 Webhook?
一个 Webhook 本身就是一个完整的、面向单频道的出站投递端点。Bot 是另一个 Discord 身份,它凭 Bot Token 直接调用 Discord API 发送 Bot 消息,并不需要自备 Webhook。因此混合模式下 OMX 只需要:
- 一个 Webhook URL,供 Webhook 发送器使用;
- 一个 Bot Token + 频道 ID,供 Bot 发送器/监听器使用。
只有当你有意创建第二个 Webhook 身份、投递到另一个频道或需要独立轮换凭据时,才需要创建第二个 Webhook——仅仅因为同时配置了 Bot 模式并不要求第二个 Webhook。
创建 Incoming Webhook URL
- 在 Discord 中打开 OMX 要投递的服务器与频道;
- 进入服务器设置或频道设置 → Integrations(集成) → Webhooks;
- 选择 New Webhook(新建 Webhook),选定目标频道、命名,然后复制 Webhook URL;
- 将其保存为
OMX_DISCORD_WEBHOOK_URL,或写入.omx-config.json的notifications.discord.webhookUrl。
Webhook URL 是频道作用域的。如果消息出现在错误的频道,请从目标频道的集成设置中重新创建/复制 Webhook。
创建 Discord Bot Token
- 打开 Discord Developer Portal,创建或选择一个应用(Application);
- 为该应用添加一个 Bot;
- 在 Bot 页面重置/复制 Bot Token,保存为
OMX_DISCORD_NOTIFIER_BOT_TOKEN,或写入notifications["discord-bot"].botToken; - 通过 Developer Portal 的 OAuth2 URL 生成器把 Bot 邀请进你的服务器:勾选
botscope,并且只授予 OMX 需要的权限; - 复制目标频道 ID,保存为
OMX_DISCORD_NOTIFIER_CHANNEL,或写入notifications["discord-bot"].channelId。在 Discord 中复制 ID 通常需要先开启开发者模式(Developer Mode)。
⚠️ 仅有 Bot Token 是不够的:Bot 还必须被邀请进服务器,并且能够看到/投递到目标频道。
最小 Bot 权限与 Intents
针对出站 Bot 通知,在目标频道授予 Bot:
- View Channel(查看频道)
- Send Messages(发送消息)
针对回复/状态工作流,再追加:
- Read Message History(读取消息历史)
- Add Reactions(添加表情回应)——如果你希望"✅ 确认已注入"的表情回应能够成功
基础的出站发送不需要特权 Gateway Intents。如果开启的 Bot/回复监听工作流需要读取消息内容,且你的 Discord 应用设置要求,请在 Developer Portal 中为该 Bot 启用 Message Content Intent(消息内容意图)。除非工作流确实需要,否则保持特权 Intents 关闭。
源码侧可以印证"表情回应确认"这条路径:回复成功注入后,pollDiscordOnce 会向 https://discord.com/api/v10/channels/{channel}/messages/{msg.id}/reactions/✅/@me 发起 PUT,失败仅记录 WARN 日志而不影响主流程(src/notifications/reply-listener.ts)。
配置示例:环境变量与 .omx-config.json
推荐将密钥放在环境变量中。下面的 JSON 展示 .omx-config.json 支持的完整形态,但你可以把机密字段从文件中省略,改用环境变量提供。配置文件位于 codex home 目录下的 .omx-config.json(源码通过 join(codexHome(), ".omx-config.json") 定位,见 src/notifications/config.ts)。
仅 Webhook 出站通知
export OMX_DISCORD_WEBHOOK_URL='https://discord.com/api/webhooks/.../...'
{
"notifications": {
"enabled": true,
"discord": {
"enabled": true,
"webhookUrl": "https://discord.com/api/webhooks/.../..."
}
}
}
仅 Bot 出站通知
export OMX_DISCORD_NOTIFIER_BOT_TOKEN='your-bot-token'
export OMX_DISCORD_NOTIFIER_CHANNEL='123456789012345678'
{
"notifications": {
"enabled": true,
"discord-bot": {
"enabled": true,
"botToken": "your-bot-token",
"channelId": "123456789012345678"
}
}
}
Hybrid:Webhook + Bot 且带回复/状态监听
export OMX_DISCORD_WEBHOOK_URL='https://discord.com/api/webhooks/.../...'
export OMX_DISCORD_NOTIFIER_BOT_TOKEN='your-bot-token'
export OMX_DISCORD_NOTIFIER_CHANNEL='123456789012345678'
export OMX_REPLY_ENABLED='true'
export OMX_REPLY_DISCORD_USER_IDS='111111111111111111,222222222222222222'
{
"notifications": {
"enabled": true,
"discord": {
"enabled": true,
"webhookUrl": "https://discord.com/api/webhooks/.../..."
},
"discord-bot": {
"enabled": true,
"botToken": "your-bot-token",
"channelId": "123456789012345678"
},
"reply": {
"enabled": true,
"authorizedDiscordUserIds": ["111111111111111111", "222222222222222222"]
}
}
}
Webhook 与 Bot 发送均可选配共享 @ 提及:
export OMX_DISCORD_MENTION='<@123456789012345678>'
# 或角色提及,例如 '<@&123456789012345678>'
提及格式在源码中有严格的校验正则:<@!?\d{17,20}>(用户)或 <@&\d{17,20}>(角色),不合法时会被静默丢弃(validateMention);解析后会被映射为 Discord allowed_mentions 中的 users 或 roles 字段(parseMentionAllowedMentions)。
回复监听(Reply Listener)与 status 状态查询的工作原理
回复监听是 Bot 模式独有的能力:它以后台守护进程(daemon)形式运行,周期性轮询 Discord 频道中回复(message_reference)了已跟踪 OMX 通知的消息,校验发送者身份后,将回复文本经 tmux 注入回正在运行的 Codex CLI 会话。仓库内的实现要点:
- 守护进程与状态文件:PID、状态与配置分别写入
~/.omx/state/下的reply-listener.pid、reply-listener-state.json、reply-listener-config.json,所有文件以0600权限写入(src/notifications/reply-listener.ts);启动时为detached子进程,并使用白名单裁剪环境变量,避免把不必要的敏感环境泄露给守护进程(src/notifications/reply-listener.ts)。 - 身份与授权双重校验:只有
authorizedDiscordUserIds中列出的 Discord 用户 ID(正则^\d{17,20}$过滤,见 parseDiscordUserIds)的回复才会被处理;注入前还会用analyzePaneContent验证目标 tmux pane 确实在运行 Codex CLI(置信度低于 0.4 时拒绝注入并清理过期映射,见 injectReply)。 - 输入消毒:
sanitizeReplyInput会剔除控制字符与双向文本控制符(bidi override)、把换行折叠为空格,并转义反引号、$()、${}等 shell 敏感序列后再注入(src/notifications/reply-listener.ts)。 - 限流与确认:守护进程按分钟限流(默认 10 条/分钟,见
RateLimiter,src/notifications/reply-listener.ts);注入成功后给回复消息加 ✅ 反应,并以"回复该消息"的形式回发一段截断的最近终端输出摘要(captureReplyAcknowledgementSummary,src/notifications/reply-listener.ts)。 status命令:被授权的操作者在已跟踪通知下精确回复status一词(大小写不敏感,见 isDiscordStatusCommand),Bot 会回发有界的只读会话摘要(会话状态、子代理摘要、技能激活状态等,组装逻辑见 src/notifications/session-status.ts);若该消息没有关联到任何已跟踪会话,则回复No tracked OMX session is associated with this message.(src/notifications/reply-listener.ts)。
回复监听的调优参数
回复子系统的可调参数集中在 notifications.reply 与对应环境变量中,源码在 getReplyConfig 中完成读取与归一化(越界值会被钳制到合法区间):
| 参数 | 环境变量 | 默认值 | 取值范围(源码钳制) | 说明 |
|---|---|---|---|---|
| 轮询间隔 | OMX_REPLY_POLL_INTERVAL_MS |
3000 ms |
500 – 60000 ms | 守护进程每次轮询的间隔 |
| 每分钟限流 | OMX_REPLY_RATE_LIMIT |
10 条/分钟 |
≥ 1 | 每分钟最多处理的回复数 |
| 单条回复最大长度 | notifications.reply.maxMessageLength |
500 字符 |
1 – 4000 | 注入前截断长度 |
| 注入前缀 | OMX_REPLY_INCLUDE_PREFIX |
true([reply:discord] ) |
false 关闭 |
注入文本前的可视化前缀 |
| 授权用户 | OMX_REPLY_DISCORD_USER_IDS |
空 | 逗号分隔的 Discord 用户 ID | Discord 回复监听的硬性门槛,为空则 Discord 回复直接禁用 |
对应常量可在 reply-listener.ts 与 config.ts 中核对。
事件、Verbosity 与配置文件位置
Discord 通知只是 OMX 通知子系统的一部分。通知会挂在会话生命周期事件上,类型定义为 session-start、session-stop、session-end、session-idle、ask-user-question(src/notifications/types.ts)。每条事件还可做平台级覆盖(events.<event>.discord / events.<event>["discord-bot"]),未覆盖时继承顶层平台配置(getEffectiveNotificationPlatformConfig)。
Verbosity(通知冗余度) 决定哪些事件值得推送,默认 session(含 start/idle/stop/end 与 tmux tail 片段),优先级为环境变量 OMX_NOTIFY_VERBOSITY > 配置字段 notifications.verbosity > 默认值 session(src/notifications/config.ts)。四档说明:
minimal:仅 start/stop/end,无 idle、无 tmux tail;session(推荐):start/idle/stop/end + tmux tail;agent:在 session 之上加入每次 agent 调用事件(含 ask-user-question);verbose:全部文本/工具调用输出。
配置文件与旧格式兼容:主配置从 codex home 下的 .omx-config.json 读取(configFile);同时保留对旧 stopHookCallbacks 格式的自动迁移(migrateStopHookCallbacks)。环境变量配置与文件配置会做合并:文件里缺失的机密字段由环境变量补齐,mention 统一经校验后回填(mergeEnvIntoFileConfig)。还支持通过 notifications.profiles + notifications.defaultProfile(或 OMX_NOTIFY_PROFILE)定义多套命名配置并在运行时切换(resolveProfileConfig)。
常见故障排查(Common Failure Modes)
- 无效的 Bot Token:在 Developer Portal 重新生成 Token,并更新
OMX_DISCORD_NOTIFIER_BOT_TOKEN/notifications["discord-bot"].botToken。 - Bot Token 在别处能用、OMX 里却不行:确认
OMX_DISCORD_NOTIFIER_CHANNEL/channelId是数字形式的频道 ID,而不是频道名或 Webhook ID。 - Bot 不在服务器里:用
bot这个 OAuth2 scope 把应用 Bot 邀请进服务器。 - 频道权限缺失:授予 View Channel 与 Send Messages;回复/状态工作流还需 Read Message History。
- Webhook 被删除或从错误的频道复制:从目标频道的 Integrations/Webhooks 页面重新创建/复制 Incoming Webhook,并更新
OMX_DISCORD_WEBHOOK_URL/notifications.discord.webhookUrl。 - 混合模式下出现重复消息:
notifications.discord与notifications["discord-bot"]同时启用,两条通道都会发送。若只需要一条 Discord 消息路径,请关闭其中一个。 - 回复监听提示 Discord 被禁用或没有授权用户:设置
OMX_REPLY_ENABLED=true,并把OMX_REPLY_DISCORD_USER_IDS或notifications.reply.authorizedDiscordUserIds配成允许回复的 Discord 用户 ID。源码中,当启用 Discord Bot 但授权列表为空时,会输出明确的警告:[notifications] Discord reply listening disabled: authorizedDiscordUserIds is empty(src/notifications/config.ts)。
进一步深入
- 完整配置项速查:docs/reference/omx-config-schema-routing.md(其中
reply支持enabled、authorizedDiscordUserIds、pollIntervalMs、rateLimitPerMinute、maxMessageLength、includePrefix)。 - 通知配置的实操技能文档:skills/configure-notifications/SKILL.md,其中提供了用
jq修改.omx-config.json、验证 JSON、以及一键notifications.enabled=false全量关闭通知的现成命令。 - 核心实现:配置读取与合并见 src/notifications/config.ts,类型契约见 src/notifications/types.ts,回复守护进程见 src/notifications/reply-listener.ts,会话状态回复组装见 src/notifications/session-status.ts,对应测试见 src/notifications/tests/config.test.ts 与 src/notifications/tests/reply-listener.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 StartedRust0632
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00