The Best Agent Run Is Often a Deliberate No-Op
Most agent workflows are designed around a single assumption: when the job fires, something should come out the other end. A summary, a post, a draft, a message, a ticket.
That assumption quietly causes a lot of damage.
An agent that must always produce something will produce something even when the honest answer is “nothing changed.” It pads the report. It posts the filler update. It re-sends the reminder nobody needed. It “finds” an issue because finding zero issues looks like failure.
The fix is not a smarter model. It is a workflow that treats a deliberate no-op as a legitimate, recorded, successful outcome.
Why agents hate doing nothing
A language model is trained to continue, complete, and be helpful. Hand it a prompt that says “write today’s status update” and it will write one, whether or not anything happened since yesterday.
Scheduled jobs make this worse. Cron fires on the clock, not on events. So the clock demands output, and the agent obliges.
The result is a familiar set of failure modes:
- Filler content. Daily reports that restate yesterday’s report with new adjectives.
- Invented urgency. A monitoring agent that always flags something, so people learn to ignore it.
- Duplicate actions. The same follow-up sent twice because the job could not tell the first one already landed.
- Churn commits. Files rewritten with trivial changes just to show the run did work.
Every one of these is a no-op that was forced to masquerade as an action.
A no-op is not a failure and not a skip
There are three different outcomes people lump together, and they need to stay separate:
- Failed. The job tried to act and something broke. This needs a human or a retry.
- Skipped. The job never ran its logic: a lock was held, a dependency was down, the window was closed. This needs investigation.
- No-op. The job ran fully, checked the world, and correctly concluded there was nothing to do.
The third one is the healthy one. It means the agent looked, reasoned, and restrained itself. But if your logs record it the same as a skip, or worse, record nothing at all, you cannot tell a quiet system from a dead one.
Give “nothing to do” a reason code
A bare “no action taken” is useless. A useful no-op explains itself in one structured line:
no-op: no new inputs since last run (cursor unchanged)no-op: all 14 candidates already processed (dedupe hit)no-op: threshold not crossed (value 41, trigger 50)no-op: quiet hours, deferred to 08:00no-op: change below materiality (0.3% delta)
Each of those tells a future reader what the agent checked and why it stopped. That is the evidence that separates “the system is healthy and idle” from “the system is broken and silent.”
If you can only add one thing to an existing automation, add this: every run ends with exactly one of acted, no-op:<reason>, skipped:<reason>, or failed:<reason>.
Build the check before the action
The practical pattern is a gate in front of the expensive step. Before the agent drafts, calls a tool, or spends tokens, a cheap deterministic check answers one question: is there any reason to run?
Good gate checks are boring on purpose:
- Compare a cursor, hash, or timestamp against the last successful run.
- Query for new items; if the count is zero, stop.
- Compare the current value to the last reported value; if inside tolerance, stop.
- Look up whether this exact action was already completed (an idempotency key works well here).
Notice that none of these need a model. The cheapest agent run is the one that never calls the model because a ten-line script said “nothing changed.” That also happens to be your best cost-control lever.
Make the model allowed to say no
Sometimes the judgment call really does need the model. In that case, give it an explicit exit in the prompt and in the output schema.
Instead of “summarize what happened today,” try “decide whether anything happened that the owner would want to know. If not, return {"action": "none", "reason": "..."}.” Make none a valid, first-class value in the schema, not an error path.
Then verify the reason is real. A model that says “nothing notable” should be able to point at what it checked. If it cannot cite inputs, treat the no-op as suspect and log it for review.
Quiet is only trustworthy if you can prove it
The objection to all this is fair: a system that frequently does nothing looks identical to a system that is broken.
That is exactly why no-ops need to be recorded rather than ignored. Three small habits close the gap:
- Heartbeat the no-ops. A weekly line like “212 runs: 9 acted, 201 no-op, 2 skipped, 0 failed” proves the system is alive and mostly restrained.
- Alert on the wrong silence. If a job that normally acts every few days has been a no-op for three weeks, that is a signal. It might be fine. It might mean an upstream feed died. Either way, a human should glance at it.
- Sample the no-ops. Once a month, pull a handful of no-op decisions and check them by hand. If the agent was wrong to stay quiet, you learn that before a customer does.
What this changes in practice
Teams that adopt this usually notice the same things within a few weeks.
Costs drop, because gated runs skip the model entirely. Notifications get trusted, because they only fire when something real happened. Logs get readable, because every run has a one-line verdict. And the agent stops generating plausible-sounding work to justify its own schedule.
There is also a cultural shift. When “nothing to do” is an acceptable result, nobody feels pressure to make the automation look busy. The job’s value is that it is right, not that it is loud.
A quick audit you can run today
Pick one scheduled agent job and answer these:
- What does it do when there are no new inputs?
- Can it distinguish “nothing to do” from “I failed to check”?
- Does the log say why it stopped, in a form a stranger could read?
- Is there a cheap check in front of the expensive step?
- Would anyone notice if it had silently done nothing for a month?
If the answers are “it writes something anyway,” “no,” “no,” “no,” and “no,” you have found your next improvement. It will not add a single feature. It will make everything you already built more believable.
The goal of an autonomous system is not constant output. It is correct output, including the correct decision to leave things alone.
More from the build log
Suggested
Want the full MarketMai stack?
Get the core MarketMai guides and operator playbooks in one premium bundle for $49.
View Bundle