Open Workflow GraphPre-release
Implementing

Examples

Complete annotated workflows from the conformance corpus — atomic, generative, linear chain, and conditional with a human gate.

View as markdownMachine-readable source for agents and scripted implementers

Every document below comes from the conformance corpus — the workflows that run as a regression suite, so they cannot silently drift from the schema.

All 22 are downloadable, not just the four annotated here: /corpus/index.json lists them with task, asset and participant counts, and each is at /corpus/<file>. Fetch one as a starting point rather than retyping from this page.

curl -O https://openworkflowgraph.org/corpus/W05.owg.json
owg-validate W05.owg.json --json

These are the corpus documents brought up to v0.9 — every one validates against the current schema. Where an earlier iteration of a document omitted something v0.9 requires, the omission has been corrected here and the correction is noted, because a specification's own examples should obey it.

W01 — atomic single task

The simplest complete workflow: transcode one file. One task, one participant, one input, one output.

{
  "$schema": "https://openworkflowgraph.org/schemas/core/v0.9.json",
  "owg_version": "0.9",
  "id": "W01-transcode-mov-mp4",
  "profiles": ["core", "cloud-services"],
  "description": "The simplest possible OWG workflow: transcode one source file MOV→MP4. One task, one participant, one input, one output.",
  "objective": "Produce an MP4 delivery from a MOV source.",
  "organizations": [
    { "id": "org_mediasvc", "name": "Example Media Services" }
  ],
  "participants": [
    { "id": "transcode_svc", "kind": "service", "name": "Transcode Service", "organization_id": "org_mediasvc" }
  ],
  "infrastructure": [
    { "id": "cloud_platform", "type": "saas_platform", "owner": "org_mediasvc" }
  ],
  "assets": [
    {
      "id": "source_mov", "role": "source", "type": "video.master",
      "content_type": "video/quicktime",
      "storage": { "provider": "s3", "locator": "s3://studio-media/in/clip.mov", "zone": "us-east-2" }
    },
    {
      "id": "delivery_mp4", "role": "delivery", "type": "video.delivery",
      "content_type": "video/mp4",
      "version_relation": "representation", "predecessor": "source_mov",
      "produced_by": "transcode",
      "storage": { "provider": "s3", "locator": "s3://studio-media/out/clip.mp4", "zone": "us-east-2" }
    }
  ],
  "tasks": [
    {
      "id": "transcode",
      "label": "Transcode MOV → MP4",
      "executor": { "type": "service", "ref": "transcode", "environment": "saas" },
      "performed_by": "transcode_svc",
      "ran_on": "cloud_platform",
      "used": ["source_mov"],
      "produced": ["delivery_mp4"],
      "failure_mode": "HALT",
      "billing": { "tier": "standard", "unit": "per_job" }
    }
  ]
}

What to take from it:

  • The five registries in order: organizations, participants, infrastructure, assets, tasks.
  • The double linkage between assets and tasks — assets[].produced_by points at the task, tasks[].produced points at the asset. The task side is authoritative.
  • version_relation: "representation" plus predecessor is the whole lineage statement. An MP4 of a MOV is a format change, not a revision.
  • Assets carry storage.locator, so nothing moved in order to be governed.

W03 — generative task with a subgraph

A single generative step, encapsulating a whole node graph, producing a credentialed asset.

{
  "$schema": "https://openworkflowgraph.org/schemas/core/v0.9.json",
  "owg_version": "0.9",
  "id": "W03",
  "project_id": "generative-ai",
  "profiles": ["core", "generative-ai"],
  "description": "W03 (T0 Atomic) — Single text→image via one ComfyUI graph. One generative task on cloud GPU, producing a C2PA-credentialed asset.",
  "objective": "Generate a single AI image from a text prompt with C2PA provenance.",
  "organizations": [
    { "id": "org_mediasvc", "name": "Example Media Services" }
  ],
  "participants": [
    { "id": "s.okafor", "kind": "human", "name": "Art Director", "role": "art-director", "organization_id": "org_mediasvc" },
    { "id": "concept_bot", "kind": "agent", "name": "SDXL Generator", "operated_by": "s.okafor", "organization_id": "org_mediasvc" }
  ],
  "infrastructure": [
    { "id": "gpu_cloud", "type": "gpu_compute", "owner": "org_mediasvc", "spec": "cloud GPU" }
  ],
  "assets": [
    {
      "id": "text_prompt", "role": "source", "type": "text.prompt",
      "content_type": "text/plain"
    },
    {
      "id": "generate_out", "role": "generated_image", "type": "image.generated",
      "content_type": "image/png",
      "version_relation": "derivation", "predecessor": "text_prompt",
      "produced_by": "generate",
      "credentials": { "scheme": "c2pa" }
    }
  ],
  "tasks": [
    {
      "id": "generate",
      "label": "SDXL text→image graph",
      "executor": { "type": "comfyui_graph", "ref": "sdxl_txt2img", "environment": "cloud" },
      "ai_role": "generative",
      "performed_by": "concept_bot",
      "ran_on": "gpu_cloud",
      "used": ["text_prompt"],
      "produced": ["generate_out"],
      "failure_mode": "HALT",
      "billing": { "tier": "custom", "unit": "per_job" },
      "subgraph": { "format": "comfyui", "ref": "graphs/sdxl_txt2img.json" }
    }
  ]
}

