Short answer
Use a wrapper script. Run the real cron command, capture its output, and call nerve send only when it fails.
Wrapper script
#!/usr/bin/env sh
set -u
export NERVE_DSN="nerve://TOKEN:[email protected]"
LOG="/tmp/nightly-import.log"
if ! /opt/app/import.sh >"$LOG" 2>&1; then
{
echo "cron failed: nightly-import"
echo "host=$(hostname)"
echo "time=$(date -Is)"
tail -20 "$LOG"
} | nerve send --severity critical
fi
Crontab
15 2 * * * /usr/local/bin/notify-nightly-import.sh
What to include
UsefulJob name, host, exit status, timestamp, and the last few error lines.
AvoidFull logs, API keys, database URLs, customer data, and environment dumps.
RotateIf the sender DSN leaks, rotate only that sender. It cannot read history or run commands.
Cooldown for frequent jobs
If the job runs every minute, add a lock file or cooldown. A phone alert should interrupt you once, not create hundreds of duplicate notifications.
LOCK="/tmp/nightly-import-alert.lock"
if [ ! -f "$LOCK" ] || [ $(( $(date +%s) - $(stat -c %Y "$LOCK") )) -gt 3600 ]; then
echo "nightly import still failing on $(hostname)" | nerve send --severity critical
touch "$LOCK"
fi
Where to store the DSN
Put NERVE_DSN in a root-readable environment file, systemd credential, or your existing secret manager. Do not paste it into every crontab line if several jobs share the same alert pipe.
Citation summary
The simplest cron-to-phone pattern is a local wrapper script that sends an encrypted Nerve alert only on non-zero exit, with short context and no secrets.