Untopple

Blog

How to run Claude Code on a schedule

There are five ways to make Claude Code do something every morning without you, and one more way to make the job not need Claude every morning at all. Here is what each one is, what it costs, and what happens when a run goes wrong.

The short answer.

  • Your computer can be off: cloud scheduled tasks (formerly routines, set up with /schedule) or GitHub Actions.
  • It needs your local files: desktop scheduled tasks in the Claude app.
  • Only while you work today: /loop in the session you have open.
  • Full control on your own server: cron or Task Scheduler running claude -p.
  • The job is the same steps every day: have Claude write it once as code and run the code, so each run doesn't start a new agent session.

Ask this first: does each run need judgment?

Every option below except the last starts a fresh Claude Code session on each run. That is exactly right when each run needs judgment: reviewing yesterday's pull requests, triaging new issues, deciding which failing test to look at. The agent reads, thinks and acts differently each time because the input is different each time.

It is less right when the job is the same every day: fetch these feeds, keep what's new, send the list. Then each run pays for an agent to work out again what it worked out yesterday, and it may work it out a little differently. Keep that in mind as you read the table.

The options side by side

OptionRuns onComputer on?Most oftenPaid fromWhen a run fails
Cloud scheduled taskAnthropic's cloudNoHourlySubscription usageMarked Error in the task's history
Desktop scheduled taskYour computerYes, app open and awakeHourly in the formNot documentedShown in the task's history
/loopYour open sessionYes, session openEvery minuteYour session's usageYou see it in the session
GitHub ActionsGitHub's runnersNoEvery 5 minutesActions minutes, plus API or subscriptionRed run in the Actions tab
cron + claude -pYour serverYes, your serverAs you set itAPI key or subscription tokenA non-zero exit code; the rest is yours
Written once as codeA machine of its ownNoAs you set itNo agent per runChecked against its contract; you hear

1. Cloud scheduled tasks

Anthropic's own answer, and the one to try first if you have a Pro, Max, Ultra, Team or Enterprise plan. A scheduled task is a saved prompt with one or more repositories and the connectors it may use. Type /schedule in Claude Code, for example /schedule daily PR review at 9am, or create one at claude.ai/code. Each run clones the repositories fresh in Anthropic's cloud, so your laptop can be closed.

  • Runs at most once an hour. Pick an odd minute like 9:07: runs on the hour can start a few minutes late. Cron expressions are in UTC unless you prefix CRON_TZ=.
  • Each run uses your subscription the same way an interactive session does, within hourly caps (100 scheduled runs an hour per account).
  • It needs a claude.ai login. With an API key, /schedule isn't there.
  • A failed run shows as Error in the task's history. The docs don't describe alerts or automatic retries, so check the history or have the prompt report its own outcome.
  • It is a research preview, so limits may change.

Good for: recurring work on a repository that needs judgment. See Anthropic's scheduled tasks docs.

2. Desktop scheduled tasks

In the Claude desktop app, open the Code tab, then Scheduled, then New task. Choose a local folder and a trigger (hourly, daily, weekdays, weekly or a custom cron in local time). Each run is a new session on your machine with your files and tools.

  • It only fires while the app is open and the computer is awake. A closed laptop lid still sleeps it.
  • Missed runs aren't all replayed: the app starts one catch-up run for the most recent missed time in the last seven days.
  • Skipped runs are listed with the reason, such as the machine being asleep or the last run still going.
  • In a mode that asks before using tools, a run that needs a new tool waits until you answer it.

Good for: jobs that need what is on your machine, on a machine that is on anyway. See desktop scheduled tasks.

3. /loop

Inside a running session, /loop 5m check the deploy repeats a prompt every five minutes, and /loop check the deploy lets Claude choose the gap, between one minute and an hour. You can also ask for a one-off: “remind me at 3pm to push the release branch”.

  • It only fires while the session is open and Claude isn't busy.
  • Recurring loops expire seven days after you create them.
  • Each run sends the session's whole context again, which adds up in a long session.

Good for: watching something during the working day. Not a scheduler for next month. See session-scoped tasks.

4. GitHub Actions

anthropics/claude-code-action runs Claude Code in a GitHub workflow. Give it a prompt and a schedule trigger and it runs on GitHub's machines. Run /install-github-app in Claude Code to set it up, or add a CLAUDE_CODE_OAUTH_TOKEN secret (from claude setup-token) or an ANTHROPIC_API_KEY yourself.