What to take from it:

  • profiles: ["core", "generative-ai"] declares the vocabulary in use.
  • The agent carries operated_by, chaining to a named human. The generative-AI profile requires this, and it is what makes the generated image attributable to a person rather than to a process.
  • ai_role: "generative" is declared explicitly. Without it the task would fail compliance rule R1 — an AI-capable executor with no declaration is a finding, not an assumption of innocence.
  • subgraph with format: "comfyui" encapsulates the entire node network as one governed task whose interior is stored opaquely.
  • executor.ref names the tool; subgraph.ref names the interior. They describe different things and need not match.
  • credentials: { "scheme": "c2pa" } sits on the asset, not the task.
  • version_relation: "derivation" — an image from a prompt is a new thing acknowledging its source, not a reformat.

W04 — linear chain across human, desktop, and SaaS

Four tasks, four executor types, two organizations. The first workflow where the executor abstraction earns its keep.

{
  "$schema": "https://openworkflowgraph.org/schemas/core/v0.9.json",
  "owg_version": "0.9",
  "id": "W04",
  "project_id": "audio-workflows",
  "profiles": ["core", "cloud-services"],
  "description": "W04 (T1 Linear Chain) — Record raw podcast audio (human), edit in DAW (local_app), normalise levels (cloud service), publish to an RSS host (SaaS API).",
  "objective": "Produce and publish a finished podcast episode to an RSS host.",
  "organizations": [
    { "id": "org_studio_media", "name": "Example Studio Media" },
    { "id": "org_mediasvc", "name": "Example Media Services" }
  ],
  "participants": [
    { "id": "podcast_host", "kind": "human", "name": "Podcast Host", "role": "host", "organization_id": "org_studio_media" },
    { "id": "audacity_app", "kind": "service", "name": "Audacity", "organization_id": "org_studio_media" },
    { "id": "media_svc", "kind": "service", "name": "Media Services", "organization_id": "org_mediasvc" },
    { "id": "publish_api", "kind": "service", "name": "Example Publishing" }
  ],
  "infrastructure": [
    { "id": "studio_ws", "type": "workstation", "owner": "org_studio_media", "apps": ["audacity"] },
    { "id": "cloud_platform", "type": "saas_platform", "owner": "org_mediasvc" },
    { "id": "publish_platform", "type": "saas_platform" }
  ],
  "assets": [
    { "id": "raw_wav", "role": "source", "type": "audio.raw",
      "content_type": "audio/wav", "produced_by": "record" },
    { "id": "edited_wav", "role": "edited_audio", "type": "audio.edited",
      "content_type": "audio/wav",
      "version_relation": "revision", "predecessor": "raw_wav",
      "produced_by": "edit" },
    { "id": "episode_mp3", "role": "delivery", "type": "audio.delivery",
      "content_type": "audio/mpeg",
      "version_relation": "representation", "predecessor": "edited_wav",
      "produced_by": "normalize" },
    { "id": "publish_out", "role": "publish_record", "type": "record.json",
      "content_type": "application/json",
      "version_relation": "derivation", "predecessor": "episode_mp3",
      "produced_by": "publish" }
  ],
  "tasks": [
    {
      "id": "record",
      "label": "Record raw podcast audio",
      "executor": { "type": "human", "environment": "manual" },
      "performed_by": "podcast_host",
      "ran_on": "studio_ws",
      "produced": ["raw_wav"],
      "failure_mode": "HALT"
    },
    {
      "id": "edit",
      "label": "Edit recording in Audacity",
      "executor": { "type": "local_app", "ref": "audacity", "environment": "desktop" },
      "performed_by": "audacity_app",
      "ran_on": "studio_ws",
      "depends_on": ["record"],
      "used": ["raw_wav"],
      "produced": ["edited_wav"],
      "failure_mode": "HALT"
    },
    {
      "id": "normalize",
      "label": "Normalise loudness and encode MP3",
      "executor": { "type": "service", "ref": "transcode_from_url", "environment": "saas" },
      "performed_by": "media_svc",
      "ran_on": "cloud_platform",
      "depends_on": ["edit"],
      "used": ["edited_wav"],
      "produced": ["episode_mp3"],
      "failure_mode": "CONTINUE",
      "billing": { "tier": "standard", "unit": "per_minute" },
      "retry": { "max_attempts": 2, "initial_interval_seconds": 5 }
    },
    {
      "id": "publish",
      "label": "Publish episode to host",
      "executor": { "type": "saas_api", "ref": "publish_upload", "environment": "saas" },
      "performed_by": "publish_api",
      "ran_on": "publish_platform",
      "depends_on": ["normalize"],
      "used": ["episode_mp3"],
      "produced": ["publish_out"],
      "failure_mode": "HALT",
      "retry": { "max_attempts": 3, "initial_interval_seconds": 10, "backoff_coefficient": 2.0, "retryable_errors": ["RATE_LIMIT", "TRANSIENT_ERROR"] }
    }
  ]
}

