Scheduling
Schedules are a first-class resource in Lantern — separate from agents, so one agent can have many schedules with different inputs and timezones. They are managed through /v1/schedules.
In plain termsA schedule makes an agent run itself — "every weekday at 9am, summarize my inbox" — with no one clicking a button. The "cron expression" below is just the standard shorthand for describing when: five fields for minute, hour, day, month, and weekday. You can attach several schedules to one agent, each with its own input and its own timezone, and every scheduled run shows up in the dashboard like any other.
Cron expressions
Schedules use standard 5-field cron syntax (minute, hour, day-of-month, month, day-of-week):
# ┌─── minute (0-59)
# │ ┌─── hour (0-23)
# │ │ ┌─── day of month (1-31)
# │ │ │ ┌─── month (1-12)
# │ │ │ │ ┌─── day of week (0-6, Sun=0)
# │ │ │ │ │
# * * * * *
0 9 * * 1-5 # every weekday at 9:00 AM (in the schedule timezone)
*/15 * * * * # every 15 minutes
0 0 1 * * # first day of every month at midnightDOM + DOW footgun. When both day-of-month and day-of-week are non-wildcard (e.g.
0 9 1-7 * 1), standard cron fires on either condition — not only on days that satisfy both. To target the first Monday of a month reliably, use a workflow with a conditional node, not a cron expression.Schedule API
Create a schedule
POST /v1/schedules
Content-Type: application/json
{
"agentName": "research-agent",
"cronExpr": "0 9 * * 1-5",
"timezone": "America/New_York",
"config": { "input": { "mode": "daily-digest" } },
"enabled": true
}
Response: 201 Created
{
"id": "sched-uuid",
"agentName": "research-agent",
"cronExpr": "0 9 * * 1-5",
"timezone": "America/New_York",
"enabled": true,
"nextFireAt": "2026-07-28T13:00:00Z"
}List schedules
GET /v1/schedules
Response: 200 OK — bare array
[
{ "id": "sched-uuid", "agentName": "...", "cronExpr": "...", "enabled": true, ... }
]Update a schedule
PUT /v1/schedules/{id}
Content-Type: application/json
{ "enabled": false } // pause the scheduleDelete a schedule
DELETE /v1/schedules/{id}
Response: 204 No ContentTimezone handling
Each schedule carries an optional timezone field (IANA, e.g. America/New_York). When set, cron matching fires at the schedule's local time; DST transitions are handled automatically. Without a per-schedule timezone, the deployment-wideLANTERN_DEFAULT_TIMEZONE applies; both unset means UTC.
The same timezone logic governs the budget-enforcement day boundary:max_cost_usd_per_day rolls at local midnight, not UTC.
Surfaces trigger runs too. Incoming messages on a WhatsApp, Slack, or webchat surface trigger a run (via
POST /v1/runs under the hood) — they are not schedules but follow the same run lifecycle. See Surfaces.