# Quickstart

> Write a valid OWG document, validate it, and understand what the graph now knows — in about ten minutes.

This walks through the smallest complete OWG document, then adds the pieces that make it useful. You need Node 20 or newer.

## 1. What you need

A JSON editor and a validator that implements the [four validation passes](/validation).
Pointing your editor at the schema gives you completion and inline errors as you type:

```json
{ "$schema": "https://openworkflowgraph.org/schemas/core/v0.92.json" }
```

## 2. The smallest complete document

A single task that transcodes one file. Save as `hello.owg.json`:

```json
{
  "$schema": "https://openworkflowgraph.org/schemas/core/v0.92.json",
  "owg_version": "0.92",
  "id": "hello-transcode",
  "profiles": ["core", "cloud-services"],
  "description": "Transcode one source file MOV→MP4.",
  "objective": "Produce an MP4 delivery from a MOV source.",

  "organizations": [
    { "id": "org_mine", "name": "My Facility" }
  ],

  "participants": [
    { "id": "transcode_svc", "kind": "service", "name": "Transcode Service",
      "organization_id": "org_mine" }
  ],

  "infrastructure": [
    { "id": "cloud_saas", "type": "saas_platform", "owner": "org_mine" }
  ],

  "assets": [
    {
      "id": "source_mov",
      "role": "source",
      "type": "video.master",
      "content_type": "video/quicktime",
      "storage": { "provider": "s3", "locator": "s3://my-bucket/in/clip.mov" }
    },
    {
      "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://my-bucket/out/clip.mp4" }
    }
  ],

  "tasks": [
    {
      "id": "transcode",
      "label": "Transcode MOV → MP4",
      "type": "work",
      "executor": { "type": "service", "ref": "transcode",
                    "environment": "saas" },
      "ai_role": "none",
      "performed_by": "transcode_svc",
      "ran_on": "cloud_saas",
      "used": ["source_mov"],
      "produced": ["delivery_mp4"],
      "failure_mode": "HALT"
    }
  ]
}
```

Three things to notice:

- **`used` and `produced` are the provenance edges.** They are what make this a graph rather than a list. The asset's `produced_by` mirrors the task's `produced[]` — the task is authoritative.
- **`version_relation: "representation"`** says the MP4 is a *format change of the same content*, not a revision of it. That distinction matters more than it looks — see [Assets and versioning](/assets-and-versioning#typed-version-relations).
- **`ai_role: "none"`** is declared explicitly rather than left absent. AI involvement is never inferred from the executor type.

## 3. Validate it

```bash
owg-validate hello.owg.json
```

```
✓ Valid — "hello-transcode" (v0.92): 1 task, 2 assets, 1 participant
```

Now break it deliberately. Change `"used": ["source_mov"]` to `"used": ["source_mv"]` and re-run:

```
✗ Invalid — 1 error(s):

  [OWG_UNKNOWN_REFERENCE] /tasks/0/used/0
    Task "transcode" uses "source_mv", which doesn't exist in this document.
    Did you mean "source_mov"?
```

Try a misspelled field too — change `performed_by` to `performed_bye`:

```
✗ Invalid — 1 error(s):

  [OWG_UNKNOWN_PROPERTY] /tasks/0
    Unknown property "performed_bye". Did you mean "performed_by"?
```

Both matter more than they look. Unknown properties are errors rather than silently accepted fields, which is what stops a generated document from validating and then doing nothing. See [Validation](/validation).

> **Implementation note.** The reference validator currently implements the structural pass fully and the referential, graph, and expression passes partially. Until they land, run the [pre-flight checklist](/for-agents#pre-flight-checklist) yourself.

## 4. What the graph now knows

From those few lines, without anything else being recorded:

- **Lineage** — `delivery_mp4` came from `source_mov` via `transcode`, as a format representation.
- **Attribution** — `transcode_svc` performed it, on behalf of `org_mine`.
- **Placement** — it ran on `cloud_saas`, so cost attributes somewhere real.
- **Location** — both assets carry locators, so nothing had to move to be governed.

None of that required a separate provenance step. These are [structural edges](/concepts#edges-come-in-two-kinds) — they fall out of describing the work.

## 5. Add a chain and a human gate

Real workflows have dependencies and decisions. Add a review task:

```json
{
  "tasks": [
    {
      "id": "transcode",
      "executor": { "type": "service" },
      "performed_by": "transcode_svc",
      "used": ["source_mov"],
      "produced": ["delivery_mp4"],
      "failure_mode": "HALT"
    },
    {
      "id": "qc",
      "type": "qc",
      "executor": { "type": "service", "ref": "qc_validate" },
      "performed_by": "transcode_svc",
      "depends_on": ["transcode"],
      "used": ["delivery_mp4"],
      "checks": ["duration_match", "codec_compliance"],
      "on_pass": "approve",
      "on_fail": "transcode",
      "max_reroutes": 2
    },
    {
      "id": "approve",
      "type": "review",
      "executor": { "type": "human" },
      "performed_by": "a.singh",
      "depends_on": ["qc"],
      "used": ["delivery_mp4"],
      "failure_mode": "HALT"
    }
  ]
}
```

Add `a.singh` to `participants` as `kind: "human"` with a `role`, and the document stays valid.

The `qc` task is a **gate**: it routes on outcome rather than merely succeeding, and `max_reroutes` caps how many times it can send work back. A human review is an ordinary task with `executor.type: "human"` — the same shape as a machine task, which is what lets a schedule and a cost model span both. See [Gates and re-routes](/tasks#gates-and-re-routes).

## 6. Add an AI step

```json
{
  "id": "generate_thumb",
  "type": "work",
  "executor": { "type": "comfyui_graph", "environment": "cloud" },
  "ai_role": "generative",
  "performed_by": "agent_thumb",
  "ran_on": "gpu_cloud",
  "depends_on": ["approve"],
  "used": ["delivery_mp4"],
  "produced": ["thumb_png"],
  "subgraph": "graphs/sdxl_thumb.json"
}
```

With `agent_thumb` declared as an agent carrying `operated_by`:

```json
{ "id": "agent_thumb", "kind": "agent", "operated_by": "a.singh",
  "organization_id": "org_mine" }
```

And the produced asset carrying credentials:

```json
{ "id": "thumb_png", "type": "image.generated",
  "version_relation": "derivation", "predecessor": "delivery_mp4",
  "produced_by": "generate_thumb",
  "credentials": { "scheme": "c2pa" } }
```

That gives you three things at once:

1. **Accountability** — the agent's work traces to `a.singh` via `operated_by`.
2. **Disclosure** — `ai_role: "generative"` means an [Article 50 manifest](/compliance) can be computed from lineage.
3. **Encapsulation** — the whole node graph is [one task with an interior](/subgraphs-and-turnovers), not fifty governed nodes.

## Next steps

- [Core concepts](/concepts) — the model behind what you just wrote
- [Document structure](/specification) — every top-level field, parameters, and governance
- [Examples](/examples) — full annotated corpus workflows
- [For agents](/for-agents) — if you are a machine implementing this
- [Implementation considerations](/implementation-considerations) — the decisions left to you, with recommended approaches
- [Versioning and stability](/versioning-and-stability) — what you can rely on, and what will grow
