Skip to main content
pull reads every schedule on the revision and writes them back out as manifest entries — exactly as the platform holds each one. It is how an existing scheduler blob becomes a file you can version-control, and how a schedule someone created in the browser gets adopted into a manifest that already exists.

Synopsis

It overwrites the manifest, with nothing to stop it

There is no --force and no --dry-run. The file named by -f is replaced with a freshly generated document every time, and the run before it did not ask. This is worth stating plainly because the file being replaced is your own hand-authored manifest, not a generated artifact. Its comments, its key order, its quoting, and any entry it declares that the revision does not actually carry are all gone afterwards. Against a revision holding no schedules at all, a two-entry manifest comes back as:
That is the correct answer — the revision really does hold nothing — but it is also the whole file. The single quotes are the writer’s own: it emits YAML that round-trips, quoting version so it cannot be read back as a float and an invocation_time so it cannot be read back as a timestamp, and leaving alone what does not need it. The document is regenerated rather than merged, deliberately: the point of pull is to report what the platform actually holds, and folding stale local entries back in would defeat it. It also means pull is not the command to reach for when you want to know what would change. That is diff, which writes nothing at all. Run it first, and keep the manifest in version control so a surprising pull is one git checkout away. Elsewhere in this CLI a local write is guarded: blobhub workflow eject refuses outright with EJECT_TARGET_EXISTS if any destination file exists. pull does not, here or in the workflow group — a pull’s whole purpose is to replace the file, where an eject’s is to create one.

What it does

  1. Reads only the manifest’s type, version, blob and revision — never its schedules: list — and resolves the scheduler blob and revision. This is a read, so a commit-phase revision pulls fine.
  2. Pages list_schedules to completion.
  3. Sets aside every schedule the platform stored with no alias — they cannot be expressed as manifest entries.
  4. Writes each remaining schedule back exactly as the platform holds it.
  5. Writes a fresh document to the manifest path, entries sorted by alias.
Under --json the payload carries blob, schedules (the aliases written), unmanageable (the ids skipped) and path, alongside the envelope’s schema_version.

Written back exactly as stored

deploy sends invocation_target as the manifest wrote it, so there is nothing here for pull to look up or resolve — it writes back what list_schedules returns, field for field: A schedule deployed by blobhub-cli ≤ v0.4.0 pulls its invocation_target.target.blob back as the raw id, not as an alias. Those releases resolved a manifest’s blob alias before writing, storing only the id, so pull writes that same id back. Redeploying the original alias manifest once — diff reports it as update (invocation_target.target.blob, invocation_target.target.org) — stores the target the way the manifest wrote it, and it round-trips through pull unchanged from then on. The written entry always carries invocation_target_type, set to workflow, even where the manifest you started from omitted it. It is the platform’s only accepted value, but a required field rather than a default the platform infers — pull writes it explicitly every time.

It adopts drift

pull writes out every aliased schedule on the revision, not only the ones your manifest already names. A schedule created in the web UI, or by a colleague’s deploy, is drift before the pull and an ordinary manifest entry after it. That is the intended path from a browser-managed scheduler blob to a declarative one, and it is the only resolution for drift that this group offers — the alternative, removal, needs blobhub scheduler prune, which is not yet available. It is also the reason to read the version-control changes to your own manifest afterwards: adopting drift is a decision, and pull makes it for every aliased schedule at once.

Aliasless schedules are skipped, not silently

A schedule the platform stored with no alias has no manifest representation. alias is a schedule entry’s required identity, so writing one out would produce a file this CLI’s own loader rejects — and inventing an alias for it would make the next deploy create a second, separate schedule beside the one already firing. So it is left out of the document and named on its own output line instead, by id, under unmanageable in the JSON payload. It is still firing; dropping it in silence is how an operator ends up with a schedule they cannot see. To bring one under management, give it an alias through the platform’s Update Schedule operation and pull again.

pull reads only the scheduler blob

Writing a schedule back verbatim means there is nothing left to look up. pull never reads a schedule’s target blob, revision or session — only the scheduler blob itself, through list_schedules. That makes it the same reach as ls; the two commands differ only in what they do with what they list, not in what they touch to get it.

pull and deploy are not inverses

Worth repeating here, because the file-in, file-out symmetry of workflow pull/push makes it tempting to assume otherwise: a round trip through pull and deploy is not the identity. deploy sends the manifest’s target and workflow unchanged, but it resolves the target session — finding or creating it — and may create a session that did not exist; nothing in a manifest deletes a session, and pull will not undo it. See Scheduler overview.

Errors

A skipped aliasless schedule is not an error: it is reported and the exit code stays 0. Every code above, with its remediation, is in Error codes.

See also