Schedules
Have a runner start work on its own — a fixed message sent daily or hourly.
A schedule sends your runner the same message on a recurring cadence, so work starts without anyone typing it. It is how a runner becomes a standing role — a daily triage pass, an hourly check on something — rather than something you have to remember to poke.
Add a schedule
Schedules live on the runner's own page, under Connectors. There is no separate settings page and no CLI command — you add one where the runner is. A runner can have as many as you like, each independent.
You give it:
- A message — what the runner is asked to do each time.
- A cadence — daily at a time you choose, or hourly. Those are the only two.
- A time, as
HH:MMon a 24-hour clock. For an hourly schedule only the minute matters, so:15means a quarter past every hour. - A timezone, as a standard IANA name like
Europe/LondonorAmerica/New_York. The form starts from your own timezone. - Optionally a name, and its own OpenCode agent and model.
Every run starts a fresh conversation. A schedule is the same as opening a new chat and typing the message — it never continues the previous run's thread. Give it a message that stands on its own.
Keeping runs from piling up
Two different problems, two separate switches — worth knowing which is which, because their defaults differ.
- Skip while the previous run is still active — for a runner still working when the next occurrence comes round. The occurrence is recorded as skipped and starts no conversation. This is on by default for new schedules. A schedule you created earlier keeps whatever it was set to.
- Cancel a still-queued previous run — for a runner that has been offline and has occurrences stacked up waiting. The earlier run is marked cancelled and only the newest one is delivered. This is off by default, so by default every occurrence queues its own run and all of them are delivered on reconnect.
Run now, by hand
You can trigger a schedule immediately. The run is marked manual so it is easy to tell from a cadence run, and it does not move the next scheduled time. A manual trigger also bypasses the skip guard — if you ask for it while the previous run is still going, it runs.
When your runner is offline
The run is recorded as queued and delivered when the runner reconnects. Every runner holds messages while it is offline — there is nothing to turn on. The queued run still links to the conversation it started, so you can open it.
One schedule failing never stops the others due at the same time. A transient delivery problem is retried automatically without re-firing the occurrence or shifting the cadence, and is only recorded as failed once the retries are exhausted. A scheduled turn interrupted by a runner restart is picked back up on reconnect, the same as a Slack or GitHub turn.
Reviewing what happened
Each schedule keeps its recent runs, newest first, showing when it ran, whether it was sent, queued, failed, cancelled or skipped, and a link to the conversation it started. Runs you triggered by hand are marked as manual.
You can disable a schedule temporarily — it stops running and starts again when you re-enable it — or remove it entirely.
A schedule fires at the time you choose, not on the dot. Evident checks for due schedules every few minutes, so read "09:00" as "shortly after 09:00". Don't build anything that needs the message to land at an exact clock time.
Next steps
- Webhooks — get told when work arrives for a stopped runner
- Local runner — keep the runner online for its schedules
- Core concepts — runners, conversations and OpenCode agents