> ## 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.

# Workflow overview

> What a workflow deployment is, the shape of a deployable project, and the ten commands that move it

A workflow blob's revision holds definitions, and a definition's `logic.code` components normally have their code
typed into the visual editor. The `workflow` command group moves that whole arrangement into a repository: the
code becomes an ordinary Python package, the definition documents become files, and one manifest says which
revision they belong to.

The manifest is the unit of work. It names a blob and a revision, lists every definition that belongs on that
revision, and binds each code component to a package entry point. Every command in this group starts by loading
it.

## The shape of a deployable project

Three parts, in one directory tree:

```
my-project/
├── manifest.yaml               # the revision, and everything that belongs on it
├── definitions/
│   └── checkout_flow.json      # the definition document — pulled from, or pushed to, the platform
└── pkg/
    ├── entry.py                # entry_point: the module the compiler starts from
    └── lib/
        └── pricing.py          # a local module entry.py imports
```

`manifest.yaml`, for a revision holding one workflow definition whose `logic.code` component (`id: c1`) is
compiled from `pkg/`:

```yaml theme={null}
type: workflow_blob_deployment
version: "1.0"
blob: acme-corp/checkout                # <org>/<blob>, or a bare <blob> plus --org / BLOBHUB_ORG
revision: latest                        # or a pinned revision UUID
definitions:
  - alias: checkout_flow
    source: definitions/checkout_flow.json
    category: workflow
    components:
      - id: c1
        code:
          base_path: pkg
          entry_point: entry.py
```

Every path in a manifest anchors to the **manifest file's own directory** — `source`, `code.base_path` and
`value.source` alike. `entry_point` is the one exception: it resolves against `base_path`, because it names a
module inside the package rather than a file in the project. The full grammar is in the
[Manifest](/cli/workflow/manifest) reference.

This example runs through every command page in this group. Where a page says `checkout_flow`, it means this
definition and this package.

## The lifecycle

```mermaid theme={null}
flowchart LR
    subgraph repo["Your repository"]
        direction TB
        PKG["Python package<br/>pkg/entry.py"]
        FILE["Definition file<br/>definitions/checkout_flow.json"]
    end

    REV["The revision on BlobHub<br/>workflow and playground definitions"]

    PKG -->|build| FILE
    FILE -->|push| REV
    REV -->|pull| FILE
    PKG -.->|"deploy: build, upload what changed, check"| REV
```

The definition file sits in the middle of everything, and it is always a **complete, uploadable document**: its
code ports hold compiled content, not a reference to the package that produced it. That is what lets `push` work
with no compiler in the path, `pull` work without knowing a package exists, and a reviewer see the compiled code
in a pull request beside the sources it came from.

`build` and `deploy` are the two commands that know Python exists. What they do to a package — resolving its
local imports and flattening it into one import-less namespace — is the [Compiler](/cli/workflow/compiler)
reference; what that namespace already contains, and what it refuses, is the [Sandbox](/cli/workflow/sandbox)
reference. `pull` and `push` are a symmetric pair: a document that goes out through one and comes back through
the other comes back byte-symmetric. See [Concepts](/cli/concepts) for the verbatim/compiled split in full.

## The ten commands

They sort into three bands. A reader arriving with a task is in exactly one of them.

### Lifecycle

The six that move a definition between your repository and the revision, or report on the gap.

| Command                                   | What it does                                                                  | Network  | Writes locally             |
| ----------------------------------------- | ----------------------------------------------------------------------------- | -------- | -------------------------- |
| [`pull`](/cli/workflow/commands/pull)     | Downloads each manifest definition into its `source` file, verbatim.          | Read     | Yes — the definition files |
| [`push`](/cli/workflow/commands/push)     | Uploads each definition verbatim, creating an absent alias first.             | Write    | No                         |
| [`build`](/cli/workflow/commands/build)   | Compiles each bound component and writes the result into the definition file. | **None** | Yes — the definition files |
| [`deploy`](/cli/workflow/commands/deploy) | `build`, upload only what changed, then check what was uploaded.              | Write    | Yes — what it uploads      |
| [`diff`](/cli/workflow/commands/diff)     | Reports every local/remote difference. Writes and uploads nothing.            | Read     | No                         |
| [`check`](/cli/workflow/commands/check)   | Runs the platform's `check_definition` against what is already deployed.      | Read     | No                         |

