{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://leji.org/schemas/v1.0/agent-profile.schema.json",
  "title": "Leji agent profile frontmatter",
  "description": "Validates the YAML frontmatter of an agent profile document. The markdown body stays free-form.",
  "type": "object",
  "required": [
    "id",
    "name",
    "role",
    "requiredRead",
    "mustAskWhen"
  ],
  "additionalProperties": false,
  "properties": {
    "id": {
      "description": "Stable identifier for this profile, e.g. \"core\" or \"reviewer\".",
      "type": "string",
      "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
    },
    "name": {
      "description": "Human-readable name of the role.",
      "type": "string",
      "minLength": 1
    },
    "role": {
      "description": "The role identifier this profile fills, bound in the manifest's agents map.",
      "type": "string",
      "minLength": 1
    },
    "purpose": {
      "description": "One line on what this role is for.",
      "type": "string"
    },
    "version": {
      "description": "Optional version of this profile.",
      "type": "string"
    },
    "inherits": {
      "type": "string",
      "description": "id of the profile this one extends, typically the core profile."
    },
    "requiredRead": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "string",
        "pattern": "^(?!/)(?!\\./)(?!.*(^|/)\\.\\.(/|$))(?!.*\\\\).+$"
      },
      "description": "Paths this role loads before any task."
    },
    "defaultContext": {
      "type": "array",
      "items": {
        "enum": [
          "domain",
          "system",
          "practice",
          "governance",
          "decisions"
        ]
      },
      "description": "Categories this role loads by default."
    },
    "mustAskWhen": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "string"
      },
      "description": "Conditions under which the role must stop and ask a human."
    },
    "mustRefuseWhen": {
      "description": "Conditions under which the role must refuse outright rather than ask.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "escalation": {
      "type": "string",
      "description": "Who or what to escalate to."
    },
    "owners": {
      "description": "Optional owners of this profile.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "freshness": {
      "description": "Review horizon for this profile.",
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "reviewAfter": {
          "description": "ISO 8601 date after which the profile should be reviewed for staleness.",
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
        }
      }
    },
    "host": {
      "type": "string",
      "description": "The agent host that runs this agent, e.g. \"claude-code\", \"codex\", \"cursor\". Omit for host-agnostic profiles."
    },
    "invocation": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "command"
      ],
      "properties": {
        "command": {
          "type": "string",
          "description": "Command template to engage this agent from a shell, with <prompt> as the placeholder."
        },
        "constraints": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Operational constraints worth machine-knowing, e.g. prompt length limits, timeouts."
        }
      },
      "description": "How to engage this agent as an external CLI. Omit for the host's own resident agent."
    }
  }
}
