AI Stack Library · Schedules and pipelines
How to schedule AI agents: jobs on a timer, chained into pipelines
To schedule AI agents, run each job as a small script that calls the agent, started by a scheduler that keeps going whatever the agent does, such as launchd on a Mac, a systemd timer on Linux or a self-hosted workflow tool. Make every job safe to run twice, stop for a person before anything is spent, sent or published, and have each job tell you when it fails or quietly stops running.
| If you are | Start with |
|---|---|
| An owner who wants a summary every morning | A dedicated always-on machine, then one scheduled job that writes a briefing file before you wake and sends you a notice |
| A service business with a list to follow up every evening | A dedicated always-on machine, then a job that drafts the follow-ups and waits for your approval before any is sent |
| A developer | A dedicated always-on machine, then the operating system's scheduler, with a log, a lock and an alert when a run is missed |
| A creator with a weekly publishing rhythm | A dedicated always-on machine, then a pipeline from script to finished file whose last step is your approval |
A timer, a trigger, a pipeline
Three shapes cover most recurring work. A timer starts a job at a set time: the backup at one in the morning, the report at six. A trigger starts a job when something happens: a form arrives, a payment clears. A pipeline chains jobs, so each one's output becomes the next one's input.
A pipeline whose work reaches a customer should end the same way every time: with a person.
Four steps in a chain. Fetch the new form entries since the last run. Draft a reply for each from the price sheet. Check the prices, names and dates against their sources. Wait for approval: nothing is sent until a person says yes.
- Fetchnew form entries since the last run
- Drafta reply for each, from the price sheet
- Checkprices, names and dates against their sources
- Wait for approvalnothing is sent until a person says yes
Where the schedule lives
Put the schedule somewhere that outlives the agent. Many agents now come with a scheduler of their own, and it is convenient. It also lives inside the agent. If the agent stops, every job on that scheduler stops with it, at the same moment.
Read the small print, too. Claude Code's desktop app, for example, runs local scheduled tasks only while the app is open and the computer is awake; its cloud tasks run even when the computer is off, on Anthropic's servers. Tasks started with its /loop command belong to one session and expire seven days after they are created.
The operating system's scheduler keeps running whatever the agent is doing. On a Mac that is launchd. Apple's archived guide to timed jobs, last updated in 2016, says a launchd calendar job missed while the computer was asleep runs when it wakes, while a cron job missed while asleep or off does not run at all, and calls cron deprecated in favour of launchd. Neither runs a job missed while the machine was switched off; launchd waits for the next scheduled time.
On Linux, a systemd timer set with Persistent=true remembers when it last fired and runs straight away if it missed a run while the timer was inactive. The setting works only on calendar timers, and it is off by default.
A five-row table. The operating system's scheduler, such as launchd or a systemd timer, keeps running when the agent stops and can catch up a missed run. Classic cron keeps running but skips runs missed while asleep or off. A self-hosted workflow tool keeps running while the tool runs; n8n's schedule discards missed runs by default. The agent's own scheduler stops when the agent stops. A hosted runner runs in someone else's cloud and can be delayed.
| Where the schedule lives | Example | If the agent stops | A run missed while asleep or off |
|---|---|---|---|
| The operating system | launchd on a Mac, a systemd timer on Linux | Jobs keep running | launchd runs it on wake from sleep; a systemd timer catches up if set to Persistent |
| Classic cron | cron on Mac or Linux | Jobs keep running | Skipped |
| A self-hosted workflow tool | n8n on the same machine | Jobs keep running while the tool runs | n8n's Schedule Trigger discards missed runs by default |
| The agent's own scheduler | Built into some agents and harnesses | Every job stops with it | Depends on the agent; read its docs |
| A hosted runner | GitHub Actions on a schedule | Runs in someone else's cloud | Not affected, but runs can be delayed when the service is busy |
Read from each project's own documentation on 2026-10-23.
Keep the owned machine first. A hosted runner suits a short trial or a burst of work, but it runs away from the files on your machine. GitHub's docs say scheduled runs can be delayed during busy periods, the shortest interval is once every five minutes, and in a public repository scheduled workflows are switched off after 60 days with no activity.
A job is a script, not a chat left open
A scheduled job should be a small script that calls the agent with named inputs and writes its result to a file. Not a chat window left open overnight, waiting for someone to type.
Give every run an exit code that means something: finished, nothing to do, or failed. The scheduler and your alerts read that code, not the agent's cheerful summary of how well it went.
Never put a password or key in a job file. Refer to it by name and let the script fetch it from wherever you keep secrets.
Safe to run twice
Every scheduled job runs twice eventually. The machine wakes and catches up a missed run; you start it by hand while it is already running; a retry fires after a timeout.
So each job checks before it writes. A marker that says today's run is done. A lock, so two copies never run at once. A look at the destination before anything is added to it. The second run should change nothing the first one already did, and above all it should never send the same email twice.
Stop before anything leaves the building
A job that drafts can run at three in the morning. A job that spends, sends or publishes waits for a person. Put the approval point inside the pipeline, as a step of its own, so a change to the schedule can never skip it.
Workflow tools have this built in. n8n's Wait node pauses a workflow until a web request or a form submission resumes it, and its human-in-the-loop setup pauses the workflow and waits for a person, for example through an approval message in Slack.
Three questions asked in order. If the step spends money, it waits for approval. If it sends or publishes anything outside the business, it waits for approval. If it deletes something that cannot be rebuilt, it waits for approval. Otherwise it runs, and you read the log in the morning.
- Does it spend money?Yes Wait for approval
- Does it send or publish anything outside the business?Yes Wait for approval
- Does it delete something that cannot be rebuilt?Yes Wait for approval
- None of the aboveLet it run, and read the log in the morning
A schedule multiplies everything
A step that costs a little runs thirty times a month. A job that writes a large file fills a disk while you sleep.
Give each step the cheapest model that passes its test. Put a spending cap on the job that refuses further calls, not one that only warns. And have any job that writes large files check the free space first and skip its run when the disk is low. A skipped run is healthy. A full disk is not.
Know it ran
The job that fails loudly is not the dangerous one. The one that quietly stops running is, because nothing ever tells you.
So every job should leave four signs. Services such as Healthchecks.io watch for the last one: it stays silent while a job's pings arrive on time and raises an alert as soon as one does not. Healthchecks is open source under the BSD 3-clause licence, so you can also run it yourself.
A four-item checklist: a log line for every run with the time and the result, a heartbeat sent when the job finishes, an alert when it fails, and an alert when the heartbeat goes quiet.
- A log line for every run, with the time and the result
- A heartbeat: a ping sent, or a file touched, when it finishes
- An alert when it fails
- An alert when the heartbeat goes quiet
Hand each step a package
In a pipeline, the trouble usually starts between the steps. Have each step hand the next one a defined package, such as a file with known fields, plus a rule for when to stop. The next step never has to guess what it was given, and a bad batch stops at the first check instead of reaching a customer.
Start with one job
Pick one recurring task, time how long it takes you by hand today, and schedule only that. A nightly backup or a morning briefing makes a good first job: useful from day one, and easy to check.
Add the second job when the first has run for a week without you thinking about it.
What goes wrong
- Every job on the agent's own scheduler, so one stopped agent stops them all.
- A job that sends at three in the morning with nobody reading first.
- A job that runs twice after a wake-up and sends every follow-up twice.
- Success read from the agent's summary instead of the exit code.
- A job that stopped running weeks ago, with no alert for silence.
- A key pasted into a job file, where every backup and log can copy it.
Questions
Can you run an AI agent as a cron job?
Yes. A cron job runs a command at set times, and that command can be a script that calls the agent. On a Mac, Apple's own guide recommends launchd instead of cron, because launchd runs a job missed while the computer slept once it wakes.
What happens to a scheduled job when the computer is asleep or off?
It depends on the scheduler. On a Mac, launchd runs a missed calendar job when the computer wakes, but not one missed while it was switched off; cron skips both. On Linux, a systemd timer with Persistent=true catches up a missed run. An agent's own scheduler may need the app open.
Should a scheduled AI agent send emails on its own?
Not at first. Let the schedule draft and check, and have a person approve each send until the job has proved itself on your own work. Keep spending and publishing behind an approval for good.
Sources
- Apple Developer: Scheduling Timed Jobs (archived, updated 2016), checked 2026-10-23
- systemd.timer manual, checked 2026-10-23
- crontab(5) manual (man7.org), checked 2026-10-23
- GitHub Docs: Events that trigger workflows, checked 2026-10-23
- n8n docs: Schedule Trigger, checked 2026-10-23
- n8n docs: Wait, checked 2026-10-23
- n8n docs: Human-in-the-loop for tools, checked 2026-10-23
- n8n docs: Slack approvals, checked 2026-10-23
- Claude Code docs: Desktop scheduled tasks, checked 2026-10-23
- Claude Code docs: Cloud scheduled tasks, checked 2026-10-23
- Claude Code docs: Run prompts on a schedule, checked 2026-10-23
- Healthchecks.io docs, checked 2026-10-23
- Healthchecks on GitHub, checked 2026-10-23