Problem
loadWorkspaceTasks (tower-cron.js) requires all four of name/schedule/command/message and silently skips a task file missing any of them. The only trace is a WARN in the Tower log, which no task author watches. afx cron list simply omits the file with no explanation, and afx cron status <name> returns NOT_FOUND — indistinguishable from a typo'd name.
Real-world impact (shannon workspace, 2026-07-27)
Two independently-written operator watchdogs sat unscheduled because neither author knew message: was required (it's not obvious a command task needs one — the natural mental model is that the command does its own alerting):
cost-lane-watchdog.yaml — an overnight-stall watchdog created 2026-07-26 precisely because a stall had gone uncaught; it then silently protected nothing for a day.
zbb-gate-watchdog.yaml — caught at creation time only because the author diffed against afx cron list output and went source-diving.
Asks (any subset helps)
afx cron list grows an INVALID/SKIPPED row per malformed file with the reason ("missing field: message"), instead of omitting it. This is the load-bearing one — the author's first verification step then catches the problem.
codev doctor validates .af-cron/*.yaml shape.
- Docs: state that
message is required, that timeout defaults to 30s (easy to exceed with a couple of gh calls), and that a non-zero command exit suppresses message delivery entirely (commands must exit 0 even when alerting).
Problem
loadWorkspaceTasks(tower-cron.js) requires all four ofname/schedule/command/messageand silently skips a task file missing any of them. The only trace is a WARN in the Tower log, which no task author watches.afx cron listsimply omits the file with no explanation, andafx cron status <name>returns NOT_FOUND — indistinguishable from a typo'd name.Real-world impact (shannon workspace, 2026-07-27)
Two independently-written operator watchdogs sat unscheduled because neither author knew
message:was required (it's not obvious a command task needs one — the natural mental model is that the command does its own alerting):cost-lane-watchdog.yaml— an overnight-stall watchdog created 2026-07-26 precisely because a stall had gone uncaught; it then silently protected nothing for a day.zbb-gate-watchdog.yaml— caught at creation time only because the author diffed againstafx cron listoutput and went source-diving.Asks (any subset helps)
afx cron listgrows an INVALID/SKIPPED row per malformed file with the reason ("missing field: message"), instead of omitting it. This is the load-bearing one — the author's first verification step then catches the problem.codev doctorvalidates.af-cron/*.yamlshape.messageis required, thattimeoutdefaults to 30s (easy to exceed with a couple ofghcalls), and that a non-zero command exit suppresses message delivery entirely (commands must exit 0 even when alerting).