What to take from it:

  • Four executor types in one graphhuman, local_app, service, saas_api — scheduled and attributed identically. This is the central claim of the model, made concrete.
  • The version chain is typed at every hop: raw → edited is a revision, edited → MP3 is a representation, MP3 → publish record is a derivation. Three different relationships, three different meanings.
  • record has no used — it is an origin task. Assets can enter the graph by being captured.
  • failure_mode: "CONTINUE" on normalize lets other branches proceed.
  • publish_api has no organization_id — a third party. Legitimate, but nothing in the graph vouches for it.
  • Two organizations means this document already crosses a company boundary.

W05 — conditional execution and a human review gate

Five tasks with a conditional AI step, a human gate, and fan-in.

{
  "$schema": "https://openworkflowgraph.org/schemas/core/v0.9.json",
  "owg_version": "0.9",
  "id": "W05",
  "project_id": "video-workflows",
  "profiles": ["core", "cloud-services"],
  "description": "W05 (T1 Linear + Conditional) — Import UGC footage (local Premiere), colour grade and edit, conditionally generate captions via AI agent, thumbnail review by human, then publish.",
  "objective": "Edit, caption, and publish a UGC video.",
  "params": {
    "add_captions": { "type": "boolean", "required": false, "default": false }
  },
  "organizations": [
    { "id": "org_studio_media", "name": "Example Studio Media" }
  ],
  "participants": [
    { "id": "premiere_app", "kind": "service", "name": "Premiere Pro", "organization_id": "org_studio_media" },
    { "id": "caption_agent", "kind": "agent", "name": "Caption Agent", "operated_by": "creator", "organization_id": "org_studio_media" },
    { "id": "creator", "kind": "human", "name": "Creator", "role": "creator", "organization_id": "org_studio_media" },
    { "id": "youtube_api", "kind": "service", "name": "YouTube" }
  ],
  "infrastructure": [
    { "id": "edit_ws", "type": "workstation", "owner": "org_studio_media", "apps": ["premiere"] },
    { "id": "agent_cloud", "type": "saas_platform", "owner": "org_studio_media" },
    { "id": "youtube_saas", "type": "saas_platform" }
  ],
  "assets": [
    { "id": "project_prproj", "role": "project", "type": "project.premiere",
      "content_type": "application/octet-stream", "produced_by": "ingest" },
    { "id": "master_mp4", "role": "edited_master", "type": "video.master",
      "content_type": "video/mp4",
      "version_relation": "derivation", "predecessor": "project_prproj",
      "produced_by": "edit" },
    { "id": "captions_srt", "role": "captions", "type": "text.captions",
      "content_type": "text/vtt",
      "version_relation": "derivation", "predecessor": "master_mp4",
      "produced_by": "caption" },
    { "id": "thumbnail_jpg", "role": "thumbnail", "type": "image.thumbnail",
      "content_type": "image/jpeg",
      "version_relation": "derivation", "predecessor": "master_mp4",
      "produced_by": "thumbnail_review" },
    { "id": "publish_out", "role": "publish_record", "type": "record.json",
      "content_type": "application/json",
      "version_relation": "derivation", "predecessor": "master_mp4",
      "produced_by": "publish" }
  ],
  "tasks": [
    {
      "id": "ingest",
      "label": "Import UGC footage into Premiere",
      "executor": { "type": "local_app", "ref": "premiere", "environment": "desktop" },
      "performed_by": "premiere_app",
      "ran_on": "edit_ws",
      "produced": ["project_prproj"],
      "failure_mode": "HALT"
    },
    {
      "id": "edit",
      "label": "Edit, grade and export master",
      "executor": { "type": "local_app", "ref": "premiere", "environment": "desktop" },
      "performed_by": "premiere_app",
      "ran_on": "edit_ws",
      "depends_on": ["ingest"],
      "used": ["project_prproj"],
      "produced": ["master_mp4"],
      "failure_mode": "HALT"
    },
    {
      "id": "caption",
      "label": "AI generate captions (SRT)",
      "executor": { "type": "agent", "ref": "generate_captions", "environment": "saas" },
      "ai_role": "generative",
      "performed_by": "caption_agent",
      "ran_on": "agent_cloud",
      "depends_on": ["edit"],
      "when": "$.params.add_captions == true",
      "used": ["master_mp4"],
      "produced": ["captions_srt"],
      "failure_mode": "SKIP_DEPENDENTS"
    },
    {
      "id": "thumbnail_review",
      "label": "Creator reviews thumbnail",
      "type": "review",
      "executor": { "type": "human", "environment": "manual" },
      "performed_by": "creator",
      "ran_on": "edit_ws",
      "depends_on": ["edit"],
      "used": ["master_mp4"],
      "produced": ["thumbnail_jpg"],
      "failure_mode": "HALT"
    },
    {
      "id": "publish",
      "label": "Upload to YouTube",
      "executor": { "type": "saas_api", "ref": "youtube_upload", "environment": "saas" },
      "performed_by": "youtube_api",
      "ran_on": "youtube_saas",
      "depends_on": ["edit", "thumbnail_review", "caption"],
      "used": ["master_mp4", "thumbnail_jpg"],
      "inputs": {
        "captions_key": "$.tasks.caption.outputs.output_key",
        "include_captions": "exists($.tasks.caption.outputs.output_key)"
      },
      "produced": ["publish_out"],
      "failure_mode": "HALT",
      "retry": { "max_attempts": 3, "initial_interval_seconds": 30, "backoff_coefficient": 2.0, "retryable_errors": ["RATE_LIMIT", "QUOTA_EXCEEDED", "TRANSIENT_ERROR"] }
    }
  ]
}