`deploy` is the one to reach for day to day; the other five are what you use when you need one half of it.

### Adoption and execution

| Command   | What it does                                                                                                                                                                                                               |
| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `eject`   | Splits a definition's stored code back into local files, for adopting a workflow that was authored in the browser. It is **not** the inverse of `build`: the code was already compiled, and compilation is not reversible. |
| `execute` | Creates an execution of a workflow definition, and with `--watch` follows it to completion.                                                                                                                                |

### Reconciliation

| Command | What it does                                                                    |
| ------- | ------------------------------------------------------------------------------- |
| `ls`    | Lists the revision's definitions, marking which ones the manifest covers.       |
| `prune` | Deletes the definitions the manifest does not cover. Never implied by `deploy`. |

Definitions on the revision that the manifest does not mention are **drift**. No command in this group ever acts
on them: they are left untouched, and the command still exits `0`. Five report them on one line — `pull`, `push`,
`deploy`, `diff` and `check`. The rest report them differently or not at all: `build` never talks to the platform
and cannot; `ls` marks each drifted row in its table instead of printing the line; `prune` prints its own
`prune:` summary of what it is about to delete; and `eject` and `execute` do not report drift at all. `prune` is
the only command that removes them, and only when asked.

## What every command shares

**The manifest is always explicit.** `-f/--file` is required everywhere; there is no default path and no search
of the working directory.

**`--definition <alias>` narrows the set** and is repeatable. It takes a bare alias, and because a definition is
identified by the `(category, alias)` pair, an alias that names both a workflow and a playground definition
selects both rather than erroring.

**`--dry-run` withholds every side effect** on the five commands that carry it: `pull`, `push`, `build`,
`deploy` and `prune`. `diff`, `check` and `ls` have nothing to withhold. `eject` and `execute` do have side
effects and still have no dry run — `eject` guards its writes with `--force` instead.

**Global flags come before the group**, since they belong to the binary rather than the command:

```bash theme={null}
# --json and --org are global; -f belongs to the subcommand
blobhub --json --org acme-corp workflow diff -f manifest.yaml
```

**The revision gate depends on the direction.** A write needs status `ready` and phase `draft` or `managed`; a
read also allows `commit`. `push`, `deploy` and `prune` are the writes. Everything else in the group is a read,
which is why `diff` still answers on a revision that `deploy` refuses — and why the CLI's own hints point you at
`diff` when a command stops.

## See also

* [Manifest](/cli/workflow/manifest) — the `workflow_blob_deployment` body in full, over the shared base every
  blob domain extends.
* [Compiler](/cli/workflow/compiler) — how `build` and `deploy` turn a Python package into the flat namespace a
  `logic.code` component executes, and where that translation stops.
* [Sandbox](/cli/workflow/sandbox) — what that namespace pre-binds, what it refuses, and how the blob's import
  allowlist extends it.
* [Concepts](/cli/concepts) — manifests, the verbatim/compiled split, managed code ports, and the platform
  behaviours behind several messages in this group.
* [Configuration](/cli/configuration) — credentials, the precedence ladder, output streams and the `--json`
  envelope.
* [Error codes](/cli/error-codes) — every code these commands can raise, with its remediation.
* [Workflow definition format](/blob-types/workflow/workflows/definition-format) — the document the definition
  file holds.
* [Component code](/blob-types/workflow/workflows/component-code) — what the platform executes once you have
  deployed it.
