{
  "$comment": "Generated by secretspec schema --config. Do not edit by hand. Runtime validation also checks cross-field and provider-specific constraints.",
  "$id": "https://secretspec.dev/schema/secretspec.schema.json",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "additionalProperties": false,
  "definitions": {
    "CredentialBinding": {
      "description": "How a typed secret obtains one credential it needs (SecretSpec 0.22+).\n\nWritten in a secret's `credentials` table keyed by the role its type\ndefines, with the bare name of another declared secret as the value:\n\n```toml\nTLS_PFX = { type = \"pkcs12\", from = \"TLS_IDENTITY\", credentials = { password = \"TLS_PFX_PASSWORD\" } }\n```\n\nThe named secret is an ordinary declaration: it resolves through its own\nproviders, default, prompt, or generator, joins the dependency graph, and is\nstored with `secretspec set` like any other value. Table values are rejected\nand reserved for a future provider-pinned source, so adding one later is\nadditive.",
      "type": "string"
    },
    "CredentialSource": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "additionalProperties": false,
          "properties": {
            "provider": {
              "description": "Provider alias, name, or URI supplying the credential.",
              "type": "string"
            },
            "ref": {
              "anyOf": [
                {
                  "$ref": "#/definitions/NativeAddress"
                }
              ],
              "description": "Native coordinates of the credential; otherwise uses convention naming."
            }
          },
          "required": [
            "provider"
          ],
          "type": "object"
        }
      ],
      "description": "Provider supplying a credential, optionally with native coordinates."
    },
    "ExtractFormat": {
      "description": "A structured-data format from which one logical secret can be extracted.\n\nAvailable since SecretSpec 0.19.",
      "oneOf": [
        {
          "const": "json",
          "description": "A JSON document selected with an RFC 6901 JSON Pointer.",
          "type": "string"
        },
        {
          "const": "ini",
          "description": "An INI document selected with an RFC 6901-escaped `/key` or\n`/section/key` pointer.\n\nAvailable since SecretSpec 0.20.",
          "type": "string"
        }
      ]
    },
    "GenerateConfig": {
      "anyOf": [
        {
          "description": "Simple boolean flag to enable/disable generation with defaults",
          "type": "boolean"
        },
        {
          "allOf": [
            {
              "$ref": "#/definitions/GenerateOptions"
            }
          ],
          "description": "Detailed generation options"
        }
      ],
      "description": "Configuration for auto-generation of a secret.\n\nCan be either a simple boolean (`generate = true`) or a table with\ntype-specific options (`generate = { length = 64 }`)."
    },
    "GenerateOptions": {
      "additionalProperties": false,
      "description": "Type-specific options for secret generation.",
      "properties": {
        "algorithm": {
          "description": "OpenPGP or SSH algorithm (0.21+), or JWK or mnemonic algorithm (0.22+).",
          "enum": [
            "ed25519",
            "rsa",
            "p256",
            "bip39"
          ],
          "type": [
            "string"
          ]
        },
        "bits": {
          "description": "RSA key size in bits (`rsa_private_key` defaults to 2048; OpenPGP, SSH, and JWK RSA default to 3072).",
          "format": "uint",
          "minimum": 0,
          "type": [
            "integer"
          ]
        },
        "bytes": {
          "description": "Number of random bytes (for `hex` and `base64` types)",
          "format": "uint",
          "minimum": 0,
          "type": [
            "integer"
          ]
        },
        "capabilities": {
          "description": "OpenPGP subkey capabilities (`sign` and/or `encrypt`, 0.21+).",
          "items": {
            "enum": [
              "sign",
              "encrypt"
            ],
            "type": "string"
          },
          "minItems": 1,
          "type": [
            "array"
          ]
        },
        "charset": {
          "description": "Character set for password generation (\"alphanumeric\" or \"ascii\")",
          "enum": [
            "alphanumeric",
            "ascii"
          ],
          "type": [
            "string"
          ]
        },
        "command": {
          "description": "Shell command to run (for `command` type)",
          "type": [
            "string"
          ]
        },
        "comment": {
          "description": "Comment embedded in a generated OpenSSH private key (0.21+).",
          "type": [
            "string"
          ]
        },
        "issuer": {
          "description": "X.509 issuer mode (currently `self_signed`; 0.22+).",
          "type": [
            "string"
          ]
        },
        "kid": {
          "description": "Optional JSON Web Key identifier (`kid`; 0.22+).",
          "type": [
            "string"
          ]
        },
        "language": {
          "description": "Word-list language for a generated mnemonic (currently `english`; 0.22+).",
          "type": [
            "string"
          ]
        },
        "length": {
          "description": "Length of generated password (for `password` type)",
          "format": "uint",
          "minimum": 0,
          "type": [
            "integer"
          ]
        },
        "san": {
          "description": "X.509 subject alternative names, written as `dns:name` or `ip:address` (0.22+).",
          "items": {
            "type": "string"
          },
          "type": [
            "array"
          ]
        },
        "separator": {
          "description": "Separator placed between generated passphrase words (default `-`; 0.22+).",
          "type": [
            "string"
          ]
        },
        "usages": {
          "description": "X.509 extended key usages (`server_auth` and/or `client_auth`; 0.22+).",
          "items": {
            "type": "string"
          },
          "type": [
            "array"
          ]
        },
        "user_id": {
          "description": "OpenPGP User ID bound to a generated certificate (0.21+).",
          "type": [
            "string"
          ]
        },
        "valid_for": {
          "description": "X.509 certificate lifetime as whole days, for example `30d` (0.22+).",
          "type": [
            "string"
          ]
        },
        "words": {
          "description": "Number of words in a generated passphrase or mnemonic (defaults 7 or 24; 0.22+).",
          "format": "uint",
          "minimum": 0,
          "type": [
            "integer"
          ]
        }
      },
      "type": "object"
    },
    "GroupNames": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "items": {
            "type": "string"
          },
          "type": "array"
        }
      ]
    },
    "NativeAddress": {
      "additionalProperties": false,
      "description": "Provider-native coordinates for one secret. Routing follows the selected provider chain; supported coordinates depend on the provider.",
      "properties": {
        "field": {
          "description": "A component within the item: field label (1Password), KV field\n(Vault), JSON key (AWS), account (keyring). Providers whose secrets\nhave no sub-components reject it.",
          "type": [
            "string"
          ]
        },
        "item": {
          "description": "The store's own name for the secret: item title (1Password, Proton\nPass, LastPass), entry path (pass), KV path (Vault), secret name/ARN\n(AWS), secret id (GCSM), key name (BWS, dotenv), variable name (env),\nservice (keyring).",
          "minLength": 1,
          "type": "string"
        },
        "section": {
          "description": "1Password only: the section containing the field.",
          "type": [
            "string"
          ]
        },
        "vault": {
          "description": "1Password only: the vault holding the item, overriding the store's\ndefault vault for this secret.",
          "type": [
            "string"
          ]
        },
        "version": {
          "description": "The secret version to read on stores that support version-pinned reads;\ndefaults to the latest.",
          "type": [
            "string"
          ]
        }
      },
      "required": [
        "item"
      ],
      "type": "object"
    },
    "NativeAddressTemplate": {
      "additionalProperties": false,
      "description": "A provider-alias template for native secret coordinates (0.19+).\n\nEach coordinate accepts the logical placeholders `{project}`, `{profile}`,\nand `{key}`. The template belongs to one provider alias, so fallback links\nand import endpoints can map the same logical secret into different native\naddress shapes without sharing provider-specific coordinates.",
      "properties": {
        "field": {
          "description": "Optional template for a component within the item.",
          "type": [
            "string"
          ]
        },
        "item": {
          "description": "Template for the provider's required `item` coordinate.",
          "type": "string"
        },
        "section": {
          "description": "Optional section template.",
          "type": [
            "string"
          ]
        },
        "vault": {
          "description": "Optional container template.",
          "type": [
            "string"
          ]
        },
        "version": {
          "description": "Optional version template.",
          "type": [
            "string"
          ]
        }
      },
      "required": [
        "item"
      ],
      "type": "object"
    },
    "Profile": {
      "additionalProperties": {
        "$ref": "#/definitions/Secret"
      },
      "description": "Configuration for a specific profile (environment).\n\nA profile represents a specific environment or context (e.g., \"default\", \"production\", \"staging\").\nEach profile contains its own set of secret definitions with their requirements.",
      "properties": {
        "defaults": {
          "anyOf": [
            {
              "$ref": "#/definitions/ProfileDefaults"
            }
          ],
          "description": "Default configuration for secrets in this profile"
        }
      },
      "type": "object"
    },
    "ProfileDefaults": {
      "additionalProperties": false,
      "description": "Default configuration for a profile.\n\nProvides defaults that apply to all secrets within the profile.\nIndividual secrets can override any of these defaults.",
      "properties": {
        "default": {
          "description": "Default value to use for secrets in this profile if they are not found.\nIndividual secrets can override this with their own default value.",
          "type": [
            "string"
          ]
        },
        "inherit": {
          "description": "Whether this non-default profile inherits declarations and omitted\nfields from `[profiles.default]`. Omitted means `true`. Available since\nSecretSpec 0.19.",
          "type": [
            "boolean"
          ]
        },
        "providers": {
          "description": "List of provider aliases to use for secrets in this profile.\nProviders are tried in order until one has the secret.\nIndividual secrets can override this with their own providers field.",
          "items": {
            "type": "string"
          },
          "type": [
            "array"
          ]
        },
        "required": {
          "description": "Default value for the required field of secrets in this profile.\nIf not specified, secrets default to required=true.",
          "type": [
            "boolean"
          ]
        }
      },
      "type": "object"
    },
    "Project": {
      "additionalProperties": false,
      "description": "Project metadata and inheritance configuration.\n\nContains essential project information and optional configuration inheritance.\nThe `extends` field allows projects to inherit secrets from other configurations,\nenabling shared configuration patterns across multiple projects.",
      "properties": {
        "extends": {
          "description": "Optional list of relative paths to other SecretSpec projects to inherit from",
          "items": {
            "type": "string"
          },
          "type": [
            "array"
          ]
        },
        "name": {
          "description": "The name of the project, used for identification and namespacing",
          "minLength": 1,
          "type": "string"
        },
        "require_reason": {
          "anyOf": [
            {
              "$ref": "#/definitions/RequireReason"
            }
          ],
          "description": "Policy controlling when secret access must supply a reason. Accepts a boolean\nor `\"agents\"`; enforced by [`crate::Secrets`]. `None` means \"unspecified\": it\nresolves to [`RequireReason::default`] unless a parent config supplies a value\nvia `extends`, in which case the overlay from that parent fills it in."
        },
        "revision": {
          "description": "Configuration format revision (currently must be \"1.0\")",
          "enum": [
            "1.0"
          ],
          "type": "string"
        }
      },
      "required": [
        "name",
        "revision"
      ],
      "type": "object"
    },
    "ProjectDefaults": {
      "additionalProperties": false,
      "description": "Project-wide defaults for provider-backed secrets (0.21+).\n\nThis is deliberately narrower than [`ProfileDefaults`]: a project can\nselect one provider chain without assigning the same fallback value or\nrequiredness policy to every secret in every profile.",
      "properties": {
        "providers": {
          "description": "Provider aliases, names, or URIs used when neither a secret nor its\nprofile declares a provider chain.",
          "items": {
            "type": "string"
          },
          "minItems": 1,
          "type": "array"
        }
      },
      "required": [
        "providers"
      ],
      "type": "object"
    },
    "ProviderAlias": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "additionalProperties": false,
          "oneOf": [
            {
              "not": {
                "anyOf": [
                  {
                    "required": [
                      "fallback"
                    ]
                  },
                  {
                    "required": [
                      "ref",
                      "cache"
                    ]
                  }
                ]
              },
              "required": [
                "uri"
              ]
            },
            {
              "not": {
                "anyOf": [
                  {
                    "required": [
                      "uri"
                    ]
                  },
                  {
                    "required": [
                      "credentials"
                    ]
                  },
                  {
                    "required": [
                      "ref"
                    ]
                  }
                ]
              },
              "required": [
                "fallback",
                "cache"
              ]
            }
          ],
          "properties": {
            "cache": {
              "anyOf": [
                {
                  "$ref": "#/definitions/ProviderCache"
                }
              ],
              "description": "Cache storage and freshness policy (0.17+)."
            },
            "credentials": {
              "additionalProperties": {
                "$ref": "#/definitions/CredentialSource"
              },
              "description": "Provider credentials mapped to their secret sources.",
              "type": [
                "object"
              ]
            },
            "fallback": {
              "description": "Ordered leaf provider aliases for a cached fallback chain (0.17+).",
              "items": {
                "type": "string"
              },
              "minItems": 1,
              "type": [
                "array"
              ]
            },
            "ref": {
              "anyOf": [
                {
                  "$ref": "#/definitions/NativeAddressTemplate"
                }
              ],
              "description": "Native address template (0.19+); accepts {project}, {profile}, and {key}."
            },
            "uri": {
              "description": "Provider URI, for example dotenv://.env.",
              "type": [
                "string"
              ]
            }
          },
          "type": "object"
        }
      ],
      "description": "Provider URI, provider table, or cached fallback chain (0.17+)."
    },
    "ProviderCache": {
      "additionalProperties": false,
      "description": "Cache storage and freshness policy (0.17+).",
      "properties": {
        "max_age": {
          "description": "Human-readable freshness duration (`30m`, `8h`, `1d`, or combinations).",
          "minLength": 1,
          "type": "string"
        },
        "provider": {
          "description": "Leaf provider spec used to persist the cache envelope.",
          "pattern": "\\S",
          "type": "string"
        }
      },
      "required": [
        "provider",
        "max_age"
      ],
      "type": "object"
    },
    "RequireReason": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "enum": [
            "agents"
          ],
          "type": "string"
        }
      ],
      "description": "When to require an access reason. Defaults to agents."
    },
    "RequiredGroups": {
      "additionalProperties": false,
      "minProperties": 1,
      "properties": {
        "at_least_one": {
          "anyOf": [
            {
              "$ref": "#/definitions/GroupNames"
            }
          ],
          "description": "At least one member of each named group must resolve (0.17+)."
        },
        "exactly_one": {
          "anyOf": [
            {
              "$ref": "#/definitions/GroupNames"
            }
          ],
          "description": "Exactly one member of each named group must resolve (0.17+)."
        }
      },
      "type": "object"
    },
    "RequiredSetting": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "$ref": "#/definitions/RequiredGroups"
        }
      ],
      "description": "The serialized form of `required`: either the existing boolean or a table\nof cross-secret presence groups."
    },
    "Scope": {
      "additionalProperties": false,
      "description": "A named, membership-only subset of a profile's secrets.\n\nScopes are orthogonal to profiles. A profile decides how a secret resolves\n(`required`, `default`, providers, references, generation, `as_path`, and the\nstorage namespace); a scope only decides *which* secrets take part in a given\nresolution. Selecting `--scope api` resolves exactly the intersection of the\nmerged profile and this scope's `secrets` list, so a single service loads only\nwhat it declares instead of the entire profile.",
      "properties": {
        "secrets": {
          "description": "The secret names that belong to this scope. Every name must be declared by\nat least one profile; an unknown name is a configuration error.",
          "items": {
            "type": "string"
          },
          "type": "array"
        }
      },
      "required": [
        "secrets"
      ],
      "type": "object"
    },
    "Secret": {
      "additionalProperties": false,
      "description": "Configuration for an individual secret.\n\nDefines the properties of a secret including its documentation,\nwhether it's required, an optional default value, and optionally\nwhich providers to use for retrieving this secret (in fallback order).",
      "not": {
        "required": [
          "ref",
          "refs"
        ]
      },
      "properties": {
        "as_path": {
          "description": "Write the resolved value to a temporary file and expose its path.",
          "type": [
            "boolean"
          ]
        },
        "composed": {
          "description": "Template using ${SECRET_NAME} references; $$ escapes a dollar sign (0.16+).",
          "type": [
            "string"
          ]
        },
        "credentials": {
          "additionalProperties": {
            "$ref": "#/definitions/CredentialBinding"
          },
          "description": "Declared secrets bound to typed credential roles (0.22+).",
          "type": [
            "object"
          ]
        },
        "default": {
          "description": "Fallback value when no provider supplies the secret.",
          "type": [
            "string"
          ]
        },
        "description": {
          "description": "Human-readable explanation of this secret.",
          "type": [
            "string"
          ]
        },
        "encoding": {
          "anyOf": [
            {
              "$ref": "#/definitions/SecretEncoding"
            }
          ],
          "description": "Encoding of the stored value (0.19+)."
        },
        "extract": {
          "anyOf": [
            {
              "$ref": "#/definitions/SecretExtract"
            }
          ],
          "description": "Select a logical value from structured provider data (0.19+)."
        },
        "format": {
          "description": "Typed output serialization, such as pem or der (0.22+).",
          "type": [
            "string"
          ]
        },
        "from": {
          "description": "Declared source secret for a conversion or extraction (0.22+).",
          "type": [
            "string"
          ]
        },
        "generate": {
          "anyOf": [
            {
              "$ref": "#/definitions/GenerateConfig"
            }
          ],
          "description": "Generate a missing secret with defaults or type-specific options."
        },
        "prompt": {
          "description": "Whether an interactive caller may prompt for a missing secret.",
          "type": [
            "boolean"
          ]
        },
        "providers": {
          "description": "Provider aliases, names, or URIs to try in order.",
          "items": {
            "type": "string"
          },
          "type": [
            "array"
          ]
        },
        "ref": {
          "anyOf": [
            {
              "$ref": "#/definitions/NativeAddress"
            }
          ],
          "description": "Native coordinates for the secret, replacing convention naming."
        },
        "refs": {
          "additionalProperties": {
            "$ref": "#/definitions/NativeAddress"
          },
          "description": "Native coordinates per provider alias (0.19+); mutually exclusive with ref.",
          "type": [
            "object"
          ]
        },
        "required": {
          "anyOf": [
            {
              "$ref": "#/definitions/RequiredSetting"
            }
          ],
          "description": "Whether this secret is required, or named presence groups (0.17+)."
        },
        "type": {
          "description": "Secret type for validation and generation. OpenPGP and SSH private keys require 0.21+.\nPassphrases, mnemonics, WireGuard, JWK, age, and X.509 types require 0.22+.",
          "enum": [
            "password",
            "passphrase",
            "mnemonic",
            "hex",
            "base64",
            "uuid",
            "command",
            "rsa_private_key",
            "openpgp_private_key",
            "ssh_private_key",
            "wireguard_private_key",
            "jwk_private_key",
            "age_identity",
            "x509_identity",
            "pkcs12",
            "pkcs8_private_key",
            "x509_certificate",
            "x509_certificate_chain",
            "x509_issuer_chain"
          ],
          "type": [
            "string"
          ]
        }
      },
      "type": "object"
    },
    "SecretEncoding": {
      "description": "Text encoding used for a secret's stored representation.\n\nAvailable since SecretSpec 0.19.",
      "oneOf": [
        {
          "const": "base64",
          "description": "RFC 4648 Base64. Writes use padding; reads accept padded or unpadded input.",
          "type": "string"
        },
        {
          "const": "base64url",
          "description": "RFC 4648 URL- and filename-safe Base64. Writes omit padding; reads\naccept padded or unpadded input.",
          "type": "string"
        },
        {
          "const": "hex",
          "description": "RFC 4648 Base16. Writes use lowercase; reads are case-insensitive.",
          "type": "string"
        }
      ]
    },
    "SecretExtract": {
      "additionalProperties": false,
      "description": "Selects one logical secret from a structured text document.\n\nOn a provider-backed secret, extraction is applied after [`SecretEncoding`]\nis decoded and only to values read from providers or caches. On a secret\nwith [`from`](Secret::from) (0.22+), the named declared secret is resolved\nfirst and its logical text becomes the extraction input.\n\nAvailable since SecretSpec 0.19.",
      "properties": {
        "format": {
          "allOf": [
            {
              "$ref": "#/definitions/ExtractFormat"
            }
          ],
          "description": "The structured-data format of the document."
        },
        "pointer": {
          "description": "Slash-delimited pointer selecting the logical value. JSON accepts a\ncomplete RFC 6901 JSON Pointer; INI accepts `/key` or `/section/key`\nwith RFC 6901 escaping for each segment.",
          "type": "string"
        }
      },
      "required": [
        "format"
      ],
      "type": "object"
    }
  },
  "description": "The root configuration structure for a SecretSpec project.\n\nThis is the top-level type that represents the entire `secretspec.toml` file.\nIt contains project metadata and profile-specific secret definitions.",
  "properties": {
    "defaults": {
      "anyOf": [
        {
          "$ref": "#/definitions/ProjectDefaults"
        }
      ],
      "description": "Project-wide defaults applied to every provider-backed secret (0.21+)."
    },
    "profiles": {
      "additionalProperties": {
        "$ref": "#/definitions/Profile"
      },
      "description": "Map of profile names to their configurations (e.g., \"default\", \"production\", \"staging\")",
      "minProperties": 1,
      "type": "object"
    },
    "project": {
      "allOf": [
        {
          "$ref": "#/definitions/Project"
        }
      ],
      "description": "Project metadata including name, revision, and optional inheritance"
    },
    "providers": {
      "additionalProperties": {
        "$ref": "#/definitions/ProviderAlias"
      },
      "description": "Project-level provider aliases that map alias names to provider URIs.\n\nTake precedence over aliases in the user-global config\n(`~/.config/secretspec/config.toml`), so teams can check vault mappings\ninto version control instead of replicating them on every machine.",
      "type": [
        "object"
      ]
    },
    "scopes": {
      "additionalProperties": {
        "$ref": "#/definitions/Scope"
      },
      "description": "Named secret scopes: membership-only subsets of a profile's secrets, used\nto resolve only what one service/task needs (`--scope api`) rather than the\nwhole profile. A scope never changes a secret's `required`/`default`/\nproviders or its storage address — it only narrows which secrets\nparticipate in a resolution. Orthogonal to profiles: the resolved set is\nthe intersection of the merged profile and the scope's secret list.",
      "type": [
        "object"
      ]
    }
  },
  "required": [
    "project",
    "profiles"
  ],
  "title": "SecretSpec project configuration",
  "type": "object"
}
