Get a Discord notification when a local Codex turn finishes or when Codex is waiting for your answer.
This is for the common failure mode where Codex is doing real work in another window, finishes, asks a question, or waits for confirmation, and you miss it.
It is especially useful for remote Codex workflows. Codex Mobile and Codex Desktop can connect to a remote VM through Application Connection, but work that finishes on the remote VM does not necessarily trigger a local desktop/mobile notification. The same gap exists when you run Codex CLI directly on a remote VM. This notifier runs beside Codex on that machine and sends Discord notifications when the remote work needs your attention.
Codex Discord Notifier runs as a small user-level daemon on the same machine as Codex. It watches Codex's local SQLite/log state and sends a Discord webhook message when:
- a Codex turn runs longer than
CODEX_NOTIFY_MIN_SECONDSand completes - Codex asks a question or appears to be waiting for user input
- a Codex agent job reaches a terminal state
It deliberately ignores internal Codex approval/reviewer subagents such as codex-auto-review, so Discord does not get spammed by background policy checks.
Discord webhooks are the right primitive for this project:
- no bot token
- no Gateway connection
- no privileged intents
- no OAuth install flow
- one HTTPS
POSTper notification
Webhooks post into a Discord channel. They do not send direct messages. If you want private notifications, create a private channel or a personal Discord server, then create the webhook there.
- Codex Desktop or Codex CLI state under
~/.codex - Python 3
- outbound HTTPS access to Discord's webhook API
No pip install step is required. The daemon uses only Python standard library modules, including sqlite3, urllib, json, pathlib, and socket.
Clone and install:
git clone https://github.com/d11nn/codex-discord-notifier.git
cd codex-discord-notifier
./install.shThe installer detects your OS:
- Linux: installs a systemd user service.
- macOS: installs a launchd LaunchAgent.
Create a Discord webhook:
- Open Discord desktop or web.
- Pick the server and channel that should receive Codex notifications.
- Open
Edit Channel. - Go to
Integrations. - Open
Webhooks. - Create a webhook named
Codex Finish Notifier. - Copy the webhook URL.
Paste the webhook URL into the env file:
nano ~/.config/codex-discord-notifier/envSet:
DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/..."
CODEX_NOTIFY_MIN_SECONDS=3
CODEX_NOTIFY_POLL_SECONDS=2
CODEX_NOTIFY_HOST="VM1"
CODEX_NOTIFY_MENTION="@here"Send a test notification:
codex-discord-notifier --send-testLinux uses a systemd user service.
Check status:
systemctl --user status codex-discord-notifier.serviceIf you want the user service to keep running after SSH logout:
loginctl enable-linger "$USER"macOS uses a launchd LaunchAgent.
If python3 is not available, install it first:
xcode-select --installIf that does not provide Python 3 on your macOS version, install Python from python.org.
Check status:
launchctl list | grep com.d11nn.codex-discord-notifierView logs:
tail -f /tmp/codex-discord-notifier.out.log /tmp/codex-discord-notifier.err.logIf your Codex directory is not ~/.codex, set it explicitly in ~/.config/codex-discord-notifier/env:
CODEX_NOTIFY_CODEX_DIR="$HOME/.codex"./uninstall.shWindows is not yet a verified target. The Python daemon itself is portable, but production support still needs validation for:
- Codex Desktop's Windows state directory layout
- service installation strategy, such as Task Scheduler or NSSM
- path handling for rollout JSONL files
Pull requests for Windows support are welcome, but the current documented production paths are Linux and macOS.
Send two synthetic test notifications:
codex-discord-notifier --send-testPreview the payload without touching Discord:
codex-discord-notifier --send-test --dry-runRun one polling pass without sending Discord messages:
codex-discord-notifier --once --dry-runInitialize state to the current Codex log position:
codex-discord-notifier --init-stateThis prevents old events from being sent after a fresh install.
The notifier reads:
~/.config/codex-discord-notifier/envSupported settings:
| Variable | Default | Meaning |
|---|---|---|
DISCORD_WEBHOOK_URL |
required | Discord channel webhook URL. Treat it as a secret. |
CODEX_NOTIFY_MIN_SECONDS |
3 |
Notify completed turns/jobs that ran at least this long. |
CODEX_NOTIFY_POLL_SECONDS |
2 |
Poll interval for local Codex SQLite/log state. |
CODEX_NOTIFY_HOST |
hostname | Display name in Discord notification fields. |
CODEX_NOTIFY_MENTION |
@here |
Plain message mention. Use @here in a private channel, <@USER_ID> for one user, <@&ROLE_ID> for a role, or empty string to disable pings. |
CODEX_NOTIFY_CODEX_DIR |
~/.codex |
Codex state directory. |
CODEX_NOTIFY_STATE_PATH |
~/.local/state/codex-discord-notifier/state.json |
Notifier state file. |
CODEX_NOTIFY_DRY_RUN |
unset | Set to 1 to print payloads instead of sending. |
The daemon sends two main notification classes.
Sent as Codex job finished.
This fires when a user-facing Codex turn completes and ran for at least CODEX_NOTIFY_MIN_SECONDS.
Sent as Codex is waiting for you.
This fires when the final assistant message looks like it needs your input. Examples include messages containing:
?please provideplease confirmdo you wantQuestion:
Waiting notifications bypass the duration threshold because even a short question can leave Codex blocked until you answer.
Codex stores local state under ~/.codex. This daemon reads:
~/.codex/logs_2.sqlite~/.codex/state_5.sqlite- rollout JSONL paths referenced by Codex thread metadata
It tracks the last processed log id in:
~/.local/state/codex-discord-notifier/state.jsonPolling is safe because the daemon processes durable log rows using id > last_log_id. A 2-second poll interval does not miss events; if an event is written to SQLite, a later poll can still read it.
The daemon also records its startup time and ignores Codex turns that started before the daemon started. This prevents service restarts from sending notifications for half-finished old turns.
Treat your Discord webhook URL as a credential.
Do:
- store it only in
~/.config/codex-discord-notifier/env - keep that env file mode private
- use a private Discord channel if your Codex work may include sensitive repo names or paths
Do not:
- commit your webhook URL
- paste the webhook URL into public issues or PRs
- include full Codex output in Discord notifications
The notifier sends CODEX_NOTIFY_MENTION in the plain message content. By default this is @here, which works well when the webhook posts into a private channel that only you use.
Discord webhooks cannot automatically mention the webhook creator. If you need an exact user mention instead of @here, set CODEX_NOTIFY_MENTION="<@USER_ID>".
The notifier also sets allowed_mentions narrowly. Assistant text inside the embed cannot create surprise pings.
When CODEX_NOTIFY_MENTION="@here", the payload uses:
{"content": "@here", "allowed_mentions": {"parse": ["everyone"]}}Set CODEX_NOTIFY_MENTION="" to disable all pings:
{"allowed_mentions": {"parse": []}}View Linux status:
systemctl --user status codex-discord-notifier.serviceView Linux logs:
journalctl --user -u codex-discord-notifier.service -fRestart Linux service after editing config:
systemctl --user restart codex-discord-notifier.serviceView macOS status:
launchctl list | grep com.d11nn.codex-discord-notifierView macOS logs:
tail -f /tmp/codex-discord-notifier.out.log /tmp/codex-discord-notifier.err.logRestart macOS agent after editing config:
launchctl unload ~/Library/LaunchAgents/com.d11nn.codex-discord-notifier.plist
launchctl load ~/Library/LaunchAgents/com.d11nn.codex-discord-notifier.plist
launchctl start com.d11nn.codex-discord-notifierUninstall the binary and service:
./uninstall.shThe uninstall script preserves config and state so you do not lose your webhook or deduplication history.
This project is intentionally dependency-free: it uses Python 3 standard library modules only.
Production behavior built in:
- read-only SQLite access
- durable deduplication with a local state file
- service restart guard for half-finished turns
- exclusion for internal Codex reviewer/subagent threads
- Discord mention suppression
- webhook retry on transient network failure/rate limit
- dry-run and test modes
Apache License 2.0. See LICENSE.