For three mornings in a row, one scheduled job drained my entire Claude Code usage window before the morning’s real work could run. That is the part the tips lists skip. Keep CLAUDE.md short, use plan mode, always use git: all good advice, and all of it written by someone sitting at the keyboard watching each step. The harder question is whether you can close the laptop and let Claude Code run on a schedule without waking up to a 6,000 dollar bill, a job that swears it finished work it never did, or something deleted that you cannot get back.
I run my entire back office that way. More than thirty scheduled Claude Code jobs across eight products, firing every day whether I am at my desk or on a plane: the blogs, the SEO reports, the signup digests, the inbox cleanup, an infrastructure check every morning. It has run for months without a runaway bill and without an agent deleting anything. It has also broken in ways the tips lists never mention, and every break turned into a rule. Those rules are this article. They are the same worries people raise over and over on r/ClaudeAI, answered from a fleet that has actually run.
On this page
- The short answer
- What I actually run on Claude Code schedules
- Rule 1: Bound every run so it cannot run up a bill
- Rule 2: Never let a job mark its own work done
- Rule 3: Scope its hands and keep secrets out of context
- Rule 4: Keep the context file lean or the job degrades
- How to schedule it, and the method I would pick
- Frequently asked questions
- Where this comes from
The short answer
Running Claude Code unattended is worth it, and it is not reckless, but the failure modes are real and none of them are the ones the horror stories obsess over. Across months of scheduled runs, nothing my agents did was dangerous; everything that broke was the cron around them. No wiped database, no deleted repository. What went wrong was orchestration: a job that ran twice at once and drained my usage window, a guardrail that emailed me forty-six times in a night, a run that published two articles and then reported zero.
So the practices below are not about prompting well. They are the operating rules that keep a fleet of scheduled agents from hurting you while you are not looking: four rules and one scheduling decision, each earned from a specific morning I would rather not have had. The short version is that an unattended agent is safe when every job is bounded, verified, and scoped, and when you never let it be the judge of its own work.
What I actually run on Claude Code schedules
The setup is deliberately boring, and boring is the point. Each job is a small shell script that runs one claude session against one repository with one clear task, launched on a timer. A sample of what fires on a normal day:
- A daily article run for each blog that picks the next topic from a backlog, writes it, and publishes it.
- A daily upkeep pass that refreshes a handful of live articles.
- A morning infrastructure check that pings every product and emails me only when something is down.
- A founder digest that reports new signups across all nine products with a rough score, so the interesting ones surface.
- Weekly and monthly SEO reports, and an inbox cleanup that forwards on only the mail worth reading.
Two structural choices matter more than any single job. First, on a Mac I use launchd rather than cron. On a Mac, cron has no Full Disk Access and inherits the wrong PATH, so launchd, not cron, is the right scheduler for unattended Claude Code; half my jobs failed silently until I switched. Second, a small supervisor ticks every twenty minutes and reruns anything the machine missed while it was asleep. That supervisor is also where most of my trouble started, which is Rule 1. If you want the fuller walkthrough of the setup itself, I wrote up how I run a business on Claude Code separately; this piece is the rules that keep it safe.
Rule 1: Bound every run so it cannot run up a bill
The loudest fear about unattended agents is the bill, and it is justified. The public stories are real: a thirty-minute update check left in a loop that re-sent its whole context every cycle and cost thousands, subagent fan-outs that burned tens of thousands in days. What makes it worse is that the usage dashboard lags, so the money is gone before anything warns you.
My version was smaller but the same shape. For three mornings in a row, one upkeep job drained my entire five-hour usage window before the important jobs could run. Two causes, both orchestration: the supervisor judged whether the job had run from a stamp written only on success, so twenty minutes into a run that can take two hours it launched a second full run on top of the first, and a catch-up window set too wide fired the same job again and again.
The rules that came out of it:
- One run at a time. A simple lock, taken at the start of every job, so a slow run can never be doubled.
- Stamp the attempt when the job starts, not when it succeeds, so the supervisor can tell running from never ran.
- Cap the run itself. A headless
claude -pjob takes a--max-turnsceiling, so a single run cannot spin forever no matter what it decides to do. - Give every run fresh, scoped context. Nothing carries over between runs, so there is no loop that quietly grows.
- Cap subagent fan-out hard, and route trivial long tasks to a cheaper model so they never spend the expensive weekly limit.
- Any job that has done its work, including one that just alerted you, exits zero. Exit non-zero and the supervisor reads the alert as a crash and runs it again. Forty-six emails in one night taught me that.
At list API prices my monthly usage would cost far more than the flat plan I actually pay, which is exactly why an unbounded loop is a live grenade rather than a rounding error. Bound the run and the bill stops being a risk.
Rule 2: Never let a job mark its own work done
The next fear is that Claude Code will tell you it finished when it did not, and for unattended runs that is the whole ballgame, because no human is in the chair to catch the lie.
I learned it twice in one week. One night a run published two articles, then ended its turn while waiting on a background task it had started, and the process exited. The email it sent said it had published zero. Everything worked and the report was still wrong. A few nights later a different run wrote its article, verified it live, and then the network connection dropped; nothing retried, and the failure email again claimed nothing had shipped.
A scheduled agent that certifies its own work is sending you a rumor, not a report. Make it prove the outcome, not announce it.
The rules:
- The job never ends a turn waiting to be notified. If it must wait for something to propagate, it sleeps inside one synchronous step and keeps the turn open.
- Verification is part of the task, not an afterthought. The article job re-fetches the live URL and confirms a real 200 independently of anything the model claimed, before it calls itself done.
- Pin the session and resume it after a dropped connection instead of starting over, up to a small retry cap.
- Build the status email from what actually happened during the run, not from the model’s own summary of it.
Bad days are real, too. Every operator running a fleet sees a job occasionally turn in weaker work, and you cannot prompt that away. I do not try to detect it automatically, because the false positives would cost more than the misses. The defenses that actually hold are boring: each job runs its own quality checks before it ships, every change is a git commit so a bad run is recoverable rather than final, and when a model hits its limits the job falls back to another instead of pushing degraded output. The report an unattended agent sends you is worth exactly as much as the verification you baked into the job, and no more.
Rule 3: Scope its hands and keep secrets out of context
This is the fear people mean when they say they will not leave an agent alone: the empty variable in an rm -rf, the .env from one project read into a committed file, the API key nearly pasted into a repository. My honest position is that “an agent wiped my database” is mostly fear talking, because I have never had one delete anything. But that is a result of how the jobs are scoped, not luck, and the single time a helper made changes to two live systems I had not asked it to touch, it set the rule.
What keeps it safe:
- Explicit confirmation before any production database write or deploy. No scheduled job makes a silent change to a live system.
- Least privilege per job. A job that writes blog posts cannot reach anything but the blog, so a misfire has nowhere to spread.
- Secrets never enter the model’s context. I keep credentials in a local store keyed by name and description; the agent looks a secret up by name and the value is injected by code at the moment it is used, so the key does its job without ever being read into the conversation. This is the one guardrail I deliberately built, and it is what lets me leave a job on auto instead of babysitting a permission prompt.
- Git is the undo button. Clean branch, real commits, so any change a run makes can be read and reversed.
And the point the horror stories get right: unattended is not the same as unpermissioned. A headless claude -p run starts in manual permission mode, and the temptation is to reach for the skip-all-permissions flag. The skip-all-permissions flag is the single most dangerous setting for a scheduled job; scope the allowed tools instead, so the job can do its one thing and nothing else.
Rule 4: Keep the context file lean or the job degrades
A scheduled job is only as good as the instructions it reads on every run, and those instructions rot. People describe CLAUDE.md files that quietly grow until a memory file crosses some threshold and every turn starts to wobble. On a job you are watching, you notice. On a job that runs at 3am, you do not, and it gets a little worse each night.
How I keep each job stable:
- One tight instruction file per job, written like how I would do this exact task by hand, with an example of a good output. Not a kitchen sink.
- Five separate skills, one per blog, each with its own voice and rules, specifically so one shared file cannot flatten five different jobs into the same average.
- Delegate verbose work to subagents, so the main run reads a short conclusion instead of a wall of file dumps and its context stays light across a long job.
- Fresh context every run. The quick-memory keyboard shortcuts of a year ago are gone anyway, so put durable rules in the file itself with
/memoryor by editing it directly.
If your CLAUDE.md has quietly become a novel, a free CLAUDE.md analyzer I keep at Locul scores it and points at the lines to cut, in the browser, with no account. The principle underneath it is the one Anthropic’s own Claude Code memory docs push: the file loads on every single turn, so every line you add is a tax you pay on every run.
How to schedule it, and the method I would pick
There are three honest ways to put Claude Code on a timer, and they are not interchangeable. Here is the comparison, and my pick.
| Method | Machine can be off | Best for | The catch |
|---|---|---|---|
Headless claude -p on cron or launchd |
No, your machine runs it | Real automation with full repo access and any frequency | You own the locks, retries, and scheduling yourself |
| Desktop scheduled tasks | No, the app must be open | Light, recurring personal tasks | Tied to the desktop app staying open |
| Cloud routines | Yes, it runs in the cloud | Set-and-forget checks while your machine sleeps | Hourly at most, and not your full local environment |
For a business back office, headless on launchd wins, and it is not close. It is the only option that hands a job your real repository, your real tools, and any schedule you want. You pay for that power by owning the reliability layer yourself, which is exactly what Rules 1 and 2 are. If all you want is a machine-off reminder or a simple hourly check, cloud routines are the right tool and you should not build the launchd rig at all. Anthropic’s headless mode docs and its scheduling comparison lay out the trade-offs from the primary source.
Before you leave any job running unattended, this is the checklist I actually use:
- Is the run bounded, with a lock, fresh context, a
--max-turnsceiling, and a fan-out cap? - Does the job verify its own outcome instead of announcing it?
- Are its tools scoped, its secrets out of context, and production writes gated?
- Is the instruction file short enough to load cheaply on every run?
- Does the failure email come from what happened, not from the model’s summary?
- Is the whole job idempotent, and is every change a git commit you can reverse?
If you want a running start on the instruction files, I keep 23 free Claude skills you can install with one command, /plugin marketplace add mkhalid1/locul-skills. Each one is a worked example of the “how I would do this by hand” file this whole article argues for.
FAQ
Is it safe to run Claude Code unattended?
Yes, with guardrails. Across months of scheduled runs I have never had an agent delete data or run away, but that is because every job is bounded, scoped, and verified, not because the model is inherently safe to leave alone. The danger in autonomous runs lives in the orchestration around the agent, so that is where the safety has to be built.
How do I stop Claude Code from running up a huge bill overnight?
Bound the run. Put a --max-turns ceiling on the call, give it fresh scoped context so nothing loops and grows, take a lock so a job cannot double up, cap subagent fan-out, and route trivial long tasks to a cheaper model. Bills explode from an open-ended loop or a fan-out re-sending a large context every cycle, and because the usage dashboard lags, prevention beats monitoring.
Can I trust Claude Code when it says a task is done?
Not on its own word. Bake verification into the job so it proves the outcome, for example by re-fetching the live result and checking it independently, and build your status report from what actually happened rather than the model’s summary. I have had a run publish work correctly and still report the opposite, which is exactly why a job should never be the judge of its own success.
Should I use the skip-permissions flag for scheduled jobs?
No. A headless run starts in manual permission mode for a reason. Instead of skipping all permissions, scope the allowed tools so the job can do its one task and nothing else. Unattended is not the same as unpermissioned, and the difference is your blast radius when something misfires.
How big should CLAUDE.md be for a scheduled job?
Small. The file loads on every single turn, so keep it to the instructions plus one example of a good output, and split different jobs into separate files so one does not average out the others. A bloated instruction file degrades quietly on a job nobody is watching.
Where this comes from
I build and run eight products solo, and the back office runs on Claude Code schedules, so these rules are what I actually operate on, not demos. Every one of them cost me a specific morning: a usage window burned three days running, forty-six emails in a night, a run that published two articles and told me it had published zero. I publish my real skills, agents, and conventions as I go, and the ones ready to share are free at Locul. If you reduce the whole thing to one line: an unattended agent is only as trustworthy as the bounds, checks, and scopes you put around it, and building those is the actual work.
