| name | agent-self-scheduling |
| description | How to make an AI coding agent run on a schedule, loop, or interval — cron jobs, heartbeats, self-starting/self-terminating loops, recurring autonomous checks. Use when the user asks to "run every N minutes/hours", "check something on a regular interval", "schedule a task", "run on a loop", "self-start", "heartbeat", "cron job for an agent", or wants an agent to fire periodically without manual launching. Covers two camps — one-shot agents you wrap in an external clock (Claude Code, Codex, Pi) vs agents with a built-in scheduler daemon (Hermes). |
Agent Self-Scheduling
Make an agent run periodically. First question: does the agent have a built-in scheduler, or do you own the clock?
Decision: pick the camp first
- Need it NOW, agent has no scheduler, or sub-minute polling → Camp A (external clock).
- Want managed recurring jobs, isolated sessions, chaining, loop safety → Camp B (Hermes built-in).
Universal floor: ALL cron is 1 minute (5-field expr, no seconds) — every camp. For sub-minute / sub-second you MUST use a dumb while ...; sleep N; done loop, a TS extension, or a webhook/event hook. Never put an LLM on a tight timer.
Camp A — One-shot agents, you own the clock
These run once and exit (amnesiac unless resumed). You schedule them externally.
One-shot invocations:
claude -p "PROMPT" --output-format json --allowedTools "Read,Edit,Bash"
codex exec --json "PROMPT"
pi run "PROMPT"
Wrap in a clock — three options:
*/10 * * * * cd /path/to/project && pi run "check X and report" >> ~/agent.log 2>&1
while true; do pi run "check X"; sleep 30; done
Camp A gotchas (all three break unattended runs if ignored):
- Permissions block unattended runs. Pass
--allowedTools (Claude) or a sandbox/auto-approve flag (Codex) or the run hangs on a prompt forever.
- Use structured JSON output, not prose (
--output-format json / --json) so the wrapper can parse the result deterministically.
- Each run is amnesiac. No memory across runs unless you resume:
codex exec resume --last. Otherwise persist state to a file the next run reads.
Pi specifics: Pi has NO built-in loop/scheduler/heartbeat by design — only the agent reasoning loop (not time-based). OpenClaw's runtime is built ON Pi but is a separate project. To schedule Pi: external cron/systemd, a while-sleep loop, or a TS extension for agent-side timers.
cmux (orchestration layer — NO scheduler)
cmux has NO scheduler/timer/watch/cron. It is visibility + orchestration only. Primitives: list-workspaces, read-screen (non-interruptive — safe to poll), send. An MCP wrapper cmux-agent-mcp exists.
Three ways to make cmux loop:
- Orchestrator-driven — the orchestrator runs
send → sleep → read-screen on its own clock.
- Dumb wrapper — external
while true; ...; sleep N; done.
- Event-driven (preferred over polling) — use
cmux notify + OSC 9/99/777 terminal hooks so work fires on a real signal instead of a timer. Cheaper and more responsive than read-screen polling.
Camp B — Hermes (built-in scheduler daemon)
Hermes ships a gateway that ticks every 60s and runs due jobs in fresh, isolated sessions. No external cron needed.
State-check first — is the gateway running?
hermes gateway install
hermes gateway install --system
Create jobs (CLI or /cron add in TUI):
hermes cron create "every 1h" "summarize new emails and report" --skill himalaya
hermes cron create "0 9 * * *" "post daily standup"
hermes cron create "30m" "one-shot reminder in 30 min"
Schedule formats: one-shot delays (30m, 2h), recurring (every 30m, every 1d), cron (0 9 * * *), ISO timestamps.
Hermes-unique capabilities:
- Zero-token / no-agent mode — run a script on schedule, deliver its stdout verbatim. No LLM cost. Use for watchdogs/heartbeats where the script produces the exact message.
- Chaining —
context_from injects an upstream job's last output into a downstream job; combine with a working dir to pipeline jobs.
- Self-terminating loops — a recurring job can stop itself when a condition is met.
- Fresh self-contained sessions — each run starts clean; the prompt must carry all needed context (no chat history).
- Loop safety — cron-run sessions CANNOT create more cron jobs (prevents runaway recursion). Don't try to schedule from inside a scheduled job.
- Persistent
/goal loop — long-running autonomous loop with pause/resume, separate from cron.
Heartbeat pattern (proactive self-check)
A heartbeat = a fast recurring tick that gates slower per-task checks, so one loop handles many intervals at different cadences.
- In Camp B: a recurring Hermes job (e.g.
every 5m) whose prompt/script checks a task list and only acts on tasks whose own interval is due. Use no-agent mode + a script for zero token cost when nothing's due.
- In Camp A: same idea via a while-sleep loop that reads a tasks file and per-task
last_run timestamps.
- Save tokens: define active-hours and skip ticks outside them; skip the tick entirely when there's nothing due (stay silent — don't emit empty noise).
Verify it actually fires (do this before reporting success)
- Camp A: check the log file grows after one interval, or run the wrapped command once by hand and confirm clean JSON exit (0).
- Camp B:
hermes cron list shows the job; check next_run; trigger once with a run-now to confirm it executes and delivers.
- Confirm permissions/sandbox flags are present (Camp A) — the #1 silent failure is a hung permission prompt.
- For heartbeats, confirm a tick with nothing-due stays silent (no spam).
Pitfalls
- Cron CANNOT do sub-minute. Don't promise
every 30s via crontab — use a loop.
- Camp A unattended hangs without explicit tool allowlists / sandbox.
- Don't schedule a job from inside a scheduled Hermes job (loop safety blocks it).
- Each scheduled run is a fresh/amnesiac session — pass all context in the prompt or persist to a file.