$schema: https://json-schema.org/draft/2020-12/schema
$id: https://opendataproducts.org/odpr-v1.0/schema/odpr.yaml
title: Data Product Recipe Specification
description: Lightweight workflow recipes for repeatable data product delivery.
type: object
additionalProperties: false
required:
  - schema
  - version
  - kind
properties:
  schema:
    type: string
    const: https://opendataproducts.org/odpr-v1.0/schema/odpr.yaml
  version:
    type: string
    const: "1.0"
  kind:
    type: string
    enum:
      - Recipe
      - RuntimeProfile
      - RecipeCatalog
      - DataProductRecipe
  recipe:
    $ref: "#/$defs/Recipe"
  runtimeProfile:
    $ref: "#/$defs/RuntimeProfile"
  recipeCatalog:
    $ref: "#/$defs/RecipeCatalog"
  dataProductRecipe:
    $ref: "#/$defs/DataProductRecipe"
oneOf:
  - required:
      - recipe
    properties:
      kind:
        const: Recipe
    not:
      anyOf:
        - required:
            - provider
        - required:
            - recipeCatalog
        - required:
            - dataProductRecipe
  - required:
      - runtimeProfile
    properties:
      kind:
        const: RuntimeProfile
    not:
      anyOf:
        - required:
            - recipe
        - required:
            - recipeCatalog
        - required:
            - dataProductRecipe
  - required:
      - recipeCatalog
    properties:
      kind:
        const: RecipeCatalog
    not:
      anyOf:
        - required:
            - recipe
        - required:
            - provider
        - required:
            - dataProductRecipe
  - required:
      - dataProductRecipe
    properties:
      kind:
        const: DataProductRecipe
    not:
      anyOf:
        - required:
            - recipe
        - required:
            - provider
        - required:
            - recipeCatalog
