{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/bitbybit-dev/json-schema/bitbybit-dev-pipeline-body-schema.json",
  "title": "PipelineBody",
  "description": "Execute a chain of Bitbybit CAD operations sequentially. Supports $ref:N step references, $file:N file inputs, map iteration, and choice conditionals.",
  "x-generated": "2026-10-29",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/bitbybit-dev-openapi.json#/components/schemas/PipelineBody",
  "type": "object",
  "properties": {
    "steps": {
      "minItems": 1,
      "maxItems": 50,
      "type": "array",
      "items": {
        "$ref": "#/$defs/PipelineAnyStep"
      },
      "description": "Ordered list of CAD operations executed sequentially. Later steps can reference earlier results using '$ref:N' syntax. Supports map and choice control-flow steps."
    },
    "inputFiles": {
      "description": "References to previously uploaded files. Use '$file:N' in step params to inject file contents (optionally '$file:N:<format>:<codec>' to pick a read format and/or decompress - see PipelineStep.params).",
      "maxItems": 5,
      "type": "array",
      "items": {
        "$ref": "#/$defs/InputFileItem"
      }
    },
    "outputs": {
      "description": "Output format options applied to the final pipeline result. Supports json, csv, stl, 3mf in addition to standard formats. If omitted, raw result data is stored.",
      "$ref": "#/$defs/PipelineOutputOptions"
    }
  },
  "required": [
    "steps"
  ],
  "additionalProperties": false,
  "$defs": {
    "ChoiceStep": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "choice",
          "description": "Declares this step as a choice (conditional) step"
        },
        "value": {
          "description": "Value to compare. Typically a '$ref:N' reference to a previous step result."
        },
        "operator": {
          "description": "Comparison operator to apply between value and compareTo",
          "$ref": "#/$defs/ComparisonOperator"
        },
        "compareTo": {
          "description": "Value to compare against. Not required for 'exists' operator."
        },
        "then": {
          "minItems": 1,
          "type": "array",
          "items": {
            "$ref": "#/$defs/PipelineStep"
          },
          "description": "Sub-steps to execute when condition is true"
        },
        "else": {
          "description": "Sub-steps to execute when condition is false. If omitted, produces null.",
          "type": "array",
          "items": {
            "$ref": "#/$defs/PipelineStep"
          }
        }
      },
      "required": [
        "type",
        "value",
        "operator",
        "then"
      ],
      "description": "Conditional execution - evaluate a condition and run the matching branch."
    },
    "ComparisonOperator": {
      "type": "string",
      "enum": [
        "eq",
        "neq",
        "gt",
        "gte",
        "lt",
        "lte",
        "exists"
      ],
      "description": "Comparison operator: 'eq' (equal), 'neq' (not equal), 'gt' (greater than), 'gte' (greater or equal), 'lt' (less than), 'lte' (less or equal), 'exists' (value is not null/undefined)."
    },
    "InputFileItem": {
      "type": "object",
      "properties": {
        "fileId": {
          "type": "string",
          "minLength": 1,
          "description": "ID of a previously uploaded file (from POST /files/upload)"
        },
        "role": {
          "type": "string",
          "minLength": 1,
          "description": "Role identifier for the file (e.g. 'step-model', 'coordinates-csv')"
        }
      },
      "required": [
        "fileId",
        "role"
      ],
      "additionalProperties": false,
      "description": "Reference to an uploaded file to be used as input"
    },
    "LengthUnit": {
      "type": "string",
      "enum": [
        "mm",
        "cm",
        "m",
        "in"
      ],
      "description": "A unit of length: 'mm' (millimetres), 'cm' (centimetres), 'm' (metres) or 'in' (inches)."
    },
    "MapStep": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "const": "map",
          "description": "Declares this step as a map (iteration) step"
        },
        "items": {
          "description": "Source array to iterate over. Typically a '$ref:N' reference to a previous step that produced an array."
        },
        "steps": {
          "minItems": 1,
          "type": "array",
          "items": {
            "$ref": "#/$defs/PipelineStep"
          },
          "description": "Sub-steps to execute for each item. Use '$item' for the current element, '$index' for the iteration number."
        },
        "reduce": {
          "description": "Optional sub-steps to combine map results. Use '$mapResult' to reference the collected array of iteration outputs.",
          "type": "array",
          "items": {
            "$ref": "#/$defs/PipelineStep"
          }
        }
      },
      "required": [
        "type",
        "items",
        "steps"
      ],
      "description": "Iterate over an array, executing sub-steps for each element. Produces an array of results (or a reduced value)."
    },
    "MeshPrecision": {
      "type": "number",
      "minimum": 0.0001,
      "maximum": 10,
      "description": "Mesh tessellation precision (lower = finer). Range: [0.0001, 10]"
    },
    "PipelineAnyStep": {
      "anyOf": [
        {
          "$ref": "#/$defs/MapStep"
        },
        {
          "$ref": "#/$defs/ChoiceStep"
        },
        {
          "$ref": "#/$defs/PipelineStep"
        }
      ],
      "description": "A pipeline step - either a plain operation, a map (iteration), or a choice (conditional)."
    },
    "PipelineOutputFormat": {
      "type": "string",
      "enum": [
        "step",
        "stpz",
        "decomposed-mesh",
        "gltf",
        "json",
        "csv",
        "stl",
        "3mf",
        "brep",
        "brep-binary"
      ],
      "description": "Pipeline output file format. Includes all standard formats plus: 'json' (JSON data), 'csv' (CSV text), 'stl' (binary STL mesh - Manifold/JSCAD only), '3mf' (3MF mesh package - Manifold/JSCAD only), 'brep' (OpenCascade BREP as text, which OCCT-based tools such as FreeCAD read) and 'brep-binary' (OpenCascade binary BREP, the smallest and fastest exact form, which keeps the numbering of faces and edges; read back with occt.io.loadBrepBinary) - both OCCT only, without triangulation."
    },
    "PipelineOutputOptions": {
      "type": "object",
      "properties": {
        "formats": {
          "minItems": 1,
          "type": "array",
          "items": {
            "$ref": "#/$defs/PipelineOutputFormat"
          },
          "description": "Output formats to generate. Supports standard CAD formats (step, stpz, gltf, decomposed-mesh) plus pipeline-specific formats (json, csv, stl, 3mf, brep, brep-binary)."
        },
        "meshPrecision": {
          "description": "Tessellation precision for mesh-based outputs (decomposed-mesh and gltf). Lower values produce denser meshes.",
          "$ref": "#/$defs/MeshPrecision"
        },
        "gltfMeshPrecision": {
          "description": "Override tessellation precision specifically for glTF output. When set, takes precedence over meshPrecision for glTF only.",
          "$ref": "#/$defs/MeshPrecision"
        },
        "adjustYtoZ": {
          "description": "Convert from Y-up to Z-up coordinate system in the output. Useful for software that expects Z-up.",
          "type": "boolean"
        },
        "includePipelineInMetadata": {
          "description": "Include the full pipeline definition in metadata.json. Defaults to true. Set to false to exclude it for smaller metadata.",
          "type": "boolean"
        },
        "unit": {
          "description": "The unit the pipeline's shapes are modelled in. Given, a STEP output is written at its true size in millimetres, so CAD tools open the shapes at the right size, and a glTF output is written in metres, the unit glTF viewers assume. Left out, the numbers are written as they are: STEP takes them as millimetres and glTF holds them unscaled. The other formats carry no unit and always hold the numbers as they are. A design build's documents state their own unit, and a unit given here must be the same.",
          "$ref": "#/$defs/LengthUnit"
        }
      },
      "required": [
        "formats"
      ],
      "additionalProperties": false,
      "description": "Controls which output formats are generated for pipeline results. Supports additional formats (json, csv, stl, 3mf, brep, brep-binary) beyond standard model outputs."
    },
    "PipelineStep": {
      "type": "object",
      "properties": {
        "operation": {
          "type": "string",
          "minLength": 1,
          "description": "Fully-qualified CAD operation identifier (e.g. 'occt.shapes.solid.createSphere'). Supports OCCT, Manifold, JSCAD, and vector/math operations."
        },
        "params": {
          "description": "Operation parameters. Use '$ref:N' (e.g. '$ref:0') to reference the output of a previous step by its zero-based index. Use '$file:N[:<format>][:<codec>]' to reference an input file's contents - <format> is one of text|buffer|uint8|json|base64 (default text), and the optional <codec> is one of raw|gunzip|auto (default raw) to decompress the file first; 'auto' gunzips only when gzip magic bytes are present, so '$file:0:text:auto' reads both plain and gzip-compressed uploads (e.g. .step and .stpz)."
        },
        "output": {
          "description": "When true, this step's result is included in a separate result.json output alongside any shape files.",
          "type": "boolean"
        }
      },
      "required": [
        "operation",
        "params"
      ],
      "description": "A single step in a sequential CAD pipeline. Steps can reference outputs of earlier steps via $ref or input files via $file."
    }
  }
}