Proposal: Multi-athlete local-time delivery

Published 2026-04-11

A multi-athlete local-time delivery architecture for Coach Luca

Purpose: Replace per-athlete timezone-bound cron scheduling with a scalable local-time delivery system for multiple athletes across changing timezones and communication channels.


1. Problem

The current model uses fixed cron jobs with a single timezone baked into each job. That approach fails once the system must support:

  • multiple athletes in different timezones
  • athletes who travel frequently
  • daylight saving transitions
  • different communication channels per athlete
  • different message schedules per athlete

Rewriting cron jobs when an athlete changes location is not a viable architecture. It creates operational fragility, does not scale across a roster, and places scheduling logic in the wrong layer.


2. Core design principle

Time is an athlete property, not a cron property.

Cron should wake a scheduler. The scheduler should decide which athlete messages are due based on each athlete's effective local time, delivery settings, and current state.

This means the system should move from:

  • static athlete-specific cron jobs tied to fixed timezones

To:

  • one central dispatcher that runs on a fixed cadence and evaluates all active athletes dynamically

3. Proposed architecture

3.1 One global dispatcher cron

Use a single cron job that runs every 15 minutes in UTC.

That job does not send athlete messages directly. Instead, it performs one responsibility:

  • evaluate which athlete workflows are due right now

A 15-minute cadence is sufficient for this use case and avoids unnecessary scheduler churn.

3.2 Athlete delivery registry

Each athlete should have a durable delivery configuration record. That record should include:

Field Purpose
Athlete ID Stable internal identity
Preferred channel Delivery connector to use
Channel target Channel-specific destination, such as Telegram user ID, WhatsApp recipient, iMessage handle, Slack DM target, or other OpenClaw-supported connector target
Morning enabled Whether the morning workflow is active
Evening enabled Whether the evening workflow is active
Morning local send time Preferred local send time, for example 08:00
Evening local send time Preferred local send time, for example 20:00
Default timezone Fallback home timezone
Active status Whether the athlete is currently in the live automation pool

The preferred channel should not be limited to Telegram. It should support whatever message sending connectors OpenClaw supports, for example:

  • Telegram
  • WhatsApp
  • iMessage
  • Slack
  • any other supported outbound messaging connector

The dispatcher should route through the athlete's configured preferred channel rather than hard-coding delivery behavior per workflow.

3.3 Timezone resolver

Each athlete should have an effective timezone resolved dynamically at runtime.

Resolution order should be:

  1. Same-day explicit override, if present
  2. Current travel/location record
  3. Default home timezone

This lets the system determine the athlete's true local time without rewriting cron jobs.

3.4 Due-work evaluator

Every 15 minutes, the dispatcher should evaluate each active athlete and ask:

  • What is this athlete's effective timezone right now?
  • What is the local date and time in that timezone?
  • Is the athlete due for a morning message?
  • Is the athlete due for an evening message?
  • Has that workflow already been sent for this athlete on this local date?
  • Is there any athlete-specific suppression rule that should skip the send?

If the workflow is due, the dispatcher should enqueue or spawn the relevant athlete workflow.

3.5 Workflow execution layer

Once an athlete workflow is due, the dispatcher should launch the existing morning or evening generation logic for that athlete.

That workflow should:

  • read the athlete's current context
  • generate the message
  • send it through the athlete's preferred channel
  • save durable records
  • report success or failure to the scheduler ledger

This preserves the existing coaching logic while moving the scheduling responsibility into the correct layer.


4. Required durable state

4.1 Send ledger

A durable send ledger is required to guarantee idempotency.

Each send attempt should record at least:

Field Purpose
Athlete ID Which athlete was evaluated
Workflow type Morning or evening
Local date Athlete-local date used for scheduling
Effective timezone Timezone used for evaluation
Scheduled local time Intended athlete-local send time
Evaluated at Actual dispatcher evaluation timestamp
Sent at Actual send timestamp
Delivery channel Telegram, WhatsApp, iMessage, Slack, etc.
Delivery target Channel-specific destination
Status Sent, skipped, failed, retried
Failure detail Error detail when applicable

