· AI

CEO of Tallyfy · AI advisor at Blue Sheen for mid-size companies

How Claude Code scheduled jobs actually work

Claude Code scheduled jobs come in three forms with very different guarantees: the in-session /loop, Desktop tasks, and Cloud routines. A missed run does not queue up a backlog. And despite a common belief, none of them creates a Windows Task Scheduler entry or a .bat file. Here is how each one actually behaves.

The short version

Claude Code has three schedulers, not one. They differ on a single question that decides everything: what happens when your machine is off. Pick the wrong one and your nightly job quietly does not run.

  • /loop is in-session: it stops the moment you close the terminal
  • Desktop tasks run while the app is open, and do exactly one catch-up for a missed run, not a backlog
  • Cloud routines run on Anthropic infrastructure and do not care if your machine is off
  • None of the three creates a Windows Task Scheduler entry or a .bat file

A scheduled job set for 9am ran at 11pm. Once. Not six times, although it had missed six days while the laptop was shut. Just one run, late, against a day of stale state.

That single observation is the whole subject of this post, because it is the moment most people learn that “scheduled” in Claude Code does not mean what they assumed. They picture a cron daemon and a backlog of missed runs waiting patiently to fire. None of that is how it works. Claude Code has three separate scheduling mechanisms, each one makes a different promise about reliability, and the gap between them is exactly where automation silently fails.

Think about why that assumption is so easy to make. For thirty years, “schedule a task” has meant a small piece of operating-system plumbing that sits there, awake, waiting. A cron daemon does not care whether you are logged in. A Windows service does not care whether you opened any particular window. The schedule and the work were always separate things, and the schedule was the part that did not blink. Claude Code does not work that way for two of its three options, and the reason it does not is worth understanding rather than just memorizing. The schedule is something an application checks, on a timer, while that application is alive. Kill the application and you have not paused the schedule. You have removed it. That is a different model, and once you see it the late run at 11pm stops being mysterious and becomes obvious.

So the useful way to think about Claude Code scheduled jobs is not “how do I schedule a task.” It is “which of the three schedulers am I using, and what does it do the moment my machine goes to sleep.” Answer that and the late-night surprise stops happening. Get it wrong and the failure is the worst kind: silent. The job does not error. It does not warn you. It just does not run, and you find out days later when the report you depend on is missing or, worse, when it arrives full of stale numbers and you act on them.

The three ways to schedule

Claude Code offers three ways to run work on a schedule, and the official scheduled tasks documentation lays them side by side. The first is /loop, a bundled skill that re-runs a prompt on an interval inside your current session. The second is a Desktop scheduled task, created in the Claude Code Desktop app, which starts a fresh session on your machine at a set time. The third is a Cloud routine, which runs on Anthropic-managed infrastructure rather than your computer at all. They look interchangeable in a feature list and they are not, because they answer the reliability question in three different ways. /loop needs your session open. A Desktop task needs the app open and the machine awake. A Cloud routine needs nothing of yours running. That single column, “what has to be on for this to fire,” is the one you choose by, and everything else is detail.

The three Claude Code scheduling options compared: in-session /loop, Desktop tasks, and Cloud routines

The mistake to avoid is treating the choice as a matter of taste. It is a matter of what you are scheduling. A poll that babysits a deploy for the next hour and a job that must run every night unattended are not the same problem, and they do not want the same scheduler.

Here is a quick way to sort any job into the right bucket. Ask yourself: will I be sitting at this machine, with this session open, the whole time the job needs to run? If yes, /loop is fine. It is the lightest tool and you are right there to see it work or fail. Ask the next question: will the machine at least be awake and the app open, even if I am not watching every minute? If yes, a Desktop task fits, with the caveat about missed runs that the next sections cover. Ask the last question: does this job have to run on time regardless of where I am or whether my laptop is even powered on? If yes, only a Cloud routine qualifies, and nothing local will save you. Three questions, three answers. The work decides, not your preference.

Notice that the questions form a ladder of dependence. /loop depends on a session, a session depends on an app, and an app depends on a powered machine. Each step up removes one of those dependencies. A Desktop task no longer needs your session. A Cloud routine no longer needs your app or your machine. So the choice is really a question of how many of your own fragile things you are willing to let the job lean on. The more a job matters, the fewer of them it should touch.

The in-session loop

