> ## Documentation Index
> Fetch the complete documentation index at: https://docs.os.meetluno.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Schedules

> Run a workflow on a recurring schedule.

A schedule trigger runs a [workflow](https://docs.os.meetluno.ai/learn/workflows/overview.md) or [agent](https://docs.os.meetluno.ai/learn/agents/overview.md) on a recurring cron schedule. Use it for anything time-driven: a morning digest, an hourly sync, a nightly cleanup.

## Example requests

Ask your coding agent what should happen and how often. It can set up the schedule and attach it.

> "Every weekday at 8am, run the morning briefing workflow and post it to Slack."

> "On the first of each month, have the FP\&A agent review recurring charges and flag anything unused."

> "Every night, sync new rows from the form submissions table in Postgres into the reporting spreadsheet."

## Define a schedule

Use `defineCronSource` with a `slug`, `name`, `description`, and a cron `schedule`, then attach a target.

```ts src/triggers/morning-check.ts theme={null}
import { defineCronSource } from "@meetluno/luno/trigger";
import workflow from "../workflows/morning-check";

export default defineCronSource({
  slug: "morning-check",
  name: "Morning check",
  description: "Runs the morning check workflow every day at 09:00.",
  schedule: "0 9 * * *",
}).attach({ workflow });
```

| Option | Required | What it does |
| - | - | - |
| `slug` | Yes | Stable trigger slug (used in the [attachment id](https://docs.os.meetluno.ai/learn/triggers/overview.md#attachment-id) and run history) |
| `name` | Yes | Human-readable label shown in the platform |
| `description` | Yes | What the schedule does, shown in the platform |
| `schedule` | Yes | A cron expression for when the trigger fires |
| `timezone` | No | IANA timezone for schedule wall-clock fields (e.g. `America/New_York`). When omitted, UTC |
| `payload` | No | Static JSON passed to attachments on each tick (defaults to `{}`) |

> [!TIP]
>
> For a workflow that only needs a timer, declare it inline instead: `defineWorkflow({ ..., schedule: { cron: "0 9 * * *", timezone?, input? } })` (or an array of schedules with an `id` each). It becomes the same cron trigger, with the attachment id `<workflow-slug>:schedule[:<id>]`. See [Schedule](https://docs.os.meetluno.ai/learn/workflows/build-workflows.md#schedule).

## The cron schedule

The `schedule` is a standard cron expression. The common five-field form is `minute hour day-of-month month day-of-week`:

```ts theme={null}
schedule: "0 9 * * *"      // every day at 09:00
schedule: "*/15 * * * *"   // every 15 minutes
schedule: "0 0 * * 1"      // every Monday at midnight
```

Named months and weekdays (`MON`, `JAN`) and shorthand nicknames (`@daily`, `@hourly`) are also accepted.

Pass an optional IANA `timezone` so the cron fields are wall-clock times in that zone (DST-aware). When omitted, schedules evaluate in UTC:

```ts theme={null}
defineCronSource({
  slug: "morning-check",
  name: "Morning check",
  description: "Runs the morning check workflow every day at 09:00 Eastern.",
  schedule: "0 9 * * *",
  timezone: "America/New_York", // 9:00 AM Eastern every day
}).attach({ workflow });
```

> [!NOTE]
>
> Prefer `timezone` for wall-clock times like "9am" in a specific region. Without it, `"0 9 * * *"` means 09:00 UTC.

## Input / payload

By default a schedule fires with an empty input (`{}`). Pass an optional static `payload` on the source when the workflow needs input — it flows to attachments the same way a webhook body does:

```ts src/triggers/morning-report.ts theme={null}
import { defineCronSource } from "@meetluno/luno/trigger";
import workflow from "../workflows/morning-report";

export default defineCronSource({
  slug: "morning-report",
  name: "Morning report",
  description: "Runs the daily regional report.",
  schedule: "0 9 * * *",
  payload: { report: "daily", region: "us" },
}).attach({ workflow });
```

Without a `transform`, the payload must match the workflow's `input` schema (TypeScript enforces this at the `.attach()` call). Use `transform` to reshape the payload per attachment:

```ts theme={null}
.attach({
  workflow: euReport,
  transform: (payload) => ({ ...payload, region: "eu" }),
})
```

When `payload` is omitted, attachments still receive `{}`, so empty-input workflows keep working:

```ts theme={null}
input: z.object({}),
```

A schedule attached to an agent can use a static `prompt`, or a `prompt(payload)` function that reads the cron payload:

```ts src/triggers/morning-check.ts theme={null}
import { defineCronSource } from "@meetluno/luno/trigger";
import support from "../agents/support";

export default defineCronSource({
  slug: "morning-check",
  name: "Morning check",
  description: "Asks support to summarize overnight issues.",
  schedule: "0 9 * * *",
  payload: { focus: "overnight" },
}).attach({
  agent: support,
  prompt: (payload) =>
    `Run the morning check (focus: ${(payload as { focus: string }).focus}) and summarize anything that needs attention.`,
});
```

## Test it while building

You don't have to wait for the clock. After deploy, fire the cron trigger immediately (same static payload as a scheduled tick — platform only):

```bash theme={null}
luno triggers invoke morning-check
luno triggers invoke morning-check --workflow morning-check   # narrow to one attachment
```

Or invoke the target directly while developing:

```bash theme={null}
luno workflows run morning-check --input '{}'
luno agents prompt support --message "Run the morning check."
```

After deploy, the platform also fires the schedule on time — every tick runs the target unconditionally (cron has no filters). Inspect runs with `luno triggers runs list morning-check --workflow <target-slug>` (or `--agent <target-slug>`).

## Next steps

> **[Polling](https://docs.os.meetluno.ai/learn/triggers/polling.md)**
>
> Run on a schedule, but only when there's new work.

> **[Webhooks](https://docs.os.meetluno.ai/learn/triggers/webhooks.md)**
>
> Run on inbound HTTP requests instead of a clock.

> **[Advanced triggers](https://docs.os.meetluno.ai/learn/triggers/advanced-triggers.md)**
>
> Agent prompts, transforms, and filtering.

> **[Triggers overview](https://docs.os.meetluno.ai/learn/triggers/overview.md)**
>
> Sources, attach, and attachment ids.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.