{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "additionalProperties": false,
  "definitions": {
    "ApplicationSpec": {
      "additionalProperties": false,
      "description": "What the application runs, and how its environments and previews deploy\nit.",
      "properties": {
        "environments": {
          "additionalProperties": {
            "$ref": "#/definitions/EnvironmentConfig"
          },
          "default": {},
          "description": "Declares the environment `<environment>` and how it deploys, for at\nmost 64 environments.",
          "propertyNames": {
            "type": "string"
          },
          "type": "object"
        },
        "exports": {
          "default": [],
          "description": "Services of this application that other applications may reach, at\nmost 64.",
          "items": {
            "$ref": "#/definitions/Export"
          },
          "type": "array"
        },
        "imports": {
          "default": [],
          "description": "Services of other applications this application reaches, at most 64.",
          "items": {
            "$ref": "#/definitions/Import"
          },
          "type": "array"
        },
        "jobs": {
          "default": [],
          "description": "Containers that run to completion during each deployment, such as\ndatabase migrations, at most 16. They run in the order listed.",
          "items": {
            "$ref": "#/definitions/Job"
          },
          "type": "array"
        },
        "manifest": {
          "default": null,
          "oneOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/definitions/RepositoryManifest",
              "description": "The Git repository each deployment reads the manifest from. Without\nit, deployments use the saved manifest. A manifest read from the\nrepository can't change it: its own `spec.manifest` is ignored."
            }
          ]
        },
        "previews": {
          "default": {
            "visibility": "private"
          },
          "oneOf": [
            {
              "$ref": "#/definitions/PreviewConfig",
              "description": "Settings shared by every preview."
            }
          ]
        },
        "routes": {
          "default": [],
          "description": "HTTP routes to the services, at most 64. They take effect when an\nenvironment deploys them.",
          "items": {
            "$ref": "#/definitions/Route"
          },
          "type": "array"
        },
        "secrets": {
          "default": [],
          "description": "Secrets piqueld generates a value for in each environment, at most 64.",
          "items": {
            "$ref": "#/definitions/SecretDeclaration"
          },
          "type": "array"
        },
        "services": {
          "default": [],
          "description": "The application's services, at most 64.",
          "items": {
            "$ref": "#/definitions/Service"
          },
          "type": "array"
        },
        "variables": {
          "additionalProperties": {
            "$ref": "#/definitions/Variable"
          },
          "default": {},
          "description": "Default value of the variable `<variable>`, referenced as\n`${{ vars.<variable> }}`. An environment's or the previews' own value\nreplaces it. Variable names start with a letter or `_`, use letters,\ndigits, `_` or `-`, and are at most 63 bytes. Each table of variables\nholds at most 128.",
          "propertyNames": {
            "type": "string"
          },
          "type": "object"
        },
        "volumes": {
          "default": [],
          "description": "Named volumes the services mount, at most 64.",
          "items": {
            "$ref": "#/definitions/Volume"
          },
          "type": "array"
        }
      },
      "type": "object"
    },
    "Build": {
      "description": "How to build a Git source's image.",
      "oneOf": [
        {
          "additionalProperties": false,
          "description": "Build the image with Docker Buildx, from a Dockerfile.",
          "properties": {
            "args": {
              "additionalProperties": {
                "$ref": "#/definitions/Template"
              },
              "description": "The value of the build argument `<name>`, passed with\n`--build-arg`. Docker records it in the image's metadata, so pass\nsensitive values as secrets instead. Build arguments total at most\n256 KiB.",
              "propertyNames": {
                "type": "string"
              },
              "type": "object"
            },
            "context": {
              "default": ".",
              "oneOf": [
                {
                  "$ref": "#/definitions/Template",
                  "description": "Build context directory, relative to the repository root."
                }
              ]
            },
            "dockerfile": {
              "$ref": "#/definitions/Template",
              "description": "Path of the Dockerfile, relative to the repository root."
            },
            "target": {
              "oneOf": [
                {
                  "type": "null"
                },
                {
                  "$ref": "#/definitions/Template",
                  "description": "Stage of a multi-stage Dockerfile to build. By default, the final\nstage."
                }
              ]
            },
            "type": {
              "enum": [
                "docker"
              ],
              "type": "string"
            }
          },
          "required": [
            "dockerfile",
            "type"
          ],
          "type": "object"
        }
      ]
    },
    "EnvironmentConfig": {
      "additionalProperties": false,
      "description": "Declares an environment and where it deploys from. Without\n`promote_from`, the environment builds its own manifest: the saved one, or\na branch of the `spec.manifest` repository. A block that sets none of\n`branch`, `commit`, `promote_from` and `sync` leaves an existing\nenvironment's source as it is, unless the previous manifest set one of\nthem: removing them returns the environment to the default source.",
      "properties": {
        "branch": {
          "default": null,
          "description": "Branch of the manifest repository the environment deploys. By\ndefault, the branch `spec.manifest` names. Needs `spec.manifest`.",
          "type": [
            "string",
            "null"
          ]
        },
        "commit": {
          "default": null,
          "description": "Full commit the environment deploys instead of its branch's head.\nWithout `branch`, by default the commit `spec.manifest` pins. Needs\n`spec.manifest`, and excludes `sync`.",
          "type": [
            "string",
            "null"
          ]
        },
        "promote_from": {
          "default": null,
          "description": "Another environment whose releases this one receives with\n`piquelctl env promote`, instead of building. It excludes `branch`,\n`commit` and `sync`, and can't lead back to this environment.",
          "type": [
            "string",
            "null"
          ]
        },
        "rollback": {
          "default": null,
          "oneOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/definitions/Rollback",
              "description": "What happens when a rollout fails: `automatic` restores the\nenvironment's last successful deployment, `manual` leaves it degraded\nuntil someone acts. By default `automatic` for promoted environments\nand `manual` for the others."
            }
          ]
        },
        "sync": {
          "default": null,
          "description": "Whether pushes to the environment's branch deploy it while\n`spec.manifest.sync` is on. Off when unset. `true` needs\n`spec.manifest`.",
          "type": [
            "boolean",
            "null"
          ]
        },
        "variables": {
          "additionalProperties": {
            "$ref": "#/definitions/Variable"
          },
          "default": {},
          "description": "The environment's value of the variable `<variable>`. It replaces the\n`[spec.variables]` default, or declares a variable without one.",
          "propertyNames": {
            "type": "string"
          },
          "type": "object"
        },
        "visibility": {
          "default": "public",
          "oneOf": [
            {
              "$ref": "#/definitions/Visibility",
              "description": "The strictest visibility the environment's routes get. `public`\nrestricts nothing; `private` keeps every route on the tailnet."
            }
          ]
        }
      },
      "type": "object"
    },
    "Export": {
      "additionalProperties": false,
      "description": "A service of this application that other applications may reach over a\nprivate link, as `<service>.<application>`.",
      "properties": {
        "applications": {
          "description": "Applications whose environments may import the service: at least one,\nat most 64, each listed once.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "previews": {
          "default": false,
          "description": "Whether previews of those applications may import the service too.",
          "type": "boolean"
        },
        "service": {
          "description": "Service of this application to export, at most once.",
          "type": "string"
        }
      },
      "required": [
        "service",
        "applications"
      ],
      "type": "object"
    },
    "FileMode": {
      "description": "Octal file permissions from `0000` to `0777`, written as text such as\n`\"0444\"` or `\"644\"`.",
      "example": "0444",
      "pattern": "^0?[0-7]{3}$",
      "type": "string"
    },
    "FileSource": {
      "description": "Where a file's content comes from.",
      "oneOf": [
        {
          "description": "Path of a UTF-8 text file in the manifest's repository, relative to\nits root, read at the commit the manifest was read from. Only\nrepository-backed applications can use it.",
          "properties": {
            "path": {
              "description": "Path of a UTF-8 text file in the manifest's repository, relative to\nits root, read at the commit the manifest was read from. Only\nrepository-backed applications can use it.",
              "type": "string"
            }
          },
          "required": [
            "path"
          ],
          "type": "object"
        },
        {
          "description": "The file's content, inline.",
          "properties": {
            "content": {
              "description": "The file's content, inline.",
              "type": "string"
            }
          },
          "required": [
            "content"
          ],
          "type": "object"
        }
      ]
    },
    "GitRepository": {
      "additionalProperties": false,
      "description": "A Git repository and the revision to check out. Git uses the host's\ncredentials.",
      "properties": {
        "branch": {
          "description": "Branch whose head is checked out when no commit is set.",
          "type": "string"
        },
        "commit": {
          "description": "Full commit hash to check out instead of the branch's head.",
          "type": [
            "string",
            "null"
          ]
        },
        "url": {
          "description": "Clone URL or local path of the repository. It can't contain\ncredentials.",
          "type": "string"
        }
      },
      "required": [
        "url",
        "branch"
      ],
      "type": "object"
    },
    "HealthCheck": {
      "description": "How Docker checks that a service's containers are healthy.",
      "oneOf": [
        {
          "additionalProperties": false,
          "description": "Send an HTTP `GET` to a port of the container. A 2xx or 3xx status\npasses. The image needs nothing for it.",
          "properties": {
            "interval_seconds": {
              "default": 10,
              "oneOf": [
                {
                  "$ref": "#/definitions/Typed_u32",
                  "description": "Seconds between checks, from 1 to 3,600."
                }
              ]
            },
            "path": {
              "default": "/health",
              "oneOf": [
                {
                  "$ref": "#/definitions/Template",
                  "description": "Absolute HTTP path to request."
                }
              ]
            },
            "port": {
              "$ref": "#/definitions/Typed_u16",
              "description": "Container port to request, from 1 to 65535."
            },
            "retries": {
              "default": 3,
              "oneOf": [
                {
                  "$ref": "#/definitions/Typed_u32",
                  "description": "Consecutive failed checks that make a container unhealthy, from 1\nto 100."
                }
              ]
            },
            "start_period_seconds": {
              "default": 0,
              "oneOf": [
                {
                  "$ref": "#/definitions/Typed_u32",
                  "description": "Seconds after a container starts during which failed checks don't\ncount, up to 3,600."
                }
              ]
            },
            "timeout_seconds": {
              "default": 3,
              "oneOf": [
                {
                  "$ref": "#/definitions/Typed_u32",
                  "description": "Seconds a check may take before it fails, from 1 to the interval."
                }
              ]
            },
            "type": {
              "enum": [
                "http"
              ],
              "type": "string"
            }
          },
          "required": [
            "port",
            "type"
          ],
          "type": "object"
        },
        {
          "additionalProperties": false,
          "description": "Run a command in the container, without a shell. Exit code 0 passes.",
          "properties": {
            "command": {
              "description": "Command and arguments to run. It can't be empty.",
              "items": {
                "$ref": "#/definitions/Template"
              },
              "type": "array"
            },
            "interval_seconds": {
              "default": 10,
              "oneOf": [
                {
                  "$ref": "#/definitions/Typed_u32",
                  "description": "Seconds between checks, from 1 to 3,600."
                }
              ]
            },
            "retries": {
              "default": 3,
              "oneOf": [
                {
                  "$ref": "#/definitions/Typed_u32",
                  "description": "Consecutive failed checks that make a container unhealthy, from 1\nto 100."
                }
              ]
            },
            "start_period_seconds": {
              "default": 0,
              "oneOf": [
                {
                  "$ref": "#/definitions/Typed_u32",
                  "description": "Seconds after a container starts during which failed checks don't\ncount, up to 3,600."
                }
              ]
            },
            "timeout_seconds": {
              "default": 3,
              "oneOf": [
                {
                  "$ref": "#/definitions/Typed_u32",
                  "description": "Seconds a check may take before it fails, from 1 to the interval."
                }
              ]
            },
            "type": {
              "enum": [
                "command"
              ],
              "type": "string"
            }
          },
          "required": [
            "command",
            "type"
          ],
          "type": "object"
        }
      ]
    },
    "Import": {
      "additionalProperties": false,
      "description": "A service of another application this application reaches over a private\nlink, as `<service>.<application>`.",
      "properties": {
        "application": {
          "description": "Application exporting the service. It may be this application.",
          "type": "string"
        },
        "environment": {
          "oneOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/definitions/Template",
              "description": "Environment of that application to reach. By default, the one named\nlike the importing environment. It may reference variables, so\npreviews can reach e.g. `staging`."
            }
          ]
        },
        "service": {
          "description": "Service that application exports, imported at most once.",
          "type": "string"
        }
      },
      "required": [
        "application",
        "service"
      ],
      "type": "object"
    },
    "Job": {
      "additionalProperties": false,
      "description": "A container that runs to completion during each deployment, such as a\ndatabase migration.",
      "properties": {
        "command": {
          "description": "Command the job runs, instead of its service's command and arguments.\nIt can't be empty.",
          "items": {
            "$ref": "#/definitions/Template"
          },
          "type": "array"
        },
        "environment": {
          "additionalProperties": {
            "$ref": "#/definitions/Template"
          },
          "description": "The environment variable `<name>` of the job's container only, in\naddition to its service's. A name the service also sets is an error.",
          "propertyNames": {
            "type": "string"
          },
          "type": "object"
        },
        "name": {
          "description": "Name of the job, unique in the application.",
          "type": "string"
        },
        "run": {
          "$ref": "#/definitions/JobRun",
          "description": "When the job runs. `before-rollout` runs it after every source is\nprepared, before the services roll out."
        },
        "secrets": {
          "description": "Secrets only the job's container mounts, in addition to its service's.\nA target the service already uses is an error.",
          "items": {
            "$ref": "#/definitions/SecretMount"
          },
          "type": "array"
        },
        "service": {
          "description": "Service whose image, environment, secrets, volumes, resource limits\nand network the job reuses. The job also waits for the service's\n`depends_on`.",
          "type": "string"
        },
        "stop_service": {
          "default": false,
          "description": "Whether the job's service stops before the job runs, once the job's\nstartup dependencies are ready, so its previous version never runs\nagainst what the job changes. The service starts again with the\nrollout, or with the previous deployment if a job fails.",
          "type": "boolean"
        },
        "timeout_seconds": {
          "default": 300,
          "description": "Seconds the job may run before the deployment fails, from 1 to 86,400.",
          "format": "int32",
          "maximum": 4294967295,
          "minimum": 0,
          "type": "integer"
        },
        "volume_access": {
          "default": "read-only",
          "oneOf": [
            {
              "$ref": "#/definitions/JobVolumeAccess",
              "description": "How the job mounts its service's volumes. `read-only` mounts every\nvolume read-only, so the job runs beside the services. `exclusive`\nkeeps the writable volumes writable, and stops every service mounting\nthem while the job runs."
            }
          ]
        }
      },
      "required": [
        "name",
        "service",
        "command",
        "run"
      ],
      "type": "object"
    },
    "JobRun": {
      "description": "Deployment point at which a job runs.",
      "enum": [
        "before-rollout"
      ],
      "type": "string"
    },
    "JobVolumeAccess": {
      "description": "How a job may use the volumes its service mounts.",
      "enum": [
        "read-only",
        "exclusive"
      ],
      "type": "string"
    },
    "ManifestRepository": {
      "description": "The literal `\"self\"`, selecting the manifest's own repository.",
      "enum": [
        "self"
      ],
      "type": "string"
    },
    "Metadata": {
      "additionalProperties": false,
      "description": "The application's identity.",
      "properties": {
        "name": {
          "description": "Name of the application. A manifest with another name applies to\nanother application, so rename one with `piquelctl app rename`.",
          "type": "string"
        }
      },
      "required": [
        "name"
      ],
      "type": "object"
    },
    "Mount": {
      "additionalProperties": false,
      "description": "A volume mounted into a service's containers.",
      "properties": {
        "read_only": {
          "default": false,
          "description": "Whether the containers mount the volume read-only. A writable mount\nmakes rollouts stop the old container before starting its\nreplacement.",
          "type": "boolean"
        },
        "target": {
          "description": "Absolute path of the mount in the container, unique in the service.\nIt can't be `/run/piqueld/probe` or `/run/piqueld/telemetry`, or a\npath inside them.",
          "type": "string"
        },
        "volume": {
          "description": "Name of a volume in `spec.volumes`.",
          "type": "string"
        }
      },
      "required": [
        "volume",
        "target"
      ],
      "type": "object"
    },
    "PreviewConfig": {
      "additionalProperties": false,
      "description": "Settings shared by every preview.",
      "properties": {
        "variables": {
          "additionalProperties": {
            "$ref": "#/definitions/Variable"
          },
          "default": {},
          "description": "The previews' value of the variable `<variable>`. It replaces the\n`[spec.variables]` default, or declares a variable without one.",
          "propertyNames": {
            "type": "string"
          },
          "type": "object"
        },
        "visibility": {
          "default": "private",
          "oneOf": [
            {
              "$ref": "#/definitions/Visibility",
              "description": "The strictest visibility preview routes get. `private` keeps every\nroute on the tailnet; `public` restricts nothing."
            }
          ]
        }
      },
      "type": "object"
    },
    "Redirect": {
      "additionalProperties": false,
      "description": "A redirect the gateway answers with.",
      "properties": {
        "preserve_path": {
          "default": true,
          "description": "Whether to append the request's path and query to `to`.",
          "type": "boolean"
        },
        "status": {
          "default": 308,
          "description": "HTTP status of the redirect.",
          "oneOf": [
            {
              "enum": [
                301,
                302,
                303,
                307,
                308
              ],
              "type": "integer"
            }
          ]
        },
        "to": {
          "$ref": "#/definitions/Template",
          "description": "Absolute `http` or `https` URL to redirect to, with a lowercase\nhostname and no query or fragment. It can't target a hostname the\nroute serves."
        }
      },
      "required": [
        "to"
      ],
      "type": "object"
    },
    "RepositoryManifest": {
      "additionalProperties": false,
      "description": "The Git repository and file each deployment reads the manifest from.",
      "properties": {
        "path": {
          "description": "Path of the TOML or JSON manifest file, relative to the repository\nroot.",
          "type": "string"
        },
        "repository": {
          "$ref": "#/definitions/GitRepository",
          "description": "The repository holding the manifest, and the branch environments\ndeploy by default."
        },
        "sync": {
          "default": {
            "mode": "off"
          },
          "oneOf": [
            {
              "$ref": "#/definitions/RepositorySync",
              "description": "Whether pushes to the repository deploy environments and previews."
            }
          ]
        }
      },
      "required": [
        "repository",
        "path"
      ],
      "type": "object"
    },
    "RepositorySync": {
      "description": "Whether pushes to the manifest repository deploy. It applies to every\npreview, and to every environment that opted in and follows a branch\nwithout a pinned commit.",
      "oneOf": [
        {
          "description": "Deploy only when asked.",
          "properties": {
            "mode": {
              "enum": [
                "off"
              ],
              "type": "string"
            }
          },
          "required": [
            "mode"
          ],
          "type": "object"
        },
        {
          "additionalProperties": false,
          "description": "List the repository's branch heads every `interval_seconds`.",
          "properties": {
            "interval_seconds": {
              "default": 300,
              "description": "Seconds between listings, from 60 to 86,400.",
              "format": "int32",
              "maximum": 4294967295,
              "minimum": 0,
              "type": "integer"
            },
            "mode": {
              "enum": [
                "poll"
              ],
              "type": "string"
            }
          },
          "required": [
            "mode"
          ],
          "type": "object"
        },
        {
          "description": "List the branch heads when GitHub reports a push.",
          "properties": {
            "mode": {
              "enum": [
                "webhook"
              ],
              "type": "string"
            }
          },
          "required": [
            "mode"
          ],
          "type": "object"
        }
      ]
    },
    "ResourceLimits": {
      "additionalProperties": false,
      "description": "CPU and memory limits of each of a service's containers. Set at least\none.",
      "properties": {
        "cpu_millis": {
          "oneOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/definitions/Typed_u32",
              "description": "CPU limit in thousandths of a CPU, from 1 to 1,048,576: `500` is half\na CPU."
            }
          ]
        },
        "memory_bytes": {
          "oneOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/definitions/Typed_u64",
              "description": "Memory limit in bytes, from 1 to 9,223,372,036,854,775,807."
            }
          ]
        }
      },
      "type": "object"
    },
    "Rollback": {
      "description": "What happens when an environment's rollout fails: a service update\nthat Docker pauses because a new task failed within its monitor\nwindow.",
      "enum": [
        "automatic",
        "manual"
      ],
      "type": "string"
    },
    "Rollout": {
      "additionalProperties": false,
      "description": "How Docker replaces a service's containers during a deployment, one at a\ntime. An empty block keeps the defaults.",
      "properties": {
        "monitor_seconds": {
          "default": null,
          "oneOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/definitions/Typed_u32",
              "description": "Seconds Docker watches each new container for failure before it\nreplaces the next one, from 1 to 3,600. 30 when unset."
            }
          ]
        },
        "order": {
          "default": null,
          "oneOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/definitions/Typed_RolloutOrder",
              "description": "`stop-first` stops the old container before starting its replacement,\nwith a short downtime. `start-first` starts the replacement first, so\nboth briefly run side by side. When unset, `stop-first` if the service\nmounts a volume writable or receives telemetry, `start-first`\notherwise."
            }
          ]
        }
      },
      "type": "object"
    },
    "Route": {
      "additionalProperties": false,
      "description": "An HTTP route: requests for a hostname go to a service, or get a\nredirect. A route sets either `service` and `port`, or `redirect`.",
      "properties": {
        "hostname": {
          "$ref": "#/definitions/Template",
          "description": "Hostname the route serves, such as `notes.example.com`, unique in the\napplication. A wildcard such as `*.example.com` serves every name one\nlabel below `example.com` that no exact route claims."
        },
        "name": {
          "description": "Name that selects the route in every environment and preview, e.g.\n`piquelctl env url --route web`. It is unique in the application and\ncan't reference variables.",
          "type": [
            "string",
            "null"
          ]
        },
        "port": {
          "description": "Port the service serves HTTP on, from 1 to 65535. Needs `service`.",
          "format": "int32",
          "maximum": 65535,
          "minimum": 1,
          "type": [
            "integer",
            "null"
          ]
        },
        "redirect": {
          "oneOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/definitions/Redirect",
              "description": "Redirect the gateway answers with, instead of a service."
            }
          ]
        },
        "service": {
          "description": "Service of this application that receives the requests. Needs `port`.",
          "type": [
            "string",
            "null"
          ]
        },
        "visibility": {
          "default": "private",
          "oneOf": [
            {
              "$ref": "#/definitions/Visibility",
              "description": "Who may connect: `public` for the internet, or `private` for the\ntailnet only. The environment's or the previews' visibility can make\nit stricter, never looser."
            }
          ]
        }
      },
      "required": [
        "hostname"
      ],
      "type": "object"
    },
    "SecretDeclaration": {
      "additionalProperties": false,
      "description": "A secret whose value piqueld generates for each environment when one of\nits deployments first needs it. Later deployments and manifest edits keep\nthat value; `piquelctl env secret regenerate` replaces it. A value is never\nshared with another environment.",
      "properties": {
        "generate": {
          "$ref": "#/definitions/SecretGenerator",
          "description": "How piqueld generates the value."
        },
        "name": {
          "description": "Name of the secret, unique in the application. It can't reference\nvariables.",
          "type": "string"
        }
      },
      "required": [
        "name",
        "generate"
      ],
      "type": "object"
    },
    "SecretEncoding": {
      "description": "Text encoding of generated random bytes.",
      "enum": [
        "hex",
        "base64url"
      ],
      "type": "string"
    },
    "SecretGenerator": {
      "description": "How piqueld generates a secret's value.",
      "oneOf": [
        {
          "additionalProperties": false,
          "description": "Random bytes from the operating system, encoded as text.",
          "properties": {
            "bytes": {
              "description": "Number of random bytes before encoding, from 16 to 512.",
              "format": "int32",
              "maximum": 65535,
              "minimum": 0,
              "type": "integer"
            },
            "encoding": {
              "default": "hex",
              "oneOf": [
                {
                  "$ref": "#/definitions/SecretEncoding",
                  "description": "Text encoding of the bytes: lowercase `hex`, or unpadded\n`base64url`."
                }
              ]
            },
            "type": {
              "enum": [
                "random"
              ],
              "type": "string"
            }
          },
          "required": [
            "bytes",
            "type"
          ],
          "type": "object"
        },
        {
          "additionalProperties": false,
          "description": "An RSA private key, in PKCS#8 PEM.",
          "properties": {
            "bits": {
              "description": "Size of the key in bits: 2048, 3072 or 4096.",
              "format": "int32",
              "maximum": 65535,
              "minimum": 0,
              "type": "integer"
            },
            "type": {
              "enum": [
                "rsa"
              ],
              "type": "string"
            }
          },
          "required": [
            "bits",
            "type"
          ],
          "type": "object"
        }
      ]
    },
    "SecretMount": {
      "additionalProperties": false,
      "description": "A secret mounted as a file. A name `spec.secrets` declares mounts the\nenvironment's generated value; any other name mounts a value from the\napplication's secret store.",
      "properties": {
        "name": {
          "$ref": "#/definitions/Template",
          "description": "Name of the secret. It may reference variables, so each environment\ncan mount its own stored secret, e.g. `${{ vars.stripe_key }}`."
        },
        "target": {
          "description": "Absolute path of the file under `/run/secrets/`, unique in the\nservice.",
          "type": "string"
        }
      },
      "required": [
        "name",
        "target"
      ],
      "type": "object"
    },
    "Service": {
      "additionalProperties": false,
      "description": "A service: containers running one image, kept at their replica count.",
      "properties": {
        "arguments": {
          "description": "Arguments that replace the image's default arguments, at most 128\nelements of 4,096 bytes each.",
          "items": {
            "$ref": "#/definitions/Template"
          },
          "type": "array"
        },
        "command": {
          "description": "Command that replaces the image's entrypoint, at most 128 elements of\n4,096 bytes each. When empty, the image's entrypoint runs.",
          "items": {
            "$ref": "#/definitions/Template"
          },
          "type": "array"
        },
        "depends_on": {
          "description": "Services of this application that must be running and healthy before\nthis one rolls out, each listed once.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "environment": {
          "additionalProperties": {
            "$ref": "#/definitions/Template"
          },
          "description": "The environment variable `<name>` of the service's containers. Names\nuse letters, digits and `_`, don't start with a digit, and are at most\n255 bytes. Values are at most 65,536 bytes. At most 256 variables;\n`PIQUELD_INGRESS_PROXIES` is reserved.",
          "propertyNames": {
            "type": "string"
          },
          "type": "object"
        },
        "files": {
          "description": "Read-only files mounted into the containers, at most 32. Their\ncontents are never rendered with variables. An application's files\ntotal at most 2 MiB.",
          "items": {
            "$ref": "#/definitions/ServiceFile"
          },
          "type": "array"
        },
        "healthcheck": {
          "oneOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/definitions/HealthCheck",
              "description": "How Docker checks that a container is healthy. Rollouts and the\nservices depending on this one wait until it passes."
            }
          ]
        },
        "mounts": {
          "description": "Volumes mounted into the containers, at most 32.",
          "items": {
            "$ref": "#/definitions/Mount"
          },
          "type": "array"
        },
        "name": {
          "description": "Name of the service, unique in the application. The application's\nother services reach it by this name.",
          "type": "string"
        },
        "receives_telemetry": {
          "default": false,
          "description": "Whether the service receives the daemon's traces, metrics and logs,\non a socket in `/run/piqueld/telemetry`, once its environment is\ngranted telemetry. At most one service of an application receives\ntelemetry, with one replica.",
          "type": "boolean"
        },
        "replicas": {
          "default": 1,
          "oneOf": [
            {
              "$ref": "#/definitions/Typed_u16",
              "description": "Number of containers, from 1 to 100."
            }
          ]
        },
        "resources": {
          "oneOf": [
            {
              "type": "null"
            },
            {
              "$ref": "#/definitions/ResourceLimits",
              "description": "CPU and memory limits of each container."
            }
          ]
        },
        "rollout": {
          "$ref": "#/definitions/Rollout",
          "description": "How Docker replaces the service's containers on each deployment."
        },
        "secrets": {
          "description": "Secrets mounted as files, at most 64.",
          "items": {
            "$ref": "#/definitions/SecretMount"
          },
          "type": "array"
        },
        "source": {
          "$ref": "#/definitions/Source",
          "description": "Where the service's image comes from: a prebuilt image, or a Git\nbuild."
        }
      },
      "required": [
        "name",
        "source"
      ],
      "type": "object"
    },
    "ServiceFile": {
      "allOf": [
        {
          "$ref": "#/definitions/FileSource",
          "description": "Where the file's content comes from."
        },
        {
          "properties": {
            "mode": {
              "default": "0444",
              "oneOf": [
                {
                  "$ref": "#/definitions/FileMode",
                  "description": "Octal permissions, from `\"0000\"` to `\"0777\"`. The file is owned by\nroot."
                }
              ]
            },
            "target": {
              "description": "Absolute path of the file in the container, unique among the\nservice's mount, secret and file targets. It can't be in\n`/run/secrets` or `/run/piqueld`.",
              "type": "string"
            }
          },
          "required": [
            "target"
          ],
          "type": "object"
        }
      ],
      "description": "A read-only file mounted into a service's containers, from exactly one\nsource: `path` in the manifest's repository, or inline `content`. Its\ncontent can't be empty, and is at most 500 KiB."
    },
    "Source": {
      "description": "Where a service's image comes from.",
      "oneOf": [
        {
          "additionalProperties": false,
          "description": "Pull a prebuilt image from a registry.",
          "properties": {
            "image": {
              "$ref": "#/definitions/Template",
              "description": "Image reference, such as `ghcr.io/example/notes:1.4.0`, with an\noptional tag or digest. It can't contain a URL scheme or\ncredentials."
            },
            "type": {
              "enum": [
                "image"
              ],
              "type": "string"
            }
          },
          "required": [
            "image",
            "type"
          ],
          "type": "object"
        },
        {
          "additionalProperties": false,
          "description": "Build the image from a Git repository.",
          "properties": {
            "build": {
              "$ref": "#/definitions/Build",
              "description": "How to build the image."
            },
            "repository": {
              "$ref": "#/definitions/SourceRepository",
              "description": "Repository to build: `\"self\"` for the manifest's own repository,\nat the commit the manifest was read from, or a table naming\nanother one. `\"self\"` needs `spec.manifest`."
            },
            "type": {
              "enum": [
                "git"
              ],
              "type": "string"
            }
          },
          "required": [
            "repository",
            "build",
            "type"
          ],
          "type": "object"
        }
      ]
    },
    "SourceRepository": {
      "description": "The repository a Git build source checks out.",
      "oneOf": [
        {
          "$ref": "#/definitions/ManifestRepository",
          "description": "`\"self\"`: the application's manifest repository, at the exact commit its\nmanifest was read from, so one deployment builds from one revision."
        },
        {
          "$ref": "#/definitions/GitRepository",
          "description": "Another repository, and the revision to build."
        }
      ]
    },
    "Template": {
      "description": "Text that may contain `${{ namespace.name }}` references, with optional\nwhitespace inside the braces. `$${{` writes a literal `${{`; `${VAR}` and\n`$VAR` are ordinary text, left for shells and applications to expand.\n\n```text\n\"${{ vars.domain }}\"       -> the value of `domain`\n\"api.${{vars.domain}}\"     -> \"api.\" followed by the value of `domain`\n\"$${{ vars.domain }}\"      -> \"${{ vars.domain }}\", literally\n```",
      "type": "string"
    },
    "TypedTemplate": {
      "description": "A template in a setting of another type, such as an integer: text\ncontaining a `${{` reference. A template that is exactly one reference\ntakes the variable's own value, which must have the setting's type;\nstrings are never parsed into numbers. For example, with `replicas =\n\"${{ vars.replicas }}\"`, the variable `replicas` must be the integer `2`,\nnot the string `\"2\"`.",
      "pattern": "\\$\\{\\{",
      "type": "string"
    },
    "Typed_RolloutOrder": {
      "description": "A value written directly, or a template rendered for each environment.\n\nA template that is exactly one reference takes the variable's own value;\nany other template renders to text. The value must have the setting's\ntype: strings are never parsed into numbers.",
      "oneOf": [
        {
          "description": "Whether Docker stops the old container before or after starting its\nreplacement.",
          "enum": [
            "stop-first",
            "start-first"
          ],
          "type": "string"
        },
        {
          "$ref": "#/definitions/TypedTemplate",
          "description": "A value rendered from variables."
        }
      ]
    },
    "Typed_u16": {
      "description": "A value written directly, or a template rendered for each environment.\n\nA template that is exactly one reference takes the variable's own value;\nany other template renders to text. The value must have the setting's\ntype: strings are never parsed into numbers.",
      "oneOf": [
        {
          "format": "int32",
          "maximum": 65535,
          "minimum": 0,
          "type": "integer"
        },
        {
          "$ref": "#/definitions/TypedTemplate",
          "description": "A value rendered from variables."
        }
      ]
    },
    "Typed_u32": {
      "description": "A value written directly, or a template rendered for each environment.\n\nA template that is exactly one reference takes the variable's own value;\nany other template renders to text. The value must have the setting's\ntype: strings are never parsed into numbers.",
      "oneOf": [
        {
          "format": "int32",
          "maximum": 4294967295,
          "minimum": 0,
          "type": "integer"
        },
        {
          "$ref": "#/definitions/TypedTemplate",
          "description": "A value rendered from variables."
        }
      ]
    },
    "Typed_u64": {
      "description": "A value written directly, or a template rendered for each environment.\n\nA template that is exactly one reference takes the variable's own value;\nany other template renders to text. The value must have the setting's\ntype: strings are never parsed into numbers.",
      "oneOf": [
        {
          "format": "int64",
          "maximum": 18446744073709551615,
          "minimum": 0,
          "type": "integer"
        },
        {
          "$ref": "#/definitions/TypedTemplate",
          "description": "A value rendered from variables."
        }
      ]
    },
    "Variable": {
      "description": "A variable's value: a string, an integer or a boolean. A string may\nreference system variables, such as `${{ env.name }}`, but not other\nvariables.",
      "oneOf": [
        {
          "description": "A boolean.",
          "type": "boolean"
        },
        {
          "description": "A signed 64-bit integer.",
          "format": "int64",
          "type": "integer"
        },
        {
          "$ref": "#/definitions/Template",
          "description": "Text of at most 65,536 bytes, which may reference system variables."
        }
      ]
    },
    "Visibility": {
      "description": "Who may connect to a route: everyone, or only tailnet devices.",
      "enum": [
        "public",
        "private"
      ],
      "type": "string"
    },
    "Volume": {
      "additionalProperties": false,
      "description": "A named volume the services mount. Its data is kept across deployments,\nand when the application is deleted. A preview's volumes are deleted with\nthe preview.",
      "properties": {
        "name": {
          "description": "Name of the volume, unique in the application.",
          "type": "string"
        }
      },
      "required": [
        "name"
      ],
      "type": "object"
    }
  },
  "description": "An application: what it runs, and how its environments and previews\ndeploy it.",
  "properties": {
    "api_version": {
      "const": "piqueld.dev/v1alpha1",
      "description": "Version of the manifest format.",
      "type": "string"
    },
    "kind": {
      "const": "Application",
      "description": "Kind of resource the manifest describes.",
      "type": "string"
    },
    "metadata": {
      "$ref": "#/definitions/Metadata",
      "description": "The application's identity."
    },
    "spec": {
      "$ref": "#/definitions/ApplicationSpec",
      "description": "What the application runs, and how it deploys."
    }
  },
  "required": [
    "api_version",
    "kind",
    "metadata",
    "spec"
  ],
  "title": "piqueld application manifest",
  "type": "object"
}
