The Loop  ·  Issue 016

The Loop

A field journal of the AI frontier — for engineers who ship.

§ Guides

By AI Blog Editor
Apr 20, 2026 · 1 min read

Putting Claude on a schedule: routines, loops, and background work

Four shapes for recurring or long-running Claude work — cron schedules, session loops, background tasks, and event hooks. What each one is for, and how not to set money on fire.

Most useful work with Claude isn't a single prompt. It's a pattern that repeats — a daily digest, a poll of a slow deploy, an overnight audit, a long build you kick off and go make coffee. When you want Claude to keep doing something without you holding its hand, you reach for a routine.

Claude gives you four distinct shapes for this, and they're easy to blur together. They fire on different triggers, they carry different amounts of context, and they cost money in very different ways. This piece lays each one out and shows when to reach for which.

00:0003:0006:0009:0012:0015:0018:0021:0024:00SCHEDULEcron-triggeredstandup digestEOD summaryLOOPinterval / dynamicpolling a deploy every ~45m until it reports greenBACKGROUNDone-off, fires and waitslong bun build · notifies on completionHOOKevent-triggered · covered in the primer
Fig. 1 — one day, four patterns. Rust dots are agent invocations; black bars are durations; grey ticks are reactive events.

Schedule — cron for agents

Scheduled triggers are the most literal reading of "routine". You give Claude a cron expression and a prompt; at each fire the harness spawns a fresh isolated agent, runs the prompt, and exits. No session, no lingering state. Think of it as a cron job whose worker is an LLM.

The killer use cases are the ones a human shouldn't have to show up for: a 9am standup digest, a Friday release-notes draft, an overnight dependency audit, a monthly billing reconciliation. Anything where the when is predictable and the what doesn't depend on yesterday's session.

If your routine needs to know what happened last time it ran, write that state somewhere — a file, a ticket, a comment — before the scheduler clocks off. The next fire starts with a blank slate.

Cron expressions have five fields — minute, hour, day-of-month, month, day-of-week — and a handful of modifiers (*, */N, ranges, lists). Click around below: the preset buttons set the input, the decoder explains the expression, and the box at the bottom shows the next three times it would fire.

  Preset routines

You can also type your own

In plain English

At 09:00 on weekdays

Next three fires

  1. 01Tue, Apr 21, 09:00 AM
  2. 02Wed, Apr 22, 09:00 AM
  3. 03Thu, Apr 23, 09:00 AM
Interactive · click a preset or type your own cron expression

Loop — repeat until done

Loops live inside the current session. You either give a fixed cadence (/loop 2m …) or let Claude self-pace with dynamic mode (/loop … with no interval). Each tick wakes up in the same conversation, so whatever context the previous tick built up is still there.

Loops shine when the work has a stopping condition that only becomes true at some future moment: a deploy that eventually goes green, a PR that eventually gets reviewed, a refactor that eventually compiles clean. You want the session to keep trying, notice the change, and respond.

The tradeoff is cost. Each tick is a full turn; without a budget, loops can bleed quietly. Three defenses: a hard max step count, a wall clock deadline, and a clear success signal so the loop exits when it should.

Background — fire and get notified

Background tasks aren't recurring at all. You kick a one-off piece of work off to the side — a long build, a training run, a sequence of tests — and Claude is notified when it finishes. The main session continues working on whatever else you care about meanwhile.

In practice this is the run_in_background: true flag on Bash or the Agent tool. It pairs naturally with the Monitor tool, which streams specific lines from the background process back as notifications — essential when a 20-minute build might crash in the first 30 seconds and you want to know right away.

Hook — event-triggered routines

The fourth shape is the hook, and it deserves a nod here even though the primer already covers it in depth. Hooks are event-driven — they fire on lifecycle events like PostToolUse or Stop, not on a clock. When your "routine" is really "do X whenever Y happens", a hook is the right shape.

They're also the only one of the four that doesn't cost model tokens: a hook is a shell command, not an LLM turn. If a thing must run after every edit (format, lint, typecheck), that's a hook.

So which do I use?

Pick the sentence that matches your need; the right tool and a concrete example appear on the right.

Interactive · § choose your cadence

When does it fire?

Pick a cadence
PatternWhen it firesContextCost shapeBest for
ScheduleCron expression (time-of-day, day-of-week, …)Fresh agent per fire — no memory of last runPer-fire. Costs scale with cadence × turn lengthRecurring reports, audits, overnight jobs
LoopFixed interval, or dynamic (Claude self-paces)Stays in the current session across ticksCompounds within a session — set a budgetPolling, iterative work, watch-until-green
BackgroundOnce, when you kick it offSame session — notification on completionOne execution, paid when it returnsLong builds, training runs, anything > a few min
HookLifecycle event (pre/post tool, submit, stop…)Runs in the shell — no model tokens at allDeterministic shell cost, no LLM spendGuardrails, linting, must-run-every-time checks
Fig. 3 — four patterns, at a glance. Pick the one whose shape matches your need.

Pitfalls, in a line each

Runaway loops. No exit condition is a cost leak. Add a budget — step count, wall clock, or a clear success signal.

Silent scheduled failures. A cron agent that errors at 2am will cheerfully not-work until you notice. Have it post to a channel on both success and failure, and you'll know within a day.

Stale context across fires. Scheduled agents start fresh every run. Don't reference "yesterday's thread"; reference committed artefacts instead.

Loops that should've been hooks. If the trigger is "something just happened", you want a hook, not a loop checking every 30 seconds whether anything happened.

Background when you needed foreground. If you're going to immediately wait for the output anyway, you're paying cache misses for nothing. Run it inline.

A one-line mental model

Schedule fires on a clock. Loop fires in a session until you stop it. Background fires once and calls you back. Hook fires when something happens. Get the trigger right and the rest follows.

* * *

Thanks for reading. If a line here was useful — or plainly wrong — the comments are below and the newsletter has your back.

Elsewhere in this issue

3 more
  1. 01

    Guides

    Writing a CLAUDE.md that actually helps

    Apr 20, 2026

  2. 02

    Guides

    A field guide to Claude Code: CLAUDE.md, hooks, skills, plugins

    Apr 20, 2026

  3. 03

    Guides

    Building agents that actually work

    Apr 20, 2026

Letters

Arguments, corrections, questions. Anonymous comments allowed; be kind, be specific.