What to take from it:

  • "type": "review" marks the human gate. The graph knows this is a decision point, not just work.
  • depends_on: ["edit", "thumbnail_review"] is fan-in — two branches converge.
  • failure_mode: "SKIP_DEPENDENTS" on the optional caption step contains the blast radius.

Three details worth studying, because each is a rule the earlier version of this document broke:

  1. The condition resolves. "when": "$.params.add_captions == true" reads a parameter the document declares in params. An earlier version referenced an undeclared parameter, which v0.9 rejects as OWG_UNRESOLVED_REFERENCE — the reference grammar is validated, not merely stored. See Reference syntax.
  2. publish does not claim a lineage edge it cannot guarantee. captions_srt is not in used[], because caption may be skipped. The captions path is passed through inputs and gated with exists(), so the executor learns whether captions exist without the graph asserting an edge to an asset that may never have been produced.
  3. The agent has an accountability chain. caption_agent carries operated_by: "creator", so the generated captions trace to a person.

The second is the subtle one, and the mistake people make most often. depends_on establishes ordering; used[] asserts that consumption actually happened. Conflating them produces lineage that reads as fact but is conditional.

Going further

Other corpus documents worth reading:

  • W14 — the headline case. Ten tasks, LoRA training, two human gates, C2PA signing.
  • helios-concept-dev — the only document exercising the full QC re-route vocabulary (on_pass, on_fail, reroute_feedback, max_reroutes).
  • tams-live-sports and usd-scene-composition — the standards bindings in practice: a growing asset under governance, and USD composition arcs as typed edges.
  • europa-project, helios-project — registry-only documents with zero tasks.