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

# How BlobHub works

> Organizations, blobs and revisions: the storage beneath what you build, and the blob type behind each primitive that has one.

export const Shot = ({src, alt, caption}) => <Frame caption={caption}>
    <img className="block dark:hidden" src={src} alt={alt} />
    <img className="hidden dark:block" src={src.replace(/\.(png|svg)$/, '.dark.$1')} alt={alt} />
  </Frame>;

What you build on BlobHub is stored the same way: in a typed, versioned blob that an organization owns. A workflow
blob holds workflow definitions, playgrounds, and the sessions with their threads and objects; a scheduler blob
holds schedules; an ONNX blob holds a model. This page is that storage layer: organizations, blobs, blob types,
revisions, and the metadata and operations around them.

## Organizations, blobs and revisions

A **blob** is the unit your work is stored in: a typed, versioned object with a stable id and an alias unique in
its organization. It holds no content of its own. Its content lives in its **revisions**, and the blob names one of
them as its **default**, the one anyone sees who has not chosen another.

Blobs are grouped into **organizations**. An organization is both a container and an access boundary: it owns its
blobs, every blob belongs to exactly one organization for its whole life, and reaching a blob starts with your
standing in its organization. A person can belong to several organizations, each with its own blobs, keys,
credentials and limits.

```mermaid theme={null}
flowchart LR
    U1([User A])
    U2([User B])
    U3([User C])

    subgraph ORG1["Organization · acme-corp"]
        B1[/"Blob · ticket-triage"/]
        B2[/"Blob · digit-reader"/]
        B3[/"Blob · ops-schedules"/]
    end

    subgraph ORG2["Organization · research"]
        B4[/"Blob · dataset-prep"/]
        B5[/"Blob · classifier"/]
    end

    U1 --> ORG1
    U2 --> ORG1
    U2 --> ORG2
    U3 --> ORG2
```

Every blob has a stable identifier, an owning organization, a blob type, a visibility, and its revisions. On most
types they are a history of how its content has changed; a scheduler blob has one revision, changed in place, and no
history.

<Shot src="/general/images/how-it-works/org-blobs.png" alt="The acme-corp organization's blob list" caption="An organization holds blobs; each one has a type that says what it is." />

## Blob types

A blob's **type** is a dotted string, `<namespace>.<content kind>.<name>`, chosen when the blob is created and
fixed for its life. It decides what the blob's revisions hold and which commands reach them. Five types are
registered: Workflow (`blobhub.compute.workflow`), Scheduler (`blobhub.compute.scheduler`), ONNX Model
(`blobhub.model.onnx`), Graph (`blobhub.graph.orientdb`) and NLP Dataset (`blobhub.dataset.nlp`).

