{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://swl-ses.dev/schemas/agent-frontmatter.json",
  "title": "SWL Agent Frontmatter",
  "description": "Schema de validacion para el frontmatter YAML de agentes del sistema SWL",
  "type": "object",
  "required": ["name", "description", "tools", "model", "version", "nivelRiesgo"],
  "properties": {
    "name": {
      "type": "string",
      "pattern": "^[a-z][a-z0-9-]+-swl$",
      "maxLength": 64,
      "description": "Nombre en kebab-case terminado en -swl"
    },
    "description": {
      "type": "string",
      "minLength": 20,
      "maxLength": 1024,
      "description": "Descripcion que incluye QUE hace y CUANDO invocarlo"
    },
    "tools": {
      "type": "array",
      "items": {
        "type": "string",
        "enum": ["Read", "Write", "Edit", "Bash", "Grep", "Glob", "Agent", "Skill", "WebSearch", "WebFetch"]
      },
      "minItems": 1,
      "description": "Herramientas permitidas para este agente"
    },
    "model": {
      "type": "string",
      "oneOf": [
        { "enum": ["opus", "sonnet", "haiku", "inherit"] },
        { "pattern": "^claude-(opus|sonnet|haiku)-[0-9]+-[0-9]+(-[0-9]+)?$" }
      ],
      "description": "Modelo principal del agente. Acepta alias cortos (opus/sonnet/haiku), 'inherit' para sub-agentes, o nombre completo tipo 'claude-opus-4-7', 'claude-sonnet-4-6', 'claude-haiku-4-5-20251001'."
    },
    "modeloAlterno": {
      "type": "string",
      "oneOf": [
        { "enum": ["opus", "sonnet", "haiku", "inherit"] },
        { "pattern": "^claude-(opus|sonnet|haiku)-[0-9]+-[0-9]+(-[0-9]+)?$" }
      ],
      "description": "Modelo alternativo cuando el principal no esta disponible. Mismos formatos aceptados que 'model'."
    },
    "ventanaContexto": {
      "type": "string",
      "description": "Ventana de contexto recomendada"
    },
    "version": {
      "type": "string",
      "pattern": "^\\d+\\.\\d+\\.\\d+$",
      "description": "Version semantica del agente"
    },
    "nivelRiesgo": {
      "type": "string",
      "enum": ["BAJO", "MEDIO", "ALTO"],
      "description": "Nivel de riesgo de las operaciones del agente"
    },
    "skillsInvocables": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Skills que este agente puede invocar"
    },
    "skillsRestringidos": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Skills que este agente NO debe invocar"
    },
    "permisosRed": {
      "type": "boolean",
      "description": "Si el agente puede hacer llamadas de red"
    },
    "permisosEscritura": {
      "type": "boolean",
      "description": "Si el agente puede escribir archivos"
    },
    "permisosComandos": {
      "type": "boolean",
      "description": "Si el agente puede ejecutar comandos bash"
    },
    "presupuestoMaxUsd": {
      "type": "number",
      "minimum": 0.01,
      "maximum": 50.0,
      "description": "Presupuesto maximo en USD por invocacion del agente. Inspirado en maxBudgetUsd del Anthropic Agent SDK. El hook tracking-costos emite alerta al 80% y sugiere detener al 100%"
    },
    "maxTurnos": {
      "type": "integer",
      "minimum": 1,
      "maximum": 100,
      "description": "Maximo de turnos (iteraciones de herramienta) por invocacion. Previene loops infinitos. Inspirado en maxTurns del Anthropic Agent SDK"
    },
    "toolBudget": {
      "type": "object",
      "properties": {
        "simple": { "type": "integer", "description": "Tool calls para tareas simples" },
        "standard": { "type": "integer", "description": "Tool calls para tareas estandar" },
        "complex": { "type": "integer", "description": "Tool calls para tareas complejas" }
      },
      "description": "Presupuesto de tool calls por nivel de complejidad"
    },
    "evolvable": {
      "type": "boolean",
      "description": "Marca AGP learnability. Si false, el loop de auto-evolucion NO debe proponer cambios a este agente. Default implicito (ausencia del campo): true para BAJO, false para MEDIO/ALTO."
    },
    "evolvable_scope": {
      "type": "array",
      "items": {
        "type": "string",
        "enum": ["description", "examples", "instructions", "skillsInvocables", "skillsRestringidos", "tools", "model", "nivelRiesgo", "permisosRed", "permisosEscritura", "permisosComandos"]
      },
      "description": "Si evolvable=true, limita las secciones/campos que el loop puede modificar. Ausente implica 'description' y 'examples' unicamente — campos de seguridad NUNCA evolucionan sin aprobacion humana."
    },
    "invariantes": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["campo", "operador", "valor"],
        "properties": {
          "campo": {
            "type": "string",
            "description": "Nombre de la propiedad del frontmatter a validar tras una evolucion (ej: 'permisosRed')."
          },
          "operador": {
            "type": "string",
            "enum": ["eq", "neq", "lte", "gte", "in", "not_in"],
            "description": "Operador de comparacion. eq/neq: igualdad; lte/gte: orden numerico; in/not_in: pertenencia a lista."
          },
          "valor": {
            "description": "Valor esperado. Para in/not_in debe ser array."
          },
          "razon": {
            "type": "string",
            "description": "Justificacion humana del invariante. Opcional pero recomendado."
          }
        },
        "additionalProperties": false
      },
      "description": "Safety invariants que el commit gate (run-skill-evals.js) debe verificar tras cada evolucion."
    },
    "exclusiones": {
      "type": "array",
      "items": { "type": "string" },
      "description": "Situaciones donde este agente NO debe invocarse aunque parezca relevante superficialmente. Campo propio de swl-ses; previene activacion tangencial (agent hijacking) por similitud de terminos en description. Equivalente estructural de la seccion 'Cuando NO invocarme' en el cuerpo, legible por herramientas de analisis sin parsear markdown. Aditivo, no breaking, aplicable a agentes con evolvable:false (metadata defensiva, no evolucion AGP — ver ADR-0004)."
    }
  },
  "additionalProperties": true
}
