Most developers who adopt AI agents start with reactive systems: the agent responds when called. The next step — scheduling agents to run autonomously — is where a lot of teams hit a wall.
Not because scheduling is hard. Because unsupervised scheduled agents behave differently than supervised ones, and most configs aren't built for it.
Here's what I've learned running cron-scheduled AI agents 24/7.
Why Scheduled Agents Fail Differently
A reactive agent waits for input. If it gets confused, a human provides more context.
A scheduled agent runs alone. If it drifts, there's no one to correct it mid-run. By the time you notice the drift, it's been running wrong for hours.
The failure modes are different:
- Identity drift: The agent gradually stops acting like itself
- Task scope creep: Minor decisions compound into major direction changes
- Silent errors: Nothing crashes; the agent just does the wrong thing confidently
- State accumulation: Each run inherits noise from the previous one
All of these are solvable. But they require specific patterns in your agent config.
The Five Rules for Reliable Cron Agents
1. Reload identity on every run
This is the non-negotiable. Your SOUL.md (or equivalent identity file) must be the first thing read at the start of every scheduled run — not just at agent startup.
# Cron entry
*/30 * * * * /usr/local/bin/openclaw session run --instruction "Read SOUL.md and MEMORY.md first. Then..."
Why: Each new session starts fresh. Without an explicit reload, the agent invents an identity from context. That invented identity drifts from the real one — usually toward whatever the last conversation suggested.
2. Write task state before acting
Before any scheduled agent takes action, it should write what it's about to do:
// current-task.json
{
"task": "post morning tweet",
"started": "2026-03-08T09:00:00Z",
"status": "in_progress",
"next_action": "draft tweet from content queue"
}
This does two things:
- Creates an audit trail you can inspect
- Prevents duplicate actions if the cron fires twice (check if status is already
complete)
3. Define a hard exit condition
Every scheduled task needs a written definition of "done" that doesn't require judgment.
Bad: "Stop when the task feels complete."
Good: "Stop when one tweet has been posted and logged to content/daily/YYYY-MM-DD.md."
The agent should evaluate against a concrete, observable outcome — not a subjective feeling.
4. Build a silence rule
Scheduled agents that run at odd hours need to know when not to act.
# In SOUL.md
Silence rule: Do not send outbound messages between 22:00-07:00 MT
unless explicitly flagged as urgent by the human.
Without this, your 3 AM maintenance cron will cheerfully send emails, post to social media, and message people while everyone sleeps.
5. Separate heartbeats from cron
There's a difference between:
- Heartbeat: A quick check-in. "Anything need attention?" Light context, low cost.
- Cron task: A scheduled action. Specific job, full execution, complete output.
Blurring these creates bloated heartbeats that do too much, and heavy cron jobs that check too little. Keep them separate.
Heartbeats batch multiple small checks (email, calendar, notifications). Cron jobs execute one specific task cleanly.
The Config Pattern That Prevents Runaway Agents
Here's the structure I use for every scheduled agent:
# Agent Loop Pattern
1. Read SOUL.md (identity)
2. Read MEMORY.md (long-term context)
3. Read current-task.json (what was I doing?)
4. If current task is complete → write completion log → exit
5. If current task is in_progress → check last action → resume
6. If no current task → read task queue → pick next task
7. Write task state ("starting X")
8. Execute task
9. Write completion state
10. Write to memory/YYYY-MM-DD.md
11. Exit cleanly
This loop handles restarts, duplicate fires, and partial completions. It also creates a paper trail for every run.
Real Numbers
Before implementing these patterns: ~3 agent misfires per week (wrong action, wrong timing, or duplicate action).
After: Zero in 30 days.
The cost of the pattern (file reads at start of each run) is negligible. The cost of not having it — debugging misfires, cleaning up duplicates — was hours per week.
The Quick Audit
For any scheduled agent you're running, ask:
- [ ] Does it reload its identity file every run?
- [ ] Does it write task state before acting?
- [ ] Does it have a hard exit condition?
- [ ] Does it have a silence rule for overnight hours?
- [ ] Is it separated from your heartbeat logic?
If you're missing more than two of these, your agent will eventually misfire.
I publish the exact configs I use for scheduled agents — including cron examples, task queue format, and the SOUL.md escalation rules — in the Ask Patrick Library. New patterns added weekly based on what's actually working in production.
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.