/loop is the lightweight option and the one people reach for first, because it is a single command. Type /loop 5m check the deploy and Claude re-runs that prompt every five minutes. Under the hood it writes a cron expression and schedules the job; a session can hold up to 50 such tasks at once.

What matters about /loop is everything it does not survive. It is session-scoped. The documentation is blunt: tasks “only fire while Claude Code is running and idle. Closing the terminal or letting the session exit stops them firing.” Resuming with --resume brings back tasks that have not expired, but a fresh conversation clears them. And recurring loops carry a hard seven-day expiry: a recurring task “automatically expire[s] 7 days after creation,” fires one final time, and deletes itself. That expiry is a feature, a guard against a forgotten loop running forever, but it surprises people who expected “recurring” to mean permanent.

/loop also does not catch up. If a fire time passes while Claude is busy, the documentation says it “fires once when Claude becomes idle, not once per missed interval.” That is the right behavior for what /loop is for, which is active polling while you watch a build or a pull request. It is the wrong tool for anything that has to run while you are not there. For that, the terminal has to be the wrong place altogether, because the terminal closes.

It helps to picture the kind of work /loop was built for. Say you push a deploy and want Claude to check the build status every few minutes, tell you the moment it goes green or red, and otherwise stay quiet. You are at your desk. The session is open because you opened it. A five-minute loop is perfect here: it is cheap to set up, you can see each run scroll past, and when the deploy finishes you close the terminal and the loop is gone with it. Nothing to clean up. The fact that it dies with the session is a feature, not a flaw, for this use. The same goes for watching a long test suite, or polling a pull request for review comments while you work on something else in the same window.

The trouble starts when people stretch /loop past that shape. Imagine setting a /loop to “post a daily summary at 9am” and then closing the terminal at the end of the day, the way anyone would. The loop does not run that night. It cannot. The process that held it is gone, and the seven-day expiry means even a loop you carefully resume each morning is living on borrowed time. So treat /loop as a tool with a short, deliberate life. It is for the next hour or the next afternoon, while you are present. The moment a job needs to outlive your attention, /loop is not the answer, and reaching for it anyway is the most common way a “scheduled” Claude Code job ends up never running.

Desktop tasks and missed runs

A Desktop scheduled task is the next step up in durability. You create it in the Claude Code Desktop app under Routines, give it a prompt and a schedule, and the app starts a fresh session for it when it is due. It survives closing your manual sessions and it survives restarts, because the task definition lives on disk, not in a conversation.

It does not survive a closed laptop. The official Desktop scheduled tasks documentation is exact about the limit: tasks “only run while the desktop app is running and your computer is awake. If your computer sleeps through a scheduled time, the run is skipped.” The Desktop app polls the schedule every minute while it is open. No app, or no power, means no fire.

That polling detail is small but it explains a lot. The schedule is not a wake-up call sent to your machine. It is a question the app asks itself once a minute: is anything due right now? If the app is not running, nobody is asking the question. If the machine is asleep, the app is frozen along with everything else and the minute-by-minute check stops too. So a Desktop task is exactly as reliable as the app and the machine underneath it, and not one bit more. Most laptops sleep when you close the lid. Many sleep on their own after a stretch of no use. A desktop machine you leave running and plugged in is a far better host for these tasks than a laptop that travels with you, and if you find yourself depending on Desktop tasks, that difference is worth a thought.

This is where the late-night surprise comes from, and the documentation explains the rule precisely. When the app starts or the machine wakes, “Desktop checks whether each task missed any runs in the last seven days. If it did, Desktop starts exactly one catch-up run for the most recently missed time and discards anything older. A daily task that missed six days runs once on wake.” So a missed schedule is not a queue. It is a single catch-up for the most recent miss, and everything older is gone. That is why the 9am job ran once at 11pm.

It is worth being clear about why a single catch-up is the sane choice here, because at first it can feel like lost work. Picture the alternative. Your laptop is shut for a week of vacation. You open it Monday morning and a daily task fires six times in a row, each run racing the others, each one acting on a week-old picture of the world. That is not recovery. That is a small stampede of confused jobs, and the output would be worse than nothing. One catch-up for the most recent miss is the least-bad behavior: it gives you a fresh result and throws away the stale ones that could only mislead. The cost is that the work from the missed days is gone for good, and you have to design around that rather than wish it away.

