Skip to main content

Schedule

Say when the work should run in plain terms. Use the same schedule for gates, eval monitors, and reports. Drop to cron only when you need it.

Status: Beta Companion docs: Release gates · Evals onboarding · The closed loop Source of truth: Test suites API · Evals API · Reports API.

Start with the cadence you mean

from trinitite import Schedule

nightly = Schedule.nightly()
every_six_hours = Schedule.every("6h")
monday_morning = Schedule.weekly(on="mon", at="09:00")

Schedule turns a readable cadence into the five-field cron used by the job runner. Your app does not need to build cron strings for common cases.

Use named constructors

ConstructorMeaning
Schedule.every("45m")Every 45 minutes
Schedule.hourly()Every hour at minute zero
Schedule.daily(at="02:30")Every day at 02:30 UTC
Schedule.nightly()Daily off-hours preset
Schedule.weekly(on="mon", at="09:00")Monday at 09:00 UTC
Schedule.monthly(on_day=1)First day of each month
Schedule.cron("...")Explicit five-field cron escape hatch

A bare duration or preset also works on schedule=:

ev.monitor(schedule="nightly", min_pass_rate=0.90)

tr.gate(
scope="refund-flow",
mode="continuous",
schedule="6h",
thresholds={"accuracy": 0.95},
)

A bare cron string does not work. Wrap it with Schedule.cron(...) so the intent is clear.

Set the local time zone

schedule = Schedule.daily(at="02:30").in_tz("America/New_York")

print(schedule.describe)
print(schedule.to_cron)

The time zone is an IANA name. It stays attached to the schedule so daylight-saving changes do not silently shift a local job.

Spread work across a fleet

schedule = Schedule.nightly().with_jitter("5m")

Jitter spreads jobs around the target time. This keeps a large fleet from starting every check at the same second.

Bound a campaign

campaign = (
Schedule.nightly()
.starting("2026-09-01")
.until("2026-11-30")
)

The start and end dates are inclusive. Use a window for a trial, launch period, or fixed audit cycle.

Attach the same type to each surface

schedule = Schedule.weekly(on="mon", at="09:00").in_tz(
"America/New_York"
)

monitor = ev.monitor(
schedule=schedule,
min_pass_rate=0.90,
)

gate = tr.gate(
scope="refund-flow",
mode="continuous",
schedule=schedule,
thresholds={"accuracy": 0.95},
persist=True,
)

The surface decides permissions and behavior. Schedule only describes when it should run.

Where to go next