← the writing notes 9 min

Claude Code Routines vs GitHub Actions: Where to Schedule Agents

Claude Code Routines (launched April 2026) run scheduled AI agents on Anthropic's cloud with zero server setup. GitHub Actions cost less and give you more control. Here's how to pick the right host for each job, wire up the blog queue worker, and handle retries without guessing.

Blueprint schematic of two parallel automation pipelines merging into a central scheduler node with gears and trigger arrows.

Claude Code Routines, which Anthropic launched in April 2026, are a saved Claude Code configuration: a prompt, one or more repositories, and connectors, packaged once and run automatically on Anthropic-managed cloud infrastructure. The official docs lay out three trigger types: scheduled cadence, API (HTTP POST with a bearer token), and GitHub events. GitHub Actions, by contrast, execute the scripts you write on GitHub-hosted runners. Both can run AI agents on a schedule. They are not the same thing, and picking the wrong one costs you either money or hours of YAML-wrangling. This post maps the decision, walks the blog queue worker, and covers failure recovery.

Choose Cloud Routines, Desktop, Session Loops, or Actions

Four hosting options exist. They are not interchangeable.

Cloud Routines execute on Anthropic's infrastructure regardless of whether your laptop is on. Per the docs, each routine can carry a scheduled trigger, an API trigger, or a GitHub event trigger, and you can combine all three on one routine. The trade-off: every execution does a fresh clone, so local files are never available.

Desktop scheduled tasks run on your machine. They have full access to your local filesystem, local databases, and .env files. If the machine is off, the task doesn't run. Simple.

Session-scoped scheduling (the CronCreate , CronList , CronDelete tools) operates inside an open CLI session only. These are session scheduling tools, not the cloud routines API. They disappear when the session ends.

GitHub Actions with a cron trigger is a workflow YAML file that GitHub executes on a hosted runner. Free for public repos, cheap for private ones, deterministic, and deeply integrated with your codebase. The overhead is real if you don't already live in GitHub, but for developers who do, it's minimal.

So: how do you choose?

  1. Task runs whether or not your machine is on, and it needs genuine AI reasoning (summarising, drafting, triaging)? Cloud Routine.
  2. Task needs your local .env, a local database, or local tooling? Desktop scheduled task.
  3. Task is a CI/CD pipeline, PR event handler, or a deterministic script that calls an API and posts to Slack? GitHub Actions, possibly with a short Python script and no LLM at all.
  4. Task is exploratory and lives inside a single session you're already running? Session loop.

AI Magicx's breakdown puts it cleanly: if your routine is "call an API, transform, post to Slack," GitHub Actions with a 10-line Python script is cheaper and simpler. Routines become the right choice when the work genuinely benefits from Claude's reasoning: picking what to report, writing a narrative, reviewing quality.

Persistence, Local Files, and Credentials by Host

This is where operators get burned. The table below uses information from the official docs and community research, not claimed test results.

HostLocal files.envCredentialsSurvives closed laptop
Cloud RoutineNo (fresh clone)NoRoutine environment variablesYes
Desktop scheduled taskYesYesLocal configNo
Session loop (CronCreate)Yes (session scope)YesSession scopeNo
GitHub ActionsRepo files onlyNoGitHub SecretsYes

Shareuhack's 2026 write-up flags a specific gotcha worth quoting:

"Every Cloud Routine execution performs a fresh clone in Anthropic's cloud environment, it cannot access your local .env.local, local databases, or other local state."

And one more: network access in cloud routines defaults to "trusted," which some APIs reject outright. If you're hitting ClickUp or another API that drops trusted-mode requests, switch to "full" network access in the routine's environment settings. There is a small security trade-off, so weigh it against your repo's sensitivity.

For GitHub Actions, secrets live in the repository's Secrets settings and are injected as environment variables at runtime. The anthropics/claude-code-action@v1 action, which is built on the Claude Agent SDK, picks those up automatically. You pass --model , --max-turns , and --allowedTools via the claude_args input to control what the agent can actually do.

Read the Current Blog Queue Worker

The blog queue worker is a routine (or equivalent scheduled job) that picks a post from a queue, generates content, and marks it as done. Here's the structure as it stands, with clear caveats about what the code actually does versus what you might assume.

Blueprint diagram of a job queue cylinder with conditional gate, retry loop pipe, and completion valve.

The conditional claim: the worker checks whether a post is already claimed before picking it up. That prevents two executions from grabbing the same item simultaneously, at least in the happy path. What the current code does not have is stale-claim recovery. If a worker dies mid-run with a post marked "in progress," that post stays claimed until someone manually resets it. Do not describe this as exactly-once delivery or guarantee one post per day; both claims go further than the code supports.

The worker diagram looks roughly like this:

  1. Fetch queue, filter for status = queued
  2. Claim the first available post (set status = in_progress, write a timestamp)
  3. Run the generation prompt against the claimed post's metadata
  4. On success: set status = published, write the output path
  5. On failure: increment retry_count , reset status = queued (if retries remain) or set status = failed

Step 5 is where most teams underinvest. The retry logic needs to live in the routine prompt or the wrapper script, because the cloud infrastructure itself does not re-run a routine that exits with an error.

If you're building content pipelines like this and want the agentic layer handled for you, the work we do at agentic engineering covers exactly this pattern.

Schedule Due Jobs and Handle Retries

