Skip to main content
A schedule fires an agent on a cron: each firing starts one session with a fixed first message, so a recurring job needs no scheduler of your own. The session is ordinary — same runtime, streaming, and destinations as any other.
Preview — APIs may change before general availability.
Declare schedules in the agent’s agent.toml, or manage them over the SDK, CLI, or REST. They live on the agent, not a session.

How it works

A platform tick runs every minute: it claims schedules whose next_fire_at has passed, enacts each, and advances next_fire_at to the next occurrence. Enacting starts a session on the agent’s active revision at fire time with input as the first message; everything downstream — boot, events, SSE, destinations — is the normal session path. Common crons (minute hour day-of-month month day-of-week):

agent.toml

An agent can carry several schedules — the same behavior on different cadences and inputs — each a [[schedules]] entry keyed by a name unique to the agent.
input is the entire first message and no human is in the loop, so write it as a self-contained instruction. Each deploy (git push or oc agent deploy) syncs the table: upsert by name, drop schedules no longer declared, preserve paused. Omitting the [[schedules]] table syncs nothing — existing schedules are left alone. A schedule is a binding, not behavior: it sits outside the revision digest, so editing one doesn’t cut a revision and a rollback doesn’t touch it.
For a repo-linked agent the agent.toml owns the schedules — the API and dashboard can pause/resume but reject other edits (409), same as prompt/model.

Management API

Org-key authenticated, server-side. Schedules are addressed under the agent. Create:
List and fetch:
Update, pause, resume. PATCH accepts cron, tz, input, overlap, and paused. A cron/tz change recomputes next_fire_at from now; resume recomputes from now and resets the failure counter — the paused window never back-fires.
Delete — removes the schedule; run history is retained.
Fire now — enacts immediately in any state (paused included) and doesn’t advance the cron. The test loop is create then fire. A failed manual fire returns the run with outcome: "failed" and updates last_error, but never changes the schedule’s state or failure counter.
Runs — newest-first; each row carries session_id to chain into GET /sessions/:id.

The schedule object

States

Runs

Each firing decision appends a srn_… run, so the history shows why a slot did or didn’t produce a session. Fields: id (srn_…), scheduled_for? (the slot; null for a manual fire), fired_at, outcome, session_id?, error?.

Limits

  • ≤ 20 schedules per agent.
  • input ≤ 32 KiB.
  • Cron floor 1 minute.
Scheduled sessions run unattended — cap them. Set agent limits turns and turn_seconds (every run inherits them). limits.tokens is not enforced yet, so don’t rely on it to bound spend.

Dashboard

The agent’s Schedules tab lists each schedule with its next fire and state, plus controls (pause/resume, test-fire, edit, delete) and per-schedule run history. The create form takes a cron — with quick presets and a plain-English gloss for common expressions — and a message; schedules created here run in UTC (a zone set via the API/CLI still displays). Repo-linked schedules are read-only except pause/resume; auto_paused shows the last error.

Example

  1. agent.toml declares [[schedules]] name = "morning-docs-sweep", cron = "0 9 * * 1-5". git push deploys the agent and the schedule goes active.
  2. Weekday 09:00 → a session starts on the active revision, first message = input, actor.kind = "schedule".
  3. The agent reconciles docs/ and opens a draft PR — an ordinary session on the dashboard and your destinations.
  4. Next 09:00, if the prior run is still running (overlap: "skip") → the firing records skipped and the schedule advances.