Workflow frontmatter
Set schedules, approval policies, and run budgets in a workflow’s YAML frontmatter. See Workflows for the prompt body and Guides for examples.
Fields
---
name: daily-standup-prep
description: "Prepare my daily standup notes"
schedule: "0 9 * * 1-5"
agent: my-dev-agent
autoApprove: read-only
skills:
- github-action
catchUpOnRestart: true
maxCatchUpAge: 7200
maxIterations: 40
maxCostUSD: 0.20
maxTokens: 200000
maxDurationMs: 1800000
deliver: phone
---
| Field | Type | Required | Purpose |
|---|---|---|---|
name | string | ✅ | Workflow identifier used by every jazz workflow command |
description | string | ✅ | One-line summary shown in jazz workflow list |
agent | string | no | Agent id or name to run this workflow with. Overridable at runtime with --agent |
schedule | cron string | no | When to run. Default frequency for jazz workflow schedule; --cron installs another beside it |
autoApprove | see below | no | Approval policy for every run of this workflow. Unset means false |
skills | string[] | no | Skills to make available to the agent for this workflow |
catchUpOnRestart | boolean | no | Whether a recent missed run may be replayed after daemon restart |
maxCatchUpAge | seconds | no | Past this age a missed run is skipped. Default 86400 (24 h) |
maxIterations | number | no | Iteration cap for this workflow. Default 100. Overridable with --max-iterations |
maxCostUSD | number | no | Spend cap in USD, checked between iterations. Unset = uncapped. Overridable with --max-cost-usd |
maxTokens | number | no | Cap on cumulative prompt + completion tokens for this run (not sub-agents), checked between iterations. Unset = uncapped. Overridable with --max-tokens |
maxDurationMs | ms | no | Wall-clock budget with 50/80/90% agent pressure nudges. Unset = uncapped. Overridable with --max-duration-ms |
deliver | string(s) | no | Notify target name, or a list, that receives each run’s answer. Its failures and approval requests go there too |
maxCostUSD and maxTokens are soft checkpoints, evaluated between iterations.
maxDurationMs is a deadline that interrupts a model call or tool in flight. See
Configuration → run budgets
for the full enforcement model and how maxDurationMs differs from --timeout.
There is no autoApprovedCommands field in frontmatter. That is a global config setting.
See the note below.
autoApprove
Accepts exactly one of false, read-only, low-risk, high-risk or true, with true and
false unquoted. Leaving it out means false.
Any other value (readonly, Read-Only, low_risk, a quoted "false", yolo) is invalid. jazz workflow list and jazz workflow show print the reason, and the workflow
refuses to run, to be scheduled, or to be installed from the library until it is fixed.
The same policy applies to every way a workflow runs: its schedule, catch-up after a restart,
jazz workflow run --auto-approve, and a plain jazz workflow run, where anything the policy
does not clear asks you first.
| Value | Auto-approves |
|---|---|
false | Nothing, and so does leaving it out. A gated tool is declined and the agent can continue or report the limitation |
read-only | Reads, search, web requests, git status/log/diff/blame/branch |
low-risk | + memory writes, reminders, triggers, and shell commands classified low-risk |
high-risk | + every gated tool: write_file, edit_file, rm, mv, cp, mkdir, execute_command |
true | Same as high-risk |
Exact per-tool tiers: tool inventory.
Running a workflow fully unattended (yolo)
To let a workflow run every tool without asking, write it out:
autoApprove: high-risk # or true
Read
Running fully unattended first, and
prefer the narrower tier plus an autoApprovedCommands entry when one command is all the
workflow needs.
The low-risk trap
low-risk covers memory writes, reminders, triggers, and commands classified low-risk.
Todos, work state, the scratchpad, and subagents already run at read-only.
Email, calendar, and file changes require approval when their risk exceeds the policy.
To permit a specific command, keep the tier low and add a narrow global grant:
{ "autoApprovedCommands": ["git status"] }
Grants match the binary and its next word when that word is not a flag. They do not match
compound, redirected, substituted, or environment-prefixed commands. Granting a whole
binary such as himalaya permits its mutation commands too; see
email and calendar setup.
high-risk permits arbitrary shell commands and file mutations. Use it only when the
workflow needs that authority.
schedule
Standard 5-field cron. macOS caveat: launchd’s StartCalendarInterval supports only plain
integers and wildcards: no step values (*/15), ranges (1-5), or 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 something else.
launchd runs missed sleep slots once on wake; cron skips them. Powered-off machines miss their slots. See Scheduled runs for catch-up options.
Where workflows live
Discovered in this order; later overrides earlier on name collision:
- Global:
~/.jazz/workflows/<name>/WORKFLOW.md - Local:
./workflows/<name>/WORKFLOW.mdin the current directory
Related
- Workflows: the concept and the body of the file
- Guides: complete examples
- Surfaces → Scheduled: running them unattended
- Workflow commands: invocation and scheduling flags
Run-time placeholders
The body may use these; Jazz fills them when the run starts, so one definition can serve several schedules.
| Placeholder | Value |
|---|---|
{schedule.label} | Label of the schedule that fired, manual for a terminal run |
{schedule.cron} | Its cron expression, empty for a manual run |
{schedule.lastRunAt} | ISO time this workflow last completed under that label |
{run.startedAt} | ISO time this run started |