Schedules
A schedule is a stored recipe — a job template plus its inputs, a recurrence rule, and a timezone — that the dispatcher turns into a fresh crew every time it comes due. It’s how you run “the daily news brief at 09:00” or “the weekly social post every Mon/Wed/Fri” without anyone kicking it off by hand.
Schedules live in the same SQLite file as the board and are materialized by the dispatcher’s schedule sweep — so, like jobs, nothing fires unless a dispatcher is running.
Cadences
Each schedule has one recurrence rule. The wall-clock math is timezone-aware (via Intl), anchored to the schedule’s IANA timezone:
| Cadence | Parameters | Example |
|---|---|---|
daily | time of day | every day at 09:00 |
weekly | days of week + time | Mon/Wed/Fri at 08:30 |
monthly | day of month + time | the 1st at 06:00 |
hourly | every N hours (1–24) | every 6 hours |
minutely | every N minutes (1–59) | every 15 minutes |
The materializer computes next_run_at, and on each due time commits a crew with an idempotency key of the form sched:<scheduleId>:<dueAt> — so a dispatcher restart can’t double-fire a run. A schedule with a broken rule is automatically disabled; a schedule whose template fails to load is logged and retried.
Creating a schedule
# Daily at 09:00
npx tsx ./src/cli.ts jobs schedules create \
-n 'Daily news brief' \
-t crew_news_brief/crew_news_brief.job_workflow.yaml \
--input '{"topic":"rust web frameworks"}' \
--cadence daily --at 09:00
# Weekly on Mon/Wed/Fri at 08:30
npx tsx ./src/cli.ts jobs schedules create \
-n 'Weekly social share' \
-t crew_social_share/crew_social_share.job_workflow.yaml \
--input '{"topic":"local-first sync engines"}' \
--cadence weekly --days mon,wed,fri --at 08:30| Flag | Required | Purpose |
|---|---|---|
-n, --name <name> | yes | Human label for the schedule. |
-t, --template <relpath> | yes | Template path relative to the data dir (e.g. crew_news_brief/crew_news_brief.job_workflow.yaml). |
--input <json> | no (default {}) | JSON object of template inputs. |
--cadence <cadence> | no | daily | weekly | monthly | hourly | minutely. |
--at <HH:MM> | no (default 09:00) | Time of day for daily/weekly/monthly. |
--days <list> | no | For weekly: mon,wed,fri or 1,3,5. |
--day-of-month <n> | no | For monthly. |
--every-hours <n> | no | For hourly (1–24). |
--every-minutes <n> | no | For minutely (1–59). |
--timezone <tz> | no (default host TZ) | IANA timezone for the cadence. |
--rule <json> | no | Raw recurrence rule JSON; overrides the cadence flags. |
--user <name> | no (default user_cli) | Creator attributed to spawned jobs. |
Managing schedules
npx tsx ./src/cli.ts jobs schedules list # alias: ls
npx tsx ./src/cli.ts jobs schedules enable <id>
npx tsx ./src/cli.ts jobs schedules disable <id> # pause; clears next run
npx tsx ./src/cli.ts jobs schedules run-now <id> # spawn a crew immediately
npx tsx ./src/cli.ts jobs schedules delete <id> # alias: rmJobs spawned by a schedule carry its scheduleId, so the board and inbox can tag them “from <schedule name>”. Deleting a schedule does not delete the jobs it already spawned.
The web client exposes all of this as a UI — a list with enable/disable switches, run-now, edit, and a cadence picker.