LanternDOCS

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 midnight
DOM + 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 schedule

Delete a schedule

DELETE /v1/schedules/{id}

Response: 204 No Content

Timezone 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.