Cron Schedules¶
Every recurring job in the stack. Times are local PDT/PST (DST-aware where the runner respects TZ; UTC-fixed where it doesn't).
Active¶
| When (PDT) | When (UTC) | Mechanism | What | Source |
|---|---|---|---|---|
| Always-on | — | launchd com.casey.warehouse-ui |
uvicorn ui.app:app --port 8765 — the warehouse FastAPI UI. Sources ~/.warehouse_secrets.sh for env, KeepAlive auto-restart, RunAtLoad. |
~/Library/LaunchAgents/com.casey.warehouse-ui.plist |
| Daily 7:00am | 14:00 | launchd com.casey.warehouse-sync |
~/garmin-warehouse/scripts/daily_sync.sh — garmindb sync, ICU refresh, kb embed, R2 backup, Worker cache build, comment scan |
~/Library/LaunchAgents/com.casey.warehouse-sync.plist |
| Sun 6:00am | 13:00 (Sun) | launchd com.casey.podcast-sync |
~/data-ingestion/scripts/podcast-sync.sh — triage + research new episodes across all shows |
~/Library/LaunchAgents/com.casey.podcast-sync.plist |
| Daily 8:00pm | 03:00 (next day) | Cloudflare Worker 0 3 * * * |
OTQCheckinAgent.runCheckin() — Telegram check-in for any unlogged scheduled events | cloudflare/otq-checkin/wrangler.jsonc |
| Daily 8:30am | 15:30 | Cloudflare Worker 30 15 * * * |
OTQCheckinAgent.runMorningSummary() — Telegram training summary | cloudflare/otq-checkin/wrangler.jsonc |
DST behavior: - launchd respects local TZ → fires at 7am PDT and 7am PST without intervention. - Cloudflare crons are UTC-fixed → when PST returns in November, evening fires at 9pm and morning at 9:30am local. Edit wrangler.jsonc twice a year, or accept the drift.
Removed (2026-05-05 — teardown-laptop.sh ran, shadow mode short-circuited¶
after first day of clean R2 → daily_sync round-trip verification)
| When | Was | Replacement | Tear-down state |
|---|---|---|---|
| Daily 8:00pm | launchd com.casey.warehouse-checkin (evening_checkin.py) |
Worker runCheckin() (cron 0 3 * * *) |
plist renamed to .disabled, kept on disk for rollback |
| 8:30/9:30/6:30am | launchd com.casey.warehouse-listener (telegram_listener.py, polling) |
Worker /webhook (Telegram push) |
plist renamed to .disabled, kept on disk for rollback |
| Daily 8pm UTC | GitHub Actions evening-checkin.yml |
Worker runCheckin() |
renamed to .disabled locally; commit + push when ready to stop GHA from firing |
To re-enable any of these (disaster recovery, e.g. Worker is broken and a
fix is hours away): rename the .disabled file back, launchctl load it
or git revert the GHA workflow rename. Both Python scripts still exist
and work; only the orchestration moved.
Inspect / manage¶
# Active launchd jobs (PID, last-exit, label):
launchctl list | grep com.casey
# Reload after editing a plist:
launchctl unload ~/Library/LaunchAgents/com.casey.<job>.plist
launchctl load ~/Library/LaunchAgents/com.casey.<job>.plist
# Force-restart an always-on job in place (preferred for warehouse-ui):
launchctl kickstart -k gui/$(id -u)/com.casey.warehouse-ui
# Cloudflare crons (registered on each wrangler deploy):
cd ~/garmin-warehouse/cloudflare/otq-checkin && grep -A4 '"crons"' wrangler.jsonc
# Worker live tail:
cd ~/garmin-warehouse/cloudflare/otq-checkin && npx wrangler tail
# Per-layer health snapshot (the same data the /status page renders):
curl -s http://127.0.0.1:8765/freshness | python3 -m json.tool
# Or visit https://warehouse.caseymanos.com/status
Wake-from-sleep¶
Mac must be awake at trigger time for launchd jobs. pmset repeat
wakeorpoweron MTWRFSU 6:55:00 schedules wake before the 7am sync if
the lid is closed. Worker is NOT subject to this — runs in CF's edge.
Quiet-hours guard¶
daily_sync.sh has a built-in 5am-11pm guard to defeat launchd's
missed-wake recovery. If the Mac was asleep at 7am and wakes at 1am,
launchd auto-fires the job — without the guard, that kicks off
garmindb downloads + kb embedding off-schedule. Override with
FORCE_RUN=1.
Notifications¶
daily_sync.sh and podcast-sync.sh both send notifications on
completion (Telegram + Resend email). See systems memory.