> ## Documentation Index
> Fetch the complete documentation index at: https://app.keystroke.ai/docs/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](/learn/workflows/overview) or [agent](/learn/agents/overview) 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` and a cron `schedule`, then attach a target.

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

export default defineCronSource({
  slug: "morning-check",
  schedule: "0 9 * * *",
}).attach({ workflow });
```

| Option     | Required | What it does                                                                                              |
| ---------- | -------- | --------------------------------------------------------------------------------------------------------- |
| `slug`     | Yes      | Stable trigger slug (used in the [attachment id](/learn/triggers/overview#attachment-id) and run history) |
| `schedule` | Yes      | A cron expression for when the trigger fires                                                              |

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

<Note>
  Cron expressions have no timezone option. They evaluate against the runtime clock: UTC on the hosted platform, and your machine's local time under `keystroke dev`. For a specific local time in production, convert it to UTC in the expression (for example, 9am US Eastern is `0 13 * * *` or `0 14 * * *` depending on daylight saving).
</Note>

## Empty input

A schedule fires on time alone; there is no inbound payload. A schedule attached to a workflow runs it with an empty input (`{}`), so its workflow should accept an empty object:

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

A schedule attached to an agent runs it with a static `prompt` (or a `prompt()` function that ignores its argument):

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

export default defineCronSource({ slug: "morning-check", schedule: "0 9 * * *" }).attach({
  agent: support,
  prompt: "Run the morning check and summarize anything that needs attention.",
});
```

## Test it while building

You don't have to wait for the clock. Invoke the target directly while developing:

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

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

## Next steps

<CardGroup cols={2}>
  <Card title="Polling" href="/learn/triggers/polling">
    Run on a schedule, but only when there's new work.
  </Card>

  <Card title="Webhooks" href="/learn/triggers/webhooks">
    Run on inbound HTTP requests instead of a clock.
  </Card>

  <Card title="Advanced triggers" href="/learn/triggers/advanced-triggers">
    Agent prompts, transforms, and filtering.
  </Card>

  <Card title="Triggers overview" href="/learn/triggers/overview">
    Sources, attach, and attachment ids.
  </Card>
</CardGroup>
