Setting Up Cron Jobs in OpenClaw for Beginners
Setting Up Cron Jobs in OpenClaw for Beginners

Let's be honest: most people who set up AI agents never actually get them running on a schedule. They build something cool in a notebook, maybe run it manually a few times, and then it just... sits there. The agent that was supposed to scrape competitor pricing every morning? Dead. The one that should summarize your inbox before you wake up? You forgot to run it three weeks ago.
The problem isn't building the agent. The problem is making it run reliably, on time, without you babysitting it. That's where cron jobs come in — and more specifically, that's where OpenClaw makes cron jobs actually work for AI agents instead of being the brittle, silent-failure nightmare they usually are.
This post is a step-by-step walkthrough. By the end, you'll have a working cron job in OpenClaw that runs your agent on a schedule, handles failures gracefully, persists state between runs, and gives you full visibility into what happened while you were sleeping.
Let's get into it.
Why Regular Cron Fails for AI Agents
Before we touch OpenClaw, it's worth understanding why the traditional approach — a crontab entry pointing at a Python script — falls apart so quickly for agent workloads.
Standard cron was built for deterministic tasks. Rotate logs. Back up a database. Delete temp files. These either work or they don't, and when they don't, the failure mode is usually obvious.
AI agents are the opposite of deterministic. They make multiple LLM API calls, any of which might rate-limit, timeout, or return garbage. They use tools that depend on external services. They sometimes get stuck in loops. They cost real money per execution. And the difference between "worked" and "worked correctly" requires inspecting the actual output, not just checking an exit code.
Here's what typically goes wrong:
- Silent failures. Your agent hits a rate limit at 3am, the script exits with code 1, and cron doesn't care. You find out days later.
- No retries. A transient OpenAI outage kills your run. Traditional cron won't retry.
- No state. Every run starts from scratch. If your agent needs context from previous runs, you're duct-taping pickle files together.
- No observability. What did the agent actually do? How many tokens did it use? Which tools did it call? Good luck finding out from a cron log.
- Environment chaos. Different PATH, missing env vars, wrong Python version — the classic "works on my machine, dies in cron" problem, now multiplied by six different API keys.
OpenClaw was built specifically to solve these problems. It treats agents as first-class scheduled workloads, not afterthoughts you cram into a crontab.
Getting Started: What You Need
If you're new to OpenClaw, the fastest way to get up and running is Felix's OpenClaw Starter Pack. It bundles the configuration templates, example agents, and environment setup that would otherwise take you a few hours of documentation spelunking to piece together. I genuinely recommend it as your starting point — it'll save you the "staring at docs trying to figure out the right project structure" phase that kills momentum.
Once you've got the starter pack or have OpenClaw installed from the repo, make sure you have:
- OpenClaw CLI installed and authenticated
- Python 3.10+ (or whatever runtime your agent uses)
- At least one agent that works when you run it manually
- A state backend configured (Postgres, Redis, or SQLite — SQLite is fine for getting started)
Let's verify your install:
openclaw --version
# openclaw 0.8.x
openclaw status
# ✓ CLI authenticated
# ✓ Runtime: python 3.11.4
# ✓ State backend: sqlite:///~/.openclaw/state.db
Good. Let's schedule something.
Your First Cron Job in OpenClaw
OpenClaw uses a declarative YAML file to define scheduled agents. This is one of its best design decisions — your schedule, retry logic, state configuration, and secrets are all defined alongside your agent, not scattered across crontabs, shell scripts, and environment files.
Create a file called agents/daily_summary.yaml:
agent:
name: daily-inbox-summary
runtime: python
entrypoint: agents/daily_summary.py
description: "Summarizes overnight emails and posts to Slack"
schedule:
cron: "0 7 * * *" # Every day at 7am
timezone: "America/New_York"
retry:
max_attempts: 3
backoff: exponential
initial_delay: 30s
max_delay: 5m
state:
backend: sqlite
persist:
- last_processed_email_id
- summary_history
secrets:
- OPENAI_API_KEY
- SLACK_WEBHOOK_URL
- GMAIL_APP_PASSWORD
observability:
trace: true
export: langfuse # or langsmith, otlp, stdout
log_level: info
limits:
max_runtime: 10m
max_cost_usd: 0.50
Let's break down what each section does, because every one of them solves a specific pain point.
The schedule Block
schedule:
cron: "0 7 * * *"
timezone: "America/New_York"
Standard cron syntax, but with timezone support baked in. This sounds trivial until you realize how many people have been burned by cron running in UTC when they expected local time. OpenClaw resolves this cleanly.
You can also use human-readable shortcuts:
schedule:
every: 6h
# or
every: monday,wednesday,friday at 09:00
The retry Block
This is where OpenClaw starts earning its keep:
retry:
max_attempts: 3
backoff: exponential
initial_delay: 30s
max_delay: 5m
When your agent fails — and it will, because LLM APIs are flaky — OpenClaw automatically retries with exponential backoff. First retry after 30 seconds, second after 60, third after 120, capped at 5 minutes. No more silent 3am failures.
You can also add conditional retries:
retry:
max_attempts: 3
backoff: exponential
initial_delay: 30s
retry_on:
- rate_limit
- timeout
- connection_error
fail_on:
- authentication_error
- invalid_config
This way, you retry transient errors but fail fast on things that won't fix themselves.
The state Block
state:
backend: sqlite
persist:
- last_processed_email_id
- summary_history
This is the killer feature for agents that need to "continue where they left off." Instead of starting from scratch every run, your agent can read and write state that persists between executions.
In your Python agent, you access it like this:
from openclaw import state
# Read state from previous run
last_id = state.get("last_processed_email_id", default=None)
# ... do your agent work ...
# Save state for next run
state.set("last_processed_email_id", newest_email_id)
state.append("summary_history", {
"date": today,
"summary": summary_text,
"token_usage": token_count
})
No pickle files. No janky JSON dumps. No "oops I overwrote the state file." OpenClaw handles serialization, atomic writes, and backend-specific optimizations. When you're ready to scale, switch sqlite to postgres and change nothing else in your agent code.
The secrets Block
secrets:
- OPENAI_API_KEY
- SLACK_WEBHOOK_URL
- GMAIL_APP_PASSWORD
OpenClaw pulls these from its secrets manager (or your configured provider — Doppler, Infisical, cloud vaults, or a local encrypted store). They're injected at runtime, never stored in the YAML, and never visible in logs.
Set them once:
openclaw secrets set OPENAI_API_KEY sk-...
openclaw secrets set SLACK_WEBHOOK_URL https://hooks.slack.com/...
openclaw secrets set GMAIL_APP_PASSWORD xxxx-xxxx-xxxx-xxxx
Done. Every agent that declares the secret gets it. No more hardcoded keys in crontabs, no more .env files drifting out of sync.
The limits Block
limits:
max_runtime: 10m
max_cost_usd: 0.50
This is something nobody thinks about until they get a $400 bill. OpenClaw tracks token usage across all LLM calls in a run and will terminate the agent if it exceeds the budget. It also enforces a hard runtime cap — if your agent gets stuck in a tool loop, it gets killed after 10 minutes instead of running until your server runs out of memory.
Writing the Agent
Here's a simple agent that would work with the config above:
# agents/daily_summary.py
from openclaw import agent, state, tools
from openclaw.llm import completion
@agent.run
def daily_inbox_summary():
# Get state from last run
last_id = state.get("last_processed_email_id")
# Fetch new emails since last run
emails = tools.gmail.fetch_unread(since_id=last_id)
if not emails:
agent.log("No new emails since last run. Skipping.")
return
# Build prompt
email_text = "\n---\n".join([
f"From: {e.sender}\nSubject: {e.subject}\nBody: {e.body[:500]}"
for e in emails
])
summary = completion(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Summarize these emails concisely. Highlight action items."},
{"role": "user", "content": email_text}
],
max_tokens=1000
)
# Post to Slack
tools.slack.post(
channel="#daily-summary",
text=f"📬 *Inbox Summary — {len(emails)} new emails*\n\n{summary}"
)
# Update state
state.set("last_processed_email_id", emails[-1].id)
state.append("summary_history", {
"date": str(agent.run_date),
"email_count": len(emails),
"summary": summary
})
agent.log(f"Processed {len(emails)} emails. Summary posted to Slack.")
Notice how clean this is. No boilerplate retry logic. No manual state file management. No secret loading. OpenClaw handles all of that based on the YAML config. You write the agent logic, and the platform handles the operations.
Deploying and Managing Your Schedule
Register and activate the agent:
# Register the agent with OpenClaw
openclaw register agents/daily_summary.yaml
# Verify it's scheduled
openclaw list
# NAME SCHEDULE NEXT RUN STATUS
# daily-inbox-summary 0 7 * * * 2026-01-16 07:00 EST active
# Test it immediately (doesn't wait for schedule)
openclaw run daily-inbox-summary --now
# Watch the execution in real time
openclaw logs daily-inbox-summary --follow
Want to see what happened on past runs?
# View execution history
openclaw history daily-inbox-summary
# RUN ID STARTED DURATION STATUS COST
# run_a8f3c2 2026-01-15 07:00:01 42s success $0.03
# run_b1d4e7 2026-01-14 07:00:01 38s success $0.02
# run_c9e2a1 2026-01-13 07:00:02 2m14s retry(2) $0.08
# run_d3f8b4 2026-01-12 07:00:01 35s success $0.02
# Deep dive into a specific run
openclaw trace run_c9e2a1
# Shows full execution trace: every LLM call, tool invocation,
# state read/write, retry attempt, with timestamps and token counts
That third run on January 13th? It failed twice (probably a rate limit), retried, and succeeded on the third attempt. Total cost was slightly higher because of the retries. With regular cron, you'd have just gotten nothing that day and never known why.
Common Patterns and Pro Tips
Once you've got the basics working, here are a few patterns that'll level up your scheduled agents:
Conditional Scheduling
Don't waste money running agents when there's nothing to do:
schedule:
cron: "0 */2 * * *" # Every 2 hours
condition:
check: webhook
endpoint: /api/has-new-data
skip_if: "response.new_items == 0"
Chaining Agents
Run agents in sequence where one depends on another:
schedule:
cron: "0 8 * * *"
depends_on:
- daily-inbox-summary # Wait for this to finish first
- competitor-price-scraper
Cost Budgets Across Agents
Set a global budget so your fleet of agents doesn't bankrupt you:
openclaw config set monthly_budget_usd 50.00
openclaw config set budget_alert_threshold 0.8 # Alert at 80%
Alerting on Failures
alerts:
on_failure:
- slack: "#ops-alerts"
- email: you@company.com
on_cost_exceeded:
- slack: "#ops-alerts"
on_consecutive_failures: 3
action: pause # Auto-pause after 3 failures in a row
Debugging When Things Go Wrong
Things will go wrong. Here's how to handle it without losing your mind:
# See why a specific run failed
openclaw trace <run_id> --verbose
# Replay a failed run with debug logging
openclaw run daily-inbox-summary --now --debug
# Check agent state
openclaw state daily-inbox-summary
# last_processed_email_id: msg_abc123
# summary_history: [14 entries]
# Reset state if something got corrupted
openclaw state daily-inbox-summary --reset last_processed_email_id
The trace command is your best friend. It shows you every step of the execution: what the LLM was asked, what it responded, which tools were called, what state was read and written, and exactly where things broke. Compare that to grepping through /var/log/syslog for cron output and you'll never go back.
What This Actually Looks Like in Practice
I've got about a dozen agents running on schedules through OpenClaw right now. A few examples:
- Competitor monitoring (every 6 hours): Scrapes pricing pages, compares to last run's state, alerts me in Slack if anything changed significantly. Cost: ~$0.15/day.
- Content research (daily at 6am): Pulls trending topics in my niche, cross-references with my content calendar state, suggests gaps. Cost: ~$0.08/day.
- Weekly report generator (Mondays at 9am): Aggregates data from multiple tools, generates a narrative summary, posts it to Notion. Cost: ~$0.20/week.
Total monthly spend across all agents: around $12. Total time I spend managing them: maybe 10 minutes a week, mostly just reading the output.
The key insight is that the setup cost is front-loaded. Getting your first cron job right in OpenClaw takes maybe an hour. Getting the next ten takes minutes each because the patterns are identical — change the entrypoint, adjust the schedule, tweak the state keys, done.
Next Steps
Here's what I'd do from here:
-
Grab Felix's OpenClaw Starter Pack if you haven't already. It includes working examples of all the patterns I covered here, plus a few advanced ones (browser agents, multi-step chains, cost optimization configs). It's the fastest path from "reading a blog post" to "agents running in production."
-
Start with one agent. Pick your simplest, lowest-stakes automation. Get it running on a schedule. Watch it succeed (and fail and retry) for a week. Trust the system.
-
Add observability early. Connect LangFuse or LangSmith from day one. Future you will be grateful when you're trying to figure out why the agent's output quality degraded last Thursday.
-
Set cost limits before you need them. It takes 30 seconds to add a
max_cost_usdlimit and will save you from the inevitable "my agent got stuck in a loop and burned $50" moment. -
Build your second agent. Then your third. The whole point of scheduled agents is that they compound — each one saves you a little time, and the time savings stack up fast.
The gap between "I built an AI agent" and "I have AI agents running my operations" is almost entirely an infrastructure problem. OpenClaw closes that gap. Cron jobs are just the starting point — once your agents are running reliably on schedules with proper state, retries, and observability, you start thinking about what else you can automate.
And that's when things get fun.