Scheduling a routine via the CLI requires Claude Code v2.1.225 or later. Before v2.1.211, the CLI reported a phantom next-run time (year 1) for routines with no schedule trigger. Worth knowing if you're reading old logs.

A routine with only API or GitHub event triggers has no next run time. The CLI shows nothing. That's correct behaviour, not a bug.

For retry handling, you have two options:

  • Retry inside the prompt. Write the prompt to re-attempt the failing step up to N times before marking the job failed. Claude's reasoning can distinguish between a transient network error and a genuine content problem.
  • Retry via a separate scheduled routine. A lightweight "requeue" routine runs hourly, scans for posts where status = queued and retry_count < 3, and re-triggers the main worker via its API trigger (a POST to the per-routine endpoint with a bearer token).

The second pattern is cleaner at scale. It decouples the retry policy from the generation prompt, and you can adjust retry limits without touching the main routine.

Daily run caps and shared subscription usage are a real constraint for teams, as Arcade's enterprise write-up points out. Their recommendation: batch work into a single daily "meta-orchestrator" routine and reserve real-time triggers for high-priority events only.

For the SEO keyword retrieval side of a content pipeline, the automation stack we documented at DataForSEO + Claude Code handles that separately and is worth reading before you design the queue schema.

Detect Stuck Claims and Verify Published Output

Stale claims are the silent killer of queue-based pipelines. A post that's been in_progress for six hours is almost certainly stuck, not running.

A detection routine can be as simple as:

  • Query for posts where status = in_progress and claimed_at < now() - 2 hours
  • Reset those to status = queued, zero out the worker identifier, log the reset
  • Alert via Slack or a webhook if the reset count exceeds a threshold

Run this as a separate low-frequency routine (every two hours is fine) rather than baking it into the main worker. Separation of concerns matters here: the main worker should not be responsible for cleaning up after itself.

Verifying published output is a different problem. "Published" as a status flag means the database was written. It does not mean the post appeared correctly on the site, passed a readability check, or got indexed. A verification step should:

  • Fetch the live URL and confirm it returns a 200
  • Check word count or a lightweight quality signal against a defined threshold (pick your own number and label it as a team heuristic, not a universal standard)
  • If the check fails, revert status to queued with an incremented retry_count and a verification_failed flag

The humaniser pipeline we described at AI Content Humanizer Pipeline runs a similar post-publish verification pass and is worth cross-referencing if you're building that layer.

Operating Cost and Ownership

This is where the "routines are simpler" narrative runs into friction.

Cloud Routines run on Anthropic's infrastructure and consume Claude Code session limits the same way an interactive session does. The research preview makes this explicit: routines drain your limits. For a small indie operator running three or four routines a day, that's probably fine. For a team batching 20+ daily runs, you'll hit the cap and need to architect around it.

GitHub Actions is free for public repos and priced per minute for private ones. A Claude Code agent run inside Actions via anthropics/claude-code-action@v1 still consumes API tokens (billed at your Anthropic API rate), but you control the runner, the timeout, and the retry logic entirely. That ownership is the point.

The ownership split in practice:

  • Routines own: judgment-heavy tasks that need Claude's reasoning, tasks that must run unattended with no infrastructure overhead, GitHub-triggered PR reviews, and Sentry/log triage.
  • GitHub Actions own: CI/CD pipelines, PR event handling and installation flows, deterministic build-test-deploy sequences, and any task where a 10-line Python script genuinely does the job.

Neither replaces the other. The Shareuhack write-up frames it well: "The optimal combination lets GitHub Actions handle CI/CD while Routines handle the reasoning-intensive parts." That framing is correct, and it's the decision boundary worth bookmarking.

FAQ

Can a Cloud Routine write back to my repository?

Yes. Routines connect to one or more repositories, and they can push commits and open pull requests through the connected repo. What they cannot do is access files that only exist on your local machine. Anything the routine needs must be in the repo or configured as an environment variable in the routine's cloud environment settings.

What happens if a Cloud Routine hits a rate limit mid-run?

The routine itself does not automatically retry on rate limit errors. If it exits with an error, it stays failed until the next scheduled run or until you manually trigger it via the API endpoint. Building retry logic into the prompt (detect a rate limit response, wait, re-attempt) or using a separate requeue routine are both reasonable mitigations.

Is the GitHub App installation separate from the CLI web-setup command?

Yes, and this catches people out. Running /web-setup in the CLI grants clone access to the routine but does not install the GitHub App. Webhook delivery for GitHub event triggers requires the separate GitHub App installation. The routine setup flow prompts you through this, but the two steps are distinct.

Do GitHub event triggers in Routines have rate limits during the research preview?

Per the official routines documentation, GitHub webhook events are subject to per-routine and per-account hourly caps during the research preview. Events beyond the cap are dropped until the window resets. Plan accordingly if you expect bursts of PR activity.

Can I use skills inside a GitHub Actions workflow with `anthropics/claude-code-action`?

Yes. The prompt input accepts skill invocations like /skill-name . You need an actions/checkout step before the action so the skill files in .claude/skills/ are present on the runner. Skills and commands are distinct concepts in Claude Code; check the official skills docs before conflating the two.

The single sharpest caveat from everything above: Cloud Routines drain your Claude Code session limits exactly as interactive sessions do, and the current queue worker has no stale-claim recovery built in. Design for both before you ship anything to production.

Need this done, not just read?

start a project book 30 minutes