Examples
Complete annotated workflows from the conformance corpus — atomic, generative, linear chain, and conditional with a human gate.
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 --jsonThese 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_bypoints at the task,tasks[].producedpoints at the asset. The task side is authoritative. version_relation: "representation"pluspredecessoris 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.subgraphwithformat: "comfyui"encapsulates the entire node network as one governed task whose interior is stored opaquely.executor.refnames the tool;subgraph.refnames 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 graph —
human,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 arepresentation, MP3 → publish record is aderivation. Three different relationships, three different meanings. recordhas noused— it is an origin task. Assets can enter the graph by being captured.failure_mode: "CONTINUE"onnormalizelets other branches proceed.publish_apihas noorganization_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:
- The condition resolves.
"when": "$.params.add_captions == true"reads a parameter the document declares inparams. An earlier version referenced an undeclared parameter, which v0.9 rejects asOWG_UNRESOLVED_REFERENCE— the reference grammar is validated, not merely stored. See Reference syntax. publishdoes not claim a lineage edge it cannot guarantee.captions_srtis not inused[], becausecaptionmay be skipped. The captions path is passed throughinputsand gated withexists(), so the executor learns whether captions exist without the graph asserting an edge to an asset that may never have been produced.- The agent has an accountability chain.
caption_agentcarriesoperated_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-sportsandusd-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.