Warcraft-style sound notifications for Codex CLI, adapted from peon-ping, because Codex is better 💯
codex-peon installs a Codex notify hook and plays sounds from the same packs used by peon-ping.
Quick install (curl | bash):
curl -fsSL https://raw.githubusercontent.com/mrdavey/codex-peon/main/install.sh | bashThen restart terminal.
What it does
- Plays a
greetingsound when Codex boots (viacodex-peon launch). - Plays an
acknowledgesound for normal task completion. - Detects
permission,error, andresource_limitoutcomes from the assistant's final message. - Plays
annoyedsounds when turns are submitted rapidly (configurable). - Supports sound pack switching and pause/resume controls.
How sounds are played
Codex currently calls notify on agent-turn-complete. codex-peon uses that payload as the trigger.
Sound pipeline:
- Codex executes the configured
notifycommand with anagent-turn-completeJSON payload. codex-peon.pyloads runtime config from~/.codex/hooks/codex-peon/config.json.- It loads persistent state from
~/.codex/hooks/codex-peon/.state.json(thread history, timing, anti-repeat). - It selects a category based on thread/timing/message heuristics.
- It resolves the active pack manifest and randomly selects a non-repeating sound from that category.
- Noise controls are applied:
- per-category cooldown (
cooldowns_seconds) - optional overlap prevention (
prevent_overlap) with scope (overlap_scope)
- per-category cooldown (
- It plays audio with a platform backend:
- macOS:
afplay - WSL:
powershell.exemedia playback - Linux:
paplay/aplay/ffplay - fallback: terminal bell (
\a)
- macOS:
- It saves updated state for next-turn routing.
Event and routing model
Important: notify does not currently expose agent-turn-start; it exposes turn completion payloads.
Default greeting mode is therefore launch (play greeting before starting Codex via launcher command).
Category routing rules:
greeting: launch-time greeting when usingcodex-peon launch(default). Optional turn-start mode is available via config.permission/error/resource_limit: keyword-based inference fromlast-assistant-messageannoyed: applied for rapid turns (annoyed_thresholdevents withinannoyed_window_seconds), unless an explicitpermission/error/resource_limitclassification is presentacknowledge: default for normal completion
Category fallback:
- If a selected category is disabled or missing in a pack, fallback categories are attempted (for example
acknowledge, thencompletewhere applicable).
Install
From a local clone:
From GitHub (curl | bash):
curl -fsSL https://raw.githubusercontent.com/mrdavey/codex-peon/main/install.sh | bashIf you host the repo elsewhere, override the base URL:
CODEX_PEON_REPO_BASE="https://raw.githubusercontent.com/mrdavey/codex-peon/main" \ curl -fsSL https://raw.githubusercontent.com/mrdavey/codex-peon/main/install.sh | bash
Installer behavior:
- Installs
codex-peoninto a writable directory already on yourPATHwhen possible. - Falls back to
~/.local/binand auto-adds it to shell startup files if needed. - Configures Codex
notifyin~/.codex/config.toml. - Installs a shell alias so
codexrunscodex-peon launch(boot greeting every time).
Command reference
codex-peon status codex-peon packs codex-peon pack peon codex-peon pack # cycle to next pack codex-peon preview greeting codex-peon preview acknowledge codex-peon preview annoyed codex-peon launch codex-peon launch -- --help codex-peon pause codex-peon resume codex-peon toggle codex-peon enable codex-peon disable codex-peon config get codex-peon config get volume codex-peon config set volume 0.7 codex-peon config set cooldowns_seconds.acknowledge 1.5 codex-peon config set prevent_overlap true codex-peon config set overlap_scope global codex-peon config keywords add permission "approve this command" codex-peon config keywords remove permission "approve this command"
Configuration
Runtime file:
~/.codex/hooks/codex-peon/config.json
Key fields:
active_pack: active sound pack directory namevolume: non-negative float (0.0and above)enabled: global on/offgreeting_mode:launch(default),turn_start,both, oroffcategories.*: enable/disable each routing categoryannoyed_threshold: number of rapid turns beforeannoyedannoyed_window_seconds: rapid-turn window lengthsession_start_idle_seconds: idle gap to treat next completion as session startprevent_overlap: defaultfalse; whentrue, skip new playback if previous playback process is still runningoverlap_scope:thread(default, per thread/session) orglobal(all terminals/sessions)cooldowns_seconds: per-category minimum seconds between plays (defaultapplies fallback)keywords.*: keyword lists forpermission,error,resource_limitinference
Example noise control config:
{
"greeting_mode": "launch",
"prevent_overlap": true,
"overlap_scope": "thread",
"cooldowns_seconds": {
"default": 0,
"acknowledge": 1.5,
"annoyed": 4
}
}To make greeting play on turn start instead of launch:
codex-peon config set greeting_mode turn_startTo launch Codex with greeting every time:
After install, codex is already aliased to codex-peon launch.
If your current shell session was open before install, reload your shell config:
source ~/.zshrc # or ~/.bashrc / ~/.profile
Optional TUI bell for approvals
Codex TUI can emit unfocused-terminal notifications for approval prompts. You can combine that with codex-peon:
[tui] notifications = ["approval-requested", "agent-turn-complete"] notification_method = "bel"
Development
Main files:
codex-peon.py: hook handler + CLI controls + routing logicinstall.sh: installation/update + Codex config wiringuninstall.sh: cleanup of symlinks and configconfig.json: default runtime configpacks/*: imported sound packs and manifests
Validation:
Uninstall
bash ~/.codex/hooks/codex-peon/uninstall.shAttribution
Sound packs and manifests are sourced from tonyyont/peon-ping (MIT). See NOTICE.