So if you write a Desktop task, write the prompt defensively. Tell it to check the current date and skip work that no longer makes sense. Tell it not to assume yesterday’s run happened. A job that emails “today’s numbers” should confirm it is actually looking at today. A job that processes a queue should handle the case where the queue piled up while it was not running, or decide on purpose to skip the backlog. A scheduled job that assumes it ran on time will eventually be wrong, and the day it is wrong is the day you least expect it. If you are wiring Claude Code automation into how a team actually operates, this is the kind of detail worth getting right before it bites, and my door is open if you want to think it through together.

Cloud routines run anywhere

If a job must run whether or not your machine is on, neither local option will do it, and that is what Cloud routines are for. A routine runs on Anthropic-managed cloud infrastructure. Your laptop can be shut, in a bag, on a plane, and the routine still fires. It can be triggered on a schedule, by an API call, or by a GitHub event.

The trade is access. A Cloud routine works from a fresh clone of your repository, so it has no view of your local files or your uncommitted changes, and its minimum interval is one hour rather than the one minute the local options allow. That is the real exchange: you give up local state and fine-grained timing, and you get a job that does not depend on a device you carry around. For a nightly dependency audit, a morning briefing, a daily report, that is the right trade. The work that has to happen on time, every time, should not be tied to whether you remembered to leave a laptop open. The same logic that makes a stop hook more reliable than a written instruction applies here: move the guarantee off the thing that can fail.

Sit with the “fresh clone” detail, because it changes what a Cloud routine is good at. The routine does not see your machine. It sees your repository, as committed, and nothing else. So a half-finished change sitting in your working directory does not exist as far as the routine is concerned. A file you keep on your desktop and never commit does not exist. A local environment variable, a credential in your shell, a tool you installed by hand: none of it travels to the cloud. This is a hard wall, not a soft one, and trying to push a routine past it leads to jobs that work when you test them locally and fail in the cloud for reasons that take a while to spot.

Read the right way, that wall is a feature. A job that runs from committed code only is a job whose behavior you can actually reason about, because what runs is what is in the repository and what is in the repository is what you can read. There is no hidden local state quietly changing the result. So the work that suits a Cloud routine is work that is already self-contained: it reads what it needs from the repo or from a service it can reach over the network, it does its thing, and it writes its output somewhere durable. A dependency audit fits that shape. A daily summary that pulls from an API fits it. Anything that needs to peek at your uncommitted edits does not, and that is the line to keep in mind.

The one-hour minimum interval matters less than it sounds for this class of work. Think about what you actually put in a Cloud routine: a nightly job, a once-a-morning briefing, a check that runs a few times a day. None of those wants minute-level timing. The jobs that need minute precision are the ones you are watching live, and those belong in /loop anyway. So the coarse interval is not really a limitation for the routine’s natural use; it is just a reminder that the cloud and the terminal are for different speeds of work.

The Task Scheduler myth

Now the question that sends people looking in the first place. Does Claude Code register a Windows Task Scheduler entry? Does it write a .bat file? It is a reasonable thing to assume, because that is how desktop software has scheduled things for thirty years. It is also not what happens.

None of the three mechanisms touches the operating system scheduler. /loop is a cron loop running inside the Claude Code process; when the process ends, so does the loop. A Cloud routine runs on Anthropic’s servers and has nothing to do with your machine at all. And a Desktop scheduled task, the one that looks the most like an OS task, is not one either. The Desktop app itself does the polling, once a minute, while it is open. The task is stored as a SKILL.md file in ~/.claude/scheduled-tasks/, with YAML frontmatter and the prompt as the body. There is no .bat, no registry entry, no launchd plist, nothing in Task Scheduler. If you went looking in Windows Task Scheduler for your Claude Code job, you would not find it, and that is not a bug. It was never there. If you do want a real operating-system schedule, you build it yourself, by wrapping the non-interactive claude -p command in your own cron job or Task Scheduler entry. That is a choice you make on purpose, not something Claude Code does for you.

The fact that a Desktop task is just a file is worth pausing on, because it tells you something useful. A task you created is plain text on disk: frontmatter at the top, your prompt below it. You can open it, read it, and see exactly what was set up, which is far easier to inspect than an opaque entry buried in the operating system’s own scheduler. But that same plainness is the reason it carries none of the operating system’s guarantees. The operating system did not promise to run it, because the operating system was never told about it. Only the app knows. That is the whole story of why these tasks behave the way they do, and it is sitting right there in where the task lives.

