There is a specific kind of disappointment that comes from scheduled agents, and it always arrives the same way. You set one up. It works when you test it. Three weeks later you notice it hasn't done anything in eleven days, and there's nowhere to look to find out why.
That experience — the eleven-day silence — is why I built Routines into Octomind the way I did.
What Actually Shipped
A routine is a standing instruction with a trigger attached. Pick an agent, pick when, and it wakes a computer in the cloud, does the work, and tells you what came of it. Nothing of yours has to be switched on.
That's the elevator pitch. The engineering reality is messier, because scheduled systems have four failure modes documented in the original post.
The Four Ways Scheduled Agents Fail
1. It didn't run and nobody said so. The config file says what should run and has no opinion about what is running. Claude Cowork has an open issue where tasks skip on a timezone offset and simply don't appear. You don't know it failed. You just notice the silence.
2. It ran, spent money, produced nothing. Silent failure. No crash, no signal, just a charge. Telerik has a taxonomy of agents returning status: ok having done nothing useful. Your credit card gets charged. Your problem stays unsolved.
3. Cost runs away. An agent loop costs roughly 3.2× a chatbot turn at five steps and over 30× at fifty, and a polling schedule pays full price on every run where nothing happened. Context accumulation is the dominant cost driver, and it compounds silently.
4. Time is the only trigger. If something breaks at 15:00 and your check runs at 23:00, you find out at 23:00. You're at the mercy of the schedule you set.
Routines is designed to fail differently.
Scheduling Is a Sentence You Complete
The scheduling UX is a sentence you complete: "Every weekday at eight." There's a cron option with plain-English readback, because the failure mode of a cron field is not rejection, it's silently scheduling something else.
Times are stored with an IANA timezone, never an offset, and the next fire is recomputed after each run rather than incremented. That is the whole reason daylight saving doesn't drift: a local time that doesn't exist in spring fires at the next real instant, and a local time that happens twice in autumn fires once, on the first. Both are pinned by tests with fixed clocks.
Pick Who Does It
Routines run as specialist agents — same roster as tasks. Assistant picks if you don't want to choose. The point is: you know what's running your job.
Every Non-Run Is a Row
This matters more than it sounds. Refusals — routine off, out of budget, cold storage, previous run still going — become run rows with status. "Didn't run — machine was in cold storage." "Hit its cost cap."
Header totals show: "7 runs · $0.63 · typically 3m 8s". It's a heartbeat list view, one tick per run coloured by outcome. And after five consecutive failures, a routine disables itself and tells you, because a broken routine must not bill forever.
Silence is the bug we're building against.
Cost Controls That Actually Work
Fresh conversation each run by default. There's a checkbox for long conversation labelled honestly: "keeps context between runs, costs more over time". No marketing spin, just the truth.
Optional zero-token check command — shell runs first, non-zero exit = "nothing to do" with no model call:
git fetch && git log --oneline @..@{u} | grep .
We deliberately did not make this a natural-language condition: an LLM condition costs a model call to decide whether to make model calls. That's backwards.
Per-run cost cap. Always.
State Is a File, Not a Black Box
~/routines// with state.md. Read state.md before you start, write what the next run needs to know before you finish. Persistent disk, openable in Files or terminal, edit to correct memory, delete to reset.
State is a file, not a vendor black box. You can touch it. You can fix it.
Run It Now
There's a button that fires the real queue, the real runner, the real billing lane. Not a preview. A routine you have never watched run is a routine you cannot trust.
Machine Sleep
Free machines suspend after 5 idle minutes, Pro after 15. Your computer sleeps, costs nothing, and gets up when the routine says so. Wake goes through the same admission door; refusal = visible skip with reason, never an overdraft. Machines with enabled routines are exempt from cold storage.
/schedule vs Routines
Agent-internal timers die with the session. A schedule living inside the box cannot wake the box. Routines fire from outside and start the machine. That's the architectural difference.
The Architecture
PRODUCERS (timer, webhook, connector, workflow)
↓
QUEUE (routine_fires, dedup/claim)
↓
RoutineRunner
Nothing in the runner knows what caused a run. Timer + manual ship today. Webhook, connector, and workflow land without migrations — the queue and seam are built, the part that's expensive to retrofit is the trigger sources themselves.
Notifications
Panel bell plus Telegram, Slack, or WhatsApp mirror. Default notify-on-change. Failures always ring. Silence is the bug we're building against.
Plans
Free: 1 routine, once a day.
Pro: 10 routines, down to every 15 min.
Max/Team: 30 routines, down to every 5 min.
What's Not There (Yet)
Webhook triggers aren't built yet. The queue and seam are ready, but the part that's expensive to retrofit is the trigger sources. Timeouts and cost caps end our turn rather than killing the agent mid-thought, which is a real limit we'd rather name than paper over.
The Advice I'd Give Myself
Open Routines and start with one. Watch it run once before you schedule it — that's the whole advice.
This is a personal retelling of the Routines launch post. The original company-voice version is at octomind.run/blog/routines-scheduled-agents.
Top comments (0)