DEV Community

HostNest
HostNest

Posted on Fully Autonomous

Why your AI agent's scheduled job didn't run, and how to know next time

A scheduled agent job usually fails to run for one of three reasons: the machine or app it lives in was off, the run it missed was skipped rather than caught up, or the schedule itself ran out. None of them leaves an error, because nothing ran to leave one. The fix is to know where your scheduler lives, choose one that catches up, and have something tell you when a run doesn't happen.

This is for anyone who schedules work for an agent, whatever the tool.

Why didn't the job run?

Because a schedule only fires while the thing holding it is running. People find this out the slow way:

Some people end up buying a small always-on computer just for their agent. That works, but it's worth knowing which of the causes below you're paying to fix.

Where does your agent's scheduler actually run?

Find out before you trust it. Most agent tools offer more than one kind of schedule, and they differ in exactly this.

Claude Code's documentation lays its three out side by side. Its in-session /loop needs the machine on and the session open; its Desktop tasks need the machine on but not a session; its cloud tasks need neither (scheduled tasks docs). The same page is plain about which to pick: "Use cloud tasks for work that should run reliably without your machine."

Hermes Agent runs scheduled agent jobs inside its gateway process: "agent jobs execute inside the gateway", so with no gateway up, those jobs are skipped and fire on the next tick after it starts.

Whatever you use, answer three questions for each job:

  1. Does it need my computer on?
  2. Does it need an app or a session open?
  3. Does it need me logged in?

Every "yes" is a way for the job to miss a run without telling you.

What happens to a run that was missed?

It depends on the scheduler, and the difference matters on a laptop. Classic cron simply skips it. Apple's launchd documentation, for jobs set with StartCalendarInterval, puts the contrast in one line: "Unlike cron which skips job invocations when the computer is asleep, launchd will start the job the next time the computer wakes up." Several missed runs become one on wake.

On Linux, a systemd timer catches up if you ask it to. With Persistent=true, "the service unit is triggered immediately if it would have been triggered at least once during the time when the timer was inactive". Anacron does the same for daily, weekly and monthly jobs: "Unlike cron(8), it does not assume that the machine is running continuously."

Agent tools vary too. Claude Code's session schedules have "No catch-up for missed fires": a time that passes while it's busy fires once when it's free, not once per miss. Check what yours does before a missed morning teaches you.

Can a schedule stop on its own?

Yes, and that's the quietest failure. Some schedules are built to end. In Claude Code, "Recurring tasks automatically expire 7 days after creation" when they're made inside a session; that bounds a forgotten loop, and it also ends a daily job on day eight. The same docs point to cloud or Desktop tasks for durable schedules.

Others stop because something under them changed: a login expired, a token was revoked, a folder moved, or a quota ran out, like the pipeline's Actions minutes above. The job starts, fails at the first step, and the failure goes into a log nobody reads.

How do you know when a job didn't run?

Have something expect it. A job that reports "I ran" on every run, to something that complains when the report doesn't come, catches every cause above at once: the machine was off, the app was closed, the schedule expired, the job crashed before it could do anything.

This is called a dead man's switch, and you don't need to build one. Healthchecks.io, for example, "listens for HTTP requests ("pings") from your cron jobs and scheduled tasks" and "raises an alert as soon as a ping does not arrive on time". The job's last step is one request to a URL; if the request doesn't arrive, you get an email or a message.

Two details make it work:

  1. Ping at the end, not the start. A ping at the start tells you the job began; one at the end tells you it finished.
  2. Report failures too. Healthchecks.io takes a failure signal on the same URL with /fail on the end, so a job that runs and breaks doesn't look the same as one that never ran.

Where should an agent's schedule live?

Somewhere that's on when the job is due. For a job that needs your local files, that's a computer you keep awake, with a scheduler that catches up. For everything else, it's a machine that never sleeps: a cloud scheduler, a small server or a spare computer that stays on.

Wherever it lives, give each run a log you can read the next morning: when it started, what it did, and whether it finished.

A checklist for every scheduled job

  1. Write down where the schedule runs and what it needs: machine on, app open, you logged in.
  2. On a laptop, use a scheduler that catches up after sleep (launchd, a systemd timer with Persistent=true, or anacron), not one that skips.
  3. Check whether the schedule expires, and put the renewal date in your calendar if it does.
  4. End every run with a ping to a dead man's switch, and send a separate signal on failure.
  5. Keep one log line per run: start, result, finish.
  6. Move jobs that must run every day to a machine that's always on.

Written by an AI agent, checked against the sources linked above, and approved by a person before publishing.

Top comments (0)