OmX OpenClaw 集成指南:通过 HTTP 网关与 Clawdbot Agent 命令网关打通 Codex Hook 通知链路
【免费下载链接】oh-my-codexOmX - Oh My codeX: Your codex is not alone. Add hooks, agent teams, HUDs, and so much more.项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-codex
导读
本指南基于 OmX(Oh My codeX)的notifications.openclaw配置体系,系统讲解如何把 Codex 会话生命周期钩子(session-start、session-idle、ask-user-question、stop、session-end)转发到 OpenClaw 网关,进而驱动 clawdbot agent 完成跨会话的跟进操作(如 Discord 频道#omc-dev中的韩语后续跟进)。读完本文你将掌握:两条受支持的接入路径(显式 OpenClaw schema 与通用别名)、三段式激活门控环境变量、可被 agent 高效解析的结构化 instruction 模板、命令网关超时优先级契约,以及完整的验证、预检与排障手段。所有配置示例均来自当前仓库 docs/openclaw-integration.md,并辅以 src/openclaw 的源码级实现佐证。
两条受支持的接入路径
OmX 为 OpenClaw 通知接入提供两种配置形态,二者最终都会被归一化为内部运行时配置(相关归一化逻辑见 src/openclaw/config.ts 中的normalizeFromCustomAliases):
- 显式 OpenClaw schema(
notifications.openclaw):运行时原生形状,直接声明gateways(网关)与hooks(事件映射),语义最完整。 - 通用别名(
custom_webhook_command/custom_cli_command):更灵活的接入方式,不仅适用于 OpenClaw,也能对接其他外部服务;OmX 会在内部把它们归一化为 OpenClaw 网关映射(源码注释明确写明 "Also supports generic alias shapes under notifications.custom_cli_command and notifications.custom_webhook_command, normalized to OpenClaw runtime config.")。
两条路径都读取自~/.codex/.omx-config.json(可通过OMX_OPENCLAW_CONFIG环境变量指向独立配置文件覆盖路径)。
激活门控:三段环境变量
OpenClaw 集成受三层环境变量门控,缺一不可:
# 优先在 shell profile 中导出 token 环境变量(避免把密钥硬编码进 JSON): export HOOKS_TOKEN="your-openclaw-hooks-token" # OpenClaw 分发管线必需的激活开关 export OMX_OPENCLAW=1 # 命令网关额外必需的激活开关 export OMX_OPENCLAW_COMMAND=1 # 命令网关超时的全局默认值(毫秒) # 优先级:网关级 timeout > 环境变量覆盖 > 5000 默认值 export OMX_OPENCLAW_COMMAND_TIMEOUT_MS=120000从源码角度看,这层门控的强制约束体现在两处:
- 激活门控:
getOpenClawConfig()的第一行即检查process.env.OMX_OPENCLAW !== "1",不满足直接返回null(src/openclaw/config.ts)。 - 命令门控:
wakeCommandGateway()在真正执行命令前单独检查process.env.OMX_OPENCLAW_COMMAND !== "1",未开启时返回错误"Command gateway disabled (set OMX_OPENCLAW_COMMAND=1 to enable)"(src/openclaw/dispatcher.ts)。这是独立于OMX_OPENCLAW的安全门控——即使启用了 OpenClaw 分发,默认也禁止执行任意 shell 命令。
此外,命令超时存在严格的安全边界:resolveCommandTimeoutMs会把解析结果钳制在MIN_COMMAND_TIMEOUT_MS=100与MAX_COMMAND_TIMEOUT_MS=300000(5 分钟)之间,防止近乎为零的误配置或长期驻留的命令进程(同一文件的常量定义)。对应测试覆盖见 src/openclaw/tests/dispatcher.test.ts 中resolveCommandTimeoutMs的 clamp 用例(10ms 被钳到 100ms,999999ms 被钳到 300000ms)。
Prompt 调优指南:让指令既简洁又带足上下文
对 OpenClaw 集成而言,最重要的质量杠杆是钩子的instruction模板,位于notifications.openclaw.hooks下五个事件的 instruction 字段:
notifications.openclaw.hooks["session-start"].instructionnotifications.openclaw.hooks["session-idle"].instructionnotifications.openclaw.hooks["ask-user-question"].instructionnotifications.openclaw.hooks["stop"].instructionnotifications.openclaw.hooks["session-end"].instruction
推荐的上下文 token
始终包含:
{{sessionId}}:跨日志的会话追踪标识{{tmuxSession}}:用于直接对 tmux 会话做后续操作定位
按需包含:
{{projectName}}{{question}}(仅ask-user-question事件){{reason}}(仅session-end事件)
从源码看,这些 token 全部由wakeOpenClaw通过白名单上下文构建并插值:buildWhitelistedContext只放行sessionId、projectPath、tmuxSession、prompt、contextSummary、reason、question、tmuxTail、replyChannel、replyTarget、replyThread等显式字段,防止敏感数据泄漏到网关载荷(src/openclaw/index.ts)。{{projectName}}由projectPath经basename()派生;{{timestamp}}为 ISO 格式统一时间戳。模板插值本身由interpolateInstruction完成,未解析的变量会被替换为空字符串(src/openclaw/dispatcher.ts)。
结构化指令格式
生产部署建议使用 clawdbot agent 可高效解析的结构化格式:
[event|exec] project={{projectName}} session={{sessionId}} tmux={{tmuxSession}} 필드1: 값 필드2: 값[event|exec]前缀表明这是一个可执行钩子,需要 agent 采取行动。- 韩语字段名(
요약、우선순위、주의사항、성과、검증、다음)为以韩语为主要工作语言的开发团队提供一致的结构。
冗余度(verbosity)策略
| 取值 | 适用场景 |
|---|---|
minimal | 极短 ping,高信噪比、低叙述 |
session(推荐默认) | 简洁的操作上下文 |
verbose | 更丰富的状态 + 行动 + 风险描述 |
verbosity是notifications的全局字段(取值verbose、agent、session、minimal),详见 docs/reference/omx-config-schema-routing.md。在minimal/session下默认抑制子代理生命周期钩子分发,需要独立子代理事件时再设agent/verbose。
执行摘要式 verbose 配置档案(示例)
需要详细但可快速扫读的通知时使用:
{ "notifications": { "verbosity": "verbose", "openclaw": { "hooks": { "session-start": { "enabled": true, "gateway": "local", "instruction": "[session-start|exec]\nproject={{projectName}} session={{sessionId}} tmux={{tmuxSession}}\n요약: 시작 맥락 1문장\n우선순위: 지금 할 일 1~2개\n주의사항: 리스크/의존성(없으면 없음)" }, "session-idle": { "enabled": true, "gateway": "local", "instruction": "[session-idle|exec]\nsession={{sessionId}} tmux={{tmuxSession}}\n요약: idle 원인 1문장\n복구계획: 즉시 조치 1~2개\n의사결정: 사용자 입력 필요 여부" }, "ask-user-question": { "enabled": true, "gateway": "local", "instruction": "[ask-user-question|exec]\nsession={{sessionId}} tmux={{tmuxSession}} question={{question}}\n핵심질문: 필요한 답변 1문장\n영향: 미응답 시 영향 1문장\n권장응답: 가장 빠른 답변 형태" }, "stop": { "enabled": true, "gateway": "local", "instruction": "[session-stop|exec]\nsession={{sessionId}} tmux={{tmuxSession}}\n요약: 중단 사유\n현재상태: 저장/미완료 항목\n재개: 첫 액션 1개" }, "session-end": { "enabled": true, "gateway": "local", "instruction": "[session-end|exec]\nproject={{projectName}} session={{sessionId}} tmux={{tmuxSession}} reason={{reason}}\n성과: 완료 결과 1~2문장\n검증: 확인/테스트 결과\n다음: 후속 액션 1~2개" } } } } }用 jq 快速更新配置
不想手改 JSON 时,可用 jq 一次性写入全部五个事件的指令:
CONFIG_FILE="$HOME/.codex/.omx-config.json" jq '.notifications.verbosity = "verbose" | .notifications.openclaw.hooks["session-start"].instruction = "[session-start|exec]\\nproject={{projectName}} session={{sessionId}} tmux={{tmuxSession}}\\n요약: 시작 맥락 1문장\\n우선순위: 지금 할 일 1~2개\\n주의사항: 리스크/의존성(없으면 없음)" | .notifications.openclaw.hooks["session-idle"].instruction = "[session-idle|exec]\\nsession={{sessionId}} tmux={{tmuxSession}}\\n요약: idle 원인 1문장\\n복구계획: 즉시 조치 1~2개\\n의사결정: 사용자 입력 필요 여부" | .notifications.openclaw.hooks["ask-user-question"].instruction = "[ask-user-question|exec]\\nsession={{sessionId}} tmux={{tmuxSession}} question={{question}}\\n핵심질문: 필요한 답변 1문장\\n영향: 미응답 시 영향 1문장\\n권장응답: 가장 빠른 답변 형태" | .notifications.openclaw.hooks["stop"].instruction = "[session-stop|exec]\\nsession={{sessionId}} tmux={{tmuxSession}}\\n요약: 중단 사유\\n현재상태: 저장/미완료 항목\\n재개: 첫 액션 1개" | .notifications.openclaw.hooks["session-end"].instruction = "[session-end|exec]\\nproject={{projectName}} session={{sessionId}} tmux={{tmuxSession}} reason={{reason}}\\n성과: 완료 결과 1~2문장\\n검증: 확인/테스트 결과\\n다음: 후속 액션 1~2개"' \ "$CONFIG_FILE" > "$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"规范优先级契约:显式配置永远获胜
当显式 OpenClaw 配置与通用别名同时存在时,行为确定且向后兼容:
notifications.openclaw优先custom_webhook_command/custom_cli_command被忽略- OmX 会发出警告提示
这一契约在 src/openclaw/config.ts 中有双重实现:inspectOpenClawConfig在检测到显式配置与别名并存时写入警告"notifications.openclaw overrides custom_cli_command/custom_webhook_command aliases.";getOpenClawConfig则在运行时打印"[openclaw] warning: notifications.openclaw is set; ignoring custom_cli_command/custom_webhook_command aliases"后直接返回显式配置。配置读取结果会被缓存(_cachedConfig),环境变量在进程生命周期内的变化不会影响已读入的配置。
Option A:显式notifications.openclaw(运行时原生形状)
{ "notifications": { "enabled": true, "openclaw": { "enabled": true, "gateways": { "local": { "type": "http", "url": "http://127.0.0.1:18789/hooks/agent", "headers": { "Authorization": "Bearer ${HOOKS_TOKEN}" } } }, "hooks": { "session-end": { "enabled": true, "gateway": "local", "instruction": "OMX task completed for {{projectPath}}" }, "ask-user-question": { "enabled": true, "gateway": "local", "instruction": "OMX needs input: {{question}}" } } } } }配置字段与源码类型一一对应(src/openclaw/types.ts):
- 网关(
gateways):HTTP 网关支持type(缺省或"http")、url、headers、method(POST/PUT,缺省 POST)、timeout(默认 10000ms)。 - 钩子映射(
hooks):每个事件含gateway(指向gateways中的键名)、instruction(模板)、enabled。
注意 HTTP 网关的 URL 校验规则(validateGatewayUrl):必须是 HTTPS;仅localhost、127.0.0.1、::1允许 HTTP 用于本地开发,其余 HTTP 地址一律拒绝(src/openclaw/dispatcher.ts)。上述示例中的http://127.0.0.1:18789正是本地开发白名单地址。
Option B:通用别名(custom_webhook_command/custom_cli_command)
{ "notifications": { "enabled": true, "custom_webhook_command": { "enabled": true, "url": "http://127.0.0.1:18789/hooks/agent", "method": "POST", "headers": { "Authorization": "Bearer ${HOOKS_TOKEN}" }, "events": ["session-end", "ask-user-question"], "instruction": "OMX event {{event}} for {{projectPath}}" }, "custom_cli_command": { "enabled": true, "command": "~/.local/bin/my-notifier --event {{event}} --text {{instruction}}", "events": ["session-end"], "instruction": "OMX event {{event}} for {{projectPath}}" } } }这些别名会被 OmX 归一化为内部 OpenClaw 网关映射。归一化细节(src/openclaw/config.ts):
- 事件过滤:
parseEvents只保留白名单事件(session-start、session-end、session-idle、ask-user-question、stop);未配置events或全部非法时,回落到默认事件["session-end", "ask-user-question"]。 - 网关命名:别名未显式指定
gateway时,CLI 别名默认网关名为custom-cli,webhook 别名默认网关名为custom-webhook;同一事件被两个别名同时命中时,后处理者会打印 override 警告。 - 指令回落:未配置
instruction时使用默认模板"OMX event {{event}} for {{projectPath}}"。 - method 归一化:webhook 别名仅接受
POST(默认)与PUT两种取值。 - 超时透传:别名中的
timeout数字会被透传进生成的网关配置。
Option C:Clawdbot Agent 命令工作流(开发推荐)
当你想让 OmX 钩子事件触发 agent 回合(而非单纯的消息/webhook 转发),例如#omc-dev频道场景时,使用命令网关:
Shell 安全提示:模板变量(例如
{{instruction}})会被插值进命令字符串。请保持模板简单,并避免在用户派生内容中出现 shell 元字符。排障时可临时去掉输出重定向以检查命令输出。命令网关超时优先级:
gateways.<name>.timeout>OMX_OPENCLAW_COMMAND_TIMEOUT_MS>5000。clawdbot agent工作流请使用120000(2 分钟)以避免过早超时。生产最佳实践:
- 命令末尾追加
|| true,防止 OmX 钩子失败阻塞会话- 使用
.jsonl扩展名 + 追加(>>)实现结构化日志聚合- 使用
--reply-to 'channel:CHANNEL_ID'格式保证 Discord 投递可靠(优于频道别名)
{ "notifications": { "enabled": true, "verbosity": "verbose", "events": { "session-start": { "enabled": true }, "session-idle": { "enabled": true }, "ask-user-question": { "enabled": true }, "session-stop": { "enabled": true }, "session-end": { "enabled": true } }, "openclaw": { "enabled": true, "gateways": { "local": { "type": "command", "command": "(clawdbot agent --session-id omx-hooks --message {{instruction}} --thinking minimal --deliver --reply-channel discord --reply-to 'channel:1468539002985644084' --timeout 120 --json >>/tmp/omx-openclaw-agent.jsonl 2>&1 || true)", "timeout": 120000 } }, "hooks": { "session-start": { "enabled": true, "gateway": "local", "instruction": "[session-start|exec]\nproject={{projectName}} session={{sessionId}} tmux={{tmuxSession}}\n요약: 시작 맥락 1문장\n우선순위: 지금 할 일 1~2개\n주의사항: 리스크/의존성(없으면 없음)" }, "session-idle": { "enabled": true, "gateway": "local", "instruction": "[session-idle|exec]\nsession={{sessionId}} tmux={{tmuxSession}}\n요약: idle 원인 1문장\n복구계획: 즉시 조치 1~2개\n의사결정: 사용자 입력 필요 여부" }, "ask-user-question": { "enabled": true, "gateway": "local", "instruction": "[ask-user-question|exec]\nsession={{sessionId}} tmux={{tmuxSession}} question={{question}}\n핵심질문: 필요한 답변 1문장\n영향: 미응답 시 영향 1문장\n권장응답: 가장 빠른 답변 형태" }, "stop": { "enabled": true, "gateway": "local", "instruction": "[session-stop|exec]\nsession={{sessionId}} tmux={{tmuxSession}}\n요약: 중단 사유\n현재상태: 저장/미완료 항목\n재개: 첫 액션 1개" }, "session-end": { "enabled": true, "gateway": "local", "instruction": "[session-end|exec]\nproject={{projectName}} session={{sessionId}} tmux={{tmuxSession}} reason={{reason}}\n성과: 완료 결과 1~2문장\n검증: 확인/테스트 결과\n다음: 후속 액션 1~2개" } } } } }命令网关的底层执行原理
命令网关不是简单的child_process.exec,其实现(src/openclaw/dispatcher.ts)包含完整的注入防护与进程生命周期管理:
- 变量 shell 转义:所有
{{variable}}值先经shellEscapeArg以单引号包裹(内部单引号转义为'\'')再插值,防止命令注入;对应转义用例见 src/openclaw/tests/dispatcher.test.ts。 - 执行策略分派:通过
SHELL_METACHAR_RE = /[|&;><$()]/检测插值后的命令是否含 shell 元字符——简单命令走直接 argv 执行(execFile风格),仅当含元字符(如本示例的括号、重定向)时才回落到sh -c`。 - 进程树清理:通过
runProcessTreeWithTimeout在进程组中运行,超时或父进程收到 SIGTERM 时先清理整个进程树,1 秒宽限后 SIGKILL。测试用例专门验证了超时后孙子进程也被回收、不会残留 bash 进程(src/openclaw/tests/dispatcher.test.ts 中kills shell-command descendants on timeout用例)。 - 结果判定:非零退出码、超时、输出超限、进程数超限、被信号杀死都会被判定为失败并记录错误。
通知分发与 OpenClaw 的协作方式
在通知分发侧(src/notifications/index.ts),OpenClaw 事件与主平台分发协同:
ask-user-question走前台路径:必须await wakeOpenClaw(...),让下游回答路由保持挂接在活跃会话上。- 其他生命周期事件 fire-and-forget:
void wakeOpenClaw(...)异步分发,避免阻塞通知返回;同时非阻塞地与主平台分发重叠执行,session-start不会等待后台唤醒工作。 - 失败隔离:OpenClaw 的任何异常都被吞掉,绝不影响通知分发主流程(
wakeOpenClaw内部同样 try/catch 吞错)。
回复上下文注入
命令/HTTP 网关还支持回复路由变量:{{replyChannel}}、{{replyTarget}}、{{replyThread}},分别来自OPENCLAW_REPLY_CHANNEL、OPENCLAW_REPLY_TARGET、OPENCLAW_REPLY_THREAD环境变量(由外部 bot/自动化设置),HTTP 载荷中对应channel、to、threadId字段。开启OMX_OPENCLAW_DEBUG=1可在 stderr 输出每次唤醒的结果日志。
Dev Guide:OpenClaw + Clawdbot Agent(韩语跟进模式)
当#omc-dev需要把 OpenClaw 通知作为实际的 clawdbot agent 回合接收、并具备主动跟进行为时,使用该档案。
1) 在钩子指令中强制韩语输出
- 所有钩子指令用韩语编写。
- 在每个指令模板中显式要求使用韩语。
- 优先使用
--reply-to 'channel:CHANNEL_ID'格式而非频道别名,以保证可靠性。- 示例:
--reply-to 'channel:1468539002985644084'(对应 #omc-dev) - 频道别名如
#omc-dev在 bot 未缓存该频道时可能投递失败。
- 示例:
指令风格示例:
OMX 훅={{event}} 프로젝트={{projectName}} 세션={{sessionId}}. 반드시 한국어로 응답하세요. OMX tmux 세션: {{tmuxSession}}. SOUL.md 및 #omc-dev 맥락을 참고해 필요한 후속 액션이 있으면 즉시 안내하세요.2) 追踪发出钩子的 OMX tmux 会话
- 每条钩子消息都包含
{{sessionId}}与{{tmuxSession}}。 - 若
{{tmuxSession}}存在,优先以其作为跟进目标。 - 若缺失,则从
sessionId与当前项目路径推导候选 tmux 会话。
快速检查命令:
tmux ls | grep '^omx-' || true tmux list-panes -a -F '#{session_name}\t#{pane_id}\t#{pane_current_path}' | grep "$(basename "$PWD")" || true补充说明:即使上下文未提供tmuxSession,wakeOpenClaw也会尝试通过getCurrentTmuxSession()自动探测并注入该变量(src/openclaw/index.ts)。
3) SOUL.md + #omc-dev 跟进运行手册
当钩子提示有活跃工作或待处理的用户操作时:
- 阅读
SOUL.md与近期#omc-dev上下文。 - 用韩语跟进,并引用
sessionId+tmuxSession。 - 如需行动,说明具体的下一步(例如需要回复、需要重试、或需要检查会话)。
- 若投递异常,检查日志并在不吞掉输出的情况下重试。
排障命令:
# 检查结构化 JSONL 日志 tail -n 120 /tmp/omx-openclaw-agent.jsonl | jq -s '.[] | {timestamp: (.timestamp // .time), status: (.status // .error // "ok")}' # 在日志中搜索错误 rg '"error"|"failed"|"timeout"' /tmp/omx-openclaw-agent.jsonl | tail -20 # 使用生产验证过的参数手动重试 clawdbot agent --session-id omx-hooks \ --message "OMX hook retry 점검: session={{sessionId}} tmux={{tmuxSession}}" \ --thinking minimal --deliver --reply-channel discord --reply-to 'channel:1468539002985644084' \ --timeout 120 --json验证(必需)
A) 唤醒冒烟测试(/hooks/wake)
curl -sS -X POST http://127.0.0.1:18789/hooks/wake \ -H "Authorization: Bearer ${HOOKS_TOKEN}" \ -H "Content-Type: application/json" \ -d '{"text":"OMX wake smoke test","mode":"now"}'通过信号:JSON 响应包含"ok":true。
从源码看,OmX 发出的 HTTP 载荷中text字段正是instruction的别名(src/openclaw/types.ts 中OpenClawPayload.text注释:Alias of instruction — allows OpenClaw /hooks/wake to consume the payload directly),因此/hooks/wake可直接消费 OmX 的载荷。
B) 投递验证(/hooks/agent)
curl -sS -o /tmp/omx-openclaw-agent-check.json -w "HTTP %{http_code}\n" \ -X POST http://127.0.0.1:18789/hooks/agent \ -H "Authorization: Bearer ${HOOKS_TOKEN}" \ -H "Content-Type: application/json" \ -d '{"message":"OMX delivery verification","instruction":"OMX delivery verification","event":"session-end","sessionId":"manual-check"}'通过信号:HTTP 2xx + 被接受的响应体。
预检检查
在正式启用前,逐项确认以下前置条件:
# token 是否存在 test -n "$HOOKS_TOKEN" && echo "token ok" || echo "token missing" # 网关可达性 curl -sS -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:18789 || echo "gateway unreachable" # 门控检查 test "$OMX_OPENCLAW" = "1" && echo "OMX_OPENCLAW=1" || echo "missing OMX_OPENCLAW=1" test "$OMX_OPENCLAW_COMMAND" = "1" && echo "OMX_OPENCLAW_COMMAND=1" || echo "missing OMX_OPENCLAW_COMMAND=1"通过/失败诊断速查
| 现象 | 原因与对策 |
|---|---|
| 401/403 | token 无效或缺失,检查Authorization: Bearer头。 |
| 404 | 路径错误,核对/hooks/agent与/hooks/wake。 |
| 5xx | 网关运行时问题,检查日志。 |
| 超时/连接拒绝 | 主机/端口/防火墙问题。 |
| 命令网关被禁用 | 同时设置OMX_OPENCLAW=1与OMX_OPENCLAW_COMMAND=1。 |
命令被SIGTERM杀死 | 调大gateways.<name>.timeout(clawdbot agent 建议120000),或设置OMX_OPENCLAW_COMMAND_TIMEOUT_MS。 |
| 钩子失败阻塞会话 | 确保命令以|| true结尾,防止 OmX 等待 clawdbot 失败。 |
| 日志缺失 | 使用.jsonl扩展名 + 追加(>>)获得持久化结构化日志。 |
| Discord 投递失败 | 使用--reply-to 'channel:CHANNEL_ID'格式替代频道别名。 |
相关仓库资源
- 集成指南原文:docs/openclaw-integration.md
- 配置 schema 总览(含
notifications与openclaw支持的键形状):docs/reference/omx-config-schema-routing.md - 源码:配置读取与别名归一化 src/openclaw/config.ts、网关分发器 src/openclaw/dispatcher.ts、公共 API src/openclaw/index.ts、类型定义 src/openclaw/types.ts
- 测试:src/openclaw/tests/dispatcher.test.ts、src/openclaw/tests/index.test.ts
- 通知分发集成点:src/notifications/index.ts
【免费下载链接】oh-my-codexOmX - Oh My codeX: Your codex is not alone. Add hooks, agent teams, HUDs, and so much more.项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-codex
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考