This matters beyond trivia, because it tells you the real failure mode. An OS-scheduled task fires whether or not the application is running. A Claude Code Desktop task does not; it needs the app. So the thing that breaks your automation is never a missing Task Scheduler entry. It is a closed app or a sleeping machine. Knowing the mechanism tells you where to look.

Picture the wrong way to debug this. A morning report did not arrive. You open Windows Task Scheduler, search for anything with “claude” in the name, find nothing, and conclude the task was never created or got deleted. You recreate it. The next time the laptop sleeps, the report goes missing again, and you are no closer to the cause. The search itself was the mistake. There was never going to be a Task Scheduler entry to find, so its absence told you nothing. Hours can disappear into chasing a thing that, by design, does not exist.

The right way is shorter. If a scheduled job did not run, do not open Task Scheduler. Ask three things in order. Was the Desktop app open at the scheduled time? Was the computer awake, or had it slept? And, stepping back, should this job have been a Cloud routine in the first place, given that it clearly needs to run when you are not around? That last question is usually the real fix. A job that keeps getting missed on a laptop is not a job with a bug. It is a job in the wrong scheduler. The three schedulers are not a ranking from worst to best. They are three answers to one question, and the only real mistake is choosing one without asking the question at all.

About the Author

Amit Kothari is an experienced consultant, advisor, coach, and educator specializing in AI and operations for executives and their companies. With 25+ years of experience, he is the Co-Founder & CEO of Tallyfy® (raised $3.6m, the Workflow Made Easy® platform) and Partner at Blue Sheen, an AI advisory firm for mid-size companies. He helps companies identify, plan, and implement practical AI solutions that actually work. Originally British and now based in St. Louis, MO, Amit combines deep technical expertise with real-world business understanding. Read Amit's full bio →

Disclaimer: The content in this article represents personal opinions based on extensive research and practical experience. While every effort has been made to ensure accuracy through data analysis and source verification, this should not be considered professional advice. Always consult with qualified professionals for decisions specific to your situation.

Related Posts

View All Posts »
Claude Code effort mode and where it falls short

Claude Code effort mode and where it falls short

Claude Code effort mode looks like a cost dial: turn it down to spend fewer tokens. The official docs say otherwise. Effort is a behavioral signal, not a strict budget, so low effort does not reliably cut spend and can quietly raise it. Here are the five levels, where they stop, and how to set effort with intent.

How Claude Code stop hooks work

How Claude Code stop hooks work

A Claude Code stop hook runs the moment Claude finishes a turn and can refuse to let it stop. It is the one hook that inverts control: Claude must pass your check before the turn ends. This post covers what a stop hook is, why exit code 2 is the whole game, the infinite-loop trap to avoid, and the patterns worth wiring up.

How to budget tokens in Claude Code

How to budget tokens in Claude Code

A surprising Claude Code bill is almost never one big expense. It is four different cost shapes stacked up: a context window that bills every turn, subagents that each cost a fixed chunk, skills that cost almost nothing until used, and caching that can cut the recurring cost or not. Budgeting tokens means knowing the four shapes.

How to ensure Claude actually follows through on a plan

How to ensure Claude actually follows through on a plan

Claude Code creates excellent plans but silently skips steps during execution. A three-layer enforcement system with CLAUDE.md rules, a structured verification protocol, and a Stop hook that physically blocks incomplete work fixed the problem after 6 bugs and 15 regression tests.

What is a hook in Claude Code and how to use them

What is a hook in Claude Code and how to use them

Hooks in Claude Code are automated actions that fire on specific events during AI sessions. They range from simple bash scripts to agent-powered validators. The difference between exit code 1 and exit code 2 will save you hours of frustrated debugging.

Using AI for semi-manual SOC 2 evidence collection

Using AI for semi-manual SOC 2 evidence collection

Fully automated SOC 2 evidence collection sounds great until you try it. Half the items need human judgment. Here is how a three-phase guided workflow at Tallyfy collected 99 evidence items across 4 sessions in 4 days, with AI handling orchestration and a human handling the judgment calls.

AI advisory services via Blue Sheen.
Contact me Follow 10k+