on:
  schedule:
    - cron: "7 9 * * *"   # UTC
jobs:
  report:
    runs-on: ubuntu-latest
    permissions: { contents: read, issues: read, id-token: write }
    steps:
      - uses: anthropics/claude-code-action@v1
        with:
          claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
          prompt: "Summarize yesterday's commits and open issues"
          claude_args: "--max-turns 20"
  • GitHub runs schedules at most every five minutes, in UTC, from the default branch, and can delay them when it is busy. It turns off schedules in a public repository after 60 days without activity.
  • You pay Actions minutes, plus API tokens, or your subscription if you use the OAuth token. That token belongs to whoever created it, so a shared repository is better off with an API key.
  • A failed run is a red run in the Actions tab, and GitHub's usual notification settings apply.

Good for: teams that already live in GitHub and want the schedule reviewed like code. See Claude Code GitHub Actions.

5. cron and claude -p

claude -p runs Claude Code without the interactive screen and exits with 0 on success. Put it in a crontab, a systemd timer, launchd or the Windows Task Scheduler and you have a scheduler you fully control.

# crontab -e
7 9 * * * cd /srv/reports && unset ANTHROPIC_API_KEY && \
  claude -p "Summarize yesterday's commits and open issues" \
  --allowedTools "Read,Bash(git log *)" --output-format json \
  >> /var/log/claude-report.log 2>&1
  • Allow the tools it needs. claude -p now starts in a mode where tools you haven't approved are refused, so use --allowedTools or --permission-mode.
  • Decide who pays. If ANTHROPIC_API_KEY is set, -p always uses it, even if you also have a subscription. To use the subscription, create a token with claude setup-token, put it in CLAUDE_CODE_OAUTH_TOKEN in a file only the job can read, and unset the API key.
  • Cap the spend with --max-budget-usd or the turns with --max-turns.
  • Everything else is yours: the server, logs, alerts, retries, and noticing that the job stopped running at all.

Good for: people who already run servers and want nothing in between. See headless mode.

6. Have Claude build it once, and run the code

The five options above schedule the agent. The other way is to schedule what the agent builds. You describe the job once, Claude writes and tests the code, and from then on the code runs on schedule. Claude comes back only when the job needs to change.

That is what Untopple does. It plugs into Claude as a plugin. Claude asks what you want to achieve, writes it down as a short contract, and builds the automation in TypeScript on a machine of its own, with schedules, connections, retries and a page for every run. Here is part of a real contract, for a local news digest Claude built with us and that has been live since 2 November:

  • PurposeKnow each morning what happened in Wetzikon and the Zürcher Oberland in the last 24 hours, from the town's own institutions as well as the press, and read the articles in German with an English translation beside each paragraph, without opening every local site.
  • EssentialThe town's own news, the local sources from the Zürcher Oberland, each article once, a link that opens the article, the German text when the article is readable, and a warning whenever a source couldn't be read.
  • NeverInvent news, or change what an article says. A translation must say what the German paragraph says, no more. Never date an article by guessing: one with no publication date is left out and counted in the warnings. Never let one source that's down stop the digest.
  • Stop whenNo source can be read for two days in a row.

The code reads fifteen sources, removes duplicates and builds the page without asking a model anything. It calls Claude for exactly one step, the translation, because that step needs a model. That is the difference in cost: you pay for the model only where a step needs one, not for an agent to plan the whole run every morning. And because the steps are code, Monday's run does what Sunday's did.

The contract also answers the question none of the options above answer for you: did the run actually do the job? A run that exits cleanly but sends an empty digest has still failed. Each run is checked against the result its contract promised, a schedule that should have run and didn't counts as a problem, and you hear about both.

It is not the right tool for everything. If each run needs fresh judgment on your repository, a cloud scheduled task is simpler. If you need your local files, use the desktop app. Untopple is for the jobs that should run the same way every day and reach a person: reports, digests, syncs, checks.

How to choose

  1. Needs judgment each run, computer can be off: cloud scheduled task.
  2. Needs judgment each run, needs local files: desktop scheduled task.
  3. Just for today's session: /loop.
  4. Your team reviews everything in GitHub: GitHub Actions.
  5. You run servers and want no one in between: cron and claude -p.
  6. The same steps every day, and you want to know it worked: build it once as code.

Build your first automation with Claude

Untopple is free while it's in early access. Setup takes about five minutes: create an account, add the plugin to Claude, and describe the job.