Schedules and triggers
Put recurring work on autopilot. A schedule starts a deputy mission at set times. An event trigger starts it when GitHub, Slack or your own system sends a webhook. Nobody has to press a button, and every run is recorded, can ask a person, and can be continued like any other.
Schedules are available when your administrator enables deputies. Event triggers also need webhooks to be enabled.
What you can do with it
- Review every new pull request. Bind a “Review PR” mission to GitHub
pull_request.openedwith the conditionevent.pull_request.draft == false. Every ready pull request gets exactly one review run. Drafts are skipped. - Bump dependencies every Monday. Schedule a mission weekly on Monday at 07:00 in
Europe/Berlin, with standing instructions that say where to post the summary. - Check large invoices. Bind a mission to
invoice.paidon a custom webhook, with the conditionevent.amount > 1000, and mapinvoice.idinto the mission’sinvoiceinput.
See it end to end: Review every pull request and Nightly dependency upgrades.
How it works
A schedule launches the mission each time it fires. A webhook delivery launches it only when the event and your condition match. The run acts as the deputy.
A mission’s Triggers list shows every way it can start:
| Way | What starts it |
|---|---|
| Launch by hand | A person, from the deputy page |
| Schedule | A time pattern you set |
| Event | A webhook delivery that matches your trigger |
| HTTP call | A curl command the page shows you, ready to copy |
| Terminal | marshal deputies launch |
A schedule or an event starts only an active mission on an active deputy. Every run acts as the deputy, with the deputy’s identity and environment. It never gains any permission from the person or the payload that started it.
marshal run and the Runs page start one run now. To run something on a timer or on an event, put it in a mission on a deputy.
Add a schedule
Open the mission
Open the deputy and expand the mission. The Triggers list is inside it.
Select Schedule
The Schedule dialog opens.
Pick the time
Use the picker: hourly, daily, weekly or monthly, with a time, a weekday or day, and a time zone. Every schedule names its time zone, so it keeps its meaning wherever Marshal runs.
For anything else, select Advanced and write a cron expression with the standard five fields (minute, hour, day of month, month, day of week), or a shortcut such as @hourly or @daily. The smallest step is one minute.
Choose catch-up
Catch-up says what to do with fire times that were missed while Marshal was unavailable:
skipdrops the missed times. The schedule carries on from its next time.onceruns the missed times one after another, one per minute, until the schedule is current.
Add standing instructions (optional)
Select Add standing instructions in the footer. They are added to the prompt every time the schedule fires. Use them for what nobody will be there to type, such as where to report.
Create
Select Create.
What you should see: the schedule in the mission’s Triggers list with its cron expression, time zone, catch-up setting, next fire time and an on badge.
Add an event trigger
For a custom webhook, create an endpoint first on Webhooks. GitHub and Slack need no endpoint, because each org has one connection to each.
Open the mission
Open the deputy and expand the mission.
Select Event
The Event trigger dialog opens.
Choose the source
Source is the kind of webhook: GitHub, Slack or Custom webhook. For a custom webhook, also pick the Endpoint.
Enter the event
Event is the name in the delivery, such as pull_request.opened. See Event names.
Add a condition (optional)
A condition narrows which deliveries start the mission. Leave it empty to start on every delivery of that event. See Conditions.
Check the preview, then create
The dialog tests your condition against recent real deliveries. Select Create.
What you should see: the trigger in the mission’s list with an on badge. Send a test delivery and a new run appears on the deputy.
Event names
An event name is family.action, for example issues.opened on GitHub. A trigger can bind to:
- one event:
issues.opened - a whole family:
issuesorissues.*, which mean the same - everything:
*
Only a trailing .* and a bare * are wildcards. A family matches every action in it: on GitHub, pull_request matches opened, closed, edited and every other action. For one run per new pull request, bind to pull_request.opened.
Each app declares the events you can bind to. If you name one the app does not declare, Marshal lists the declared events. A custom webhook accepts any name. A personal endpoint is used by its owner’s personal deputies. See Webhooks.
Conditions
A condition is a short expression that is true or false. Two names are available:
eventis the payload, as JSON. Example:event.amount > 1000.nowis the time of delivery.
The preview uses stored payloads. Marshal stores them for custom endpoints and for GitHub and Slack. For GitHub and Slack, an admin can turn this off with Keep event payloads for 7 days on the app. See Webhooks.
Map event data into mission inputs
Send invoice.id from the payload into the mission’s invoice input, so the prompt names the exact invoice. You set the input map with the API, using an API key. Create the trigger with POST /api/deputies/<deputy-slug>/triggers, or add a map to an existing one with PATCH /api/deputies/<deputy-slug>/triggers/<trigger-id>:
{
"mission": "invoice-review",
"integration": "custom-webhook",
"connection_id": "<endpoint id>",
"event_type": "invoice.paid",
"condition": "event.amount > 1000",
"inputs": {
"invoice": { "path": "invoice.id" },
"currency": { "path": "invoice.currency", "default": "USD" }
}
}Each key in inputs is a mission input. path is a dotted path into the payload, and array items use their index. A value without a default is required. Each value is cut at 8 KB, with a visible marker. A trigger maps up to 64 inputs. A trigger with no input map launches the mission with no inputs, so use a prompt that needs none.
How a delivery becomes a run
- Marshal’s webhook relay checks the signature and queues the event.
- Your Marshal picks it up a moment later.
- Marshal finds the triggers that match the event, evaluates each condition, and applies the input map. It records a firing for each match.
- The run starts.
Who can change triggers
Creating, editing, pausing and deleting a schedule or an event trigger needs the right to change the deputy. See Deputies.
Edge cases
Schedules
- A schedule carries no inputs, so the mission’s required inputs need a default.
- A mission holds each cron expression and time zone once. To change one, edit or resume the existing schedule.
- Pause stops the schedule. On resume, Marshal works out the next time from now. Delete stops it for good and keeps past runs.
- If the mission is at its concurrency limit when the schedule fires, the launch waits in a queue and starts when a slot frees.
- Marshal sets the next fire time before it launches. A launch that fails never delays or repeats the schedule. The row shows Last run failed with the error. A schedule Marshal had to switch off, such as one whose cron expression cannot be read, shows Turned off with the reason.
Event triggers
- A repeat delivery starts the mission once. Marshal uses the payload’s
id,event_id,delivery_id,webhookIdoreventIdwhen it has one, and a hash of the payload when it does not. The same key for the same trigger within 24 hours counts as one delivery. - A launch needs an active deputy, an active mission and every required input.
- If a trigger’s endpoint is deleted, the trigger is turned off and shows why.
- Pause stops the trigger and keeps it. Delete removes it.
- A trigger on a body-only endpoint with the event
*shows a replay warning, because anyone who captured one delivery could send it again.
Try it
Start a mission from a terminal, exactly as a trigger would:
marshal deputies launch <deputy-slug> --mission <mission-slug> --input key=value --notes "text for this run only" --followThen add a daily schedule to it from the deputy page. For a full walkthrough, see Run a mission on a schedule or event.