{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "prismd runtime configuration",
  "description": "Validates prismd.json, the single runtime config file generated by scripts/generate-config.mjs.",
  "type": "object",
  "additionalProperties": false,
  "required": ["version", "server", "auth", "providers", "models", "policies"],
  "properties": {
    "version": {
      "type": "integer",
      "minimum": 1
    },
    "server": {
      "type": "object",
      "additionalProperties": false,
      "required": ["host", "port"],
      "properties": {
        "host": { "type": "string", "minLength": 1 },
        "port": { "type": "integer", "minimum": 1, "maximum": 65535 }
      }
    },
    "auth": {
      "type": "object",
      "additionalProperties": false,
      "required": ["localTokenField"],
      "properties": {
        "localTokenField": { "type": "string", "minLength": 1 }
      }
    },
    "providers": {
      "type": "object",
      "minProperties": 1,
      "additionalProperties": { "$ref": "#/definitions/provider" }
    },
    "models": {
      "type": "object",
      "description": "Model aliases exposed by the gateway; each key is an alias name.",
      "additionalProperties": { "$ref": "#/definitions/model" }
    },
    "policies": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "failoverOn",
        "retryBeforeStream",
        "retryAfterStream",
        "maxCandidatesPerRequest",
        "respectRetryAfter",
        "quotaSoftLimitRatio",
        "connectTimeoutMs",
        "streamIdleTimeoutMs"
      ],
      "properties": {
        "failoverOn": {
          "type": "array",
          "items": { "type": "string" },
          "uniqueItems": true
        },
        "retryBeforeStream": { "type": "boolean" },
        "retryAfterStream": { "type": "boolean" },
        "maxCandidatesPerRequest": { "type": "integer", "minimum": 1 },
        "respectRetryAfter": { "type": "boolean" },
        "quotaSoftLimitRatio": { "type": "number", "minimum": 0, "maximum": 1 },
        "connectTimeoutMs": { "type": "integer", "minimum": 0 },
        "streamIdleTimeoutMs": { "type": "integer", "minimum": 0 },
        "failThreshold": {
          "type": "integer",
          "minimum": 1,
          "description": "Consecutive failures before a candidate is marked unhealthy (default 3)."
        },
        "cooldownMs": {
          "type": "integer",
          "minimum": 0,
          "description": "Unhealthy cooldown duration in ms (default 60000)."
        }
      }
    }
  },
  "definitions": {
    "provider": {
      "type": "object",
      "additionalProperties": false,
      "required": ["type", "baseUrl", "apiKeyField"],
      "properties": {
        "type": { "enum": ["responses", "chat"] },
        "baseUrl": { "type": "string", "minLength": 1 },
        "apiKeyField": {
          "type": "string",
          "minLength": 1,
          "description": "Key field in ~/.prismd/keys.yaml; env var lookup uses <FIELD>_API_KEY uppercased."
        },
        "auth": {
          "type": "object",
          "description": "Auth type reserved for M3+ (oauth); phase 1 only uses api_key.",
          "required": ["type"],
          "properties": {
            "type": { "enum": ["api_key", "oauth", "none"] }
          }
        },
        "extraHeaders": {
          "type": "object",
          "additionalProperties": { "type": "string" }
        }
      }
    },
    "limits": {
      "type": "object",
      "additionalProperties": false,
      "description": "Soft limits used as routing weights, never hard blocks. dailyRequests may be null or omitted when unknown.",
      "required": ["rpm", "maxConcurrent"],
      "properties": {
        "dailyRequests": { "type": ["integer", "null"], "minimum": 0 },
        "rpm": { "type": "integer", "minimum": 0 },
        "maxConcurrent": { "type": "integer", "minimum": 0 }
      }
    },
    "candidate": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "provider",
        "providerModelId",
        "contextWindow",
        "maxOutputTokens",
        "supportsTools",
        "supportsReasoning",
        "limits",
        "tags"
      ],
      "properties": {
        "provider": { "type": "string", "minLength": 1 },
        "providerModelId": { "type": "string", "minLength": 1 },
        "contextWindow": { "type": "integer", "minimum": 1 },
        "maxOutputTokens": { "type": "integer", "minimum": 1 },
        "supportsTools": { "type": "boolean" },
        "supportsReasoning": { "type": "boolean" },
        "limits": { "$ref": "#/definitions/limits" },
        "tags": {
          "type": "array",
          "items": { "type": "string" },
          "uniqueItems": true
        }
      }
    },
    "model": {
      "type": "object",
      "additionalProperties": false,
      "required": ["candidates"],
      "properties": {
        "description": { "type": "string" },
        "candidates": {
          "type": "array",
          "minItems": 1,
          "items": { "$ref": "#/definitions/candidate" }
        }
      }
    }
  }
}
