> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blobhub.io/llms.txt
> Use this file to discover all available pages before exploring further.

# blobhub workflow pull

> Download each manifest definition into its source file, verbatim and code-unaware

`pull` fetches every definition the manifest lists and writes it to that entry's `source` file, exactly as the
platform returned it. It is the command that starts a project from a revision someone else built in the browser,
and the command that brings a visual-editor change onto disk where you can read it.

It is a read: it never creates a definition, never modifies the manifest, and needs only a revision it can read.

## Synopsis

```bash theme={null}
blobhub workflow pull -f <manifest> [--definition <alias>] [--dry-run]
```

| Flag           | Default                          | Description                                 |
| -------------- | -------------------------------- | ------------------------------------------- |
| `--file`, `-f` | required                         | Path to the workflow manifest.              |
| `--definition` | every definition in the manifest | Limit to this alias. Repeatable.            |
| `--dry-run`    | off                              | Report the intended calls and perform none. |

## What it does

1. Loads and validates the manifest, then resolves its blob and revision. Reading allows phase `draft`, `commit`
   or `managed` — a committed revision is pullable even though it is not deployable.
2. Lists the revision's `workflow` and `playground` definitions and matches them against the manifest by the
   `(category, alias)` pair.
3. For each manifest entry, downloads the definition document and writes it to `source`, creating any missing
   parent directories. An entry with no matching definition on the revision is **reported, not created**.
4. Prints drift first, then one line per definition:

```text theme={null}
drift: 1 definition(s) on the revision are not in the manifest and were left untouched: playground/checkout_lab (removing them requires 'blobhub workflow prune')
pulled workflow/checkout_flow -> /home/ada/my-project/definitions/checkout_flow.json
missing on the revision, left untouched: workflow/legacy_flow
```

Under `--json` the payload carries `pulled`, `missing`, `planned`, `dry_run` and `drift`, alongside the
envelope's `schema_version`. `planned` is populated only under `--dry-run`, and `pulled` only without it.

## Verbatim, and code-unaware

The document is written as it arrived. `pull` does not know that a code port holds Python, does not compile
anything, and does not consult the manifest's `components[]` bindings at all — a definition entry with no
bindings pulls exactly like one with three.

The file is written in **its own format**, decided by the `source` extension: `.json` gets two-space indent and
a trailing newline, `.yaml`/`.yml` gets block style with key order preserved. A playground's `layout` round-trips
byte-for-byte, which matters more than it looks: the platform canonicalizes `layout` at creation and rejects an
upload whose layout differs, so a `pull` that reshaped it would break the next `push`.

**`pull` overwrites the local file unconditionally.** There is no `--force`, because there is nothing to guard:
the definition file is an output. If you have local edits you care about, run
[`diff`](/cli/workflow/commands/diff) or `--dry-run` first.

## It never rewrites the manifest

Even when `revision: latest` resolved to a concrete UUID, the manifest is left as written. Rewriting a file you
hand-wrote is a side effect nobody asked for — and if you deliberately pinned a UUID that happens to equal
today's latest revision, rewriting it to `latest` would silently change what the manifest means tomorrow.

## The first pull of a playground

Category is normally inferred from the local document's own `type`. On a first pull there is no local document
to read, so an entry that declares no `category:` defaults to `workflow` — and a playground definition pulled
that way simply reports as missing on the revision. Declare `category: playground` in the manifest entry for
anything you are pulling for the first time.

## `--dry-run`

Resolves the blob, the revision and the definition set, then reports what it would write without downloading or
touching a file:

```text theme={null}
would pull workflow/checkout_flow -> /home/ada/my-project/definitions/checkout_flow.json
```

## Errors

| Code                                                                                               | When                                                                                                                                |
| -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `MANIFEST_NOT_FOUND`, `MANIFEST_INVALID`, `MANIFEST_TYPE_MISMATCH`, `MANIFEST_VERSION_UNSUPPORTED` | The manifest is absent, unreadable, or not a `workflow_blob_deployment` this build understands.                                     |
| `DEFINITION_ALIAS_INVALID`                                                                         | A manifest entry's `alias` fails `^[a-z0-9_-]{6,42}$`.                                                                              |
| `BLOB_NOT_ACCESSIBLE`, `BLOB_NOT_WORKFLOW`                                                         | The blob is absent or unreachable with this key, or is not a workflow blob.                                                         |
| `REVISION_NOT_ACCESSIBLE`, `REVISION_NOT_WRITABLE`                                                 | The revision is unreachable, or its status is not `ready` — or its phase is none of `draft`, `commit`, `managed`.                   |
| `DEFINITION_CATEGORY_UNKNOWN`                                                                      | A local document's `type` is unrecognized and the entry declares no `category:`, or the declared category contradicts the document. |
| `DEFINITION_NOT_ACCESSIBLE`                                                                        | A `--definition` alias is not in the manifest.                                                                                      |
| `FORMAT_UNSUPPORTED`, `FORMAT_PARSE_ERROR`                                                         | A `source` path has an extension that is not `.json`/`.yaml`/`.yml`, or an existing local document does not parse.                  |
| `CREDENTIALS_NOT_FOUND`, `PROFILE_NOT_FOUND`, `INSECURE_CREDENTIALS_PERMISSIONS`                   | No usable credential, or a credentials file the CLI refuses to read.                                                                |
| `API_RATE_LIMITED`, `API_TRANSIENT_ERROR`, `API_NETWORK_ERROR`                                     | A call failed after its retries.                                                                                                    |
| `DEFINITION_LIST_TRUNCATED`                                                                        | Advisory, on stderr: the listing may be incomplete. The exit code stays `0`.                                                        |

A local file that does not parse still fails the command: `pull` reads each `source` before writing it, to decide
the entry's category. Delete an unparseable file rather than pulling over it.

Every code above, with its remediation, is in [Error codes](/cli/error-codes).

## See also

* [`blobhub workflow push`](/cli/workflow/commands/push) — the other half of the pair; a document that goes out
  through `push` and comes back through `pull` comes back byte-symmetric.
* [`blobhub workflow diff`](/cli/workflow/commands/diff) — what a pull would overwrite, before it does.
* [Workflow overview](/cli/workflow/overview) — the project shape and the other nine commands.
* [Download Definition](/blob-types/workflow/operations/download-definition) — the operation behind each write.
