docs blog library
github

Scheduled runs

Run a saved job every morning, on weekdays, or at another recurring time. Jazz installs the schedule through launchd on macOS or cron on Linux.

Schedule your first job

From a repository you want to summarize, create an agent named daily-helper with jazz agent create. Choose a tool-capable model and the coder persona.

Create workflows/daily-standup-prep/WORKFLOW.md in that repository:

---
name: daily-standup-prep
description: "Summarize yesterday's repository activity"
agent: daily-helper
schedule: "0 9 * * 1-5"
autoApprove: read-only
maxIterations: 20
maxDurationMs: 300000
---

Inspect git commits from the last day and the current working tree. Summarize
completed work, uncommitted changes, and anything needing my attention.
Do not modify files.

Test it from the same repository, then install the schedule:

jazz workflow run daily-standup-prep --auto-approve
jazz workflow schedule daily-standup-prep
jazz workflow scheduled
jazz workflow history daily-standup-prep

The test should produce a summary grounded in your commits and working tree. The schedule runs at 09:00 on weekdays in the machine’s timezone. The agent and its provider credentials must remain available on that machine.

To send the result to your phone or chat, configure a notification target and add deliver: <target-name> to the frontmatter. To stop the schedule:

jazz workflow unschedule daily-standup-prep

Use the daemon scheduler

For an always-on host without launchd or cron, switch to in-process mode and run the daemon. It checks due schedules once per minute:

jazz config set scheduler.mode in-process
jazz daemon

You can also select /settings → Scheduler in the jazz home screen. See Scheduler configuration.


Platform requirements

  • launchd doesn’t do cron arithmetic. StartCalendarInterval accepts plain integers and wildcards only: no step values (*/15), no ranges (1-5), no lists (1,3,5). Jazz expands what it can into multiple entries and rejects what it can’t with an explicit error rather than silently scheduling the wrong thing.
  • Schedulers start with a minimal environment. launchd jobs don’t inherit your shell’s PATH, so Jazz writes an explicit one into the plist. If a workflow shells out to a tool installed somewhere unusual, use an absolute path.

Approval policy

The workflow’s autoApprove: tier decides what can run without asking. Calls above that tier are declined.

autoApproveAuto-approvesGood for
falseNothingThe agent receives a decline for every gated tool
read-onlyReads, search, web, todos, work state, subagents, read-only commandsDigests, reports, watchdogs
low-risk+ memory writes, reminders, triggers, low-risk commandsDigests that track state
high-risk+ file writes, shell, git commit and pushJobs requiring unrestricted tool use

Skills such as email, calendar, and Obsidian run commands through execute_command. Their mutations may require a higher tier. Prefer human approval or a narrowly scoped command grant; see email and calendar setup.

Pick the lowest tier that lets the job finish. See Approvals for policy details.


Sleep, missed runs, and catch-up

macOS and Linux behave differently here, and the difference decides whether you need catch-up at all.

launchd fires on wake. Missed sleep slots are combined into one run when the Mac wakes. A powered-off machine misses its slots.

cron skips missed slots. If a Linux machine is asleep or off at the scheduled time, the job does not run.

Either way, catch-up is explicit rather than automatic:

jazz workflow catchup      # list what missed its slot, pick, run

It is age-bounded: a missed run older than 24 hours is skipped (and recorded in jazz workflow history as skipped), and per-workflow maxCatchUpAge overrides that. The separate catchUpOnRestart flag covers the in-process daemon, meaning a slot missed because the daemon was stopped rather than because the machine was asleep.

If the schedule really cannot be missed

  • Pick a forgiving time. Hourly, or 9 AM instead of 6 AM, gives the machine more chances to be awake.
  • Keep the machine awake while a daemon runs: caffeinate -i jazz daemon --foreground on macOS, systemd-inhibit --what=sleep jazz daemon --foreground on Linux.
  • Wake it on purpose. macOS can schedule a wake or power-on: sudo pmset repeat wakeorpoweron MTWRFSU 05:55:00 for a 6 AM job.
  • Run it somewhere always on, such as a home server, a VPS, or a Raspberry Pi.

Debugging a scheduled run

History keeps the last 20 runs of each schedule. A run whose process died before it finished (a crash, a reboot mid-run) shows as interrupted once a daemon or CLI starts again.

jazz workflow scheduled <name>           # is it actually installed, and under which labels?
jazz workflow history <name>             # did it run? what did it do?
tail -f ~/.jazz/logs/<name>.log          # stdout
tail -f ~/.jazz/logs/<name>.error.log    # stderr
jazz workflow run <name> --auto-approve  # reproduce it by hand, same policy

Log files rotate at 10 MB and are deleted 14 days after their last write, so a workflow that has not run for two weeks has no log left. See sizes and retention.

jazz workflow run <name> --auto-approve reproduces the scheduled approval policy in the terminal.

Most scheduled-run failures are one of three things: the machine was asleep (see above), a tool was declined by the policy tier, or a binary the workflow shells out to isn’t on the minimal PATH.


  • Workflows: the file format and frontmatter
  • Starting runs: the other unattended shapes, and when to pick which
  • Guides: scheduled recipes with install steps
  • Headless: for dynamic prompts instead of a fixed workflow file

machine-readable: /docs/surfaces/scheduled.md · /llms.txt · /llms-full.txt