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.
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.
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 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.
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.
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.
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. If you write a Desktop task, write the prompt defensively: tell it to check the date and skip work that no longer makes sense. A scheduled job that assumes it ran on time will eventually be wrong. 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.
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.
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. If a scheduled job did not run, do not open Task Scheduler. Ask whether the Desktop app was open, whether the laptop was awake, or whether the job should have been a Cloud routine in the first place. 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.