$defs:
  LocalizedText:
    type: object
    additionalProperties:
      type: string
    minProperties: 1
    properties:
      en:
        type: string
        minLength: 1
  Text:
    oneOf:
      - type: string
        minLength: 1
      - $ref: "#/$defs/LocalizedText"
  Metadata:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - id
      - name
    properties:
      id:
        type: string
        minLength: 1
      name:
        $ref: "#/$defs/LocalizedText"
      description:
        $ref: "#/$defs/LocalizedText"
      owner:
        type: string
      tags:
        type: array
        items:
          type: string
  NamedPath:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - id
      - path
    properties:
      id:
        type: string
        minLength: 1
      path:
        $ref: "#/$defs/RelativePath"
      description:
        $ref: "#/$defs/Text"
  RelativePath:
    type: string
    minLength: 1
    pattern: "^(?!/)(?!.*(^|/)\\.\\.(/|$)).+"
  RecipeScope:
    type: string
    enum:
      - data-product
      - catalog
      - graph
      - portfolio
  GraphNodeType:
    type: string
    enum:
      - DataProduct
      - BusinessObjective
      - UseCase
      - Signal
      - Policy
      - DataContract
      - DataService
      - API
      - Owner
      - System
      - "*"
  GraphTriggerAttributeValue:
    oneOf:
      - type: string
      - type: number
      - type: boolean
      - type: "null"
  GraphTriggerAttribute:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - name
    properties:
      name:
        type: string
        minLength: 1
        pattern: "^(?!\\*$).+"
      from:
        $ref: "#/$defs/GraphTriggerAttributeValue"
      to:
        $ref: "#/$defs/GraphTriggerAttributeValue"
    anyOf:
      - required:
          - from
      - required:
          - to
  GraphTriggerSubject:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    properties:
      nodeType:
        $ref: "#/$defs/GraphNodeType"
      edgeType:
        type: string
        minLength: 1
      fromNodeType:
        $ref: "#/$defs/GraphNodeType"
      toNodeType:
        $ref: "#/$defs/GraphNodeType"
      attribute:
        $ref: "#/$defs/GraphTriggerAttribute"
  GraphTriggerCondition:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - name
    properties:
      name:
        type: string
        minLength: 1
  GraphTrigger:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - source
      - event
    properties:
      source:
        type: string
        enum:
          - odpg
      event:
        type: string
        enum:
          - node.added
          - node.removed
          - node.attributeChanged
          - edge.added
          - edge.removed
          - edge.attributeChanged
          - graph.conditionMatched
      subject:
        $ref: "#/$defs/GraphTriggerSubject"
      condition:
        $ref: "#/$defs/GraphTriggerCondition"
    allOf:
      - if:
          properties:
            event:
              enum:
                - node.added
                - node.removed
          required:
            - event
        then:
          required:
            - subject
          properties:
            subject:
              required:
                - nodeType
      - if:
          properties:
            event:
              const: node.attributeChanged
          required:
            - event
        then:
          required:
            - subject
          properties:
            subject:
              required:
                - attribute
      - if:
          properties:
            event:
              enum:
                - edge.added
                - edge.removed
          required:
            - event
        then:
          required:
            - subject
          properties:
            subject:
              required:
                - edgeType
      - if:
          properties:
            event:
              const: edge.attributeChanged
          required:
            - event
        then:
          required:
            - subject
          properties:
            subject:
              required:
                - edgeType
                - attribute
      - if:
          properties:
            event:
              const: graph.conditionMatched
          required:
            - event
        then:
          required:
            - condition
  GraphContext:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - graphRef
      - start
    properties:
      graphRef:
        oneOf:
          - $ref: "#/$defs/RelativePath"
          - type: string
            pattern: "^https?://.+"
      start:
        type: string
        minLength: 1
      depth:
        type: integer
        minimum: 1
  ContextPolicy:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - format
    properties:
      format:
        type: string
        enum:
          - yaml
          - toon
          - gcf
          - auto
      fallback:
        type: array
        items:
          type: string
          enum:
            - yaml
            - toon
            - gcf
            - auto
  ExecutionPolicy:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    properties:
      mode:
        type: string
        enum:
          - local
          - hosted
          - hybrid
          - none
      runtimeRef:
        $ref: "#/$defs/RuntimeRef"
  RuntimeRef:
    type: string
    minLength: 1
    format: uri-reference
    pattern: "^(?=.*(?:/|#|:)).+$"
    description: URI-reference to an ODPR RuntimeProfile document. A fragment identifies the runtime profile when the target contains or exposes multiple profiles.
  Step:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - id
      - command
    properties:
      id:
        type: string
        minLength: 1
      command:
        type: string
        minLength: 1
      runtimeRef:
        $ref: "#/$defs/RuntimeRef"
      model:
        type: string
        minLength: 1
      context:
        $ref: "#/$defs/ContextPolicy"
      input:
        $ref: "#/$defs/RelativePath"
      output:
        $ref: "#/$defs/RelativePath"
      document:
        $ref: "#/$defs/RelativePath"
      kind:
        type: string
      graph:
        $ref: "#/$defs/RelativePath"
      start:
        type: string
        minLength: 1
      depth:
        type: integer
        minimum: 1
      languages:
        type: array
        minItems: 1
        items:
          type: string
          pattern: "^[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8})*$"
      defaultLanguage:
        type: string
        pattern: "^[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8})*$"
      objectives:
        type: array
        items:
          $ref: "#/$defs/RelativePath"
      useCases:
        type: array
        items:
          $ref: "#/$defs/RelativePath"
      signals:
        type: array
        items:
          $ref: "#/$defs/RelativePath"
      products:
        type: array
        items:
          $ref: "#/$defs/RelativePath"
      title:
        $ref: "#/$defs/Text"
      config:
        $ref: "#/$defs/RelativePath"
      prompts:
        $ref: "#/$defs/RelativePath"
      profile:
        type: string
      includeComponents:
        type: array
        items:
          type: string
      maxSourceChars:
        type: integer
        minimum: 1
      ollamaUrl:
        type: string
      html:
        $ref: "#/$defs/RelativePath"
      toon:
        $ref: "#/$defs/RelativePath"
      gcf:
        $ref: "#/$defs/RelativePath"
      contextGraph:
        $ref: "#/$defs/RelativePath"
      name:
        $ref: "#/$defs/Text"
      description:
        $ref: "#/$defs/Text"
      recursive:
        type: boolean
      validate:
        type: boolean
      allSources:
        type: boolean
      strictValidation:
        type: boolean
      optional:
        type: boolean
      timeoutSeconds:
        type: integer
        minimum: 1
    allOf:
      - $ref: "#/$defs/GenerateStepRule"
      - $ref: "#/$defs/OdpcBuildStepRule"
      - $ref: "#/$defs/OdpgBuildStepRule"
      - $ref: "#/$defs/OdpgAgentContextStepRule"
      - $ref: "#/$defs/OdpgRenderStepRule"
      - $ref: "#/$defs/PortfolioBuildStepRule"
      - $ref: "#/$defs/PortfolioRefreshStepRule"
      - $ref: "#/$defs/PortfolioSyncStepRule"
      - $ref: "#/$defs/PortfolioLocalizeStepRule"
      - $ref: "#/$defs/PortfolioRenderStepRule"
      - $ref: "#/$defs/PortfolioExplainStepRule"
      - $ref: "#/$defs/ValidateStepRule"
      - $ref: "#/$defs/ExplainStepRule"
      - if:
          properties:
            command:
              enum:
                - odpc.build
                - odpg.agent-context
                - odpg.render
                - portfolio.sync
                - portfolio.render
                - portfolio.explain
                - validate
                - explain
          required:
            - command
        then:
          not:
            anyOf:
              - required:
                  - runtimeRef
              - required:
                  - model
  GenerateStepRule:
    if:
      properties:
        command:
          const: generate
      required:
        - command
    then:
      required:
        - input
        - kind
        - output
      properties:
        kind:
          enum:
            - data-product-delivery-plan
            - product-reference
            - odps-product
            - use-case
            - objective
            - signal
            - graph
  OdpcBuildStepRule:
    if:
      properties:
        command:
          const: odpc.build
      required:
        - command
    then:
      required:
        - input
        - output
  OdpgBuildStepRule:
    if:
      properties:
        command:
          const: odpg.build
      required:
        - command
    then:
      required:
        - input
        - output
  OdpgAgentContextStepRule:
    if:
      properties:
        command:
          const: odpg.agent-context
      required:
        - command
    then:
      required:
        - graph
        - start
        - output
  OdpgRenderStepRule:
    if:
      properties:
        command:
          const: odpg.render
      required:
        - command
    then:
      required:
        - graph
        - output
  PortfolioBuildStepRule:
    if:
      properties:
        command:
          const: portfolio.build
      required:
        - command
    then:
      required:
        - output
      anyOf:
        - required:
            - objectives
        - required:
            - useCases
        - required:
            - signals
        - required:
            - products
  PortfolioRefreshStepRule:
    if:
      properties:
        command:
          const: portfolio.refresh
      required:
        - command
    then:
      properties: {}
  PortfolioSyncStepRule:
    if:
      properties:
        command:
          const: portfolio.sync
      required:
        - command
    then:
      properties: {}
  PortfolioLocalizeStepRule:
    if:
      properties:
        command:
          const: portfolio.localize
      required:
        - command
    then:
      required:
        - languages
  PortfolioRenderStepRule:
    if:
      properties:
        command:
          const: portfolio.render
      required:
        - command
    then:
      properties: {}
  PortfolioExplainStepRule:
    if:
      properties:
        command:
          const: portfolio.explain
      required:
        - command
    then:
      properties: {}
  ValidateStepRule:
    if:
      properties:
        command:
          const: validate
      required:
        - command
    then:
      required:
        - document
  ExplainStepRule:
    if:
      properties:
        command:
          const: explain
      required:
        - command
    then:
      required:
        - document
  Gate:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - id
      - type
    properties:
      id:
        type: string
        minLength: 1
      type:
        type: string
        enum:
          - validation
          - quality
          - review
          - publication
      required:
        type: boolean
        default: false
      description:
        $ref: "#/$defs/Text"
  ReviewPolicy:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    properties:
      required:
        type: boolean
      mode:
        type: string
        enum:
          - human
          - agent
          - both
          - none
      reviewer:
        type: string
      instructions:
        $ref: "#/$defs/Text"
  RunPolicy:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    properties:
      timeoutSeconds:
        type: integer
        minimum: 1
      stopOnFailure:
        type: boolean
        default: true
      maxRetries:
        type: integer
        minimum: 0
  RuntimeProfile:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - provider
      - providers
    properties:
      provider:
        type: string
        minLength: 1
      model:
        type: string
        minLength: 1
      input:
        type: string
        minLength: 1
      output:
        type: string
        minLength: 1
      prompts:
        type: string
        minLength: 1
      baseUrl:
        type: string
        minLength: 1
      version:
        type: string
        minLength: 1
      maxTokens:
        type: integer
        minimum: 1
      modelPath:
        type: string
        minLength: 1
      contextWindow:
        type: integer
        minimum: 1
      gpuLayers:
        type: integer
      portfolio:
        $ref: "#/$defs/RuntimeProfilePortfolioPolicy"
      providers:
        type: object
        minProperties: 1
        additionalProperties:
          $ref: "#/$defs/RuntimeProviderProfile"
  RuntimeProviderProfile:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    properties:
      type:
        type: string
        enum:
          - anthropic
          - llama-cpp
          - ollama
          - openai
          - openai-chat
      model:
        type: string
        minLength: 1
      baseUrl:
        type: string
        minLength: 1
      apiKeyEnv:
        type: string
        minLength: 1
      version:
        type: string
        minLength: 1
      maxTokens:
        type: integer
        minimum: 1
      modelPath:
        type: string
        minLength: 1
      contextWindow:
        type: integer
        minimum: 1
      gpuLayers:
        type: integer
  RuntimeProfilePortfolioPolicy:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    properties:
      sourceBudget:
        $ref: "#/$defs/RuntimeProfilePortfolioSourceBudget"
      privacy:
        $ref: "#/$defs/RuntimeProfilePortfolioPrivacy"
  RuntimeProfilePortfolioSourceBudget:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    properties:
      maxSourceChars:
        type: integer
        minimum: 1
      maxPromptChars:
        type: integer
        minimum: 1
  RuntimeProfilePortfolioPrivacy:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    properties:
      obfuscatePersonalData:
        type: boolean
  RecipeCatalogEntry:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - path
      - id
      - version
      - type
      - name
    properties:
      path:
        $ref: "#/$defs/RelativePath"
      id:
        type: string
        minLength: 1
      groupRef:
        type: string
        minLength: 1
      version:
        type: string
        pattern: "^[0-9]+\\.[0-9]+\\.[0-9]+([A-Za-z0-9.+-]*)?$"
      type:
        type: string
        minLength: 1
      scope:
        $ref: "#/$defs/RecipeScope"
      name:
        $ref: "#/$defs/LocalizedText"
      description:
        $ref: "#/$defs/LocalizedText"
      tags:
        type: array
        items:
          type: string
      environment:
        type: string
      executionMode:
        type: string
        enum:
          - local
          - hosted
          - hybrid
          - none
      runtimeRef:
        $ref: "#/$defs/RuntimeRef"
      contextFormat:
        type: string
        enum:
          - yaml
          - toon
          - gcf
          - auto
      requiresReview:
        type: boolean
      commands:
        type: array
        items:
          type: string
          minLength: 1
  RecipeCatalogGroup:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - id
      - name
    properties:
      id:
        type: string
        minLength: 1
      name:
        $ref: "#/$defs/LocalizedText"
      description:
        $ref: "#/$defs/LocalizedText"
  DataProductRecipeSection:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - id
      - path
      - format
    properties:
      id:
        type: string
        enum:
          - recipe-readme
          - source-product-spec
          - product-summary
          - delivery-plan
          - product-interface-plan
          - access-plan
          - contract-plan
          - pricing-plan
          - quality-plan
          - sla-plan
          - lifecycle-plan
          - relationship-plan
          - validation-plan
          - test-plan
          - operational-readiness
          - risk-register
          - open-questions
          - developer-review-checklist
          - ai-agent-brief
          - implementation-constraints
          - backlog-items
          - portfolio-context
          - relationship-context
      path:
        $ref: "#/$defs/RelativePath"
      format:
        type: string
        enum:
          - markdown
          - yaml
          - json
          - directory
    allOf:
      - if:
          properties:
            id:
              const: contract-plan
          required:
            - id
        then:
          properties:
            format:
              const: yaml
  DataProductRecipeReadiness:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - score
      - status
    properties:
      score:
        type: number
        minimum: 0
        maximum: 100
      status:
        type: string
        enum:
          - missing
          - partial
          - ready
  DataProductRecipeReview:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - required
      - status
    properties:
      required:
        type: boolean
      status:
        type: string
        enum:
          - pending
          - approved
          - changes-requested
  DataProductRecipe:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - metadata
      - version
      - status
      - sections
      - readiness
      - review
    properties:
      metadata:
        allOf:
          - $ref: "#/$defs/Metadata"
          - type: object
            required:
              - description
      version:
        type: string
        pattern: "^[0-9]+\\.[0-9]+\\.[0-9]+([A-Za-z0-9.+-]*)?$"
      recipeRef:
        $ref: "#/$defs/RelativePath"
      status:
        type: string
        enum:
          - announcement
          - draft
          - development
          - testing
          - acceptance
          - production
          - sunset
          - retired
      sections:
        type: array
        minItems: 7
        items:
          $ref: "#/$defs/DataProductRecipeSection"
        allOf:
          - contains:
              type: object
              required:
                - id
              properties:
                id:
                  const: recipe-readme
          - contains:
              type: object
              required:
                - id
              properties:
                id:
                  const: source-product-spec
          - contains:
              type: object
              required:
                - id
              properties:
                id:
                  const: product-summary
          - contains:
              type: object
              required:
                - id
              properties:
                id:
                  const: delivery-plan
          - contains:
              type: object
              required:
                - id
              properties:
                id:
                  const: open-questions
          - contains:
              type: object
              required:
                - id
              properties:
                id:
                  const: ai-agent-brief
          - contains:
              type: object
              required:
                - id
              properties:
                id:
                  const: relationship-context
      readiness:
        $ref: "#/$defs/DataProductRecipeReadiness"
      review:
        $ref: "#/$defs/DataProductRecipeReview"
  RecipeCatalog:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - metadata
      - version
      - recipes
    properties:
      metadata:
        $ref: "#/$defs/Metadata"
      version:
        type: string
        pattern: "^[0-9]+\\.[0-9]+\\.[0-9]+([A-Za-z0-9.+-]*)?$"
      groups:
        type: array
        items:
          $ref: "#/$defs/RecipeCatalogGroup"
      recipes:
        type: array
        minItems: 1
        items:
          $ref: "#/$defs/RecipeCatalogEntry"
  Recipe:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-": {}
    required:
      - metadata
      - version
      - type
      - steps
    properties:
      metadata:
        $ref: "#/$defs/Metadata"
      version:
        type: string
        pattern: "^[0-9]+\\.[0-9]+\\.[0-9]+([A-Za-z0-9.+-]*)?$"
      type:
        type: string
        enum:
          - dev
          - ci
          - release
          - localization
          - hybrid
          - agent
      scope:
        $ref: "#/$defs/RecipeScope"
      inputs:
        type: array
        items:
          $ref: "#/$defs/NamedPath"
      outputs:
        type: array
        items:
          $ref: "#/$defs/NamedPath"
      context:
        $ref: "#/$defs/ContextPolicy"
      trigger:
        $ref: "#/$defs/GraphTrigger"
      graphContext:
        $ref: "#/$defs/GraphContext"
      execution:
        $ref: "#/$defs/ExecutionPolicy"
      steps:
        type: array
        minItems: 1
        items:
          $ref: "#/$defs/Step"
      gates:
        type: array
        items:
          $ref: "#/$defs/Gate"
      review:
        $ref: "#/$defs/ReviewPolicy"
      environment:
        type: string
      runPolicy:
        $ref: "#/$defs/RunPolicy"
