{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://slipway.systems/schema/pipeline-v1.json",
  "$defs": {
    "APITrigger": {
      "properties": {
        "inputs": {
          "additionalProperties": {
            "$ref": "#/$defs/Input"
          },
          "type": "object"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "description": "APITrigger enables API-only runs (no UI button)."
    },
    "Artifact": {
      "properties": {
        "name": {
          "type": "string"
        },
        "path": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        },
        "when": {
          "type": "string",
          "enum": [
            "success",
            "failure",
            "always"
          ]
        },
        "retention": {
          "type": "string",
          "pattern": "^(?:(?:\\d+(?:\\.\\d+)?(?:ms|s|m|h|d|w))+|.*\\$\\{\\{.*\\}\\}.*)$",
          "description": "How long the artifact is kept (capped by plan).",
          "examples": [
            "30s",
            "15m",
            "1h30m",
            "2d"
          ]
        },
        "if_no_files": {
          "type": "string",
          "enum": [
            "warn",
            "error",
            "ignore"
          ]
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "name",
        "path"
      ],
      "description": "Artifact uploads files at the end of a job."
    },
    "Cache": {
      "properties": {
        "key": {
          "type": "string",
          "description": "Cache key; usually includes hashFiles(...)."
        },
        "restore_keys": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ],
          "description": "Fallback key prefixes tried in order when key misses."
        },
        "paths": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "key",
        "paths"
      ],
      "description": "Cache is a keyed cache restored before and saved after the job's steps."
    },
    "ConcurrencyObject": {
      "properties": {
        "group": {
          "type": "string",
          "description": "Runs sharing a group do not run concurrently."
        },
        "cancel_in_progress": {
          "oneOf": [
            {
              "type": "boolean"
            },
            {
              "type": "string",
              "pattern": "\\$\\{\\{.*\\}\\}"
            }
          ],
          "description": "Cancel the older run instead of queueing."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "group"
      ]
    },
    "ContainerObject": {
      "properties": {
        "image": {
          "type": "string",
          "description": "OCI image the job's steps run in."
        },
        "env": {
          "additionalProperties": {
            "type": [
              "string",
              "number",
              "boolean"
            ]
          },
          "type": "object"
        },
        "user": {
          "type": "string"
        },
        "pull_policy": {
          "type": "string",
          "enum": [
            "always",
            "if-not-present",
            "never"
          ]
        },
        "volumes": {
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "options": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        },
        "credentials": {
          "$ref": "#/$defs/RegistryAuth"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "image"
      ]
    },
    "Defaults": {
      "properties": {
        "runs_on": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ],
          "description": "Default runner labels for jobs that do not set runs_on."
        },
        "timeout": {
          "type": "string",
          "pattern": "^(?:(?:\\d+(?:\\.\\d+)?(?:ms|s|m|h|d|w))+|.*\\$\\{\\{.*\\}\\}.*)$",
          "description": "Default job timeout.",
          "examples": [
            "30s",
            "15m",
            "1h30m",
            "2d"
          ]
        },
        "shell": {
          "type": "string",
          "description": "Default shell for run steps."
        },
        "working_directory": {
          "type": "string"
        },
        "retry": {
          "oneOf": [
            {
              "type": "integer",
              "minimum": 0
            },
            {
              "$ref": "#/$defs/RetryObject"
            }
          ]
        }
      },
      "additionalProperties": false,
      "type": "object",
      "description": "Defaults are pipeline-wide defaults inherited by every job."
    },
    "EnvironmentObject": {
      "properties": {
        "name": {
          "type": "string"
        },
        "url": {
          "type": "string",
          "description": "URL shown in the UI for this deployment."
        },
        "service": {
          "type": "string",
          "description": "The deploy-domain service being deployed."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "name"
      ]
    },
    "Health": {
      "properties": {
        "cmd": {
          "type": "string"
        },
        "interval": {
          "type": "string",
          "pattern": "^(?:(?:\\d+(?:\\.\\d+)?(?:ms|s|m|h|d|w))+|.*\\$\\{\\{.*\\}\\}.*)$",
          "examples": [
            "30s",
            "15m",
            "1h30m",
            "2d"
          ]
        },
        "timeout": {
          "type": "string",
          "pattern": "^(?:(?:\\d+(?:\\.\\d+)?(?:ms|s|m|h|d|w))+|.*\\$\\{\\{.*\\}\\}.*)$",
          "examples": [
            "30s",
            "15m",
            "1h30m",
            "2d"
          ]
        },
        "retries": {
          "type": "integer"
        },
        "start_period": {
          "type": "string",
          "pattern": "^(?:(?:\\d+(?:\\.\\d+)?(?:ms|s|m|h|d|w))+|.*\\$\\{\\{.*\\}\\}.*)$",
          "examples": [
            "30s",
            "15m",
            "1h30m",
            "2d"
          ]
        }
      },
      "additionalProperties": false,
      "type": "object",
      "description": "Health is a service health check."
    },
    "Input": {
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "string",
            "number",
            "boolean",
            "choice",
            "environment",
            "secret"
          ]
        },
        "required": {
          "type": "boolean"
        },
        "default": {
          "description": "Value used when the input is omitted."
        },
        "description": {
          "type": "string"
        },
        "options": {
          "items": {
            "type": "string"
          },
          "type": "array",
          "description": "Allowed values for type choice."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "description": "Input declares one typed manual/API input."
    },
    "Job": {
      "properties": {
        "name": {
          "type": "string"
        },
        "runs_on": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ],
          "description": "Runner labels used to route the job."
        },
        "container": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "$ref": "#/$defs/ContainerObject"
            }
          ]
        },
        "services": {
          "additionalProperties": {
            "$ref": "#/$defs/Service"
          },
          "type": "object"
        },
        "env": {
          "additionalProperties": {
            "type": [
              "string",
              "number",
              "boolean"
            ]
          },
          "type": "object"
        },
        "steps": {
          "items": {
            "$ref": "#/$defs/Step"
          },
          "type": "array"
        },
        "artifacts": {
          "items": {
            "$ref": "#/$defs/Artifact"
          },
          "type": "array"
        },
        "cache": {
          "items": {
            "$ref": "#/$defs/Cache"
          },
          "type": "array"
        },
        "outputs": {
          "additionalProperties": {
            "type": [
              "string",
              "number",
              "boolean"
            ]
          },
          "type": "object",
          "description": "Values exported for needs.\u003cjob\u003e.outputs.\u003ckey\u003e."
        },
        "timeout": {
          "type": "string",
          "pattern": "^(?:(?:\\d+(?:\\.\\d+)?(?:ms|s|m|h|d|w))+|.*\\$\\{\\{.*\\}\\}.*)$",
          "description": "Maximum job duration (plan-limited).",
          "examples": [
            "30s",
            "15m",
            "1h30m",
            "2d"
          ]
        },
        "retry": {
          "oneOf": [
            {
              "type": "integer",
              "minimum": 0
            },
            {
              "$ref": "#/$defs/RetryObject"
            }
          ]
        },
        "allow_failure": {
          "oneOf": [
            {
              "type": "boolean"
            },
            {
              "type": "string",
              "pattern": "\\$\\{\\{.*\\}\\}"
            }
          ],
          "description": "Do not fail the run when this job fails."
        },
        "matrix": {
          "oneOf": [
            {
              "type": "string",
              "pattern": "\\$\\{\\{.*\\}\\}"
            },
            {
              "properties": {
                "include": {
                  "items": {
                    "type": "object"
                  },
                  "type": "array",
                  "description": "Extra combinations (or extra variables merged into matching combinations)."
                },
                "exclude": {
                  "items": {
                    "type": "object"
                  },
                  "type": "array",
                  "description": "Combinations to remove from the expansion."
                },
                "fail_fast": {
                  "oneOf": [
                    {
                      "type": "boolean"
                    },
                    {
                      "type": "string",
                      "pattern": "\\$\\{\\{.*\\}\\}"
                    }
                  ]
                },
                "max_parallel": {
                  "type": "integer",
                  "minimum": 1
                }
              },
              "additionalProperties": {
                "type": "array",
                "description": "Values of this matrix axis."
              },
              "type": "object"
            }
          ]
        },
        "concurrency": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "$ref": "#/$defs/ConcurrencyObject"
            }
          ]
        },
        "needs": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ],
          "description": "Jobs or stages that must finish first."
        },
        "if": {
          "type": "string",
          "description": "Condition evaluated after needs resolve. Braces are optional. Default success()."
        },
        "environment": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "$ref": "#/$defs/EnvironmentObject"
            }
          ],
          "description": "Binds the job to a deploy environment, making it a deploy job."
        },
        "permissions": {
          "oneOf": [
            {
              "type": "string",
              "enum": [
                "read-all",
                "write-all"
              ]
            },
            {
              "properties": {
                "contents": {
                  "type": "string",
                  "enum": [
                    "none",
                    "read",
                    "write"
                  ]
                },
                "artifacts": {
                  "type": "string",
                  "enum": [
                    "none",
                    "read",
                    "write"
                  ]
                },
                "secrets": {
                  "type": "string",
                  "enum": [
                    "none",
                    "read",
                    "write"
                  ]
                },
                "deployments": {
                  "type": "string",
                  "enum": [
                    "none",
                    "read",
                    "write"
                  ]
                },
                "id_token": {
                  "type": "string",
                  "enum": [
                    "none",
                    "read",
                    "write"
                  ]
                }
              },
              "additionalProperties": false,
              "type": "object"
            }
          ]
        },
        "template": {
          "type": "string"
        },
        "with": {
          "additionalProperties": true,
          "type": "object"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "description": "Job is a node of the run DAG, expanded by its matrix into job instances."
    },
    "ManualTrigger": {
      "properties": {
        "inputs": {
          "additionalProperties": {
            "$ref": "#/$defs/Input"
          },
          "type": "object",
          "description": "Typed inputs collected when the run is started."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "description": "ManualTrigger enables running from the UI, CLI or API with typed inputs."
    },
    "PipelineTrigger": {
      "properties": {
        "pipelines": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ],
          "description": "Names of pipelines in the same project to react to."
        },
        "on": {
          "oneOf": [
            {
              "type": "string",
              "enum": [
                "success",
                "failure",
                "completed"
              ]
            },
            {
              "items": {
                "type": "string",
                "enum": [
                  "success",
                  "failure",
                  "completed"
                ]
              },
              "type": "array"
            }
          ]
        },
        "branches": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        }
      },
      "additionalProperties": false,
      "type": "object",
      "description": "PipelineTrigger fans in from other pipelines of the same project."
    },
    "PullRequestTrigger": {
      "properties": {
        "branches": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        },
        "branches_ignore": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        },
        "paths": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        },
        "paths_ignore": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        },
        "types": {
          "oneOf": [
            {
              "type": "string",
              "enum": [
                "opened",
                "synchronize",
                "reopened",
                "labeled",
                "ready_for_review",
                "closed"
              ]
            },
            {
              "items": {
                "type": "string",
                "enum": [
                  "opened",
                  "synchronize",
                  "reopened",
                  "labeled",
                  "ready_for_review",
                  "closed"
                ]
              },
              "type": "array"
            }
          ]
        },
        "labels": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        }
      },
      "additionalProperties": false,
      "type": "object",
      "description": "PullRequestTrigger fires on pull/merge request events."
    },
    "PushTrigger": {
      "properties": {
        "branches": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        },
        "branches_ignore": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        },
        "tags": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        },
        "tags_ignore": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        },
        "paths": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        },
        "paths_ignore": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        }
      },
      "additionalProperties": false,
      "type": "object",
      "description": "PushTrigger fires on branch pushes and tag pushes."
    },
    "RegistryAuth": {
      "properties": {
        "username": {
          "type": "string"
        },
        "password": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "description": "RegistryAuth holds registry credentials; values are normally secrets."
    },
    "ReleaseTrigger": {
      "properties": {
        "types": {
          "oneOf": [
            {
              "type": "string",
              "enum": [
                "created",
                "promoted"
              ]
            },
            {
              "items": {
                "type": "string",
                "enum": [
                  "created",
                  "promoted"
                ]
              },
              "type": "array"
            }
          ]
        },
        "channels": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ],
          "description": "Release channels to react to."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "description": "ReleaseTrigger fires from the deploy domain."
    },
    "RetryObject": {
      "properties": {
        "max": {
          "type": "integer",
          "description": "Maximum number of retries."
        },
        "backoff": {
          "type": "string",
          "pattern": "^(?:(?:\\d+(?:\\.\\d+)?(?:ms|s|m|h|d|w))+|.*\\$\\{\\{.*\\}\\}.*)$",
          "description": "Delay before each retry.",
          "examples": [
            "30s",
            "15m",
            "1h30m",
            "2d"
          ]
        },
        "when": {
          "oneOf": [
            {
              "type": "string",
              "enum": [
                "runner_lost",
                "timeout",
                "failure",
                "any"
              ]
            },
            {
              "items": {
                "type": "string",
                "enum": [
                  "runner_lost",
                  "timeout",
                  "failure",
                  "any"
                ]
              },
              "type": "array"
            }
          ],
          "description": "Failure reasons that trigger a retry."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "max"
      ]
    },
    "ScheduleTrigger": {
      "properties": {
        "cron": {
          "type": "string",
          "description": "Five-field cron expression (minute hour day-of-month month day-of-week) or a descriptor such as @daily."
        },
        "branch": {
          "type": "string"
        },
        "timezone": {
          "type": "string"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "cron"
      ],
      "description": "ScheduleTrigger is one cron schedule."
    },
    "Service": {
      "properties": {
        "image": {
          "type": "string"
        },
        "env": {
          "additionalProperties": {
            "type": [
              "string",
              "number",
              "boolean"
            ]
          },
          "type": "object"
        },
        "ports": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        },
        "command": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        },
        "volumes": {
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "health": {
          "$ref": "#/$defs/Health",
          "description": "Health check that must pass before the job's steps start."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "required": [
        "image"
      ],
      "description": "Service is a sidecar container started before the job's steps."
    },
    "Stage": {
      "properties": {
        "name": {
          "type": "string"
        },
        "needs": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ],
          "description": "Stages or jobs that must finish first. Omitted means the previous stage; [] removes the implicit edge."
        },
        "if": {
          "type": "string"
        },
        "jobs": {
          "items": {
            "$ref": "#/$defs/Job"
          },
          "type": "array"
        },
        "template": {
          "type": "string"
        },
        "with": {
          "additionalProperties": true,
          "type": "object"
        }
      },
      "additionalProperties": false,
      "type": "object",
      "description": "Stage is an ordered grouping of jobs; stages provide default DAG edges."
    },
    "Step": {
      "oneOf": [
        {
          "not": {
            "anyOf": [
              {
                "required": [
                  "uses"
                ]
              },
              {
                "required": [
                  "template"
                ]
              }
            ]
          },
          "required": [
            "run"
          ]
        },
        {
          "not": {
            "anyOf": [
              {
                "required": [
                  "run"
                ]
              },
              {
                "required": [
                  "template"
                ]
              }
            ]
          },
          "required": [
            "uses"
          ]
        },
        {
          "not": {
            "anyOf": [
              {
                "required": [
                  "run"
                ]
              },
              {
                "required": [
                  "uses"
                ]
              }
            ]
          },
          "required": [
            "template"
          ]
        }
      ],
      "properties": {
        "id": {
          "type": "string",
          "description": "Identifier used in steps.\u003cid\u003e.outputs.\u003ckey\u003e."
        },
        "name": {
          "type": "string"
        },
        "uses": {
          "type": "string",
          "description": "Plugin step (owner/name@ref), docker://image, ./local/path or github://owner/repo@ref."
        },
        "run": {
          "type": "string",
          "description": "Shell script. Secrets must be passed through env, not interpolated."
        },
        "template": {
          "type": "string",
          "description": "Org-level step template (org/name@version)."
        },
        "with": {
          "additionalProperties": true,
          "type": "object"
        },
        "shell": {
          "type": "string",
          "enum": [
            "bash",
            "sh",
            "pwsh",
            "python",
            "node"
          ]
        },
        "working_directory": {
          "type": "string"
        },
        "env": {
          "additionalProperties": {
            "type": [
              "string",
              "number",
              "boolean"
            ]
          },
          "type": "object"
        },
        "timeout": {
          "type": "string",
          "pattern": "^(?:(?:\\d+(?:\\.\\d+)?(?:ms|s|m|h|d|w))+|.*\\$\\{\\{.*\\}\\}.*)$",
          "examples": [
            "30s",
            "15m",
            "1h30m",
            "2d"
          ]
        },
        "continue_on_error": {
          "oneOf": [
            {
              "type": "boolean"
            },
            {
              "type": "string",
              "pattern": "\\$\\{\\{.*\\}\\}"
            }
          ],
          "description": "Treat a failure of this step as non-fatal."
        },
        "if": {
          "type": "string",
          "description": "Condition for running the step. Default success()."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "description": "Step is one unit of work: exactly one of Run, Uses or Template is set."
    },
    "TagTrigger": {
      "properties": {
        "tags": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        },
        "tags_ignore": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "items": {
                "type": [
                  "string",
                  "number",
                  "boolean"
                ]
              },
              "type": "array"
            }
          ]
        }
      },
      "additionalProperties": false,
      "type": "object",
      "description": "TagTrigger is sugar for push.tags."
    },
    "TriggersObject": {
      "properties": {
        "push": {
          "anyOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/$defs/PushTrigger"
            }
          ]
        },
        "pull_request": {
          "anyOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/$defs/PullRequestTrigger"
            }
          ]
        },
        "tag": {
          "anyOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/$defs/TagTrigger"
            }
          ]
        },
        "schedule": {
          "items": {
            "$ref": "#/$defs/ScheduleTrigger"
          },
          "type": "array"
        },
        "manual": {
          "anyOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/$defs/ManualTrigger"
            }
          ]
        },
        "api": {
          "anyOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/$defs/APITrigger"
            }
          ]
        },
        "pipeline": {
          "anyOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/$defs/PipelineTrigger"
            }
          ]
        },
        "release": {
          "anyOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/$defs/ReleaseTrigger"
            }
          ]
        },
        "webhook": {
          "anyOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/$defs/WebhookTrigger"
            }
          ]
        }
      },
      "additionalProperties": false,
      "type": "object"
    },
    "WebhookTrigger": {
      "properties": {
        "secret": {
          "type": "string",
          "description": "HMAC-SHA256 shared secret, normally ${{ secrets.NAME }}."
        },
        "filter": {
          "type": "string",
          "description": "CEL expression over event.payload; the pipeline runs when it is true."
        }
      },
      "additionalProperties": false,
      "type": "object",
      "description": "WebhookTrigger is the generic HMAC-SHA256 webhook trigger."
    }
  },
  "oneOf": [
    {
      "not": {
        "required": [
          "jobs"
        ]
      },
      "required": [
        "stages"
      ]
    },
    {
      "not": {
        "required": [
          "stages"
        ]
      },
      "required": [
        "jobs"
      ]
    },
    {
      "not": {
        "anyOf": [
          {
            "required": [
              "stages"
            ]
          },
          {
            "required": [
              "jobs"
            ]
          }
        ]
      },
      "required": [
        "extends"
      ]
    }
  ],
  "if": {
    "required": [
      "extends"
    ]
  },
  "else": {
    "required": [
      "name"
    ]
  },
  "properties": {
    "version": {
      "type": "integer",
      "const": 1,
      "description": "Pipeline format version. Always 1."
    },
    "name": {
      "type": "string",
      "minLength": 1,
      "description": "Display name, unique per project."
    },
    "description": {
      "type": "string"
    },
    "extends": {
      "type": "string",
      "description": "Base pipeline template (org/name@version) this pipeline overrides by name."
    },
    "on": {
      "oneOf": [
        {
          "type": "string",
          "enum": [
            "push",
            "pull_request",
            "tag",
            "manual",
            "api",
            "pipeline",
            "release",
            "webhook"
          ]
        },
        {
          "items": {
            "type": "string",
            "enum": [
              "push",
              "pull_request",
              "tag",
              "manual",
              "api",
              "pipeline",
              "release",
              "webhook"
            ]
          },
          "type": "array"
        },
        {
          "$ref": "#/$defs/TriggersObject"
        }
      ],
      "description": "Triggers that start the pipeline."
    },
    "inputs": {
      "additionalProperties": {
        "$ref": "#/$defs/Input"
      },
      "type": "object"
    },
    "env": {
      "additionalProperties": {
        "type": [
          "string",
          "number",
          "boolean"
        ]
      },
      "type": "object",
      "description": "Pipeline-wide environment variables (strings; expressions allowed)."
    },
    "defaults": {
      "$ref": "#/$defs/Defaults"
    },
    "concurrency": {
      "oneOf": [
        {
          "type": "string"
        },
        {
          "$ref": "#/$defs/ConcurrencyObject"
        }
      ],
      "description": "Pipeline-level concurrency group."
    },
    "permissions": {
      "oneOf": [
        {
          "type": "string",
          "enum": [
            "read-all",
            "write-all"
          ]
        },
        {
          "properties": {
            "contents": {
              "type": "string",
              "enum": [
                "none",
                "read",
                "write"
              ]
            },
            "artifacts": {
              "type": "string",
              "enum": [
                "none",
                "read",
                "write"
              ]
            },
            "secrets": {
              "type": "string",
              "enum": [
                "none",
                "read",
                "write"
              ]
            },
            "deployments": {
              "type": "string",
              "enum": [
                "none",
                "read",
                "write"
              ]
            },
            "id_token": {
              "type": "string",
              "enum": [
                "none",
                "read",
                "write"
              ]
            }
          },
          "additionalProperties": false,
          "type": "object"
        }
      ],
      "description": "Scopes of the job OIDC token."
    },
    "stages": {
      "items": {
        "$ref": "#/$defs/Stage"
      },
      "type": "array",
      "description": "Ordered stages; the job DAG is derived from needs. Mutually exclusive with jobs."
    },
    "jobs": {
      "items": {
        "$ref": "#/$defs/Job"
      },
      "type": "array",
      "description": "Shorthand for a single implicit stage. Mutually exclusive with stages."
    }
  },
  "additionalProperties": false,
  "type": "object",
  "required": [
    "version"
  ],
  "title": "Slipway pipeline",
  "description": "A Slipway CI/CD pipeline definition (docs/PIPELINE_SPEC.md, version 1)."
}
