Author: The Routines Runbook

  • Cloud routines vs local scheduled tasks in Claude Code: how to choose

    Claude Code gives you three ways to run something on a schedule, and the New routine button asks you to choose between two of them before you know what the difference is. Here is how to pick, and what each one will do to you if you pick wrong.

    The short version

    • Cloud routine — runs on Anthropic’s infrastructure whether your machine is on or not. Can also fire on API calls and GitHub events. No access to your local files.
    • Local (Desktop) task — runs on your machine, with your files and your local tools. Only fires while the Desktop app is open and the computer is awake. Schedule-only.
    • /loop — polls inside an open CLI session. Dies with the session. For quick checks while you work, not for anything you rely on.

    The deciding question is almost always the same one: does the work need your local files? If yes, it is a Desktop task and the machine has to stay awake. If no, put it in the cloud and stop worrying about the lid.

    The comparison in full

    Cloud Desktop (Local) /loop
    Runs on Anthropic-managed cloud Your machine Your machine
    Needs the machine on No Yes Yes
    Needs an open session No No Yes
    Local file access No — fresh clone each run Yes Yes
    Triggers Schedule, API, GitHub events Schedule only Schedule only
    Minimum interval 1 hour 1 minute 1 minute
    Permission prompts None — runs autonomously Configurable per task Inherits from session
    MCP / connectors Connectors, per routine Config files and connectors Inherits from session

    What bites people on Desktop tasks

    Sleep means skipped

    Tasks only run while the app is running and the computer is awake. If the machine sleeps through the scheduled time, the run is skipped. Closing the laptop lid still puts it to sleep, even with Keep computer awake turned on in Settings. If a task genuinely must run, it belongs in the cloud — that is the entire reason cloud routines exist.

    The catch-up run that lies about the date

    When the app starts or the computer wakes, Desktop checks whether each task missed any runs in the last seven days. If it did, it starts exactly one catch-up run for the most recently missed time and discards everything older. A daily task that missed six days runs once.

    That single catch-up is where the damage happens. A task scheduled for 9am can run at 11pm, and unless the prompt reads the clock it will write “today” about a day that is nearly over. Anthropic’s own documentation tells you to put the guardrail in the prompt. Do that — something like:

    Read the current local date and time first and compare it with the intended
    slot of 09:05 local.
    - Within 3 hours: proceed normally.
    - More than 3 hours late: begin the output with
      "LATE RUN - produced at <time> for the <date> slot", and cover the period
      the slot intended, not the last 24 hours from now.
    - After 18:00: skip the forward-looking sections entirely.

    Manual permission mode stalls, silently

    Each task has its own permission mode. A task in Manual mode that needs a tool it hasn’t been granted will stall until you approve it — the session sits open in the sidebar waiting, which is not what you want from something that was supposed to happen at 7am. Click Run now after creating a task, watch for the prompts, and choose “always allow” for each one.

    One exception you cannot design around: MCP tools marked requiresUserInteraction prompt on every call and offer no always-allow. A task that calls one will stall every single time. Don’t build an unattended routine on top of one.

    Uncommitted changes come along for the ride

    By default a task runs against whatever state your working directory is in, including uncommitted work in progress. Turn on the worktree toggle when creating the task to give each run its own isolated Git worktree.

    What bites people on cloud routines

    No permission prompts at all

    Cloud routines run as full autonomous sessions. There is no permission-mode picker. The session runs shell commands and calls any connector you include without stopping to ask. Combined with the fact that every connector on your account is attached by default, a routine you accept without editing is holding more authority than it needs. Trim the connector list on the way in.

    A fresh clone every run

    Each repository is cloned at the start of every run from the default branch. Nothing persists between runs unless you commit it or write it somewhere external. If your routine needs history — “is this test flaky?” cannot be answered from one run — it has to store that history in the repository or a connector, not in its own head.

    The GitHub connection has a 72-hour fuse

    If your GitHub connection expires, runs are skipped for up to 72 hours and resume on their own if you reconnect inside that window. After 72 hours the routine switches off and you turn it back on by hand. Worth a calendar reminder if you depend on one.

    A rule that applies to all three

    Whichever you pick, the run list is not a report. A green status means the session started and exited without an infrastructure error — it does not mean your task succeeded. The routine has to tell you itself: an explicit OK or PARTIAL status, a named reason when a source was unreadable, and one line per run in a log you can scan.

    That is covered in full here: Why your Claude Code routine reported success and did nothing.

    Desktop’s run history helps a little — hover a skipped entry and it tells you why: the computer was asleep, the previous run was still going, or other tasks were already running. Cloud gives you /schedule why did my nightly review do nothing this morning? from v2.1.227. Neither is a substitute for a prompt that reports on itself.

    One more useful trick

    A Desktop task can change its own schedule or prompt mid-run using the update_scheduled_task MCP tool — so a code review can reschedule itself to run earlier when it notices a release branch appear. Its prompt also lives on disk at ~/.claude/scheduled-tasks/<task-name>/SKILL.md, with YAML frontmatter for name and description and the prompt as the body, so you can version-control it like anything else. Schedule, folder, model and enabled state are not in that file.

    The Routines Runbook is 32 ready-made routines built this way from the start, plus hardened replacements for all eight of Anthropic’s free templates and the fourteen guardrail patterns behind them. See what is in it, or take the free 5-routine starter.


    Verified against Anthropic’s Desktop scheduled tasks and Routines documentation on 5 October 2026. Not affiliated with Anthropic.

  • Claude Code routines: every limit, cap and gotcha

    Claude Code routines are a research preview, and the limits that govern them are spread across several documentation pages. This is all of them in one place, with the practical consequence of each spelled out.

    Everything below was checked against Anthropic’s documentation on 5 October 2026. Behaviour changes; the date is here so you can judge how stale this is.

    Run limits are hourly, not daily

    This is the one most people get wrong, because “daily quota” is the intuitive mental model and it is simply not how this works. Each way of starting a run has its own hourly cap, and they count separately.

    Action Limit Counted against Over the limit
    Scheduled runs, including one-off runs 100/hour Your account The run waits until the limit resets
    Run now, API fires, and re-running a one-off 30/hour Each routine — one count shared by all three The action fails until reset
    Run now and re-running a one-off 100/hour Your account Fails until reset
    API fires 100/hour Your account, counted separately from Run now Fails until reset
    GitHub events Per-routine and per-account hourly caps — Events are dropped

    None of these has overage. Three things follow:

    • The 30/hour per-routine cap is shared. Testing a routine by hammering Run now eats the exact allowance your production API trigger needs. Test on a copy.
    • Scheduled runs wait; API fires fail. Over the limit, a scheduled run is simply deferred, but an API fire returns an error. Whatever calls your endpoint needs to handle a rejection — log it and alert, do not retry in a tight loop.
    • Dropped GitHub events are silent. There is no queue and no retry. Nothing tells you an event was discarded. If a routine must not miss events, pair the trigger with a low-frequency scheduled sweep that reconciles against the repository.

    Separately from all of this, routines draw down your subscription usage the same way interactive sessions do. The prompt input carries a model selector, and Claude uses the selected model on every run — picking a smaller model for a routine that formats and files, rather than one that reasons, is the cheapest saving available.

    Scheduling gotchas

    • Never schedule on the hour. A run set for 9:00 can start several minutes late. Anthropic’s own advice is to pick a few minutes past, e.g. 9:07. Stagger your routines across the hour while you are at it, so they don’t all contend at once.
    • The minimum interval is one hour. Custom cron expressions that run more frequently are rejected. For a custom interval, pick the closest preset in the form, then use /schedule update in the CLI to set the cron expression.
    • Times convert automatically. You enter a local time; it runs at that wall-clock time regardless of where the infrastructure sits.
    • One-off runs auto-disable. After firing, the routine turns itself off and the UI marks it Ran. To run it again, edit it and set a new time. One-off runs count against the same hourly limit as other scheduled runs.
    • A routine with no schedule has no next run time. An API-only or GitHub-only routine shows none, which means silence from a broken caller is indistinguishable from silence from a healthy system. Give every event-driven routine a low-frequency schedule as well — not to do the work twice, but so that the absence of events is something you can see.

    GitHub trigger gotchas

    • Every event is a separate session. Claude Code does not reuse sessions across events. A contributor who pushes five times to an open PR fires your routine five times. Filter at the trigger (exclude drafts; prefer pull_request.opened over all actions) and deduplicate in the prompt, keyed on the head commit SHA rather than the PR number.
    • matches regex tests the entire field value, not a substring. To match any title containing hotfix you must write .*hotfix.*. Without the surrounding .* it matches only a title that is exactly hotfix. When you want substring matching, use contains and avoid the trap entirely.
    • /web-setup does not install the GitHub App. It grants repository access for cloning. It does not enable webhook delivery. These are separate things and assuming otherwise is a common dead end — install the app from the Claude GitHub App page.
    • An expired GitHub connection skips runs for up to 72 hours. Reconnect inside that window and the routine resumes on its own. After 72 hours it switches off, and you have to turn it back on by hand after reconnecting.
    • Claude pushes to claude/-prefixed branches unless your prompt says otherwise. Branch protection rules are evaluated against the GitHub access you connected.

    The API trigger’s payload is untrusted by design

    The optional text field on a /fire call does not arrive as a bare instruction. It is wrapped in a <routine-fire-payload> block that labels it as untrusted data and tells Claude not to follow instructions inside it unless the routine’s own prompt says to. The same wrapping applies to text typed into Run now.

    Two consequences, and people hit both:

    1. If you want the routine to act on the payload, say so explicitly. A prompt that never mentions the payload treats it as inert context, and your carefully-passed alert body does nothing at all.
    2. Anyone holding the bearer token can send text. The wrapper exists so that a leaked token produces untrusted data in a labelled box rather than direct instructions to your routine. Your prompt’s extraction rules are the second half of that protection — write them narrowly, name the fields you will read, and refuse everything else.

    Also worth knowing: the payload is freeform and is not parsed. Send JSON and the routine receives the literal string, which is fine as long as your prompt says “parse the JSON in the payload block” rather than assuming structure. And the token is shown once when you generate it and cannot be retrieved later — put it straight into the calling system’s secret store.

    The /fire endpoint ships under the dated beta header experimental-cc-routine-2026-04-01. Breaking changes ship behind new dated headers, with the two most recent previous versions still working, so you get a migration window — but pin the header you tested against and treat a change to it as a code change.

    Connectors and network access

    • Every connected connector is included by default on a new routine, and Claude can use every tool from an included connector — including writes — without asking during a run. Trim the list before the first run.
    • Local CLI MCP servers don’t appear. Servers added with claude mcp add live on your machine, not your claude.ai account. Add them at claude.ai/customize/connectors, or declare one in a committed .mcp.json.
    • The Default environment uses Trusted network access, allowing only Anthropic’s default allowlist. A request to a host outside it fails with 403 and x-deny-reason: host_not_allowed. Connector traffic routes through Anthropic’s servers, so connectors work without allowlist changes.
    • Environment variables are visible to anyone using the environment. On Pro and Max, store keys as API credentials instead.

    Diagnosing a run that did nothing

    Two things worth having in your pocket.

    First, the one that matters most: a green status means the session started and exited without an infrastructure error. It does not mean your task succeeded. Blocked network requests, missing connector tools and task-level failures all surface inside the run transcript, not in the status indicator. Open the run.

    Second, from Claude Code v2.1.227 or later you can just ask: /schedule why did my nightly review do nothing this morning? Claude lists the recent runs with their status and reads the log to explain what happened — tool errors, permission denials, the final result.

    If /schedule itself is missing, the usual cause is authentication: it requires a claude.ai subscription login, and an ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN in your shell takes precedence over it. Remove those first. It is also unavailable inside a cloud session, and an Owner can disable routines organisation-wide.

    Related

    Why your Claude Code routine reported success and did nothing — the eight-point pass that catches silent failure before you schedule anything.

    How to harden the Briefing routine template — the same method applied end to end, with the complete prompt.

    Cloud routines vs local scheduled tasks — which of the three scheduling options to use, and what each one does to you if you pick wrong.

    The Routines Runbook is 32 ready-made routines built this way from the start, plus hardened replacements for all eight of Anthropic’s free templates and the fourteen guardrail patterns behind them. See what is in it, or take the free 5-routine starter.


    Verified against Anthropic’s Routines documentation on 5 October 2026. Routines are a research preview; limits and the API surface may change. Not affiliated with Anthropic.

  • How to harden the Briefing routine template

    Anthropic ships eight starter templates on the Templates tab at claude.ai/code/routines. They are free, they are a sensible place to begin, and most people begin there. They are also unhardened: they describe what to do, and say nothing about what to do when it doesn’t work.

    This is a complete worked example of fixing that — one template, start to finish, with the full prompt at the end for you to paste in.

    The template is Briefing: summarise your calendar, email and messages into a morning brief. It is the one most people turn on first, and the one whose failures are hardest to notice.

    First, how it fails when nobody is watching

    Four specific failures, none of which produces an error in the run list.

    A dead connector reads as a free day

    If the calendar connector fails, the brief renders an empty schedule. Nothing in the output distinguishes “you have no meetings” from “I could not read your meetings”. You act on the first and discover the second on Thursday.

    It reports the wrong day

    A local Desktop task that misses its slot runs one catch-up when the machine next wakes. A 7am brief can be produced at 11pm and still be written in the present tense about “today”. Cloud routines have a milder version of the same thing: runs scheduled exactly on the hour can start several minutes late, which is why Anthropic suggests 9:07 over 9:00.

    It compresses away the thing you needed

    Three overlapping meetings become “a busy morning”. The conflict — the single most actionable fact in the whole brief — has been summarised out of existence.

    It leaves no trace

    Next week you cannot tell whether Tuesday’s brief ran and found nothing, or never ran at all. Both look identical from where you sit, which is to say: they look like nothing.

    The eight checks applied

    Each fix below maps to one of the checks in the eight-point pass.

    Check What it changes in this prompt
    Self-contained Names the slot time, the sources, the caps and the output file. No conversational context assumed.
    Sources named A SOURCES section with a status line and an item count per source.
    Verified Step 4 re-opens the report and checks counts, times and traceability — and can set the run to PARTIAL.
    Idempotent A run-id derived from the slot; a repeat run replaces its own log line instead of adding a second.
    Honest when blind Two outcomes per source — read or unavailable. Never one.
    Least privilege A hard rule banning every write action, plus trimming the connector list before the first run.
    Fails loudly An explicit OK / PARTIAL status and one log line per run.
    Time-aware Step 1 reads the clock and changes the output — not just a note about it.

    The hardened prompt

    Paste this over the template’s instructions. Adjust the slot time and the source list to match yours; leave the structure alone.

    You are running unattended as the "Morning Brief" routine. You have no conversation
    context. Everything you need is named in this prompt.
    
    STEP 1 — CLOCK
    Read the current local date and time before anything else. Compare it with the
    intended slot of 07:05 local.
    - Within 3 hours of the slot: proceed normally.
    - More than 3 hours late: put "LATE RUN — produced at <time> for the <date> slot"
      as the first line of the report, and cover the period the slot intended, not the
      last 24 hours from now.
    - After 18:00 local: produce the SCHEDULE and OPEN LOOPS sections only. Skip
      "Today's focus" entirely — a focus list written at 11pm is noise.
    
    STEP 2 — READ, ONE SOURCE AT A TIME
    For each source — calendar, email, messages — record one of exactly two outcomes:
      read: <count> items for <explicit window>
      unavailable: <the exact error or refusal text>
    Never infer absence from a failure. If a source is unavailable, the section it feeds
    says "unavailable: <reason>" and keeps any previous value with its ORIGINAL date
    stamp. An empty section and an unreadable section must never look the same.
    Cap each source at 50 items. If you hit the cap, say so and name what you did not read.
    
    STEP 3 — WRITE
    Report sections: SOURCES (the status lines from step 2), SCHEDULE, NEEDS A REPLY,
    OPEN LOOPS, TODAY'S FOCUS (max 3, each traceable to an item above).
    List every calendar item individually with its real start time. Do not summarise a
    schedule into an adjective. Flag overlapping items explicitly as CONFLICT.
    
    STEP 4 — VERIFY BEFORE YOU REPORT
    Re-open the report you wrote. Confirm: the item counts in SOURCES match the number
    of items actually listed below; every meeting time appears as read, not rounded;
    every focus item traces to a listed item. List these three checks and their results
    in a VERIFICATION section. If any check fails, the status is PARTIAL, not OK.
    
    STEP 5 — LOG
    Append one line to logs/RUNLOG.md:
    <ISO time> | brief | <run-id> | OK|PARTIAL | <one-line summary> | <owner action or none>
    Compute run-id as <YYYYMMDD-HHMM>-brief. If a line with this run-id already exists,
    replace it rather than adding a second.
    
    HARD RULES
    Never send, reply to, archive, delete or post anything. This routine reads and
    writes one report file. Nothing else.

    One more thing before you turn it on

    The prompt is only half of it. Open the routine’s Connectors section and remove everything the brief does not need.

    Every connector attached to your account is included in a new routine by default, and during a run Claude can use any tool from an included connector — writes included — without asking. A read-only brief has no business holding a connector that can send mail. The HARD RULES block above is a second line of defence, not the first one.

    What changed, in one paragraph

    A clock check that alters the output rather than annotating it. Per-source status lines, so blindness becomes visible instead of invisible. Individual meeting times instead of an adjective. A verification section that is capable of failing. And a run log keyed to a run-id, so a double fire does not double-write and a fortnight of silence is something you can look up.

    That is the whole method. The other seven templates — Email triage, System health check, Issue triage, PR review digest, Dependency update check, Release notes drafter, Flaky test tracker — each fail in their own specific way and each get the same eight-point treatment in The Routines Runbook, along with 32 ready-made routines built this way from the start.

    Want the other seven hardened the same way? The Routines Runbook covers all eight templates plus 32 ready-made routines and the fourteen guardrail patterns behind them — or take the free 5-routine starter first.


    This page describes the failure modes of the task, not the wording of Anthropic’s templates, and does not reproduce their prompt text. Platform behaviour was checked against the Routines and Desktop scheduled tasks documentation on 5 October 2026. Not affiliated with Anthropic.

  • Why your Claude Code routine reported success and did nothing

    There is one sentence in Anthropic’s routines documentation that explains more confusion than anything else on the page: a green status in the run list means the session started and exited without an infrastructure error — it does not mean the task in your prompt succeeded.

    That is the whole problem with unattended automation in one line. A routine runs with nobody watching. The run list is the only thing most people ever look at. And the run list is reporting on the wrong thing: it tells you the machine worked, not that the job got done.

    This article covers the three ways a routine fails while reporting success, and the eight-point pass that catches all three before you schedule anything.

    Three failures that look exactly like success

    1. The source that could not be read

    Your mail connector times out. The routine writes “no urgent messages”. You read that over coffee as good news.

    It is not good news. It is no news — and the two are indistinguishable in the output. This is the most expensive failure mode in unattended work, because nothing about it looks wrong. A calendar connector that fails renders an empty schedule, and an empty schedule reads as a free day. You find out on Thursday, in the meeting you missed on Tuesday.

    2. The check that never ran

    A health-check routine that cannot reach your endpoint, and says nothing about it, reads exactly like a healthy system. Silence is ambiguous, and ambiguity always defaults to “fine” in the reader’s head.

    Worth knowing the specific signature here: on the default cloud environment, network access is Trusted, which allows only Anthropic’s default allowlist. A request to a host outside that list fails with a 403 and the header x-deny-reason: host_not_allowed. That is a real, named, catchable error — but only if your prompt is written to catch it rather than to carry on.

    3. The run that fired at the wrong time

    Schedule a routine exactly on the hour and it can start several minutes late; Anthropic’s own recommendation is to pick 9:07 rather than 9:00. Local Desktop tasks are worse. A 7am brief missed because the laptop was shut can run as a catch-up when the machine wakes at 11pm — and still write “today” in the present tense, about a day that is nearly over.

    None of these three produce an error. All three produce green.

    The eight-point pass

    Run any routine prompt — a template you accepted, or one you wrote yourself — through these eight checks before you schedule it. Each one closes a specific hole.

    # Check The question it answers
    1 Self-contained If a stranger ran this with no context, would it work?
    2 Sources named Can every number in the output be traced to something read this run?
    3 Verified Did the routine re-check its own work before reporting?
    4 Idempotent If this runs twice, do I get one result or two?
    5 Honest when blind Does an unreadable source look different from an empty one?
    6 Least privilege Which connectors are attached, and which of them can write?
    7 Fails loudly When it breaks, do I find out — and does it tell me what to do?
    8 Time-aware If this fires nine hours late, is the output still true?

    Check 1 — Self-contained

    A routine session has no memory of your conversations. It cannot ask a follow-up question. Anything the prompt assumes you will supply is simply missing. Write it as instructions to a competent stranger who has never met you: name the files, name the windows, name the thresholds.

    Check 2 — Sources named

    Every figure in the output should be traceable to something the routine actually read during this run. The failure this prevents is subtle: a plausible number that came from nowhere. Require the prompt to list its sources and counts, and a fabricated figure has nowhere to hide.

    Check 3 — Verified

    Add a step where the routine re-opens its own output and checks it against what it read. Counts match the items listed. Times appear as read, not rounded. Conclusions trace to evidence. Make that step able to fail the run — a verification section that always passes is decoration.

    Check 4 — Idempotent

    Routines fire more than once. A GitHub trigger fires on every push to an open pull request, and Claude Code does not reuse sessions across events — five pushes means five independent runs. Key your state on something stable (the head commit SHA, not the PR number) so a repeat run writes nothing instead of writing a duplicate.

    Check 5 — Honest when blind

    This is the one almost every prompt fails, and the one that costs the most. The rule is short:

    A source that could not be read must never render as a source with nothing in it.

    The fix is a few lines, and it is the single highest-value edit you can make to any routine prompt:

    For each source, record exactly one of two outcomes:
      read: <count> items for <explicit window>
      unavailable: <the exact error or refusal text>
    
    Never infer absence from a failure. If a source is unavailable, the
    section it feeds says "unavailable: <reason>". An empty section and
    an unreadable section must never look the same.

    Two outcomes, never one. That is the entire trick, and it converts the most dangerous failure in unattended automation into an obvious one.

    Check 6 — Least privilege

    The platform defaults against you here, and it is worth being blunt about it. When you create a routine, every connector currently attached to your account is included by default. And during a run, Claude can use every tool from an included connector — including writes — without stopping to ask for permission.

    So a template you accept without editing arrives holding your entire connector list, write scopes and all, and will use any of it unprompted if the task seems to call for it. Strip that list down to what the routine actually needs before the first run, not after the first incident.

    Check 7 — Fails loudly

    Because green tells you nothing, the routine has to tell you itself. Give every run an explicit status — OK or PARTIAL — and make PARTIAL the result whenever a source was unavailable or a verification check failed. Append one line per run to a log file. Then a routine that has quietly been failing for a fortnight is a thing you can see, instead of a silence you have to notice.

    Check 8 — Time-aware

    Have the prompt read the clock first and compare it to the slot it was meant to run in. If it is hours late, say so in the first line of the output and report on the window the slot intended — not the last 24 hours from now. A brief written at 11pm should not contain a “today’s focus” list at all.

    What this looks like finished

    Applied together, these eight turn a prompt that describes a task into a prompt that describes a task and what to do when it doesn’t work — which is the only difference that matters once nobody is watching.

    The companion piece to this article walks the whole pass through one real template end to end, with the complete hardened prompt you can paste in: How to harden the Briefing routine template.

    Also useful: Claude Code routines — every limit, cap and gotcha, which covers the hourly caps, the dropped GitHub events, and the 72-hour GitHub expiry that switches a routine off entirely.

    Cloud routines vs local scheduled tasks — which of the three scheduling options to use, and what each one does to you if you pick wrong.

    The Routines Runbook is 32 ready-made routines built this way from the start, plus hardened replacements for all eight of Anthropic’s free templates and the fourteen guardrail patterns behind them. See what is in it, or take the free 5-routine starter.


    Platform behaviour described here was checked against Anthropic’s Routines and Desktop scheduled tasks documentation on 5 October 2026. Routines are a research preview and the details move; this page carries the date it was verified so you can tell how stale it is. Not affiliated with Anthropic.