Schedules
A schedule starts a pipeline on a cadence. Its ID stays separate from the IDs of the runs it starts. A repository declares the cadence, arguments and where it fires. Installing that declaration arms it on a selected controller.
Use --profile NAME for a saved controller connection. Omission uses the saved
default profile, or the local controller when none is selected. --profile=
selects local for one command, and --all-repos always operates locally. Reads, pause/resume, cadence edits and immediate runs share
the same HTTP contract on both connections.
Restore preparation holds schedules until acknowledgment, which discards catch-up
through its timestamp. A normal restore preserves API/local schedule consent;
schedules resume after acknowledgment without rearming. For security incidents,
restore prepare --sign-out-everyone invalidates that consent too: reinstall or
rearm those schedules with fresh credentials. Unfinished scheduled runs from
the backup are cancelled with "cancelled by restore; rerun if needed".
Schedule registration refusals explain invalid input: cron uses five fields,
for example 0 * * * * (hourly); branch names can be main or feature/build
and cannot contain spaces; commit pins use full 40- or 64-character hexadecimal
object IDs. Correct the named field and register the declaration again.
Inspect schedules
sparkwing schedules list
sparkwing schedules list --profile production --all -o json
sparkwing schedules show --schedule check/nightly --fires 10
sparkwing schedules list --next 5
sparkwing schedules show --schedule check/nightly --next 3
sparkwing schedules list --timer
Selectors accept a schedule ID, full display name, pipeline/name, or an
unambiguous pipeline name. Ambiguous selectors fail on the controller. Repeat
--schedule, or use a comma list, to select several entries. Every selector
resolves before the first mutation. Aliases resolving to the same ID act once.
A later mutation failure can leave earlier mutations applied.
List JSON emits one selection record per line, including cadence, state, pin
identity, owning team (owner), arming actor (armed_by) and next/last-fire
observations. Show JSON includes the same ownership fields, its declaration,
override, effective cadence, source pin and fire history in one object per
selected schedule. --fires 0 requests no history. --next N requires a
positive count and shows the controller's upcoming instants. It does not
calculate times against the CLI machine's clock or time-zone data.
--all, --timer and --next select separate list reports. show --next
and show --fires also select separate reports. An unhealthy timer report
still prints its diagnosis and exits with failure. Paused schedules alone do
not require an active timer.
Pause, edit and run
sparkwing schedules pause --schedule check/nightly
sparkwing schedules resume --schedule check/nightly
sparkwing schedules set --schedule check/nightly --cron '0 4 * * *' --tz America/Denver
sparkwing schedules set --schedule check/nightly --arg region=us-east,empty=
sparkwing schedules set --schedule check/nightly --catch-up 0s
sparkwing schedules set --schedule check/nightly --reset
sparkwing schedules run --schedule check/nightly --profile production
sparkwing schedules uninstall --schedule check/nightly
Pause keeps the declaration and history. Resume enables it again. An immediate run starts separately from the cadence. Its request keeps one idempotency key across transport retries, and JSON retains the run ID and replay result.
Overrides preserve field presence. An omitted field leaves the repository's
value in control. --tz= selects the default zone explicitly, --catch-up 0s
keeps zero, and --arg key= keeps an empty argument value. An argument value
may contain =. Duplicate argument names fail. Arguments replace the declared
argument map. --arg= alone replaces it with an empty map. --reset drops the override. Pin, unpin and reset each require
a separate invocation from cadence edits.
The CLI and controller embed the IANA time zone database. Named zones such as
America/Boise and Etc/UTC work on hosts and images without zoneinfo files.
Invalid --cron overrides name the failing field and include a valid example.
For example, 61 * * * * reports that the minute is outside 0-59 and suggests
0 * * * * for an hourly schedule. Cron fields are minute, hour, day of month,
month and day of week.
A schedule speaks for the repository only when a team admin armed it (through GitHub App automation consent, or as a member who holds team.admin when it fires), it follows the repository's default branch as GitHub reports it through the App at fire time, it has no locked commit and no override of arguments, cadence, timezone, overlap or catch-up, and the App resolves its commit at fire time. Its fires claim
trigger:cron with repository_id, refs/heads/<default> and the branch head
at fire time, receive reserved pools whose rules allow the default branch, read
the default branch's verified cache, and write only that schedule's own scope,
manual:schedule/<id>:refs/heads/<default>. Every other fire, and an immediate
run, is asserted: it claims trigger:manual with no repository_id, ref or
sha. A schedule a non-admin armed writes under that member's scope, an
immediate run under the caller's, and a locked, overridden or
non-default-branch schedule's fires each under their own.
See OIDC.
Mutation JSON reports the confirmed result. Plain output emits schedule IDs,
or the new run ID for run. A deletion
result distinguishes removal from an already absent row.
Declaration and installation contract
A project declares schedules as a list under on.schedule:
pipelines:
- name: check
entrypoint: Check
on:
schedule:
- name: nightly
cron: '0 3 * * *'
where: local
tz: America/Denver
overlap: skip
catch_up: 1h
args: {region: us-east}
where selects local or controller. Catch-up values pass the shared
settings and ceiling checks. Values above a ceiling fail with both values
named. They are never silently lowered.
Installing without --schedule reconciles the repository's complete declaration
set and withdraws entries removed from the project file. Installing with
--schedule updates only the selected entries. It preserves other schedules,
their pins, overrides and pause state. A selection that runs elsewhere makes no
declaration changes on the selected controller.
When a controller cannot resolve the source repository or ref during installation, it returns HTTP 422 with the repository and ref to check. Confirm the repository URL, the controller's Git credentials and that the ref exists. The refused installation leaves the stored schedules unchanged.
Installing an API schedule with an identity already owned by a GitHub App schedule returns HTTP 409 and preserves the existing declaration. Manage that schedule through the repository declaration or App automation. An API request with an unknown schedule write mode returns HTTP 400.
Local installation records the selected declarations and captured environment
identity durably. Proofs and later pin changes use that captured environment.
Environment values stay in private host storage and do not appear in schedule
views. Installation pins a proved binary unless --unpinned is selected. Linux and macOS managed timers are
intended to invoke the stable hidden sparkwing __tick entrypoint and start the
local controller on demand. Windows schedules are intended to run through that
controller. Managed-unit refresh and native timer integration remain part of
the rewrite. Reinstall units that still invoke the removed crons command.
Local schedule health reads the native timer registration and its activation
state from systemd or launchd. --no-timer leaves automatic firing disabled
unless a native timer was already installed and enabled. The local controller
evaluates schedules when __tick invokes it. Remote controller health reports
its evaluator loop as enabled only while that loop is running. Both views
report the last tick separately, including a tick older than three minutes.
An unsupported or unreachable native service manager leaves schedule rows
readable and reports timer state as unavailable, with enabled false.
See CLI schedules for the generated flag reference and Scheduling for runner placement.
Controller fires seal the repository, ref and effective arguments before they enter the run queue. Repeating the same due instant returns the original run. Due launches and immediate runs use shared run admission and count against their team's configured hourly run budget and pending-queue limit. Replaying an admitted request uses no additional run budget. An immediate run records the member who pressed Run now as its actor and leaves the cadence unchanged. App-managed schedules require a live installation and repository automation consent. Team admins may pause and resume an App-managed schedule, and each pause or resume is audited. Nobody can override or delete one, including through repository-wide deletion, and other members cannot pause it either. Edit and delete refusals tell callers to edit the schedule declaration in the repository. Update that declaration or App automation to change the schedule. A later push keeps the schedule's pause state. App-managed schedules follow the configured branch and resolve its commit at fire time. An admin-armed default-branch fire without overrides carries verified default-branch trust.