An organization can create a type only while that type's `enabled` entitlement is true for it. `workflow.enabled`,
`scheduler.enabled` and `onnx.enabled` are true by default; `orientdb.enabled` and `nlp.enabled` are false. See
[Limits](/general/limits#the-catalog) for every limit of each type, and [Blob Types](/blob-types/introduction) for
the reference.

Each primitive's page in this tab is provided by one of these types, by the worker, or by the platform itself:

| Page | Provided by | Reference |
| :- | :- | :- |
| [Workflows](/general/workflows), [Sessions](/general/sessions), [Threads & objects](/general/threads-and-objects), [Playgrounds](/general/playgrounds), [Debugger](/general/debugger) | `blobhub.compute.workflow` | [Workflow](/blob-types/introduction#workflow) |
| [Schedules](/general/schedules) | `blobhub.compute.scheduler` | [Scheduler](/blob-types/scheduler/overview) |
| [Models](/general/models) | `blobhub.model.onnx` | [ONNX](/blob-types/introduction#onnx) |
| [Agents & workers](/general/agents-and-workers), [Policies & approvals](/general/policies-and-approvals) | blobhub-worker, on your machines | [Worker](/worker/introduction) |
| [Organizations & access](/general/organizations-and-access), [Credentials](/general/credentials), [Service accounts](/general/service-accounts), [Limits](/general/limits), [The record](/general/the-record), [Apps & Missions](/general/apps), [Surfaces](/general/surfaces) | the platform, whatever the type | — |
| Labs' graphs and datasets (no page here) | `blobhub.graph.orientdb`, `blobhub.dataset.nlp` | [Graph](/blob-types/introduction#graph), [Labs](https://blobhub.io/labs) |

The graph type is legacy, and an NLP dataset has no commands of its own: the web app renders it from static hosting.

## Revisions and the revision lifecycle

A **revision** is one version of a blob's content. A blob has exactly one **default** revision at any time (the
word `default` names it wherever a blob is named) and **at most one draft**, which is always the default. A draft
is the only revision that runs, and it is edited in place: saving a definition changes the draft, it does not
produce a new revision. A committed revision is frozen, both its content and its runtime.

Every revision carries two independent axes: **phase**, where it sits in its life, and **status**, whether it is
healthy right now. Operations move them separately.

```mermaid theme={null}
stateDiagram-v2
    [*] --> draft: Blob created
    [*] --> managed: Blob created (Scheduler)
    draft --> commit: Commit
    commit --> draft: Reopen
    draft --> [*]: Discard
    commit --> [*]: Delete
```

```mermaid theme={null}
stateDiagram-v2
    [*] --> creating: New
    creating --> ready: created
    creating --> failed: create failed
    ready --> committing: Commit
    committing --> ready: committed
    committing --> failed: commit failed
    ready --> deleting: Delete
    deleting --> [*]: deleted
    deleting --> failed: delete failed
    failed --> ready: Reset
    failed --> [*]: Delete
```

* **`draft`**: open for edits, and the only phase that runs. Most write operations target the draft.
* **`commit`**: sealed, content and runtime alike. Its definitions can still be run, from a session of a draft.
* **`managed`**: a scheduler blob's single revision, created once, writable for the blob's whole life, and never
  moved through `commit` or `draft` at all.

These operations move a revision:

* **[New](/rest-api/blobs/create-revision)** branches a fresh draft from the committed default and makes it the
  default. Metadata always comes along, content only where the type copies it (a workflow's definitions, a model),
  and sessions never.
* **[Commit](/rest-api/revisions/commit-revision)** freezes the draft where it stands and closes every session open
  on it. It does not create a new draft.
* **[Reopen](/rest-api/revisions/reopen-revision)** returns the committed default to draft. The sessions its commit
  closed stay closed.
* **Discard** deletes the draft. The default moves back to the revision the draft branched from, or to the newest
  committed one when that is gone.
* **[Delete](/rest-api/revisions/delete-revision)** removes a committed revision that is not the default. Discard
  and Delete are the same call, and both need admin; every other operation needs write.
* **[Reset](/rest-api/revisions/reset-revision)** returns a failed revision to `ready`, its phase untouched.

A **failure is recoverable, not terminal.** A failed create can be deleted. A failed commit is reset back to
`draft` / `ready` and committed again; there is no direct retry for a failed commit. A failed delete or discard can
be reset and issued again. None of this locks the blob itself: the lock is the revision's own status, so one
revision's failure never strands the others.

**Nothing promotes an earlier revision back.** Every committed revision stays readable, and its definitions can
still be run from a session of a draft, but the default moves only as New, Reopen and Discard move it, never by
being set to a revision you pick.

In the web app, the selector in the blob header lists the blob's revisions with their comment, phase, author and
age. Choosing one other than the default is a preference of yours, remembered per blob, not a change to the blob.

<Shot src="/general/images/how-it-works/revision-selector.png" alt="The revision selector open on a workflow, listing its draft and committed revisions" caption="The default revision is what everyone sees; earlier commits stay readable." />

## Metadata

A blob and a revision can each carry **metadata**: small key-value records whose content is yours to define, for
tags, categories, or state an integration keeps about the object. Each item is stored and addressed on its own,
with its own id and an alias chosen when it is created, so it never appears when the blob or revision itself is
read. [Resolve Metadata](/rest-api/blobs/resolve-metadata) finds a blob's items by alias.

Revision metadata freezes when its revision is committed, and a new revision carries its parent's metadata forward.

## Operations

Creating a blob, creating, committing or deleting a revision, and deleting a blob take longer than one request. The
API accepts each one, starts it in the background and returns at once. You learn how it went by reading the blob or
the revision again and checking its `status`, the same read you would make anyway. A change that cannot finish
rolls back rather than leaving its record stuck halfway, and a revision it leaves `failed` is picked up by Reset or
Delete.

A model upload is the one change with an operation record of its own: the upload returns an operation id, and
[Get Operation](/rest-api/operations/get-operation) reports it until it is `completed` or `failed`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.