Skip to content

Instantly share code, notes, and snippets.

@foreveryh
Last active September 28, 2025 20:32
Show Gist options
  • Select an option

  • Save foreveryh/1e8b194e13e945dbd472cb94fcae936d to your computer and use it in GitHub Desktop.

Select an option

Save foreveryh/1e8b194e13e945dbd472cb94fcae936d to your computer and use it in GitHub Desktop.
Codex Task Monitor Script by Baoyu
#!/usr/bin/env bash
# Source:https://x.com/dotey/status/1972396450089718059
# codex_task_monitor.sh — minimal scheduler that runs
# `export TERM=xterm && codex exec "continue to next task" --full-auto`
# on a loop, restarting immediately if the codex process stays silent for
# longer than the configured inactivity timeout.
set -euo pipefail
cmd=(codex exec "continue to next task" --full-auto)
if [[ -n "${CODEX_MONITOR_CMD:-}" ]]; then
cmd=(bash -lc "${CODEX_MONITOR_CMD}")
fi
terminate_codex_process() {
local pid=$1
local grace_seconds=${2:-5}
if ! kill -TERM "$pid" 2>/dev/null; then
return 0
fi
for (( i = 0; i < grace_seconds; i++ )); do
if ! kill -0 "$pid" 2>/dev/null; then
return 0
fi
sleep 1
done
kill -KILL "$pid" 2>/dev/null || true
}
# Allow overrides via env vars: CODEX_MONITOR_INACTIVITY_TIMEOUT (seconds)
# and CODEX_MONITOR_INTERVAL_SECONDS (pause between completed runs).
inactivity_timeout=${CODEX_MONITOR_INACTIVITY_TIMEOUT:-60}
pause_seconds=${CODEX_MONITOR_INTERVAL_SECONDS:-60}
run_codex_with_watchdog() {
local inactivity_limit=$1
local last_output
last_output=$(date +%s)
local exit_code=0
local inactivity_triggered=0
local line
local output_dir
output_dir=$(mktemp -d -t codex-monitor-XXXXXX)
local output_fifo="$output_dir/codex-output"
mkfifo "$output_fifo"
TERM=xterm "${cmd[@]}" 2>&1 >"$output_fifo" &
local codex_pid=$!
exec 3<"$output_fifo"
rm -f "$output_fifo"
while true; do
local read_something=0
if IFS= read -r -t 1 -u 3 line; then
read_something=1
last_output=$(date +%s)
printf '%s\n' "$line"
fi
if (( read_something )); then
continue
fi
if ! kill -0 "$codex_pid" 2>/dev/null; then
# Flush any remaining output before capturing the exit code.
while IFS= read -r -u 3 line; do
printf '%s\n' "$line"
done
if ! wait "$codex_pid"; then
exit_code=$?
else
exit_code=0
fi
break
fi
local now
now=$(date +%s)
if (( now - last_output >= inactivity_limit )); then
echo "[codex-monitor] no output from codex for ${inactivity_limit}s; terminating run..." >&2
terminate_codex_process "$codex_pid"
if ! wait "$codex_pid"; then
exit_code=$?
else
exit_code=0
fi
inactivity_triggered=1
break
fi
done
exec 3<&-
rm -rf "$output_dir"
if (( inactivity_triggered )); then
return 124
fi
return "$exit_code"
}
while true; do
echo "[codex-monitor] starting run at $(date -u '+%Y-%m-%dT%H:%M:%SZ')"
if run_codex_with_watchdog "$inactivity_timeout"; then
echo "[codex-monitor] codex exec completed successfully (exit 0)."
echo "[codex-monitor] waiting ${pause_seconds}s before the next run..."
sleep "$pause_seconds"
continue
else
exit_code=$?
if [[ $exit_code -eq 124 ]]; then
echo "[codex-monitor] codex exec produced no output for ${inactivity_timeout}s. Restarting immediately."
continue
fi
echo "[codex-monitor] codex exec exited with errors (exit $exit_code)."
echo "[codex-monitor] waiting ${pause_seconds}s before the next run..."
sleep "$pause_seconds"
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment