cron-status-alert
July 16, 2026 · View on GitHub
[beta] — new; adoption feedback welcome — issues open.
Standalone Hermes plugin that
watches your cron jobs and DMs you when a Discord-delivering job fails to
deliver or runs overdue. Also provides /cron-status for on-demand health.
Listed in awesome-hermes-agent.
Installs into ~/.hermes/plugins/ — no core edits.
Why
Hermes marks a cron job ok when the agent finished, not when
Discord actually received the post. So an image job can 429, emit
[SILENT], and still show green in hermes cron list while your
channel gets nothing. You find out when someone asks where the
12:30 post is — three days later.
This plugin closes that gap. It watches the delivery-status fields
Hermes already tracks (last_delivery_error, overdue
next_run_at) and DMs you the moment a Discord-delivering job
fails or runs late, then tells you when it recovers. No more
silent misses.

Prerequisite: get your DM channel id
Alerts are sent via send_message_tool with:
target: discord:<dm_channel_id>
discord:<user_id> does not work. The send path treats the digits as a
channel snowflake. A user id fails with “channel not found” and the plugin
will log that loudly — but you will not get the alert.
How to obtain the DM channel snowflake
- Enable Discord Developer Mode (User Settings → App Settings → Advanced → Developer Mode).
- Open a DM with the Hermes bot (send it any message if needed so the DM channel exists).
- Right-click the DM channel in the sidebar (or the channel header) → Copy Channel ID.
- That value is the DM channel id (not your user id).
Confirm the form Hermes already stores for DM sessions looks like
discord:dm:<chat_id> — the <chat_id> portion is what you want after
discord: in config.
Example config value:
target: "discord:123456789012345678"
1. Install the plugin
Copy this folder to:
cp -R cron-status-alert ~/.hermes/plugins/cron-status-alert
2. Configure
Add to ~/.hermes/config.yaml:
cron_status_alert:
enabled: true
target: "discord:<dm_channel_id>" # REQUIRED for alerts
poll_seconds: 60
grace_seconds: 120
watch: [] # optional job-id allowlist (replaces default scope)
ignore: [] # optional job-id denylist
notify_recovery: true
persistent_realert_hours: 24
Default watch scope: enabled, non-paused jobs whose deliver starts with
discord:. Non-empty watch replaces that set; ignore always subtracts.
If enabled is true but target is unset, the slash command still works and
the plugin logs a clear warning — no crash, no silent DMs to nowhere.
3. Enable
hermes plugins enable cron-status-alert
4. Restart the gateway
Restart so the plugin loads and the poll thread starts.
5. Verify
In Discord:
/cron-status
/cron-status all
/cron-status <job-name-or-id>
You should see one line per watched job (or a summary if you have many).
6. How alerts work (v1)
- Poll-driven every
poll_seconds(default 60). There is no post-delivery hook in Hermes core yet; this plugin owns a daemon thread. - Conditions per job:
RUN_FAILED—last_status == "error"DELIVERY_FAILED—last_delivery_errorsetOVERDUE—now > next_run_at + grace_seconds(default grace 120s)
- Edge-triggered: fires once when a condition becomes active, silent while
it stays active, recovery notice when it clears (if
notify_recovery), and a single re-alert afterpersistent_realert_hours(default 24h) if still bad. - State is persisted at
$HERMES_HOME/cron_status_alert_state.jsonso a gateway restart does not re-DM every currently broken job.
Development
cd cron-status-alert
pytest tests/ -q
Tests use stdlib + pytest + unittest.mock only (no network).
License
MIT License — see LICENSE.