Scheduled AI agents: designing a recurring job that does not go stale
The four failure modes of a recurring agent job, the four design properties that resist them, why the schedule is the billable unit, and what should never be scheduled.
Last updated
6 minute read · Written by the team that builds UtilitySpaces. More about UtilitySpaces.
A scheduled AI agent is a standing job: an agent with a fixed role, a fixed tool set and a boundary, run on a timetable, every hour, day or week, without anyone asking. It goes stale when the world it was written for drifts and nothing forces a person to notice, which is the default outcome of any job that runs while you are not looking.
We build UtilitySpaces, where standing schedules are the thing that runs overnight and, not coincidentally, the thing the product meters. This is about designing one that is still worth paying for in three months.
What is a standing schedule?
An agent plus a timetable. The agent is the same object you would run on demand from the inbox: a role, a set of named tools and a write policy that decides which connector writes it may make. The schedule removes the person from the start of the loop. Nobody types the request; the job begins on its own, does its work, and leaves the result in a thread.
That one change is the whole difference between a task and an automation. A task has a person watching by definition, because they just asked for it. A schedule has a person watching only if one has built the habit, and habits decay faster than schedules do.
A schedule is not the only way to start a job without a person. A trigger starts it when something happens in a connected app, such as a new order arriving, rather than at a fixed time. Everything below applies to both, with one difference worth noting: a trigger’s input is whatever the app sent, which makes it easier to keep small and harder to keep predictable. A timetable at least guarantees the job runs when nothing has happened, which is the run that tells you it is still alive.
What are the four ways a schedule goes stale?
Four, and they are worth learning by name, because each has a different fix and a different time-to-notice.
| Failure | What it looks like | How long before anyone notices |
|---|---|---|
| Stale context | The rule was written for last quarter’s process. The product list changed, the pipeline stages were renamed, and the agent is faithfully applying a rule about a world that no longer exists. | Weeks. The output still looks plausible. |
| Silent failure | A credential expired or an app returned errors, and the run ended with nothing to say. No report, no alarm, just absence. | Until someone asks where the report went. |
| Runaway cost | The job started pulling more records each run, or retrying, or was duplicated by someone who did not know it existed, and the spend line climbed quietly. | Until the cost report is read. |
| Drifting scope | Someone widened the role text, then added a tool, then relaxed a gate, each change reasonable alone. The job now does three things and nobody signed off on the third. | Until the third thing goes wrong. |
The third column is the argument. None of these announce themselves; all of them are caught by a person reading the output on a schedule of their own.
How do you design a job that resists all four?
Four properties, one per failure mode. Keep it small. Make it idempotent. Make it report its own result, including nothing. And make it stop on surprise rather than push through.
- Small. One question, one output. “List yesterday’s orders that need a person and say why” is a schedule. “Manage the order pipeline” is a department. A small job has a small role text, which means the context it depends on is small too, and stale context is caught the first time the output looks odd.
- Idempotent. Running it twice produces the same state as running it once. That is what makes a retry safe, a duplicate schedule harmless, and a missed run recoverable by simply running again. A job that appends without checking what it already appended is not idempotent, and a job that creates records is only idempotent if it checks for the record first.
- Reports its own result. Every run ends with a line in the thread, including the runs where there was nothing to do and the runs that failed. “Checked, nothing new” is information; silence is not. A schedule that is only heard from when it has something to say is indistinguishable from one that has stopped.
- Stops on surprise. When the input does not match the rule, the job records that and halts rather than improvising. Twice as many records as usual, a field that is suddenly empty, a tool that errors: each is a reason to post and wait, not a reason to try harder. In UtilitySpaces a write the job attempts through a connection on “Ask a person first” already waits for a person, as the approvals page sets out; the design question is which reads and which anomalies should stop it too.
Why is the schedule the thing you pay for?
Because the scarce and risky resource is unattended work, not conversation. In UtilitySpaces the metered unit is the standing schedule; chat and one-off tasks are unmetered on paid plans. Pricing follows risk. The thing that runs while you are asleep is the thing that deserves a visible number next to it, and a visible number occasionally gets pruned. What each plan includes is on the pricing page.
Model cost is the other line, and it is tracked per run, by model and by workspace at live rates, on the cost tracking page. Runaway cost is caught by reading that page, which is why the honest advice is to put it on your own schedule: a weekly glance at spend per schedule catches the one that doubled. A workspace can also bring its own model-provider key, which moves the model bill to a statement you already read.
What should never be scheduled?
Anything where a wrong run is expensive and nobody will be reading. Concretely, four classes.
- Anything irreversible without a person in the loop. Refunds, deletions, messages to customers. A write through a connection on “Ask a person first” waits until someone is awake to approve it, and one an admin has set to run without asking runs unreviewed, so at two in the morning the first stalls and the second has nobody in the loop.
- Anything whose input is attacker-controlled and whose tools are wide. A job that reads inbound email and holds write tools is a standing invitation for an instruction hidden in a message to be acted on at the next tick. Narrow the tools or do not schedule it.
- Anything nobody reads. A weekly report to an empty channel manufactures the feeling of oversight without any of the substance. Delete any schedule nobody has referred to in a month; it is costing money and a false sense of control.
- Anything whose rule changes every month. You will spend longer rewriting the role text than the job ever took by hand, and between rewrites it is running on the old rule.
The ordering for what to hand a schedule first, and what to leave alone for a while, is the subject of what to automate first with AI agents. The short version: reporting and triage before anything that writes.
What the product will not do for you
A schedule that runs cleanly and produces a report nobody opens looks, to the product, exactly like one that is working. Nothing tells you the rule went stale; the thread shows the output and the cost page shows the spend, and reading them is a habit, not a feature. There is no anomaly detection that understands your business, and no third-party security certification behind any of it. Schedules also cannot reach an app that has no connector and no usable API. Questions about any of that go to support@utilityspaces.com.
What is left is a design discipline more than a product feature: one small idempotent job, a line in the thread every run, a stop on anything unusual, and a person who reads the thread on a schedule of their own. The demo workspace lasts exactly sixty minutes from creation, which is enough to create one schedule and watch it report. Start a demo workspace, or read how an agent is defined first.