{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://openawf.org/schemas/0.1.0/schema.yaml",
  "title": "OpenAWF Workflow",
  "description": "Structural schema for an OpenAWF workflow document. Non-normative: the specification prose is the source of truth. Some constraints (a start task that exists, edges that resolve to defined tasks, at least one terminal node) cannot be expressed here and are enforced by a conformant validator.",
  "type": "object",
  "required": [
    "openawf",
    "name",
    "start",
    "orchestration",
    "tasks"
  ],
  "additionalProperties": false,
  "properties": {
    "openawf": {
      "description": "The OpenAWF version this document is written against.",
      "type": "string",
      "const": "0.1.0"
    },
    "name": {
      "type": "string",
      "minLength": 1
    },
    "summary": {
      "type": "string"
    },
    "model": {
      "description": "The model every task runs on unless the task overrides it.",
      "type": "string"
    },
    "start": {
      "description": "The name of the task the flow begins at.",
      "type": "string",
      "minLength": 1
    },
    "orchestration": {
      "description": "The task graph. Each key is a task name; its value is the node: the transition out of that task, plus optional per-node execution policy.",
      "type": "object",
      "minProperties": 1,
      "additionalProperties": {
        "$ref": "#/$defs/transition"
      }
    },
    "tasks": {
      "description": "Task definitions keyed by name. Each entry is an inline task or a $ref to one.",
      "type": "object",
      "minProperties": 1,
      "additionalProperties": {
        "$ref": "#/$defs/taskEntry"
      }
    },
    "mcp": {
      "description": "External MCP servers the workflow depends on, keyed by name. Declares the requirement; connection details (command, url, credentials) are resolved by the runner and are not part of the document.",
      "type": "object",
      "additionalProperties": {
        "$ref": "#/$defs/mcpServer"
      }
    },
    "version": {
      "description": "The workflow's version (identity). A human version string.",
      "type": "string",
      "minLength": 1
    },
    "sha": {
      "description": "Content hash of the workflow, algorithm-prefixed (e.g. sha256-...). null until sealed. Recomputed to verify the content is unchanged.",
      "$ref": "#/$defs/sha"
    },
    "source": {
      "description": "Where this workflow is fetched from (url, path, or registry id). Omitted when the workflow is authored in place rather than referenced.",
      "type": "string",
      "minLength": 1
    }
  },
  "$defs": {
    "sha": {
      "description": "A content hash, algorithm-prefixed, or null until sealed.",
      "type": [
        "string",
        "null"
      ],
      "pattern": "^(sha256|sha384|sha512)-.+"
    },
    "transition": {
      "description": "Where a task goes next. null ends the flow; an edge is an unconditional transition; an object mapping outcomes to edges is a branch. An edge is a task name, or an object naming the task with per-edge execution policy.",
      "oneOf": [
        {
          "type": "null"
        },
        {
          "$ref": "#/$defs/edge"
        },
        {
          "$ref": "#/$defs/branch"
        }
      ]
    },
    "edge": {
      "description": "A single transition to a task. A bare string names the task; the object form names it under `task` and adds per-edge execution policy.",
      "oneOf": [
        {
          "type": "string",
          "minLength": 1
        },
        {
          "type": "object",
          "required": [
            "task"
          ],
          "additionalProperties": false,
          "properties": {
            "task": {
              "description": "The task this edge transitions to.",
              "type": "string",
              "minLength": 1
            },
            "retries": {
              "description": "Attempts after the first failure before the task fails hard. null (the default) retries indefinitely; 0 means a single attempt.",
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0,
              "default": null
            },
            "session": {
              "description": "How the task behaves when reached through this edge. \"fresh\" starts a new context; \"resume\" keeps the prior session's context.",
              "type": "string",
              "enum": [
                "fresh",
                "resume"
              ],
              "default": "fresh"
            }
          }
        }
      ]
    },
    "branch": {
      "description": "A map from each emitted outcome to the edge it takes. \"task\" is reserved (it marks an edge object), so no outcome may be named task.",
      "type": "object",
      "minProperties": 1,
      "propertyNames": {
        "not": {
          "const": "task"
        }
      },
      "additionalProperties": {
        "$ref": "#/$defs/edge"
      }
    },
    "taskEntry": {
      "oneOf": [
        {
          "$ref": "#/$defs/task"
        },
        {
          "$ref": "#/$defs/ref"
        }
      ]
    },
    "ref": {
      "description": "A reference to a task defined elsewhere (file path, URL, or id).",
      "type": "object",
      "required": [
        "$ref"
      ],
      "additionalProperties": false,
      "properties": {
        "$ref": {
          "type": "string",
          "minLength": 1
        }
      }
    },
    "task": {
      "description": "An inline task definition.",
      "type": "object",
      "required": [
        "body"
      ],
      "additionalProperties": false,
      "properties": {
        "version": {
          "description": "The task's version (identity). A human version string.",
          "type": "string",
          "minLength": 1
        },
        "sha": {
          "description": "Content hash of the task, algorithm-prefixed. null until sealed.",
          "$ref": "#/$defs/sha"
        },
        "source": {
          "description": "Where this task is fetched from (url, path, or registry id). Omitted when the task is authored in place.",
          "type": "string",
          "minLength": 1
        },
        "summary": {
          "type": "string"
        },
        "input": {
          "description": "JSON Schema the incoming data must satisfy. Absent when the task takes no input.",
          "type": "object"
        },
        "output": {
          "description": "JSON Schema the task's output must satisfy. Absent when unconstrained.",
          "type": "object"
        },
        "model": {
          "description": "Overrides the workflow model for this task.",
          "type": "string"
        },
        "outcomes": {
          "description": "The outcomes this task may emit. Absent or empty when the task does not branch.",
          "type": "array",
          "items": {
            "type": "string",
            "minLength": 1
          },
          "uniqueItems": true
        },
        "uses": {
          "description": "Names of MCP servers (declared in the top-level mcp block) this task requires.",
          "type": "array",
          "items": {
            "type": "string",
            "minLength": 1
          },
          "uniqueItems": true
        },
        "body": {
          "description": "The tool-agnostic prompt.",
          "type": "string",
          "minLength": 1
        }
      }
    },
    "mcpServer": {
      "description": "A declared dependency on an external MCP server.",
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "transport": {
          "description": "The MCP transport. A hint; connection details are resolved by the runner.",
          "type": "string",
          "enum": [
            "stdio",
            "http",
            "sse"
          ]
        },
        "tools": {
          "description": "The tools this workflow uses from the server. \"*\" (the default when omitted) grants all of the server's tools.",
          "oneOf": [
            {
              "const": "*"
            },
            {
              "type": "array",
              "items": {
                "type": "string",
                "minLength": 1
              },
              "uniqueItems": true
            }
          ],
          "default": "*"
        }
      }
    }
  }
}
