Scheduler and heartbeat¶
Scheduled jobs live in the agent's schedule list and appear in the
dashboard's Scheduler tab, where you can also create, pause, edit and
trigger them.
schedule: [
{
name: "Morning revenue check",
cron: "0 9 * * 1-5",
timezone: "America/Costa_Rica",
message: "Check yesterday's revenue and flag anything unusual.",
},
{
name: "Weekly deep analysis",
cron: "0 7 * * 1",
message: "Review last week's numbers in depth and write the report.",
model: "olano:pro", // this job only; the agent's own model is unchanged
},
]
A job is a message sent to the agent at a time you choose — so anything the
agent can do in a conversation, it can do on a schedule. Use thread_id to keep
a job's history in one continuous conversation.
A model per job. model (provider:model, for example olano:turbo or
anthropic:claude-sonnet-4-6) runs that one job on a model other than the
agent's configured one, so a cheap tier can do the nightly digest and a bigger
one the weekly analysis on the same agent. Leave it out and the job follows the
agent's model, including later changes to it. Each run is billed to the model
that ran, and the run's conversation in the chat list shows which model it was;
on a managed deployment a bigger tier spends credits faster. A model whose
provider is not connected is refused when the job is saved, and a model that
stops working later fails the run with that reason in the job's history rather
than falling back silently. The same field exists on tasks in the Scheduler tab
("Model", with "Agent default" as the first choice) and on the scheduling tools
an agent or AgentFather uses.
And a reasoning effort per job. reasoning_effort sets how much thinking
the model does before answering on this job's runs, independently of the
agent's own reasoning_effort: a nightly digest can run at low while the
weekly analysis runs at high on the same agent. The value must be one of the
levels the model the job runs on accepts (model when set, else the agent's
configured model); the Scheduler tab's "Reasoning effort" field appears only
for such a model and lists exactly that ladder, and every surface that saves a
job refuses a level the model does not take, naming the ones it does. Leave it
out to follow the agent's own setting. Higher levels cost more tokens and time
per run; a level that stops being valid later (a model retired, a package
changed) is dropped for that run with a log line rather than failing the job.
flowchart TB
subgraph start["What starts the work"]
direction LR
S1["schedule list in agent.json5<br/>cron only"] ~~~ S2["Scheduler store<br/>the New task form or the agent itself,<br/>cron or one-time"] ~~~ HB["Heartbeat<br/>every 60 minutes by default,<br/>reads HEARTBEAT.md"]
end
start --> RUN["The agent runs, exactly as in a conversation:<br/>tools, files, approvals"]
Fan-out. With multi-user mode on, for_each_customer: true runs the job once
per end user, and the message can use {customer_key}, {platform} and
{user_id}. Use action instead of message to run a named script from
allowed_actions.
Two places jobs live. The schedule list above is one of them; the other is
the scheduler's own store, which is what the Scheduler tab's "New task" form
writes and what an agent creates when it schedules something itself. The
Scheduler tab merges both and badges each row, so nothing is hidden — but the
difference matters when you go looking for what is triggering a job. A
schedule entry is cron-only and lives in the agent's configuration; a stored
task can also be one-time and can be handed to a different agent later.
Asking an agent about the schedule. Any agent can read and change its own scheduled work in chat, and AgentFather can do the same for every agent in the deployment — across both places — so "what wakes the finance agent at 3am?", "pause that job", or "schedule a Monday summary for the support agent" are all things you can simply ask for. Changing, creating or immediately running another agent's job always raises an approval card first, because it makes that agent start working on instructions you supplied. Ask to see a job's full instructions before approving an edit: a listing shows only its name, schedule and the first couple of lines.
Heartbeat is different and simpler: the agent wakes up periodically (default
every 60 minutes) and reads HEARTBEAT.md in its workspace — a plain markdown
file of standing instructions. It is the low-ceremony way to say "keep an eye on
this" without writing a cron entry. Control it with the heartbeat block per
agent, or heartbeat: in config.yaml for the fleet.