{
  "$defs": {
    "AppProjectDestination": {
      "additionalProperties": false,
      "description": "One Argo CD AppProject destination. At least one of `server` and `name` is required.",
      "properties": {
        "name": {
          "description": "Argo CD cluster name pattern.",
          "type": [
            "string",
            "null"
          ]
        },
        "namespace": {
          "description": "Namespace pattern, such as `apps`, `preview-*`, or `*`.",
          "type": "string"
        },
        "server": {
          "description": "Cluster API server URL pattern, such as `https://kubernetes.default.svc` or `*`.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "namespace"
      ],
      "type": "object"
    },
    "AppProjectResourcePattern": {
      "additionalProperties": false,
      "properties": {
        "group": {
          "description": "Kubernetes API group pattern, such as `apiextensions.k8s.io` or `*`.",
          "type": "string"
        },
        "kind": {
          "description": "Kubernetes resource kind pattern.",
          "type": "string"
        },
        "name": {
          "description": "Optional resource name pattern.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "group",
        "kind"
      ],
      "type": "object"
    },
    "AppProjectTemplate": {
      "additionalProperties": false,
      "description": "An Argo CD AppProject generated for one ApplicationGroup and target.\n\n`name`, `labels`, `annotations`, and `finalizers` set the AppProject metadata; every other field mirrors the Argo CD `AppProject.spec` field of the same name. An omitted field is derived from what the group's Applications need on the target, so a bare template only renames the implied project: the target publication repository, the target Cluster with the group's Release namespaces, and the resource kinds the group renders. Declare a field to set it explicitly.",
      "properties": {
        "annotations": {
          "additionalProperties": {
            "type": "string"
          },
          "description": "Annotations on the generated AppProject.",
          "type": "object"
        },
        "clusterResourceBlacklist": {
          "description": "Cluster-scoped resources the project denies.",
          "items": {
            "$ref": "#/$defs/AppProjectResourcePattern"
          },
          "type": [
            "array",
            "null"
          ]
        },
        "clusterResourceWhitelist": {
          "description": "Cluster-scoped resources the project admits. Omitted, the cluster-scoped kinds the group renders, including Namespaces Nyl creates for it; a declared list, including `[]`, admits only its patterns plus Namespace permissions for the admitted namespaces when namespace creation is enabled. Deriving a whitelist requires each rendered kind's scope, from a CRD rendered in the target or the Cluster's recorded capabilities.",
          "items": {
            "$ref": "#/$defs/AppProjectResourcePattern"
          },
          "type": [
            "array",
            "null"
          ]
        },
        "description": {
          "description": "Project description.",
          "type": [
            "string",
            "null"
          ]
        },
        "destinationServiceAccounts": {
          "description": "Service accounts used for sync per destination, as Argo CD `spec.destinationServiceAccounts`.",
          "items": true,
          "type": [
            "array",
            "null"
          ]
        },
        "destinations": {
          "description": "Permitted destinations. Omitted, the project admits the target workload Cluster with every effective Release namespace and additional namespace of the group. A declared list must admit every effective Release namespace and additional namespace on the target workload Cluster; a fixed `destinationNamespace` is added for that Cluster when no entry covers it.",
          "items": {
            "$ref": "#/$defs/AppProjectDestination"
          },
          "type": [
            "array",
            "null"
          ]
        },
        "finalizers": {
          "description": "Finalizers on the generated AppProject, such as `resources-finalizer.argocd.argoproj.io`.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "labels": {
          "additionalProperties": {
            "type": "string"
          },
          "description": "Labels on the generated AppProject.",
          "type": "object"
        },
        "name": {
          "description": "Generated AppProject name; defaults to the ApplicationGroup name. Must be unambiguous across targets sharing an Argo CD namespace.",
          "type": [
            "string",
            "null"
          ]
        },
        "namespaceResourceBlacklist": {
          "description": "Namespaced resources the project denies.",
          "items": {
            "$ref": "#/$defs/AppProjectResourcePattern"
          },
          "type": [
            "array",
            "null"
          ]
        },
        "namespaceResourceWhitelist": {
          "description": "Namespaced resources the project admits. Omitted, the namespaced kinds the group renders.",
          "items": {
            "$ref": "#/$defs/AppProjectResourcePattern"
          },
          "type": [
            "array",
            "null"
          ]
        },
        "orphanedResources": {
          "description": "Orphaned resource monitoring, as Argo CD `spec.orphanedResources`."
        },
        "permitOnlyProjectScopedClusters": {
          "description": "Whether only clusters scoped to this project are admitted, as Argo CD `spec.permitOnlyProjectScopedClusters`.",
          "type": [
            "boolean",
            "null"
          ]
        },
        "roles": {
          "description": "Project roles, as Argo CD `spec.roles`.",
          "items": true,
          "type": [
            "array",
            "null"
          ]
        },
        "signatureKeys": {
          "description": "GnuPG keys required to verify source commits, as Argo CD `spec.signatureKeys`.",
          "items": true,
          "type": [
            "array",
            "null"
          ]
        },
        "sourceNamespaces": {
          "description": "Namespaces whose Applications may use the project. `applicationNamespace` is always added.",
          "items": {
            "type": "string"
          },
          "type": [
            "array",
            "null"
          ]
        },
        "sourceRepos": {
          "description": "Permitted source repository URL patterns. Omitted, the project admits the target publication repository.",
          "items": {
            "type": "string"
          },
          "type": [
            "array",
            "null"
          ]
        },
        "syncWindows": {
          "description": "Sync windows, as Argo CD `spec.syncWindows`.",
          "items": true,
          "type": [
            "array",
            "null"
          ]
        }
      },
      "type": "object"
    },
    "ApplicationDeletionPolicy": {
      "oneOf": [
        {
          "const": "Foreground",
          "description": "Cascade deletion in the foreground using the Argo CD resources finalizer.",
          "type": "string"
        },
        {
          "const": "Background",
          "description": "Cascade deletion in the background using the Argo CD background finalizer.",
          "type": "string"
        },
        {
          "const": "Orphan",
          "description": "Omit the finalizer and leave workload resources in place.",
          "type": "string"
        }
      ]
    },
    "ApplicationGroupSource": {
      "additionalProperties": false,
      "description": "A local source when no repository is given, otherwise an immutable remote source.",
      "oneOf": [
        {
          "description": "Reads Releases from a checkout of the named GitRepository.",
          "not": {
            "anyOf": [
              {
                "properties": {
                  "repository": {
                    "not": {
                      "type": "null"
                    }
                  }
                },
                "required": [
                  "repository"
                ]
              }
            ]
          },
          "properties": {
            "repositoryRef": {
              "not": {
                "type": "null"
              }
            }
          },
          "required": [
            "repositoryRef"
          ],
          "title": "repositoryRef"
        },
        {
          "description": "Reads Releases from a checkout of the inline coordinates declared here.",
          "not": {
            "anyOf": [
              {
                "properties": {
                  "repositoryRef": {
                    "not": {
                      "type": "null"
                    }
                  }
                },
                "required": [
                  "repositoryRef"
                ]
              }
            ]
          },
          "properties": {
            "repository": {
              "not": {
                "type": "null"
              }
            }
          },
          "required": [
            "repository"
          ],
          "title": "repository"
        },
        {
          "description": "Reads Releases from this project, at the declared `path`.",
          "properties": {
            "repository": {
              "type": "null"
            },
            "repositoryRef": {
              "type": "null"
            }
          },
          "title": "Neither"
        }
      ],
      "properties": {
        "commit": {
          "description": "Full 40-character lowercase commit ID that is read, refreshed by `nyl update source-locks`.",
          "type": [
            "string",
            "null"
          ]
        },
        "exclude": {
          "description": "Relative file globs removed after inclusion.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "include": {
          "default": [
            "*.yaml",
            "*.yml"
          ],
          "description": "Relative candidate file globs. Only entries with a literal Release are rendered; attach other files using Release `spec.include`.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "path": {
          "description": "Path in the repository. In this repository it follows the local path rule: relative to the directory containing `nyl.toml`, may begin with `..` segments, or starts with `/` to name a path from the Git worktree root, and never leaves the worktree. In a remote repository it is relative to the checkout root, with an optional leading `/`.",
          "type": "string"
        },
        "recursive": {
          "default": true,
          "description": "Whether source discovery descends into subdirectories.",
          "type": "boolean"
        },
        "rendererConfig": {
          "$ref": "#/$defs/RendererConfig",
          "default": {
            "mode": "Central"
          },
          "description": "Whether remote rendering uses central configuration or the remote project. Remote sessions cannot access secrets or the process environment."
        },
        "repository": {
          "anyOf": [
            {
              "$ref": "#/$defs/ReadGitRepository"
            },
            {
              "type": "null"
            }
          ],
          "description": "Inline repository coordinates to read from. Mutually exclusive with `repositoryRef`."
        },
        "repositoryRef": {
          "anyOf": [
            {
              "$ref": "#/$defs/LocalReference"
            },
            {
              "type": "null"
            }
          ],
          "description": "Project-local `gitops.nyl/v1` GitRepository to read from. Mutually exclusive with inline `repository`."
        },
        "revision": {
          "description": "Human-readable branch or tag that `nyl update source-locks` resolves.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "required": [
        "path"
      ],
      "type": "object"
    },
    "ApplicationGroupSpec": {
      "additionalProperties": false,
      "oneOf": [
        {
          "description": "Uses the named AppProjectDefinition, so the project can be shared between groups or managed outside Nyl.",
          "not": {
            "anyOf": [
              {
                "properties": {
                  "projectTemplate": {
                    "not": {
                      "type": "null"
                    }
                  }
                },
                "required": [
                  "projectTemplate"
                ]
              }
            ]
          },
          "properties": {
            "projectRef": {
              "not": {
                "type": "null"
              }
            }
          },
          "required": [
            "projectRef"
          ],
          "title": "projectRef"
        },
        {
          "description": "Generates an AppProject for this group from the declared AppProject fields; omitted fields admit only what the group deploys.",
          "not": {
            "anyOf": [
              {
                "properties": {
                  "projectRef": {
                    "not": {
                      "type": "null"
                    }
                  }
                },
                "required": [
                  "projectRef"
                ]
              }
            ]
          },
          "properties": {
            "projectTemplate": {
              "not": {
                "type": "null"
              }
            }
          },
          "required": [
            "projectTemplate"
          ],
          "title": "projectTemplate"
        },
        {
          "description": "Generates an AppProject named after the group that admits only what it deploys: the target publication repository, the target Cluster with the group's Release namespaces, and the resource kinds it renders.",
          "properties": {
            "projectRef": {
              "type": "null"
            },
            "projectTemplate": {
              "type": "null"
            }
          },
          "title": "Neither"
        }
      ],
      "properties": {
        "annotations": {
          "additionalProperties": {
            "type": "string"
          },
          "description": "Annotations added to generated Applications.",
          "type": "object"
        },
        "applicationDeletionPolicy": {
          "$ref": "#/$defs/ApplicationDeletionPolicy",
          "default": "Foreground",
          "description": "Argo CD Application finalizer policy: foreground cascade, background cascade, or orphan workloads."
        },
        "applicationNameTemplate": {
          "description": "Generated workload Application name, as a template value expanded once per Release. It must contain at least one `${ expression }`, evaluated with the target context plus `release`, the rendered Release; `$${` writes a literal `${`, and all other text, including `{{ … }}`, is literal. Defaults to the Release name; use target-qualified names such as `${ target.metadata.name }-${ release.metadata.name }` when targets share an Argo CD namespace.",
          "type": [
            "string",
            "null"
          ]
        },
        "applicationNamespace": {
          "description": "Namespace containing generated Argo CD Applications.",
          "type": "string"
        },
        "destinationNamespace": {
          "description": "Workload namespace override. Defaults to each Release namespace.",
          "type": [
            "string",
            "null"
          ]
        },
        "enabled": {
          "default": true,
          "description": "Whether to render this selected group. Evaluated after target selection and may be templated.",
          "type": "boolean"
        },
        "labels": {
          "additionalProperties": {
            "type": "string"
          },
          "description": "Labels added to generated Applications.",
          "type": "object"
        },
        "namespace": {
          "$ref": "#/$defs/ManagedNamespacePolicy",
          "default": {
            "create": true,
            "deletePolicy": "Confirm",
            "prunePolicy": "Confirm"
          },
          "description": "Namespace creation and deletion policy for workload-owned namespaces."
        },
        "outputPath": {
          "description": "Relative output directory beneath the target prefix. Defaults to the group name.",
          "type": [
            "string",
            "null"
          ]
        },
        "projectRef": {
          "description": "Project-local AppProjectDefinition identity. Mutually exclusive with `projectTemplate`; omitting both implies an AppProject named after this group that admits only what the group deploys.",
          "type": [
            "string",
            "null"
          ]
        },
        "projectTemplate": {
          "anyOf": [
            {
              "$ref": "#/$defs/AppProjectTemplate"
            },
            {
              "type": "null"
            }
          ],
          "description": "Generated AppProject fields. Mutually exclusive with `projectRef`; declared fields are kept as written and omitted fields are derived from what the group deploys."
        },
        "releaseCustomization": {
          "$ref": "#/$defs/GitOpsReleaseCustomization",
          "default": {},
          "description": "Limits on per-release Application overrides. Releases cannot expand the generated project or namespace policy."
        },
        "sharedNamespaces": {
          "additionalProperties": {
            "$ref": "#/$defs/SharedNamespacePolicy"
          },
          "description": "Explicit ownership by namespace name. Every consuming group must agree. Kubernetes bootstrap namespaces are externally owned unless explicitly delegated here.",
          "type": "object"
        },
        "source": {
          "anyOf": [
            {
              "$ref": "#/$defs/ApplicationGroupSource"
            },
            {
              "type": "null"
            }
          ],
          "description": "Release source selection. Omission derives `applications/<group-name>` for central groups or the containing directory for `_application-group.yaml`."
        },
        "syncPolicy": {
          "anyOf": [
            {
              "$ref": "#/$defs/GitOpsSyncPolicy"
            },
            {
              "type": "null"
            }
          ],
          "description": "Workload Application sync policy. Generated Applications include apply-only-out-of-sync and server-side apply unless explicitly overridden."
        }
      },
      "required": [
        "applicationNamespace"
      ],
      "type": "object"
    },
    "GitOpsAutomatedSyncPolicy": {
      "additionalProperties": false,
      "properties": {
        "enabled": {
          "description": "Whether automated sync is enabled. Omission enables it when the automated block is present.",
          "type": [
            "boolean",
            "null"
          ]
        },
        "prune": {
          "default": false,
          "description": "Allow Argo CD to prune resources removed from desired manifests.",
          "type": "boolean"
        },
        "selfHeal": {
          "default": false,
          "description": "Allow Argo CD to repair live drift automatically.",
          "type": "boolean"
        }
      },
      "type": "object"
    },
    "GitOpsReleaseCustomization": {
      "additionalProperties": false,
      "properties": {
        "allowedPaths": {
          "description": "Dotted field globs admitted in Release Application overrides. `*` matches one segment; `**` matches multiple segments. Core ownership fields remain protected.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "allowedSyncOptions": {
          "description": "Exact allowed values for Release `spec.syncPolicy.+syncOptions` overrides. Same-key values replace the generated option.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "deniedPaths": {
          "description": "Dotted field globs forbidden in Release Application overrides. Deny takes precedence over allow.",
          "items": {
            "type": "string"
          },
          "type": "array"
        }
      },
      "type": "object"
    },
    "GitOpsResourceMetadata": {
      "additionalProperties": false,
      "description": "Metadata shared by local GitOps compiler resources.",
      "properties": {
        "labels": {
          "additionalProperties": {
            "type": "string"
          },
          "description": "Literal labels used for organization and target selection.",
          "type": "object"
        },
        "name": {
          "description": "Project-local identity, validated by the resource kind; remains static during discovery.",
          "type": "string"
        }
      },
      "required": [
        "name"
      ],
      "type": "object"
    },
    "GitOpsSyncPolicy": {
      "additionalProperties": false,
      "properties": {
        "automated": {
          "anyOf": [
            {
              "$ref": "#/$defs/GitOpsAutomatedSyncPolicy"
            },
            {
              "type": "null"
            }
          ],
          "description": "Presence enables automated synchronization unless `enabled` is false."
        },
        "syncOptions": {
          "description": "Argo CD sync options. Generated Applications add `ApplyOutOfSyncOnly=true` and `ServerSideApply=true` unless an option with the same key is supplied.",
          "items": {
            "type": "string"
          },
          "type": "array"
        }
      },
      "type": "object"
    },
    "LocalReference": {
      "additionalProperties": false,
      "properties": {
        "name": {
          "description": "Project-local name of the referenced resource; its kind and API group are determined by the containing field.",
          "type": "string"
        }
      },
      "required": [
        "name"
      ],
      "type": "object"
    },
    "ManagedNamespacePolicy": {
      "additionalProperties": false,
      "properties": {
        "create": {
          "default": true,
          "description": "Synthesize missing destination and additional Namespaces within the owning workload Application.",
          "type": "boolean"
        },
        "deletePolicy": {
          "$ref": "#/$defs/ManagedResourceDeletionPolicy",
          "default": "Confirm",
          "description": "Namespace deletion policy when the owning Application is deleted."
        },
        "prunePolicy": {
          "$ref": "#/$defs/ManagedResourceDeletionPolicy",
          "default": "Confirm",
          "description": "Namespace pruning policy: Automatic, Confirm, or Retain."
        }
      },
      "type": "object"
    },
    "ManagedResourceDeletionPolicy": {
      "oneOf": [
        {
          "const": "Automatic",
          "description": "Allow pruning or deletion without additional restrictions.",
          "type": "string"
        },
        {
          "const": "Confirm",
          "description": "Require confirmation through the Argo CD Prune or Delete sync option.",
          "type": "string"
        },
        {
          "const": "Retain",
          "description": "Set the Argo CD Prune or Delete sync option to false.",
          "type": "string"
        }
      ]
    },
    "ReadGitRepository": {
      "additionalProperties": false,
      "description": "Credential-free coordinates for a repository that is only read.",
      "properties": {
        "repoURL": {
          "description": "Git read URL. Source checkouts never publish to this repository.",
          "type": "string"
        }
      },
      "required": [
        "repoURL"
      ],
      "type": "object"
    },
    "RendererConfig": {
      "additionalProperties": false,
      "properties": {
        "mode": {
          "$ref": "#/$defs/RendererConfigMode",
          "default": "Central",
          "description": "Central uses platform configuration; Remote loads the remote project and requires a remote source."
        },
        "projectPath": {
          "description": "Remote project root, relative to the checkout. Defaults to `.`; valid only in Remote mode and must remain inside the checkout.",
          "type": [
            "string",
            "null"
          ]
        }
      },
      "type": "object"
    },
    "RendererConfigMode": {
      "oneOf": [
        {
          "const": "Central",
          "description": "Use the central platform project configuration.",
          "type": "string"
        },
        {
          "const": "Remote",
          "description": "Load project configuration from the remote source checkout with restricted inputs.",
          "type": "string"
        }
      ]
    },
    "SharedNamespaceOwner": {
      "oneOf": [
        {
          "additionalProperties": false,
          "description": "The selected workload Release owns the Namespace; other workloads must not render its Namespace object.",
          "properties": {
            "applicationGroup": {
              "description": "ApplicationGroup owning the Namespace Application or selected workload Release.",
              "type": "string"
            },
            "kind": {
              "const": "Release",
              "type": "string"
            },
            "release": {
              "description": "Release name within the owning ApplicationGroup.",
              "type": "string"
            }
          },
          "required": [
            "kind",
            "applicationGroup",
            "release"
          ],
          "type": "object"
        },
        {
          "additionalProperties": false,
          "description": "Generate a dedicated Namespace Application under the selected group; workloads must not render this Namespace.",
          "properties": {
            "applicationGroup": {
              "description": "ApplicationGroup owning the Namespace Application or selected workload Release.",
              "type": "string"
            },
            "kind": {
              "const": "Dedicated",
              "type": "string"
            }
          },
          "required": [
            "kind",
            "applicationGroup"
          ],
          "type": "object"
        },
        {
          "additionalProperties": false,
          "description": "The Namespace is externally owned. Nyl neither synthesizes nor accepts an authored Namespace object.",
          "properties": {
            "kind": {
              "const": "External",
              "type": "string"
            }
          },
          "required": [
            "kind"
          ],
          "type": "object"
        }
      ]
    },
    "SharedNamespacePolicy": {
      "additionalProperties": false,
      "description": "Explicit authorization and ownership for a namespace consumed by more than\none generated workload Application.",
      "properties": {
        "owner": {
          "$ref": "#/$defs/SharedNamespaceOwner",
          "description": "The sole owner of a shared Namespace. Release and Dedicated owners identify the responsible ApplicationGroup."
        }
      },
      "required": [
        "owner"
      ],
      "type": "object"
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "additionalProperties": false,
  "description": "Selects Kubernetes Releases and defines their Argo CD Application, project, and namespace policies.\n\nLiteral metadata labels participate in target selection; the spec is rendered afterward. This is compiler configuration, not a workload manifest.\n\n## When needed\n\nRequired to select Release entry files and generate their workload Applications in Kubernetes GitOps.\n\n## If omitted\n\nNyl does not infer groups from directories or Release files. Without a selected, enabled ApplicationGroup, a target emits no workload Applications. Direct file rendering does not require an ApplicationGroup.",
  "examples": [
    {
      "apiVersion": "k8s.gitops.nyl/v1",
      "kind": "ApplicationGroup",
      "metadata": {
        "name": "workloads"
      },
      "spec": {
        "applicationNamespace": "argocd",
        "destinationNamespace": "workloads",
        "projectTemplate": {
          "destinations": [
            {
              "namespace": "workloads",
              "server": "https://kubernetes.default.svc"
            }
          ]
        },
        "source": {
          "path": "applications/workloads"
        }
      }
    }
  ],
  "properties": {
    "apiVersion": {
      "const": "k8s.gitops.nyl/v1",
      "description": "API group and version defining this resource.",
      "type": "string"
    },
    "kind": {
      "const": "ApplicationGroup",
      "description": "Resource kind within the API group.",
      "type": "string"
    },
    "metadata": {
      "$ref": "#/$defs/GitOpsResourceMetadata",
      "description": "Resource identity and metadata."
    },
    "spec": {
      "$ref": "#/$defs/ApplicationGroupSpec",
      "description": "Configuration for this resource."
    }
  },
  "required": [
    "apiVersion",
    "kind",
    "metadata",
    "spec"
  ],
  "title": "ApplicationGroup",
  "type": "object"
}
