Skip to content

Codex completion hook defaults to Telegram and can pollute the main session on Feishu/OpenClaw setups #3

@ljcyt

Description

@ljcyt

Summary

In codex-agent, the completion hook currently assumes a Telegram-first delivery/wake flow. On Feishu/OpenClaw setups, this can lead to two problems:

  1. completion notifications are sent to the wrong channel when CODEX_AGENT_CHANNEL is not exported into the hook subprocess environment, and
  2. the hook auto-wakes the OpenClaw main agent session, which can pollute the user's primary chat session with Codex/MCP callback content.

Affected file

  • hooks/on_complete.py

Reproduction

Environment:

  • OpenClaw 2026.3.2
  • Feishu as the main chat channel
  • codex-agent installed under ~/.openclaw/workspace/skills/codex-agent
  • OpenClaw config contains:
    • env.CODEX_AGENT_CHANNEL=feishu
    • env.CODEX_AGENT_CHAT_ID=<feishu open_id>
    • env.CODEX_AGENT_NAME=main

Steps:

  1. Use codex-agent in an OpenClaw + Feishu setup.
  2. Let a Codex task complete so hooks/on_complete.py runs.
  3. Observe the hook behavior.

Actual behavior

  • The hook uses a hardcoded fallback channel of telegram.
  • If the expected env vars are not present in the subprocess environment, notification delivery falls back incorrectly.
  • The hook also auto-runs:
    • openclaw agent --agent main --message ... --deliver --channel <channel>
  • This injects Codex callback content such as [Codex Hook] 任务完成,请检查输出并汇报 into the main session.
  • On a live Feishu setup this can make the primary chat appear broken or “not replying”, because the main session gets polluted by hook-generated MCP/task-followup content.

Observed side effect from logs:

  • Feishu receives the inbound user message normally.
  • Dispatch runs, but the active session context has already been shifted by the hook callback.
  • In one case delivery also failed with Unknown channel: telegram while the user was actually chatting via Feishu.

Expected behavior

  • The hook should respect configured channel/target values for non-Telegram setups.
  • It should not assume Telegram as the universal default transport.
  • Auto-waking the main session should be opt-in, not on by default.
  • If waking an agent is enabled, delivery should use explicit reply routing (--reply-channel / --reply-to) rather than relying on ambiguous session/channel behavior.

Root cause

hooks/on_complete.py currently does roughly this:

  • CHANNEL = os.environ.get("CODEX_AGENT_CHANNEL", "telegram")
  • CHAT_ID = os.environ.get("CODEX_AGENT_CHAT_ID", "YOUR_CHAT_ID")
  • openclaw message send --channel CHANNEL --target CHAT_ID ...
  • openclaw agent --agent main --message ... --deliver --channel CHANNEL ...

This is fragile in OpenClaw deployments where:

  • the relevant values live in ~/.openclaw/openclaw.json under env, but are not exported into the hook subprocess environment, and/or
  • the primary chat channel is Feishu instead of Telegram.

Suggested fix

  1. In hooks/on_complete.py, load fallback values from ~/.openclaw/openclaw.json -> env when process env is missing.
  2. Default CODEX_AGENT_CHANNEL to something safer, or fail loudly instead of silently assuming Telegram.
  3. Normalize Feishu targets so bare open_id becomes user:<open_id>.
  4. Make agent auto-wake opt-in, e.g. via CODEX_AGENT_WAKE=false by default.
  5. If agent wake is enabled, use explicit reply routing:
    • --reply-channel <channel>
    • --reply-to <target>
  6. Consider documenting that the current hook is Telegram-oriented unless configured otherwise.

Why this matters

The README describes a generalized “OpenClaw operates Codex for you” workflow, but the current hook behavior is still effectively Telegram-centric. That mismatch can break or degrade real-world Feishu deployments.

Workaround used locally

A local patch that resolved the issue:

  • load CODEX_AGENT_* fallback values from ~/.openclaw/openclaw.json
  • normalize Feishu target IDs
  • switch agent wake delivery to --reply-channel + --reply-to
  • disable agent auto-wake by default to avoid polluting agent:main:main

If helpful, I can turn this into a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions