<!--
Sitemap:
- [Installation](/installation)
- [Upgrading](/upgrading): Version-specific steps for upgrading an existing Bento install.
- [Concepts](/concepts)
- [Build your first pipeline](/tutorials/pipeline-args)
- [Target a specific issue or PR from a URL](/tutorials/url-targeting)
- [Keep state across runs](/tutorials/pipeline-state)
- [Fire a pipeline on a schedule or on demand](/tutorials/schedule-and-fire)
- [Deploy a box to Railway](/tutorials/deploy-to-railway)
- [Operate a hosted daemon](/tutorials/operate-a-hosted-daemon)
- [Configuration](/configuration)
- [Members](/members)
- [Knowledge base](/knowledge-base/)
- [Method and delivery](/knowledge-base/modes)
- [Config](/knowledge-base/config)
- [MCP](/knowledge-base/mcp)
- [Pipeline configuration reference](/pipelines/config)
- [Filters](/pipelines/filters)
- [Triggers](/triggers/)
- [GitHub trigger](/triggers/github)
- [Linear trigger](/triggers/linear)
- [Webhook trigger](/triggers/webhook)
- [Schedule trigger](/triggers/schedule)
- [Manual trigger](/triggers/manual)
- [Traces](/pipelines/traces)
- [Slack](/integrations/slack)
- [Public access](/public-access)
- [Context engineering](/context-engineering)
- [Best practices](/best-practices)
- [Troubleshooting](/troubleshooting)
- [Architecture](/architecture/vision)
- [Workspaces](/workspaces)
- [Authentication](/authentication)
- [Identity](/identity)
- [Security](/security)
- [References](/references)
- [Changelog](/changelog): Bento release history.
- [CLI reference](/cli/)
- [Setup](/cli/setup)
- [Secrets](/cli/secrets)
- [Lifecycle](/cli/lifecycle)
- [Sandbox image](/cli/image)
- [Sandboxes](/cli/sandbox)
- [Observability](/cli/observability)
- [Diagnostics](/cli/diagnostics)
- [Triggers](/cli/triggers)
- [Workbench](/cli/workbench)
- [Auth](/cli/auth)
- [Knowledge](/cli/knowledge)
- [Evals](/cli/evals)
- [Bento](/index)
- [Runtime wrapper](/architecture/runtime-wrapper)
- [Skill evolve](/architecture/skill-evolve)
-->

# Schedule trigger

Schedule triggers use a standard five-field cron expression in UTC.

```yaml
trigger:
  schedule: "*/5 * * * *"   # every 5 minutes
```

Cron ticks expire after five minutes by default. Use the object form to change the limit:

```yaml
trigger:
  schedule:
    cron: "0 * * * *"
    max_age: 15m
```

The daemon discards a tick that is older than `max_age` when a worker dequeues it. The discarded trigger records the reason and does not create a workload. The age includes the time that the tick waits for a worker. Set a larger value for sparse schedules that share workers with long-running pipelines. Manual `bento trigger schedule <name>` requests do not expire.

## Cron format

```
┌───────── minute (0–59)
│ ┌─────── hour (0–23)
│ │ ┌───── day of month (1–31)
│ │ │ ┌─── month (1–12)
│ │ │ │ ┌─ day of week (0–6, 0=Sunday)
│ │ │ │ │
* * * * *
```

Common patterns:

| Expression | Schedule |
|---|---|
| `*/5 * * * *` | Every 5 minutes |
| `0 */3 * * *` | Every 3 hours (midnight, 3am, 6am, …) |
| `0 7 * * *` | Daily at 7am |
| `0 0 * * 1` | Every Monday at midnight |

Each field takes a number, a list (`1,3,5`), a range (`0-12`), a wildcard, or a step over the whole field (`*/2`). The parser rejects a step over a range, such as `1-23/2`, and it rejects month and weekday names, such as `MON`. Write the values as a list instead: `1,3,5,7,9,11,13,15,17,19,21,23`. `bento doctor` and `bento config validate` report an expression the parser rejects, and the daemon refuses to start until you fix it.

## Overlapping fires

A scheduled pipeline runs one fire at a time. A tick that arrives while the previous fire is still running waits for it. The daemon discards the tick if it exceeds `max_age`, or if a newer tick is waiting behind it. The daemon records a discarded tick as a `discarded` trigger, with the reason in its note:

```bash
bento trigger list --pipeline nightly-summary --status discarded
```

`bento trigger schedule <name>` is not subject to either cron-tick rule.

A daemon killed mid-fire — a redeploy, or a restart that outran its drain — leaves that fire holding the pipeline's slot. The next daemon releases the slot at boot, so the pipeline resumes on its next current tick. The daemon discards an expired tick at dequeue, and it does not retry the interrupted fire.

## Repo checkout

Set `repo` to the `url` of an entry under `repos:` in `daemon.yaml`. The map key of the entry is a label only, and the daemon never matches on it.

To clone a repository before the agent starts, set `trigger.repo` and, optionally, `trigger.branch`:

```yaml
trigger:
  schedule: "0 */3 * * *"
  repo: acme/my-project      # owner/name — must match a repos: entry's url in daemon.yaml
  branch: develop            # defaults to the repo's configured branch
```

## Examples

```yaml
# liveness probe
trigger:
  schedule: "*/5 * * * *"
agent: heartbeat
instructions: Reply with exactly the word "pong" and nothing else.
options:
  stateless: true
```

```yaml
# daily issue solver
trigger:
  schedule: "0 7 * * *"
  repo: acme/my-project
  branch: develop
agent: solver
skill: solve-issue
```

```yaml
# docs drift audit
trigger:
  schedule: "0 */3 * * *"
  repo: acme/my-project
  branch: develop
agent: archivist
skill: docs-drift-audit
guardrails:
  read_only: true
  timeout: 1200
```
