Scheduling workflows

Run a workflow on a cron schedule, unattended. Both kinds of workflow — flat step sequences and DAG workflow skills — can be scheduled.

mur workflow schedule set nightly-scan "0 3 * * *"
mur workflow schedule list
mur workflow schedule disable nightly-scan   # keeps the entry, stops the firing

On macOS the schedule is installed as a launchd agent; on Linux as a crontab entry. Either way it runs mur run <name>.

Schedules fire in local time

The cron expression is read in your machine's local time zone, not UTC. 0 3 * * * means 3am where you are. mur workflow schedule list shows the zone that will actually be used:

šŸ”„ Active schedules:

  nightly-scan — `0 3 * * *` (Asia/Taipei)

This is the same behaviour on both backends: launchd's StartCalendarInterval and crontab both interpret the fields as local wall-clock time, which is why a schedule set for 2:30am can fire twice or not at all on a daylight-saving changeover. Avoid scheduling anything important inside that hour.

If an entry was written by an older version it may carry a stored UTC label that never applied. The list marks those explicitly:

  old-job — `20 23 * * *` (Asia/Taipei)
     stored timezone: UTC (not used locally)

Nothing needs fixing there — the schedule already fires at 23:20 local. Do not shift the expression to "correct" for a zone that was never in play.

Use the exact name

A schedule fires mur run <name>, which resolves an exact flat workflow or an exact category: Workflow skill. A near-miss name falls through to fuzzy search, and a fuzzy match is refused when there is no terminal to confirm it — so a typo in a schedule is a silent no-op rather than an error. The scheduled run exits cleanly having done nothing.

mur workflow schedule set checks the name against both lookups when you create the schedule, so a name it accepts is a name that will run:

$ mur workflow schedule set does-not-exist "0 3 * * *"
Error: Workflow 'does-not-exist' not found — no ~/.mur/workflows/does-not-exist.yaml,
and no `category: Workflow` skill of that name with a `content.procedure`.

What a scheduled run can reach

launchd and cron start a job with a bare PATH of /usr/bin:/bin:/usr/sbin:/sbin — no Homebrew, no mise, no language version manager. A step calling mysql, gh, or node would work perfectly by hand and fail at fire time.

MUR freezes the PATH of the shell that created the schedule into the job, so the scheduled run reaches the same binaries you just proved the steps against. Two consequences worth knowing:

  • Set the schedule from the shell you actually use, not a minimal one.
  • If you later change your PATH in a way the workflow depends on, re-run mur workflow schedule set to refresh it.

Approvals still wait

A scheduled run executes non-interactively, but an approval node in a workflow skill still pauses and waits. Scheduling a workflow with unresolved human-in-the-loop gates defers the wait; it does not grant the approval.

Writing a flat workflow by hand

mur workflow new writes every field of the record, so a generated file looks like it has a dozen required keys. It does not. Only these are required — everything else (schema, tier, importance, tags, timestamps, …) has a default:

name: nightly-scan          # must match the filename stem
description: two shell steps
content: what this workflow is for
steps:
  - order: 1                # 1-based; order + description are required
    description: first
    command: echo one       # optional — omit for a prompt-only step
  - order: 2
    description: second
    command: echo two

Save it as ~/.mur/workflows/<name>.yaml. A missing required field is reported by name — missing field `content` — so read the error rather than guessing.

Note that a flat workflow's steps use order + description. That is not the same shape as a workflow skill's DAG procedure, which uses id + kind with an edges list.

Commands

CommandWhat it does
mur workflow schedule set <name> "<cron>"Create or update a recurring schedule
mur workflow schedule listShow active and disabled schedules, with the firing zone
mur workflow schedule remove <name>Delete the schedule and its system entry
mur workflow schedule disable <name>Stop firing, keep the entry
mur workflow schedule enable <name>Resume a disabled schedule

Cron only — there is no one-shot "run at" scheduling. For a single future run, use your platform's own tooling (at, a calendar event, a one-off launchd job).

If the MUR daemon is running, it claims the schedule and runs it itself; a stale daemon PID is reclaimed for system cron automatically the next time you set a schedule.