Claude Code is one of the most capable AI coding and ops tools available. Most people use it interactively. The ones building real leverage are running it headless on a schedule -- dispatching agent sessions at 5 AM, shipping deliverables while they sleep, and waking up to verified work instead of a blank cursor. Here is how to build that stack.
Why Schedule Claude Code Instead of Just Using It Live
Interactive Claude Code sessions are powerful, but they require you to be present. The moment you close the terminal, the work stops. A one-person operation that relies entirely on attended sessions caps itself at human hours, which is the exact constraint AI is supposed to lift.
Scheduled headless sessions change the math. A cron job that fires at 6 AM can run a revenue sweep, generate a content brief, check service health, and push a summary to your phone -- all before you make coffee. The output is waiting for you, verified and formatted, instead of being a task you have to start and babysit. Over a week, this compounds into tens of hours of recovered time and a business that is measurably more responsive than any human team.
This is not a theoretical workflow. It is the operational core of how one-person AI companies actually run at production cadence.
Prerequisites: What You Need Before the First Cron Job
Before scheduling anything, the following need to be solid:
- Claude Code installed and authenticated. The
claudeCLI must be accessible from your shell with a valid session. On Linux and macOS, confirm this withwhich claudeandclaude --version. On Windows, use Task Scheduler instead of cron -- the concepts are identical. - A working headless invocation. Run
claude -p "echo hello" --output-format textfrom a terminal. If it returns cleanly, headless mode is functional. If it returns a 401 or auth error, the token has expired -- re-authenticate interactively before scheduling anything. - Environment variables in place. Any API keys your prompts depend on need to be exported in the shell environment that cron runs in. Cron does not inherit your interactive shell's environment. Add
export MY_KEY=valuelines to the top of your cron wrapper script, or source a.envfile explicitly. - A working directory your prompts can reference. Use absolute paths in every prompt and script. Cron's working directory is not your home directory, and relative paths will silently fail.
The Basic Pattern: Headless Claude via Cron
The simplest scheduled Claude job looks like this in your crontab (crontab -e):
0 6 * * * /home/user/scripts/morning_sweep.sh >> /home/user/logs/morning_sweep.log 2>&1
And morning_sweep.sh:
#!/bin/bash
export ANTHROPIC_API_KEY="sk-ant-..."
claude -p "Read /home/user/projects/status.md and write a 3-sentence summary of today's top priorities to /home/user/output/morning-brief.txt" --output-format text
That is the entire foundation. The shell script handles environment, the claude -p flag passes the prompt in headless mode, and stdout is logged for debugging. Everything else is elaboration on this pattern.
Structuring Prompts for Unattended Execution
Prompts that work perfectly interactively often fail in headless sessions. The difference is that interactive sessions allow you to correct misunderstandings in real time. Unattended sessions do not. Write prompts for headless use with these rules:
- State the output format and destination explicitly. "Write a JSON file to /abs/path/output.json with keys X, Y, Z" is reliable. "Summarize this" is not -- Claude may write to stdout, to a file, or ask a clarifying question that stalls the session.
- Give it all inputs as absolute paths. "Read /abs/path/data.csv" rather than "Read data.csv." Relative paths break silently.
- Include a completion signal. End every headless prompt with an instruction like "When complete, write the single word DONE to /abs/path/status.txt." Your wrapper script can then check for that file to confirm the session completed rather than stalled or errored.
- Set scope boundaries. Headless agents will sometimes over-reach. "Only modify files in /abs/path/output/" and "Do not make any API calls" are guard rails worth adding to any unattended session that touches sensitive paths.
A Real Dispatch Architecture: Multiple Jobs, One Coordinator
A single cron job gets you started. A production solo-operator stack looks more like a dispatcher pattern: one coordinating script that runs on a schedule and decides which of several specialized jobs to fire based on current state.
The coordinator reads a state file (state.json) that tracks what ran, what succeeded, and what is blocked. It fires only the jobs whose conditions are met, writes results back to state, and logs everything. Each job is a small, focused headless prompt: one for content generation, one for revenue checks, one for service health. None of them overlap or interfere.
This is exactly how the specialized agent architecture scales -- not one general session trying to do everything, but a fleet of narrow agents each doing one thing reliably. The cron layer is what gives that fleet a heartbeat.
Handling Auth Token Expiry in Long-Running Schedules
The most common failure mode in scheduled Claude Code is auth token expiry. Claude Code's OAuth tokens have a finite lifespan. When they expire, every scheduled job that fires will return a 401 error, and your automation goes dark -- sometimes without any visible alert if you are not checking logs.
Two mitigations work reliably:
- Set
ANTHROPIC_API_KEYin every job's environment. An API key does not expire the way an OAuth token does. If you have an Anthropic API key, export it in your cron wrapper and the session will use it instead of the OAuth flow. - Add a health check job. Run a minimal probe prompt (
claude -p "respond with the word alive" --output-format text) every 15 minutes and check the output. If it fails, send an alert -- a simplecurlto a webhook, a text message via Twilio, or a write to a status file your monitoring stack watches. Catching a dead auth token in 15 minutes is better than discovering it 8 hours later when the morning brief never arrived.
The same health check pattern applies to any automated AI stack. It is the monitoring layer that separates a production system from a demo.
Output Routing: Getting Results Where They Need to Go
Headless Claude sessions write to files, which is useful but passive. A solo operator typically wants results delivered -- to a phone, a dashboard, a Slack channel, or a project file. Build delivery into the wrapper script rather than into the Claude prompt itself.
The pattern: Claude writes a structured output file, the wrapper reads it, and a separate delivery step sends it. Separation of concerns matters here. If the delivery step fails, the output is still on disk and can be resent. If Claude writes to the delivery endpoint directly, a network failure during the session loses the output entirely.
For phone delivery, a simple curl to a Telegram Bot API or Twilio SMS endpoint from the wrapper script takes about ten lines of bash. For dashboard updates, write a JSON file and have a lightweight server poll it. For the full picture of how automated AI phone systems fit into this kind of ops stack, our AI phone concierge overview covers how scheduled agents and phone routing work together in a one-person business context.
Windows: Task Scheduler Is Your Cron
If your primary machine is Windows, Task Scheduler replaces cron. The concepts are identical: a trigger (time-based), an action (run a script), and a log. The practical difference is that environment variables are set in the task properties under "Environment Variables" rather than at the top of a shell script, and the working directory needs to be set explicitly in the task action settings.
Create a .bat file that sets environment variables and calls claude -p "...", then register it as a Basic Task in Task Scheduler. Set the trigger to "Daily" or "Weekly" with a specific time, set the action to run your .bat file, and configure the task to run whether or not the user is logged in. That last setting is what makes it truly headless.
What Not to Schedule
Not every Claude Code task belongs in a cron job. Tasks with meaningful blast radius -- anything that sends external messages, modifies production data, or makes purchases -- should require human review before execution, or at minimum a dry-run mode that logs the intended action without performing it. Build the automation, but gate the destructive step behind a manual approval until you have enough logged runs to trust the output unconditionally.
Similarly, open-ended research prompts tend to be poor cron candidates. An agent asked to "research competitors and write a report" may spend unpredictable amounts of time and money on token usage without producing a consistent output. Narrow, bounded prompts -- "read this file, produce that file, exit" -- are the reliable building blocks of a scheduled AI stack.
FAQ
Do I need a server to run scheduled Claude Code jobs, or can I use my laptop?
Your laptop works for development and testing, but a always-on machine is more reliable for production schedules. A Raspberry Pi, a small VPS, or a spare desktop running Linux handles scheduled Claude jobs well and costs almost nothing to operate. The key requirement is that the machine be running when the cron job fires. A laptop that sleeps at night will miss overnight jobs silently.
How much does running Claude Code headless on a schedule cost?
It depends entirely on the token volume of your prompts and how frequently they run. A short status-check prompt running every 15 minutes is a different cost profile than a 2,000-token content generation job running three times a day. Start with infrequent schedules, check your API usage dashboard after the first week, and adjust. Most solo-operator automation stacks land well under $50 per month at sensible prompt sizes and cadences.
Can Claude Code read and write files in headless mode the same way it does interactively?
Yes. The -p headless flag does not restrict file access -- Claude Code can read and write files in headless mode the same way it does in an interactive session. The practical difference is that there is no user available to approve a permission prompt. Use the --allowedTools flag to pre-approve the specific tools (Read, Write, Bash) your automation needs, and the session will proceed without any approval gates.
What happens if a scheduled Claude job runs longer than the next trigger interval?
By default, cron will launch a new instance at the next trigger time even if the previous one is still running. This can produce overlapping jobs that write to the same output files, creating corrupted results or doubled work. Guard against it by writing a PID file at job start and checking for it at the next run -- if the PID file exists and the process is still running, the new instance exits immediately. This is a standard pattern in any long-running scheduled script and applies equally to Claude jobs.