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

# Schedule

> Cron-based signals that fire jobs on a timer.

Schedule signals fire on a cron expression, running jobs periodically without any external dependency. Friday evaluates the expression internally — no tunnel, no webhook, no credentials.

## Config

| Field      | Type   | Required | Default | Description                                     |
| ---------- | ------ | -------- | ------- | ----------------------------------------------- |
| `schedule` | string | Yes      | —       | Cron expression (standard 5-field syntax)       |
| `timezone` | string | No       | `UTC`   | IANA timezone name (e.g. `America/Los_Angeles`) |

## Example

```yaml workspace.yml theme={null}
signals:
  daily-digest:
    title: "Daily digest"
    description: "Kick off the morning summary job at 9 AM local time"
    provider: schedule
    config:
      schedule: "0 9 * * *"
      timezone: "America/Los_Angeles"
```

## Cron syntax

Standard 5-field cron: `minute hour day-of-month month day-of-week`. Ranges (`1-5`), lists (`1,3,5`), steps (`*/15`), and wildcards (`*`) are all supported via the [`cron-parser`](https://www.npmjs.com/package/cron-parser) library.

<AccordionGroup>
  <Accordion title="Common schedules">
    | Expression    | Fires                        |
    | ------------- | ---------------------------- |
    | `*/5 * * * *` | Every 5 minutes              |
    | `0 * * * *`   | Every hour on the hour       |
    | `0 9 * * *`   | 9:00 AM every day            |
    | `0 9 * * 1-5` | 9:00 AM Mon–Fri              |
    | `0 0 1 * *`   | Midnight on the 1st of month |
    | `30 2 * * 0`  | 2:30 AM every Sunday         |
  </Accordion>

  <Accordion title="Testing an expression">
    Use any online cron evaluator (e.g. [crontab.guru](https://crontab.guru)) to sanity-check your expression before committing. Invalid expressions fail space validation at load time with a clear error.
  </Accordion>
</AccordionGroup>

## Timezone

If `timezone` is omitted, the schedule runs in UTC. Set it to the IANA name of the zone you care about (e.g. `Europe/Warsaw`, `Asia/Tokyo`) — Friday handles DST transitions automatically.

<Warning>
  Don't use abbreviations like `PST` or `CET` — use full IANA zones like `America/Los_Angeles` or `Europe/Warsaw`. Abbreviations are ambiguous and some libraries reject them.
</Warning>

## Payload

Schedule signals fire with an empty payload by default. If you want to pass data into the job, add a `schema` block describing the shape — but remember Friday itself doesn't populate anything, so the job has to read constants or space state.

```yaml workspace.yml theme={null}
signals:
  hourly-refresh:
    title: "Hourly refresh"
    description: "Refresh cached data"
    provider: schedule
    config:
      schedule: "0 * * * *"
    schema:
      type: object
      properties:
        source:
          type: string
          default: "cache"
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="Schedule doesn't fire">
    Check Friday logs on startup for `invalid cron expression`. If the expression passes parsing but the job still doesn't run, verify the timezone — a schedule of `0 9 * * *` with `UTC` timezone will fire at 9 AM UTC, which might be the middle of the night locally.
  </Accordion>

  <Accordion title="Schedule fires twice around DST transitions">
    IANA zones handle DST correctly, but if your space was running during the transition moment, some cron expressions (e.g. `30 2 * * *` in a zone that springs forward past 2:30 AM) can skip or duplicate. Choose a time that doesn't fall in the DST window, or use UTC for timing-sensitive jobs.
  </Accordion>
</AccordionGroup>
