Scheduled Agents
Any agent type can be scheduled using the wake_up field. LeafMesh triggers the agent on a cron, interval, or keyword schedule.
Configuration
agents:
# Every 5 minutes
collector:
name: "collector"
agent_type: "programmatic"
wake_up: "*/5 * * * *"
yields:
readings: "array"
timestamp: "string"
can_call:
- agent: "analyzer"
condition: "readings != []"
# Every hour at :00
reporter:
name: "reporter"
model: "gpt-4o-mini"
wake_up: "0 * * * *"
yields:
summary: "string"
# Every day at midnight
daily_digest:
name: "daily_digest"
model: "gpt-4o"
wake_up: "0 0 * * *"
yields:
report: "string"Schedule Formats
| Format | Example | Meaning |
|---|---|---|
| Cron (5-field) | */5 * * * * | Every 5 minutes |
| Cron (5-field) | 0 9 * * 1 | Every Monday at 9 AM |
| Cron (5-field) | 0 9 * * 7 | Every Sunday at 9 AM (0 and 7 are both Sunday) |
| Cron (5-field) | 0 9 * * 6-7 | Saturday and Sunday at 9 AM |
| Cron (5-field) | 0 9 * * 5#3 | The third Friday of the month at 9 AM |
| Cron (5-field) | 0 9 * * 5L | The last Friday of the month at 9 AM |
| Interval | 30s | Every 30 seconds |
| Interval | 5m | Every 5 minutes |
| Interval | 2h | Every 2 hours |
| Interval | 1d | Every day |
| Keyword | @hourly | Top of every hour |
| Keyword | @daily | Midnight |
| Keyword | @weekly | Sunday midnight |
| Keyword | @monthly | First of the month |
Cron expressions follow the standard five-field format: minute hour day-of-month month day-of-week. When both day fields are set (0 9 1 * 1-5), the agent wakes on either — the 1st of the month or any weekday — as in standard cron.
Interval strings are a number plus a unit — s, m, h or d, with no
space. Keywords must carry the leading @.
Minimum cadence. Intervals below
scheduler.cron_min_interval_seconds(default 60 seconds) are rejected at load, so30sneeds that floor lowered first. See Configuration API → scheduler.
Timezones
Schedules run in UTC by default, so a laptop in one country and a server
in another fire at the same moment. Set timezone on the agent to schedule
in local time instead:
agents:
morning_report:
name: "morning_report"
wake_up: "0 9 * * *" # 9 AM...
timezone: "Asia/Kolkata" # ...India time, not UTCAny IANA zone name works (Europe/London, America/New_York,
Asia/Kolkata). The name is validated when config loads, so a typo is
caught at startup rather than firing at the wrong hour for a week.
Daylight saving is handled by the zone itself — a 0 9 * * * schedule in
Europe/London stays at 9 AM local across the March and October
transitions.
When an agent holds several schedules, any one of them can override the agent's zone:
agents:
regional_digest:
name: "regional_digest"
timezone: "UTC" # agent default
wake_up:
- cron: "0 9 * * *"
timezone: "Asia/Kolkata" # India morning
input: { region: "in" }
- cron: "0 9 * * *"
timezone: "America/New_York" # US morning
input: { region: "us" }Multiple Schedules per Agent
Since 2.4.107 an agent can hold several schedules, each carrying its own input:
researcher_agent:
wake_up:
- cron: "0 6 * * *"
input: {mode: morning_briefing, depth: quick}
- cron: "0 18 * * *"
input: {mode: evening_summary, depth: full}
wake_up_input: # shared base merged into EVERY wake
audience: ops-teamThree accepted shapes: a single cron string (as above in the earlier examples), a list of cron strings, or a list of {cron, input} entries. Malformed entries are rejected at config load.
How It Works
When wake_up fires:
- The scheduler publishes a scheduled-run event (carrying that schedule's
input, if declared) - The agent is invoked with the merged wake payload —
wake_up_input(shared base) → the firing schedule'sinput→ the trigger markerswake_up_trigger: trueandtrigger_time(markers always win on collision). With none declared, the payload is just the trigger markers. - The full pipeline executes: pre-compose → LLM call (or intelligence function) → yields parsing → can_call evaluation
- Downstream agents are triggered if conditions match
Scheduler timer fires
│
▼
Scheduled-run event published
│
▼
Agent pipeline executes
│ (merged wake payload: wake_up_input → schedule input → markers)
▼
can_call conditions evaluated
│
▼
Downstream agents triggered
The execution follows the same pipeline as interactive calls. Scheduled agents are not special — they just have an automatic trigger.
Changing a Schedule at Runtime
Schedules are declared on the agent, so you change one by changing its
wake_up — through Agent Studio or the config API:
PATCH /api/yaml/config
{"agents": {"collector": {"wake_up": "1m"}}}The schedule is rebuilt in place; no restart is needed. Send null to stop
an agent waking up at all:
PATCH /api/yaml/config
{"agents": {"collector": {"wake_up": null}}}Execution tracking records last execution time, execution count, and next run time.
Common Patterns
Periodic Data Collection
agents:
sensor_collector:
name: "sensor_collector"
agent_type: "programmatic"
wake_up: "*/5 * * * *"
yields:
readings: "array"
timestamp: "string"
can_call:
- agent: "analyzer"
condition: "readings != []"# Function name "sensor_collector" matches the YAML agent name — auto_discover finds it
async def sensor_collector(llm_response, input_data, context):
"""Collect sensor data every 5 minutes"""
import random
from datetime import datetime
readings = [round(random.gauss(100, 10), 2) for _ in range(20)]
return {
"readings": readings,
"timestamp": datetime.now().isoformat()
}Health Reporting
agents:
health_reporter:
name: "health_reporter"
model: "gpt-4o-mini"
wake_up: "0 9 * * *" # Daily at 9 AM
prompt: |
Summarize the system health metrics into a brief report.
Include any anomalies or concerns.
yields:
report: "string"
status: "string"
can_call:
- agent: "human_reviewer"
condition: "status == 'critical'"Cache Maintenance
agents:
cache_monitor:
name: "cache_monitor"
agent_type: "programmatic"
wake_up: "30m"
yields:
hit_rate: "number"
action_taken: "string"# Function name "cache_monitor" matches the YAML agent name — auto_discover finds it
async def cache_monitor(llm_response, input_data, context):
"""Check cache health and invalidate if needed"""
stats = await Studio's Dashboard (HTTP)
hit_rate = stats.get("hit_rate", 0)
action = "none"
if hit_rate < 0.3:
action = "invalidated_stale_entries"
return {
"hit_rate": round(hit_rate, 2),
"action_taken": action
}Isolation
Scheduled agent executions run isolated from interactive traffic — they never block request processing.
Next Steps
- Agent Types — All four agent types
- Monitoring Patterns — Scheduled monitoring systems
- Agent Configuration — Full YAML reference
LeafMesh — Time-triggered agents, same pipeline