This ledger prevents duplicate sends when the dispatcher runs every 15 minutes and provides a durable audit trail.

4.2 Athlete status source of truth

The dispatcher should rely on one athlete status source of truth for:

  • current location
  • effective timezone inputs
  • active/inactive delivery status
  • preferred channel and target
  • workflow enablement

That state should be centralized and durable, not scattered across multiple workflow-specific cron payloads.


5. Why this solves the real problem

This design supports:

  • many athletes in different timezones at the same time
  • athletes moving between locations without cron rewrites
  • per-athlete local send times
  • per-athlete channel preferences
  • future expansion to new messaging connectors
  • daylight saving changes through timezone-aware local-time evaluation
  • operational safety through a durable idempotency ledger

Most importantly, it removes the false assumption that a cron job itself should embody an athlete's local schedule.


6. Why fixed athlete cron jobs are the wrong abstraction

Per-athlete fixed crons create the following problems:

  • timezone changes require manual edits or cron rewrites
  • scaling to many athletes becomes operationally messy
  • channel logic ends up duplicated across cron payloads
  • DST handling becomes brittle
  • delivery state and due-state are implicit rather than durable
  • the system cannot reason cleanly about whether a send was due, skipped, missed, or retried

A central dispatcher turns those hidden assumptions into explicit system logic.


7. Minimal viable implementation

A practical first version should include:

  1. One UTC cron job every 15 minutes
  2. One athlete delivery registry
  3. One timezone resolver
  4. One due-work evaluator
  5. One durable send ledger
  6. Reuse of the existing morning and evening generation workflows
  7. Channel dispatch through the athlete's configured preferred connector

This is enough to support multiple athletes in different locations without rewriting cron jobs.


A simple normalized structure could look like this:

Athlete delivery profile

Field Example
athlete_id sidney
preferred_channel telegram
channel_target 8761249729
morning_enabled true
morning_local_time 08:00
evening_enabled true
evening_local_time 20:00
default_timezone America/Edmonton
active true

Timezone resolution inputs

Field Example
current_location Victoria, BC
resolved_timezone America/Vancouver
resolution_source travel-schedule
resolved_at 2026-04-11T23:00:00-06:00

Send ledger row

Field Example
athlete_id sidney
workflow morning
local_date 2026-04-12
local_time_target 08:00
effective_timezone America/Vancouver
delivery_channel telegram
delivery_target 8761249729
status sent
sent_at 2026-04-12T08:01:12-07:00

9. Channel architecture requirement

The design should be channel-agnostic.

The scheduler must not assume Telegram-only delivery. Instead, the athlete record should point to the preferred OpenClaw-supported outbound channel and target. The same due-work and idempotency logic should work regardless of connector.

Examples:

  • Telegram user ID
  • WhatsApp recipient target
  • iMessage handle or chat target
  • Slack user or channel DM target
  • future supported connectors

This keeps coaching workflow logic separate from transport selection.


10. Operational recommendation

Do not continue extending the current fixed-cron-per-athlete approach.

Treat the current direct morning and evening crons as a temporary stopgap for a single athlete, not as the long-term architecture.

The proper next design layer is a roster-aware dispatcher with:

  • a 15-minute UTC wake cycle
  • athlete-local due-time evaluation
  • channel-aware delivery routing
  • durable send-state tracking

11. Summary

The right solution is not dynamic cron rewriting per athlete trip.

The right solution is:

  • one central dispatcher
  • every 15 minutes
  • athlete-local due-time evaluation
  • per-athlete preferred channel support
  • per-athlete target records
  • durable idempotent send tracking

That architecture supports a real coaching roster instead of a single-athlete workaround.