Scheduled runs — repo-owned cron
Your repo can declare cron schedules in its own .slipstream.json. The control plane fires each
one as a first-class run — logged, ledgered, and visible on the dashboard and through the MCP —
without any separate scheduler infrastructure on your side.
:::note A schedule is a monitor, not a commit verdict
A scheduled run never posts the RunsGreen check, never ships, never merges, and never rolls or
targets the executor fleet's own deploy path. Use schedules for proofs, health probes, and
housekeeping — never for CI or CD.
:::
Declaring a schedule
schedules is a recipe v2 field, alongside stages:
{
"version": 2,
"tenant": "k2k",
"stages": [
{ "name": "install", "cmd": "bun install --frozen-lockfile" },
{ "name": "test", "cmd": "bun test", "needs": ["install"] }
],
"schedules": [
{
"name": "nightly-health-probe",
"cron": "0 3 * * *",
"stages": [
{ "name": "install", "cmd": "bun install --frozen-lockfile" },
{ "name": "probe", "cmd": "bun run scripts/health-probe.ts", "needs": ["install"] }
]
}
]
}
| Field | Required | Notes |
|---|---|---|
name | yes | Unique within the recipe's schedules array. |
cron | yes | 5-field UTC cron expression, or an @hourly / @daily / @weekly / @monthly / @yearly nickname. Always UTC — there is no per-schedule timezone. |
stages | yes | Inline v2 stage objects — the same shape as your CI stages, including needs, if_changed, secrets, and resource hints. A scheduled run resolves through the exact same stage-execution path a CI run does. |
enabled | no (default true) | Set false to keep a schedule declared but paused. Removing an entry from schedules entirely also disables it — it is never deleted, so its run history and failure streak survive. |
A scheduled stage may not deploy, roll the executor, or target the executor's own Fly app —
validation refuses the whole schedules block if any stage does. Validation also refuses: an
unparseable cron, an effective cadence faster than 5 minutes, more schedules than your repo's
cap (default 5), and a duplicate name. A recipe with an invalid schedules block fails validation
entirely — nothing half-lands.
These rules are enforced twice: once when a push adopts your schedules, and again when a fire resolves the schedule at that commit. A schedule whose stages stop passing validation fails the run with the named reason instead of executing — an already-adopted schedule cannot be turned into a deploy by a later push.
How firing works
- Adoption reconciles your declared schedules into the platform on every default-branch push, independent of whether the feature flag is on — so a schedule is ready to fire the moment the platform operator flips it.
- Firing happens on a 30-second dispatch tick that re-checks the platform flag, your repo's
allowlist membership, the schedule's own
enabled, and the platform kill switch / repo quarantine every time. An operator pulling the global brake stops your schedules too. - Missed fires: a schedule due within the last 10 minutes fires once; later than that, it skips forward to its next future occurrence instead of firing a backlog. A control-plane restart never produces a stampede of missed fires.
- No overlap: if the previous run for a schedule is still in flight, the due occurrence is skipped (and counted in telemetry, not as a failure) rather than piling up concurrent runs.
- Scheduled runs share the same 6-minute wall-clock ceiling as CI runs.
What a scheduled run is — and isn't
- It appears on the dashboard's runs view under a
scheduledfilter, and inslipstream_status/slipstream_fleet_statuslike any other run. A red one is diagnosable withslipstream_diagnose. - It is excluded from CI health KPIs — a monitor going red is not a commit going red. Schedules have their own KPIs instead; see How a schedule is scored.
- It posts no GitHub check — not the required
RunsGreencheck, not the legacy mirror. It cannot gate a PR. - It can never trigger ship-on-green or auto-merge, even if every stage is green.
- A red scheduled run is rerunnable by run id through the API or the dashboard's Rerun button.
A repo+sha rerun is refused — several schedules can fire at the same commit, so "rerun repo@sha"
is ambiguous for this run kind. The
slipstream_rerunMCP tool does not yet accept a run id, so today rerunning a scheduled run needs the API or the dashboard.
Three reds raise one alert
Three consecutive red runs for a schedule raise a single deduped critical alert on the dashboard's
alerts feed; it does not repeat on the 4th or 5th red. A green run clears the counter. This is a
convenience signal for schedule owners — it is separate from the platform's own deadman watch on
the scheduler process itself, described in docs/CONTROL-PLANE.md § Scheduled runs.
How a schedule is scored
Each schedule carries its own KPIs over a rolling 30-day window, shown on the platform operator's Schedules view:
- Lateness — how far after its due time a fire actually started, as a median and a worst case. This is the headline number. A schedule creeping from one minute late toward the ten-minute grace window is on its way to having fires silently skipped, and lateness is the only signal that shows it before that happens.
- Success rate — the share of completed fires that passed. A schedule that has fired but not finished reads as "no result yet", never as 0%.
- Duration — median and p95 wall-clock, so a monitor drifting toward the 6-minute ceiling is visible before it starts getting killed.
- Recent outcomes — a compact history of the last several fires, newest first.
Two things deliberately do not count toward lateness. An operator rerun is scored for success and duration but not lateness — someone clicked, so measuring it against the original occurrence would say more about the human than the clock. And a fire that was skipped forward past the grace window is not a late run; it never ran at all.
Availability
Scheduled runs are a platform-operator-enabled feature — there is nothing in
slipstream_onboard to turn them on yourself yet. Declaring schedules in your recipe is safe at
any time (validation and adoption both work today); ask your platform operator to enable firing for
the fleet.