{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://getpromptscript.dev/latest/schema/config.json",
  "title": "PromptScript Configuration",
  "description": "PromptScript configuration file (promptscript.yaml).",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "Project identifier"
    },
    "syntax": {
      "type": "string",
      "description": "PromptScript syntax version"
    },
    "description": {
      "type": "string",
      "description": "Project description"
    },
    "extends": {
      "type": "string",
      "description": "Extend another configuration file. Paths are resolved relative to the current config file.",
      "example": "extends: '../base-config.yaml'"
    },
    "inherit": {
      "type": "string",
      "description": "Inheritance path"
    },
    "input": {
      "type": "object",
      "properties": {
        "entry": {
          "type": "string",
          "description": "Entry file path (defaults to '.promptscript/project.prs')"
        },
        "include": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Glob patterns for additional files to include"
        },
        "exclude": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Glob patterns for files to exclude"
        }
      },
      "additionalProperties": false,
      "description": "Input file configuration. Controls which PromptScript files to compile."
    },
    "registry": {
      "type": "object",
      "properties": {
        "path": {
          "type": "string",
          "description": "Local path to registry"
        },
        "url": {
          "type": "string",
          "description": "Remote URL (HTTP registry)"
        },
        "git": {
          "type": "object",
          "properties": {
            "url": {
              "type": "string",
              "description": "Git repository URL (HTTPS or SSH)"
            },
            "fallbackUrl": {
              "type": "string",
              "description": "Fallback Git URL to try when the primary `url` fails with an auth error. Useful when the registry references an HTTPS URL but the user authenticates via SSH (or vice versa).",
              "example": "registry:\n  git:\n    url: 'https://github.com/org/registry.git'\n    fallbackUrl: 'git@github.com:org/registry.git'"
            },
            "ref": {
              "type": "string",
              "description": "Git ref to checkout (branch, tag, or commit hash).",
              "default": "main"
            },
            "path": {
              "type": "string",
              "description": "Subdirectory within the repository to use as registry root.",
              "examples": [
                "registry/"
              ],
              "example": "registry/"
            },
            "auth": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "token",
                    "ssh"
                  ],
                  "description": "Authentication type.\n- 'token': Use a personal access token (PAT)\n- 'ssh': Use SSH key authentication"
                },
                "token": {
                  "type": "string",
                  "description": "Personal access token (for token auth)"
                },
                "tokenEnvVar": {
                  "type": "string",
                  "description": "Environment variable containing the token"
                },
                "sshKeyPath": {
                  "type": "string",
                  "description": "Path to SSH key (for SSH auth).",
                  "default": "~/.ssh/id_rsa"
                }
              },
              "required": [
                "type"
              ],
              "additionalProperties": false,
              "description": "Authentication options for private repositories"
            }
          },
          "required": [
            "url"
          ],
          "additionalProperties": false,
          "description": "Git repository configuration. When specified, the registry will be cloned from a Git repository."
        },
        "cache": {
          "type": "object",
          "properties": {
            "enabled": {
              "type": "boolean",
              "description": "Whether caching is enabled"
            },
            "ttl": {
              "type": "number",
              "description": "Cache TTL in milliseconds"
            }
          },
          "additionalProperties": false,
          "description": "Cache settings"
        },
        "auth": {
          "type": "object",
          "properties": {
            "type": {
              "type": "string",
              "enum": [
                "bearer",
                "basic"
              ],
              "description": "Authentication type"
            },
            "token": {
              "type": "string",
              "description": "Token for bearer auth, or \"username:password\" for basic auth"
            },
            "tokenEnvVar": {
              "type": "string",
              "description": "Environment variable containing the token (alternative to token)"
            }
          },
          "required": [
            "type"
          ],
          "additionalProperties": false,
          "description": "Authentication for HTTP registries"
        }
      },
      "additionalProperties": false,
      "description": "Registry configuration"
    },
    "registries": {
      "$ref": "#/definitions/RegistriesConfig",
      "description": "Named registry aliases for multi-source imports. Maps alias names to Git repository URLs. Coexists with `registry` — aliases take precedence for matching paths."
    },
    "watch": {
      "type": "object",
      "properties": {
        "include": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Glob patterns for files to watch (defaults to '**\\/*.prs')"
        },
        "exclude": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Glob patterns for files to ignore"
        },
        "debounce": {
          "type": "number",
          "description": "Debounce time in milliseconds before recompiling"
        },
        "clearScreen": {
          "type": "boolean",
          "description": "Clear screen before each recompilation"
        }
      },
      "additionalProperties": false,
      "description": "Watch mode configuration. Settings for `prs compile --watch`."
    },
    "output": {
      "type": "object",
      "properties": {
        "baseDir": {
          "type": "string",
          "description": "Base directory for all output files"
        },
        "header": {
          "type": "string",
          "description": "Custom header to prepend to generated files"
        },
        "overwrite": {
          "type": "boolean",
          "description": "Whether to overwrite existing files without warning"
        }
      },
      "additionalProperties": false,
      "description": "Output configuration. Global output settings applied to all targets."
    },
    "builds": {
      "type": "object",
      "additionalProperties": {
        "$ref": "#/definitions/BuildProfileConfig"
      },
      "description": "Named per-command build profiles. Profiles let one repository build multiple instruction artifacts to different target directories without changing the default project compile."
    },
    "skillTargets": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      },
      "description": "Per-source output directories for `@use` imports.\n\nMaps a `@use` source string (matching the path's `raw` value) to a relative directory underneath each target's skill output location. An inline `into \"<path>\"` on the same `@use` declaration overrides the configured value.",
      "example": "skillTargets:\n  \"github.com/coreyhaines31/marketingskills/skills/seo-audit\": \"skills/seo-audit\""
    },
    "formatting": {
      "$ref": "#/definitions/FormattingConfig",
      "description": "Formatting configuration. Controls how generated markdown files are formatted.",
      "example": "formatting:\n  prettier: true  # Auto-detect .prettierrc\n\nformatting:\n  tabWidth: 4\n  proseWrap: always"
    },
    "targets": {
      "type": "array",
      "items": {
        "$ref": "#/definitions/TargetEntry"
      },
      "description": "Output targets.\n\nCan be simple names or objects with configuration:",
      "example": "targets:\n  - github\n  - claude:\n      convention: markdown\n      output: custom/CLAUDE.md"
    },
    "customConventions": {
      "type": "object",
      "additionalProperties": {
        "$ref": "#/definitions/OutputConvention"
      },
      "description": "Custom convention definitions. Register custom conventions that can be referenced by name in targets."
    },
    "universalDir": {
      "type": [
        "string",
        "boolean"
      ],
      "description": "Universal directory for auto-discovering skills and commands. Skills are discovered from `<universalDir>/skills/` and commands from `<universalDir>/commands/`.\n\n- `true` or omitted: Use default `.agents/` directory\n- `false`: Disable universal directory discovery\n- `string`: Custom path (relative to project root)",
      "default": ".agents",
      "example": "universalDir: true           # Use .agents/ (default)\nuniversalDir: '.my-agents'   # Custom directory\nuniversalDir: false          # Disable"
    },
    "includePromptScriptSkill": {
      "type": "boolean",
      "description": "Include the bundled PromptScript language skill in compilation output. When enabled, the SKILL.md that teaches AI agents how to work with .prs files is automatically added to each target's native skill directory.",
      "default": true
    },
    "validation": {
      "type": "object",
      "properties": {
        "requiredGuards": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "rules": {
          "type": "object",
          "additionalProperties": {
            "type": "string",
            "enum": [
              "error",
              "warning",
              "off"
            ]
          }
        },
        "guardRequiresDepth": {
          "type": "number",
          "description": "Maximum depth for recursive guard requires resolution. Default: 3. Must be >= 1. Values <= 0 are clamped to 1 by the resolver."
        }
      },
      "additionalProperties": false,
      "description": "Validation settings"
    },
    "policies": {
      "type": "array",
      "items": {
        "$ref": "#/definitions/PolicyDefinition"
      },
      "description": "Extension compliance policies"
    }
  },
  "required": [
    "id",
    "syntax",
    "targets"
  ],
  "additionalProperties": false,
  "definitions": {
    "RegistriesConfig": {
      "type": "object",
      "additionalProperties": {
        "anyOf": [
          {
            "type": "string"
          },
          {
            "$ref": "#/definitions/RegistryAliasEntry"
          }
        ]
      },
      "description": "Registry alias configuration. Maps alias names (e.g., '@acme') to Git URLs or extended entries.",
      "example": "registries:\n  '@company': 'github.com/company/promptscript-base'\n  '@internal':\n    url: 'git@gitlab.internal.com:company/monorepo'\n    root: 'packages/promptscript'"
    },
    "RegistryAliasEntry": {
      "type": "object",
      "properties": {
        "url": {
          "type": "string",
          "description": "Git repository URL (HTTPS or SSH)"
        },
        "fallbackUrl": {
          "type": "string",
          "description": "Fallback Git URL to try when the primary `url` fails with an auth error. Useful when registries reference HTTPS URLs but the user authenticates via SSH (or vice versa).",
          "example": "registries:\n  '@acme':\n    url: 'https://github.com/acme/standards.git'\n    fallbackUrl: 'git@github.com:acme/standards.git'"
        },
        "root": {
          "type": "string",
          "description": "Base path within the repository"
        }
      },
      "required": [
        "url"
      ],
      "additionalProperties": false,
      "description": "Extended registry alias entry for monorepos or custom roots."
    },
    "BuildProfileConfig": {
      "type": "object",
      "properties": {
        "entry": {
          "type": "string",
          "description": "Entry file path for this build profile"
        },
        "output": {
          "type": "string",
          "description": "Output directory for this build profile"
        },
        "targets": {
          "type": "array",
          "items": {
            "$ref": "#/definitions/TargetEntry"
          },
          "description": "Target list for this build profile"
        }
      },
      "additionalProperties": false,
      "description": "Named build profile for compiling a specific entry point to specific outputs."
    },
    "TargetEntry": {
      "anyOf": [
        {
          "$ref": "#/definitions/TargetName"
        },
        {
          "type": "object",
          "properties": {
            "github": {
              "$ref": "#/definitions/TargetConfig"
            },
            "claude": {
              "$ref": "#/definitions/TargetConfig"
            },
            "cursor": {
              "$ref": "#/definitions/TargetConfig"
            },
            "antigravity": {
              "$ref": "#/definitions/TargetConfig"
            },
            "factory": {
              "$ref": "#/definitions/TargetConfig"
            },
            "opencode": {
              "$ref": "#/definitions/TargetConfig"
            },
            "gemini": {
              "$ref": "#/definitions/TargetConfig"
            },
            "windsurf": {
              "$ref": "#/definitions/TargetConfig"
            },
            "cline": {
              "$ref": "#/definitions/TargetConfig"
            },
            "roo": {
              "$ref": "#/definitions/TargetConfig"
            },
            "codex": {
              "$ref": "#/definitions/TargetConfig"
            },
            "continue": {
              "$ref": "#/definitions/TargetConfig"
            },
            "augment": {
              "$ref": "#/definitions/TargetConfig"
            },
            "goose": {
              "$ref": "#/definitions/TargetConfig"
            },
            "kilo": {
              "$ref": "#/definitions/TargetConfig"
            },
            "amp": {
              "$ref": "#/definitions/TargetConfig"
            },
            "trae": {
              "$ref": "#/definitions/TargetConfig"
            },
            "junie": {
              "$ref": "#/definitions/TargetConfig"
            },
            "kiro": {
              "$ref": "#/definitions/TargetConfig"
            },
            "cortex": {
              "$ref": "#/definitions/TargetConfig"
            },
            "crush": {
              "$ref": "#/definitions/TargetConfig"
            },
            "command-code": {
              "$ref": "#/definitions/TargetConfig"
            },
            "kode": {
              "$ref": "#/definitions/TargetConfig"
            },
            "mcpjam": {
              "$ref": "#/definitions/TargetConfig"
            },
            "mistral-vibe": {
              "$ref": "#/definitions/TargetConfig"
            },
            "mux": {
              "$ref": "#/definitions/TargetConfig"
            },
            "openhands": {
              "$ref": "#/definitions/TargetConfig"
            },
            "pi": {
              "$ref": "#/definitions/TargetConfig"
            },
            "qoder": {
              "$ref": "#/definitions/TargetConfig"
            },
            "qwen-code": {
              "$ref": "#/definitions/TargetConfig"
            },
            "zencoder": {
              "$ref": "#/definitions/TargetConfig"
            },
            "neovate": {
              "$ref": "#/definitions/TargetConfig"
            },
            "pochi": {
              "$ref": "#/definitions/TargetConfig"
            },
            "adal": {
              "$ref": "#/definitions/TargetConfig"
            },
            "iflow": {
              "$ref": "#/definitions/TargetConfig"
            },
            "openclaw": {
              "$ref": "#/definitions/TargetConfig"
            },
            "codebuddy": {
              "$ref": "#/definitions/TargetConfig"
            },
            "aider": {
              "$ref": "#/definitions/TargetConfig"
            },
            "amazon-q": {
              "$ref": "#/definitions/TargetConfig"
            },
            "warp": {
              "$ref": "#/definitions/TargetConfig"
            },
            "zed": {
              "$ref": "#/definitions/TargetConfig"
            },
            "jules": {
              "$ref": "#/definitions/TargetConfig"
            },
            "devin": {
              "$ref": "#/definitions/TargetConfig"
            },
            "grok": {
              "$ref": "#/definitions/TargetConfig"
            },
            "kimi": {
              "$ref": "#/definitions/TargetConfig"
            },
            "mimo": {
              "$ref": "#/definitions/TargetConfig"
            },
            "deep-agents": {
              "$ref": "#/definitions/TargetConfig"
            },
            "forgecode": {
              "$ref": "#/definitions/TargetConfig"
            }
          },
          "additionalProperties": {
            "$ref": "#/definitions/TargetConfig"
          }
        }
      ],
      "description": "Target can be a simple string name or a full configuration object."
    },
    "TargetName": {
      "anyOf": [
        {
          "$ref": "#/definitions/KnownTarget"
        },
        {
          "$ref": "#/definitions/CustomTarget"
        }
      ],
      "description": "Supported output targets. Includes all known built-in targets plus custom targets registered via `registerFormatter`.\n\n- Use `KnownTarget` when you need exhaustiveness checks in switch/if-else.\n- Use `TargetName` when you need to accept both known and custom targets.\n- Use `isKnownTarget()` to narrow a `TargetName` to `KnownTarget` at runtime.\n- Use `customTarget()` to create a `CustomTarget` from a plain string."
    },
    "KnownTarget": {
      "type": "string",
      "enum": [
        "github",
        "claude",
        "cursor",
        "antigravity",
        "factory",
        "opencode",
        "gemini",
        "windsurf",
        "cline",
        "roo",
        "codex",
        "continue",
        "augment",
        "goose",
        "kilo",
        "amp",
        "trae",
        "junie",
        "kiro",
        "cortex",
        "crush",
        "command-code",
        "kode",
        "mcpjam",
        "mistral-vibe",
        "mux",
        "openhands",
        "pi",
        "qoder",
        "qwen-code",
        "zencoder",
        "neovate",
        "pochi",
        "adal",
        "iflow",
        "openclaw",
        "codebuddy",
        "aider",
        "amazon-q",
        "warp",
        "zed",
        "jules",
        "devin",
        "grok",
        "kimi",
        "mimo",
        "deep-agents",
        "forgecode"
      ],
      "description": "Known built-in output targets. These are the targets with first-class formatter support."
    },
    "CustomTarget": {
      "type": "string",
      "description": "Branded type for custom (user-registered) target names. Use `customTarget()` to create values of this type."
    },
    "TargetConfig": {
      "type": "object",
      "properties": {
        "enabled": {
          "type": "boolean",
          "description": "Whether this target is enabled.",
          "default": true
        },
        "output": {
          "type": "string",
          "description": "Custom output path for this target."
        },
        "convention": {
          "$ref": "#/definitions/ConventionName",
          "description": "Output convention ('xml', 'markdown', or custom name)."
        },
        "version": {
          "type": "string",
          "description": "Target version or format variant. Use 'legacy' for deprecated formats (e.g., Cursor's .cursorrules).",
          "example": "'legacy' | '1.0' | '2.0'"
        },
        "rulesMode": {
          "$ref": "#/definitions/FactoryRulesMode",
          "description": "Factory always-on rules output mode. Split mode requires Factory's `multifile` or `full` version.",
          "default": "monolith"
        },
        "guardsAsSkills": {
          "type": "boolean",
          "description": "Generate skills from",
          "default": true
        },
        "guardsSkillsListing": {
          "type": "boolean",
          "description": "List generated guard skills in main output file (Factory).",
          "default": true
        },
        "skillBaseDir": {
          "type": "string",
          "description": "Custom base directory for generated skill files. When set, skill files are emitted under this directory instead of the target's native skill directory (for example `.factory/skills`)."
        },
        "includeSkills": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          ],
          "description": "Controls which skills are emitted for this target.\n- `true` or omitted: emit all skills\n- `false`: emit no skills\n- string array: emit only the listed skill names"
        },
        "skillPath": {
          "type": "string",
          "enum": [
            "agents",
            "gemini",
            "both"
          ],
          "description": "Gemini skill path selection.\n- `agents`: use `.agents/skills/` (interoperable, fixture-confirmed default)\n- `gemini`: use `.gemini/skills/` (legacy)\n- `both`: emit to both paths (requires explicit opt-in, deduplicates content)",
          "default": "agents"
        },
        "maxThreads": {
          "type": "number",
          "description": "Codex: maximum number of parallel agent threads. Positive integer. Maps to Codex config, never to AGENTS.md."
        },
        "maxDepth": {
          "type": "number",
          "description": "Codex: maximum nesting depth for agent delegation. Positive integer. Maps to Codex config, never to AGENTS.md."
        },
        "agentsFile": {
          "type": "string",
          "description": "Codex: override the agents file name for scoped build profiles. Defaults to `AGENTS.md`. Use `AGENTS.override.md` only for scoped builds."
        },
        "agentsFrontmatter": {
          "type": "string",
          "const": "experimental",
          "description": "AGENTS.md v1.1 frontmatter mode.\n- `experimental`: emit YAML frontmatter with `description` and `tags` from",
          "default": "undefined (no frontmatter)"
        },
        "autoMode": {
          "type": "string",
          "enum": [
            "acceptEdits",
            "plan",
            "bypassPermissions"
          ],
          "description": "Claude: auto mode setting for project settings.json. Maps to `.claude/settings.json` `autoMode` field. Only valid for Claude target with fixture-confirmed project-local schema."
        }
      },
      "additionalProperties": false,
      "description": "Configuration for a single target."
    },
    "ConventionName": {
      "anyOf": [
        {
          "$ref": "#/definitions/BuiltInConventionName"
        },
        {
          "type": "string"
        }
      ],
      "description": "Convention name (built-in or custom)."
    },
    "BuiltInConventionName": {
      "type": "string",
      "enum": [
        "xml",
        "markdown"
      ],
      "description": "Built-in convention names."
    },
    "FactoryRulesMode": {
      "type": "string",
      "enum": [
        "monolith",
        "split"
      ],
      "description": "Factory always-on rules output mode.\n- `monolith`: Keep all rule content in AGENTS.md\n- `split`: Emit rule content under .factory/rules"
    },
    "FormattingConfig": {
      "type": "object",
      "properties": {
        "prettier": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "string"
            },
            {
              "$ref": "#/definitions/PrettierMarkdownOptions"
            }
          ],
          "description": "Enable Prettier formatting.\n- `true`: Auto-detect .prettierrc in project\n- `string`: Path to Prettier config file\n- `PrettierMarkdownOptions`: Explicit options",
          "example": "formatting:\n  prettier: true  # Auto-detect\n\nformatting:\n  prettier: \"./config/.prettierrc\"  # Explicit path\n\nformatting:\n  proseWrap: always\n  tabWidth: 4"
        },
        "proseWrap": {
          "type": "string",
          "enum": [
            "always",
            "never",
            "preserve"
          ],
          "description": "Explicit proseWrap setting (shorthand for prettier.proseWrap)."
        },
        "tabWidth": {
          "type": "number",
          "description": "Explicit tabWidth setting (shorthand for prettier.tabWidth)."
        },
        "printWidth": {
          "type": "number",
          "description": "Explicit printWidth setting (shorthand for prettier.printWidth)."
        }
      },
      "additionalProperties": false,
      "description": "Formatting configuration for output files. Controls how generated markdown is formatted."
    },
    "PrettierMarkdownOptions": {
      "type": "object",
      "properties": {
        "proseWrap": {
          "type": "string",
          "enum": [
            "always",
            "never",
            "preserve"
          ],
          "description": "How to wrap prose.\n- 'always': Wrap prose at printWidth\n- 'never': Do not wrap prose\n- 'preserve': Preserve original wrapping",
          "default": "preserve"
        },
        "tabWidth": {
          "type": "number",
          "description": "Number of spaces per indentation level.",
          "default": 2
        },
        "printWidth": {
          "type": "number",
          "description": "Maximum line width for prose wrapping.",
          "default": 80
        }
      },
      "additionalProperties": false,
      "description": "Prettier markdown formatting options. These options control how markdown output is formatted."
    },
    "OutputConvention": {
      "type": "object",
      "properties": {
        "name": {
          "$ref": "#/definitions/ConventionName",
          "description": "Convention identifier."
        },
        "description": {
          "type": "string",
          "description": "Human-readable description."
        },
        "section": {
          "$ref": "#/definitions/SectionRenderer",
          "description": "Section rendering configuration."
        },
        "subsection": {
          "$ref": "#/definitions/SectionRenderer",
          "description": "Subsection rendering (defaults to section config if not specified)."
        },
        "listStyle": {
          "type": "string",
          "enum": [
            "dash",
            "asterisk",
            "bullet",
            "numbered"
          ],
          "description": "How to render lists.",
          "default": "'dash' (- item)"
        },
        "codeBlockDelimiter": {
          "type": "string",
          "description": "Code block delimiter.",
          "default": "```"
        },
        "rootWrapper": {
          "type": "object",
          "properties": {
            "start": {
              "type": "string"
            },
            "end": {
              "type": "string"
            }
          },
          "required": [
            "start",
            "end"
          ],
          "additionalProperties": false,
          "description": "Whether to wrap content in a root element."
        }
      },
      "required": [
        "name",
        "section"
      ],
      "additionalProperties": false,
      "description": "Output convention definition."
    },
    "SectionRenderer": {
      "type": "object",
      "properties": {
        "start": {
          "type": "string",
          "description": "Template for section start. Variables: {{name}}, {{level}}, {{content}}",
          "example": "Markdown: \"{{#repeat level}}#{{/repeat}} {{name}}\""
        },
        "end": {
          "type": "string",
          "description": "Template for section end (optional, for paired tags). Variables: {{name}}",
          "example": "Markdown: \"\" (empty - no closing tag)"
        },
        "nameTransform": {
          "type": "string",
          "enum": [
            "kebab-case",
            "camelCase",
            "PascalCase",
            "none"
          ],
          "description": "Whether to convert section names.",
          "default": "kebab-case"
        },
        "indent": {
          "type": "string",
          "description": "Indentation per level.",
          "default": "'  ' (2 spaces)"
        }
      },
      "required": [
        "start"
      ],
      "additionalProperties": false,
      "description": "Section rendering configuration."
    },
    "PolicyDefinition": {
      "anyOf": [
        {
          "$ref": "#/definitions/LayerBoundaryPolicy"
        },
        {
          "$ref": "#/definitions/PropertyProtectionPolicy"
        },
        {
          "$ref": "#/definitions/RegistryAllowlistPolicy"
        }
      ],
      "description": "Union of all policy definition types."
    },
    "LayerBoundaryPolicy": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "description": "Unique policy name within the config"
        },
        "description": {
          "type": "string",
          "description": "Human-readable description"
        },
        "kind": {
          "type": "string",
          "const": "layer-boundary",
          "description": "Policy kind discriminator"
        },
        "severity": {
          "$ref": "#/definitions/PolicySeverity",
          "description": "Violation severity"
        },
        "layers": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Ordered list of layers from base to leaf"
        },
        "maxDistance": {
          "type": "number",
          "description": "Maximum allowed distance between source and target layers (default: 1)"
        }
      },
      "required": [
        "kind",
        "layers",
        "name",
        "severity"
      ],
      "additionalProperties": false,
      "description": "Layer-boundary policy: controls which layers can extend which."
    },
    "PolicySeverity": {
      "type": "string",
      "enum": [
        "error",
        "warning"
      ],
      "description": "Severity for policy violations."
    },
    "PropertyProtectionPolicy": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "description": "Unique policy name within the config"
        },
        "description": {
          "type": "string",
          "description": "Human-readable description"
        },
        "kind": {
          "type": "string",
          "const": "property-protection",
          "description": "Policy kind discriminator"
        },
        "severity": {
          "$ref": "#/definitions/PolicySeverity",
          "description": "Violation severity"
        },
        "properties": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Properties that cannot be overridden"
        },
        "targetPattern": {
          "type": "string",
          "description": "Glob pattern for target skills (e.g., '@core/*'). If omitted, applies to all."
        }
      },
      "required": [
        "kind",
        "name",
        "properties",
        "severity"
      ],
      "additionalProperties": false,
      "description": "Property-protection policy: prevents overriding specific properties."
    },
    "RegistryAllowlistPolicy": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "description": "Unique policy name within the config"
        },
        "description": {
          "type": "string",
          "description": "Human-readable description"
        },
        "kind": {
          "type": "string",
          "const": "registry-allowlist",
          "description": "Policy kind discriminator"
        },
        "severity": {
          "$ref": "#/definitions/PolicySeverity",
          "description": "Violation severity"
        },
        "allowed": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "List of allowed registry prefixes"
        }
      },
      "required": [
        "allowed",
        "kind",
        "name",
        "severity"
      ],
      "additionalProperties": false,
      "description": "Registry-allowlist policy: restricts which registries can provide extensions."
    }
  }
}
