{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://raw.githubusercontent.com/itlackey/openpalm/main/packages/lib/src/control-plane/setup-config.schema.json",
  "title": "OpenPalm SetupConfig",
  "description": "Structured configuration for the OpenPalm setup wizard. Defines connections, model assignments, portals, services, and security settings needed for first-time installation or reconfiguration.",
  "type": "object",
  "required": ["version", "security", "capabilities", "assignments"],
  "additionalProperties": false,
  "properties": {
    "version": {
      "const": 1,
      "description": "Schema version. Must be 1."
    },
    "owner": {
      "type": "object",
      "description": "Optional owner identity for this OpenPalm instance.",
      "additionalProperties": false,
      "properties": {
        "name": {
          "type": "string",
          "description": "Display name of the instance owner."
        },
        "email": {
          "type": "string",
          "description": "Email address of the instance owner.",
          "format": "email"
        }
      }
    },
    "security": {
      "type": "object",
      "description": "Security settings for the instance.",
      "required": ["uiLoginPassword"],
      "additionalProperties": false,
      "properties": {
        "uiLoginPassword": {
          "type": "string",
          "description": "Operator login password for the OpenPalm UI. Persisted as knowledge/secrets/op_ui_login_password; the UI's op_session cookie value is compared against it on every authenticated request.",
          "minLength": 8
        }
      }
    },
    "capabilities": {
      "type": "array",
      "description": "LLM provider capabilities available to the instance. Must contain at least one entry.",
      "minItems": 1,
      "items": {
        "$ref": "#/$defs/SetupCapability"
      }
    },
    "assignments": {
      "$ref": "#/$defs/SetupConfigAssignments"
    },
    "portals": {
      "type": "object",
      "description": "Optional portal configurations. Keys are portal identifiers (e.g. 'chat', 'discord', 'api'). Values can be a boolean to enable (true) or skip (false) installation, or a credential object.",
      "additionalProperties": {
        "oneOf": [
          {
            "type": "boolean",
            "description": "Enable (true) or disable (false) this portal with default settings."
          },
          {
            "$ref": "#/$defs/ChannelCredentials"
          }
        ]
      }
    },
    "services": {
      "type": "object",
      "description": "Optional service configurations. Keys are service identifiers (e.g. 'admin', 'ollama'). Values can be a boolean to enable (true) or skip (false) installation, or a config object.",
      "additionalProperties": {
        "oneOf": [
          {
            "type": "boolean",
            "description": "Enable (true) or disable (false) this service with default settings."
          },
          {
            "$ref": "#/$defs/ServiceConfig"
          }
        ]
      }
    }
  },
  "$defs": {
    "SetupCapability": {
      "type": "object",
      "description": "An LLM provider capability with endpoint and credentials.",
      "required": ["id", "name", "provider", "baseUrl"],
      "additionalProperties": false,
      "properties": {
        "id": {
          "type": "string",
          "description": "Unique capability identifier. Must start with a letter or digit; allows A-Z, a-z, 0-9, underscore, and hyphen.",
          "pattern": "^[A-Za-z0-9][A-Za-z0-9_-]*$"
        },
        "name": {
          "type": "string",
          "description": "Human-readable display name for this capability.",
          "minLength": 1
        },
        "provider": {
          "type": "string",
          "description": "Provider identifier. Must be a recognized provider from the wizard scope. 'ollama-instack' is an internal alias used by the CLI to route Ollama capabilities to the in-stack Ollama service container.",
          "enum": [
            "openai",
            "anthropic",
            "ollama",
            "groq",
            "together",
            "mistral",
            "deepseek",
            "xai",
            "lmstudio",
            "model-runner",
            "ollama-instack",
            "google",
            "huggingface"
          ]
        },
        "baseUrl": {
          "type": "string",
          "description": "Base URL for the provider API endpoint. Can be empty for cloud providers that use default URLs."
        },
        "apiKey": {
          "type": "string",
          "description": "API key for authentication. Optional for local providers (e.g. Ollama, LM Studio) that do not require authentication."
        }
      }
    },
    "SetupConfigAssignments": {
      "type": "object",
      "description": "Model capability assignments mapping connections and models to system roles.",
      "required": ["llm", "embeddings"],
      "additionalProperties": false,
      "properties": {
        "llm": {
          "type": "object",
          "description": "Primary LLM assignment for the system.",
          "required": ["capabilityId", "model"],
          "additionalProperties": false,
          "properties": {
            "capabilityId": {
              "type": "string",
              "description": "ID of the connection to use for LLM inference. Must reference a capability in the capabilities array."
            },
            "model": {
              "type": "string",
              "description": "Model identifier for the primary LLM (e.g. 'gpt-4o', 'claude-sonnet-4-20250514')."
            },
            "smallModel": {
              "type": "string",
              "description": "Optional smaller/faster model for lightweight akm operations."
            }
          }
        },
        "embeddings": {
          "type": "object",
          "description": "Embedding model assignment for akm and semantic operations.",
          "required": ["capabilityId", "model"],
          "additionalProperties": false,
          "properties": {
            "capabilityId": {
              "type": "string",
              "description": "ID of the connection to use for embeddings. Must reference a capability in the capabilities array."
            },
            "model": {
              "type": "string",
              "description": "Model identifier for embeddings (e.g. 'text-embedding-3-small', 'nomic-embed-text')."
            },
            "embeddingDims": {
              "type": "integer",
              "description": "Embedding vector dimensions. Auto-detected from known models if omitted.",
              "minimum": 1
            }
          }
        },
        "tts": {
          "description": "Optional text-to-speech assignment. Can be an engine name string, an object with engine details, or null to disable.",
          "oneOf": [
            {
              "type": "string",
              "description": "TTS engine name (e.g. 'kokoro', 'piper', 'openai-tts', 'browser-tts')."
            },
            {
              "$ref": "#/$defs/VoiceAssignment"
            },
            {
              "type": "null"
            }
          ]
        },
        "stt": {
          "description": "Optional speech-to-text assignment. Can be an engine name string, an object with engine details, or null to disable.",
          "oneOf": [
            {
              "type": "string",
              "description": "STT engine name (e.g. 'whisper-local', 'openai-stt', 'browser-stt')."
            },
            {
              "$ref": "#/$defs/VoiceAssignment"
            },
            {
              "type": "null"
            }
          ]
        }
      }
    },
    "VoiceAssignment": {
      "type": "object",
      "description": "Detailed voice engine assignment with optional connection and model.",
      "required": ["engine"],
      "additionalProperties": false,
      "properties": {
        "engine": {
          "type": "string",
          "description": "Voice engine identifier."
        },
        "capabilityId": {
          "type": "string",
          "description": "Optional capability ID if the engine requires an API provider."
        },
        "model": {
          "type": "string",
          "description": "Optional model identifier for the voice engine."
        }
      }
    },
    "ChannelCredentials": {
      "type": "object",
      "description": "Portal configuration with optional credentials. Supports Discord, Slack, and custom portal fields.",
      "properties": {
        "enabled": {
          "type": "boolean",
          "description": "Whether this portal is enabled. Defaults to true if the portal entry exists."
        },
        "botToken": {
          "type": "string",
          "description": "Discord bot token."
        },
        "applicationId": {
          "type": "string",
          "description": "Discord application ID."
        },
        "registerCommands": {
          "type": "boolean",
          "description": "Whether to register Discord slash commands on startup."
        },
        "allowedGuilds": {
          "type": "string",
          "description": "Comma-separated list of allowed Discord guild IDs."
        },
        "allowedRoles": {
          "type": "string",
          "description": "Comma-separated list of allowed Discord role IDs."
        },
        "allowedUsers": {
          "type": "string",
          "description": "Comma-separated list of allowed user IDs."
        },
        "blockedUsers": {
          "type": "string",
          "description": "Comma-separated list of blocked user IDs."
        },
        "slackBotToken": {
          "type": "string",
          "description": "Slack bot token (xoxb-...)."
        },
        "slackAppToken": {
          "type": "string",
          "description": "Slack app-level token (xapp-...)."
        },
        "allowedChannels": {
          "type": "string",
          "description": "Comma-separated list of allowed Slack channel IDs."
        }
      },
      "additionalProperties": true
    },
    "ServiceConfig": {
      "type": "object",
      "description": "Service configuration with an enabled flag and optional extra settings.",
      "required": ["enabled"],
      "properties": {
        "enabled": {
          "type": "boolean",
          "description": "Whether this service is enabled."
        }
      },
      "additionalProperties": true
    }
  }
}
