Single-file Discord bridge for Codex CLI operation.
The actively maintained runtime targets Codex: one Discord channel connects to one Codex CLI process. Legacy artifacts remain only for rollback and command continuity.
Command surface remains compatible with earlier bridge flows:
/new /status /connect /handoff /help.
- Single process, single channel, single vendor (Codex)
- One process listens to exactly one
CHANNEL_ID - Multi-channel or multi-vendor HA is done by duplicating processes, not by mixing routes in one process
Discord message -> bridge.py -> codex exec/resume --json -> parse JSON events -> Discord reply
Bridge state:
- State dir:
~/.cli-discord-bridge/ - Session file:
~/.cli-discord-bridge/session.json- Primary key:
thread_id - Backward-compatible read: legacy
session_id
- Primary key:
- Handoff dir:
~/.cli-discord-bridge/handoffs/
- New thread:
codex exec --json --skip-git-repo-check [--dangerously-bypass-approvals-and-sandbox] [-m MODEL] "<prompt>"
- Resume thread:
codex exec resume --json --skip-git-repo-check [--dangerously-bypass-approvals-and-sandbox] [-m MODEL] <thread_id> "<prompt>"
- Parser rules:
- Parse JSON lines only, ignore non-JSON noise
- Use
thread.started.thread_idas authoritative thread ID - Aggregate
item.completed.item.type=="agent_message"text as reply body
/connect safety:
- Explicit
/connect <thread_id>is strict. - If resume returns a different
thread.started.thread_id, bridge treats it as failure and blocks auto-fallback.
Implicit fallback:
- In non-explicit mode, resume failure may switch to a new thread and update local state.
| Variable | Required | Default | Description |
|---|---|---|---|
DISCORD_TOKEN |
Yes | — | Discord bot token |
CHANNEL_ID |
Yes | — | Discord channel ID |
CODEX_BIN |
No | codex |
Codex CLI binary path |
CODEX_MODEL |
No | empty | Optional model override |
CODEX_TIMEOUT |
No | 300 |
Max seconds per Codex call |
CODEX_CWD |
No | $HOME |
Working directory for Codex call |
CODEX_FULL_ACCESS |
No | 0 |
1 enables --dangerously-bypass-approvals-and-sandbox |
SELFTEST_ON_START |
No | 0 |
1 runs startup selftest |
Compatibility fallback (for smooth migration):
CLAUDE_CWDcan still be used ifCODEX_CWDis not setCLAUDE_TIMEOUTcan still be used ifCODEX_TIMEOUTis not set
| Command | Behavior |
|---|---|
/new |
Clear current thread; next message creates a new thread |
/status |
Show current thread, cwd, timeout, backend |
/connect [thread-id] |
Bind explicit thread (no arg = reset) |
/handoff |
Summarize old thread -> coldstart new thread; rollback old thread if new bootstrap fails |
/help |
Show command help |
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
DISCORD_TOKEN="xxx" \
CHANNEL_ID="1234567890" \
CODEX_FULL_ACCESS="1" \
.venv/bin/python3 bridge.pyLegacy rollback example:
com.claude.discord-bridge.plist.example(legacy)
Use the active CLI bridge example:
com.cli.discord-bridge.plist.example
Install example:
cp com.cli.discord-bridge.plist.example ~/Library/LaunchAgents/com.cli.discord-bridge.plist
# edit token/channel/paths
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.cli.discord-bridge.plistStop:
launchctl bootout gui/$(id -u)/com.cli.discord-bridgeLogs:
tail -f ~/.cli-discord-bridge/bridge.log
tail -f ~/.cli-discord-bridge/bridge.err.logRecommended migration sequence:
- Start
com.cli.discord-bridgein a new Discord channel. - Keep the legacy rollback service running in parallel for observation.
- Observe 24h for stuck process, leaks, thread loss, and command compatibility.
- Switch OpenClaw DR entry to the new CLI bridge channel.
- If needed, rollback by stopping
com.cli.discord-bridgeand continuing with legacy service.
- This project does not implement dynamic multi-vendor switching in one process.
- If you need more HA lanes, copy service instances with different
CHANNEL_IDand state dirs.