Skip to main content
A scheduler blob’s revision holds schedules, and each schedule fires a workflow on a cron. Created in the browser, that set is a collection of forms; the scheduler command group makes it a file — one manifest that lists every schedule the revision should carry, with its target written in names rather than in UUIDs. The manifest is the unit of work, exactly as it is for the workflow group. It names a blob and a revision, lists every schedule that belongs on that revision, and every command in this group starts by loading it.

The shape of a deployable project

One file. A scheduler blob holds no code and no documents, so there is nothing for the manifest to point at:
schedules.yaml, for a revision holding one schedule that runs the checkout_flow workflow every morning:
The target is written entirely in symbols a person can read. What the platform stores in their place is UUIDs — a revision id, a session id. Turning one into the other, in both directions, is most of what this group does. The full grammar is in the Scheduler manifest reference.

A schedule targets a workflow in another blob

The schedule lives in the scheduler blob. What it runs does not — target: names a workflow blob, its revision, a session on that revision, and a workflow definition by alias. So a single scheduler deploy legitimately spans both of the platform’s engines: it writes schedules with scheduler_blobhub against its own blob, while validating every target with workflow_blobhub calls against the target revision. A key that can write the scheduler blob is not sufficient. Firing a schedule writes an execution into the target revision, so the platform requires WRITE on the target blob as well — the same role it gates the scheduler blob itself on. Read access on the target is not enough, and a key that has only that will still be refused. The target revision itself is only ever read by the CLI, though. Deploying a schedule creates a session on that revision but never touches the revision’s own content, so scheduling against a target in commit phase is fine — which is the normal case, since what you schedule is usually a committed workflow. Two more consequences are worth knowing before the first deploy:
  • The platform reports every target failure as the same opaque 403. A missing target revision, a target you cannot reach, an unresolvable session, a session belonging to a different revision, and a workflow alias that resolves to nothing are deliberately indistinguishable, so that a caller cannot tell “does not exist” from “exists but you may not see it”. That is a permanent security property. It is also why deploy probes the target itself, one step at a time, before writing anything: the CLI can name which of the five was wrong, and the platform structurally cannot.
  • workflow: is re-resolved every time the schedule fires. The alias is stored as a string and sent verbatim, so the definition behind it can be replaced freely — but renaming or deleting it leaves the schedule pointing at a name that resolves to nothing, invisibly, until the next fire. deploy and diff check that the alias is a live workflow-category definition on the target revision for exactly this reason.

pull and deploy are not a symmetric pair

In the workflow group, pull and push are a symmetric pair: a document that goes out through one and comes back through the other comes back byte-symmetric. Nothing here works like that. That last side effect is the asymmetry. pull cannot undo it: nothing in a manifest deletes a session, and the CLI will not delete runtime state it cannot prove it created. So a round trip through these two is not the identity, and treating it as one is how you end up with sessions you did not intend. The group has no push, and that is deliberate rather than unfinished. push means one specific thing in this CLI — a code-unaware, byte-symmetric transport that interprets nothing. The scheduler’s local-to-remote operation resolves references, creates sessions, and validates four things about every target. Calling that push would make one verb mean “move bytes” in one group and “resolve, create, validate” in another. It is deploy, which already means the composite that makes the manifest real and checks its own work.

The four commands

deploy is the one to reach for day to day, and diff is what to run before it. ls and diff are the two that write nothing at all, locally or remotely.

Drift is not inert here

Schedules on the revision that the manifest does not cover are drift. As everywhere else in this CLI, drift is reported, left untouched, and still exits 0 — but the consequence is different in this group, and the messages say so. An orphaned definition sits there doing nothing until something deploys or executes it. An orphaned schedule keeps firing on its cron: it consumes execution quota, appends to its session on every fire, and can saturate that session on its own. The message says so, names blobhub scheduler prune as the removal path, and states that it is not yet available — so removing one today means the web UI, or a delete_schedule call. One kind of drift can never be resolved from a manifest at all. A schedule’s alias is optional platform-side — the web UI’s create form offers a blank field — and nothing declarative can address a schedule that has none. ls shows it anyway, by id, because a schedule you cannot see is worse than one you cannot manage; pull skips it and reports it separately, since writing an aliasless entry would produce a manifest this CLI’s own loader rejects.

What every command shares

The manifest is always explicit. -f/--file is required on all four commands; there is no default path and no search of the working directory. Every command operates on the whole schedule set. There is no per-schedule narrowing flag — no counterpart to the workflow group’s --definition. A manifest describes one revision’s schedules, and these commands act on that set. --dry-run belongs to deploy alone, and it is not free of side effects. It skips the create_schedule/update_schedule calls, and nothing else: every target is still resolved, which means a session: alias that does not exist yet is still created. diff is the command that does not — it reports an absent session as one deploy would create. That is the one place the two genuinely differ in cost. Global flags come before the group, since they belong to the binary rather than the command:
Only deploy needs a writable revision. It requires status ready and phase draft or managed; ls, pull and diff also accept commit. A scheduler blob is created in phase managed with a single revision, so in practice revision: latest names the one revision there is and the gate is rarely what stops you.

See also

  • Scheduler manifest — the scheduler_blob_deployment body in full, and the four constraints checked before anything is written.
  • Concepts — manifests, drift, and the platform behaviours behind several messages in this group.
  • Configuration — credentials, the precedence ladder, output streams and the --json envelope.
  • Error codes — every code these commands can raise, with its remediation.
  • Scheduler blob type — cron syntax, timezones, date windowing, schedule states and what the platform records for every fire.
  • Workflow overview — the group this one is modelled on, where pull and push really are a symmetric pair.