agno_schedules table) and use the same FastAPI process used by the agents.
agno_schedules every scheduler_poll_interval seconds, fires due jobs, retries failures, and persists state.
Two ways to create schedules
| Pattern | How |
|---|---|
| Agent Managed | Agent has tools to create, read, update active schedules. Users ask the agent to schedule things in chat, agent uses tool calls to manage schedules. |
| Manually Registered | Schedules created in code, registered at startup. |
Agent Managed
Give an agentSchedulerTools and it can schedule its own work via chat:
Manually Registered
For schedules that should always exist (the daily digest, the hourly sync, the nightly cleanup), create them in your app’s lifespan viaScheduleManager:
if_exists="update" makes the call idempotent — re-running on restart updates the existing schedule rather than raising or duplicating. Pass "skip" if you want to leave manually-edited schedules alone, or "raise" (the default) to surface accidental name collisions. This is the pattern Coda uses for daily digest, issue triage, and repo sync.
Workflows for multi-step jobs
Schedules fire single endpoints. When the work is multi-step — research, then outline, then draft, then review — you reach for a workflow. Workflows aren’t strictly a scheduling feature, but they’re the most common thing a schedule fires. A workflow is a typed pipeline. Steps run in order.Parallel runs them concurrently. Loop repeats until a condition holds. Router picks one branch.
Loop.end_condition accepts a CEL expression string (as above) or a callable that takes the iteration’s step outputs and returns a bool. Condition is a separate primitive for if/else branching inside a workflow — pair it with Router for dynamic branches, not with Loop.
Workflows are first-class AgentOS citizens: /workflows/<id>/runs POST endpoint, schedulable, traced, persisted in the same db.
| Pattern | Use when |
|---|---|
| Sequential | Steps depend on each other |
| Parallel | Steps are independent and you want fanout |
| Loop with condition | Quality threshold or max iterations |
| Router + Condition | Dynamic branching on input |
| Cross-modal chaining | Output of one agent is input to a different modality (text → speech, code → narration) |
Schedule runs and observability
When a schedule fires, AgentOS:- Looks up the schedule in
agno_schedulesand claims it via a row-level lease. - Calls the configured endpoint (
POST /agents/<id>/runsorPOST /workflows/<id>/runs) over HTTP viahttpx.AsyncClient— the same path an external caller would take, including auth headers. - Records the result in
agno_schedule_runs(status, attempt, timings, error if any) and the underlying run inagno_sessionsandagno_traceslike any other run.
run_id from agno_schedule_runs back to agno_traces. See Observability for the full data model.
Scheduler in HA
Every replica can run the scheduler loop safely. Due schedules are claimed via a row-level lease (locked_by, locked_at on agno_schedules) — the first replica to claim a due job runs it, the others skip. No leader election needed; the lease is the coordination primitive.
If you’d rather keep scheduler polling off your hot request path, pin it to a dedicated replica via deployment config. See Scheduler for tuning details.