Open Workflow GraphPre-release
Specification

Assets and versioning

Asset identity, storage locators, the five typed version relations, lifecycle states, and how composition and external identifiers ride along.

View as markdownMachine-readable source for agents and scripted implementers

An asset in OWG is a typed, versioned, governed object that carries a locator to wherever the bytes physically live. The asset node holds governance; the storage system holds content. That separation is what lets the same governance record survive a migration between clouds.

{
  "id": "delivery_mp4",
  "role": "delivery",
  "type": "video.delivery",
  "content_type": "video/mp4",
  "version_relation": "representation",
  "predecessor": "source_mov",
  "produced_by": "transcode",
  "state": "delivered",
  "storage": {
    "provider": "s3",
    "locator": "s3://studio-media/out/clip.mp4",
    "zone": "us-east-2"
  }
}

Only id is required.

Fields

FieldTypeNotes
idstringRequired. Document-local identifier
identitystringGlobal content-derived identity — content hash or credential manifest reference
typestringAsset kind. Open set: video, audio, image, text, model, lora, document
rolestringIts function in this workflow: source, delivery, thumbnail, captions
content_typestringMIME type
storageobjectProvider, locator, and optional zone or timerange
produced_bystringTask id — derived; the task's produced[] is authoritative
predecessorstringThe asset this one came from
version_relationenumHow it relates to its predecessor. See below
stateenumLifecycle position. See below
assuranceenumattested | asserted | inferred. See below
credentialsobjecte.g. { "scheme": "c2pa" }
identifiersarrayExternal identifier pass-through
depictsWhat the asset shows
depicts_real_entityDeepfake trigger. See AI disclosure
composesarrayComposition arcs. See below
profilesobjectProfile-contributed extensions, keyed by profile id (v0.92). See Extensions

id versus identity. id is local to the document and is what tasks reference. identity is the global, content-derived identity — a hash, URN, or content-credential manifest reference — and it is what lets the same asset be recognised across many runs, systems, and organizations. Populate both.

Typed version relations

This is one of the most consequential details in the specification. The relationship between versions is typed, not merely numbered.

RelationMeaningExample
revisionIncremental change, same contextRejected comp re-rendered after notes
variantChange for a different contextPristine versus battle-damaged prop
derivationA new thing that acknowledges its sourceA model trained from a base checkpoint
representationPure format change, same meaningThe proxy of a master
alternativeOne pick from equivalent optionsConcept sketches to choose between

Correctly labelling the relation is the difference between semantically correct lineage and a version counter that quietly lies. Two rules are worth memorising:

  • A proxy is not a revision of the master. It is a representation — same meaning, different format.
  • An approved retake is a revision, not a new asset.

Get these wrong and every downstream question — which shots use the latest approved version?, what is this derived from? — returns a confidently incorrect answer. A numbered version chain cannot distinguish "this replaces that" from "this is another way of expressing that", and those have opposite implications for approval.

{
  "id": "hero_prop_battle_damaged",
  "version_relation": "variant",
  "predecessor": "hero_prop_pristine"
}
{
  "id": "master_proxy_h264",
  "version_relation": "representation",
  "predecessor": "master_prores"
}

Lifecycle states

StateMeaning
draftWork in progress
growingStill being appended to — a live feed. See below
in_reviewSubmitted, awaiting a decision
acceptedApproved
deliveredHanded over
supersededReplaced by a newer version
rejectedNot approved — and retained in the graph

A rejected asset stays in the graph as a rejected state rather than disappearing. Nothing is overwritten, which is what makes the audit trail a record rather than a reconstruction.

Growing assets

growing is how OWG handles media that is still being captured, without mirroring a single byte:

  • While an asset is growing, its identity is the source UUID from identifiers[] rather than a content hash — you cannot hash a file that is still being written.
  • The producing ingest task stays open for the duration.
  • When the referenced range closes, fixity is computed over the now-bounded range and the state advances.

This is what carries the model into live sports and news. See the TAMS binding.

Storage locators

{
  "storage": {
    "provider": "tams",
    "timerange": "[1500:0_1620:0)"
  }
}

provider is an open string. Commonly used values — an implementation may register its own:

ProviderMeaning
s3, gcsObject storage
saas_dam, iconik, frameioSaaS asset managers
camera_media_cardMedia not yet ingested
tamsTime-addressable media store
usd_resolverAn OpenUSD logical asset identifier
protected_storeA hardened or protective storage tier

timerange is stored opaquely. OWG does not parse or interpret time. The half-open [s:ns_s:ns) syntax belongs to TAMS, and resolving it to bytes is TAMS's job. OWG deliberately does not attempt to solve the International Atomic Time to SMPTE timecode mapping.

External identifiers

OWG never strips an incoming identifier, even one it does not use itself.

{
  "identifiers": [
    { "scope": "tams.source",   "id": "0f7e...-a91c" },
    { "scope": "usd.assetInfo", "id": "asset://hero_prop/v23" },
    { "scope": "frameio.id",    "id": "b2c8e9f1" },
    { "scope": "c2pa",          "id": "urn:uuid:9e21..." }
  ]
}

Both scope and id are required per entry. Documented scopes: tams.source, usd.assetInfo, frameio.id, c2pa, urn. Preserved identifiers are the highest-confidence signal for relating objects that arrive from different systems — see declared assurance.

Composition

composes[] records that an asset is assembled from other assets, using the arc vocabulary of the composition system it came from.

{
  "id": "shot_0140_assembly",
  "composes": [
    { "component": "hero_prop_v23", "arc_type": "reference",
      "prim_path": "/World/Set/Hero", "variant_selection": "lod=high" },
    { "component": "env_backlot_v4", "arc_type": "payload",
      "prim_path": "/World/Env" }
  ]
}

Arc types: reference, payload, sublayer, inherit, specialize, variant. Only component is required.

The graph never descends below the published-asset boundary. prim_path and variant_selection are opaque edge properties — OWG stores them and does not interpret them. That boundary is what keeps a governance graph from turning into a scene graph.

Assurance and credentials

{
  "assurance": "attested",
  "credentials": { "scheme": "c2pa" }
}

Assurance states how strongly an asset's identity is backed. It uses the same three levels, and the same rule about confidence, as relationships:

LevelMeaningRequires confidence + method
attestedA cryptographically verified content credential backs thisNo
assertedDeclared by a participant or system, without cryptographic attestationNo
inferredIdentity established by a matcher rather than declaredYes

An inferred identity carries its score and method, exactly as a proposed edge does:

{
  "id": "recovered_plate_0140",
  "identity": "sha256:9f2c…",
  "assurance": "inferred",
  "confidence": 0.79,
  "method": "m-corroborated-2"
}

The schema enforces the pairing in both directions: inferred without confidence and method is a validation error, and attested or asserted with them is also an error — a confidence score on a human assertion is meaningless.

Offline and physical steps default to asserted: a manually logged camera card is an assertion, whereas signed device output is an attestation. The ingest station — where physical provenance becomes digital provenance — is the boundary where one can become the other.

Note that the C2PA declaration lives on the asset, not on the task that produced it.