#  Copyright (c) 2026 Cisco Systems, Inc. and its affiliates
#  SPDX-License-Identifier: Apache-2.0
$schema: "https://json-schema.org/draft-07/schema#"
$id: "mas/v1"
title: "MAS Manifest"
description: >
  Schema for kind: MAS manifests (apiVersion: mas/v1). Authoritative field list
  is derived from MASSpec in mas.py. Validate with: python -m jsonschema
  --instance mas.yaml mas.schema.yaml
type: object
required:
  - apiVersion
  - kind
  - metadata
  - spec
additionalProperties: false
patternProperties:
  "^x-":
    description: "Extension properties (UI metadata, canvas state, etc.) — ignored by the runtime."
properties:
  apiVersion:
    type: string
    const: "mas/v1"

  kind:
    type: string
    const: "MAS"

  intent:
    type: object
    description: "Optional: what this system knows and can do."
    additionalProperties: false
    properties:
      summary:
        type: string
        default: ""

  x-canvas-positions:
    type: object
    description: "UI-only: React Flow node positions (not consumed by runtime)."
    additionalProperties:
      type: object
      additionalProperties: false
      properties:
        x:
          type: number
        y:
          type: number
      required: [x, y]

  metadata:
    type: object
    required: [name]
    additionalProperties: false
    patternProperties:
      "^x-":
        description: "Extension properties (UI metadata) — ignored by the runtime."
    properties:
      name:
        type: string
        minLength: 1
        not:
          pattern: "[/\\\\]"
        description: >
          Unique MAS identifier. Used in run output paths and agent URNs.
          A filesystem path is not a name.
      version:
        type: string
        pattern: "^[0-9]+\\.[0-9]+\\.[0-9]+.*$"
        default: "0.1.0"
      description:
        type: string
        default: ""
      tags:
        type: array
        items:
          type: string
        default: []
      default_flavour:
        type: string
        description: "Name of the flavour to use when none is specified on the CLI."
        default: "local"

  spec:
    type: object
    additionalProperties: false
    patternProperties:
      "^x-":
        description: "Extension properties (UI metadata) — ignored by the runtime."
    properties:
      models:
        type: array
        description: >
          MAS default model(s). Agents that omit spec.models or set
          model: any inherit the primary entry (id: main). `any` means
          this MAS does not pin a provider id — inherit experiment.models.main
          / experiment.model, then local config.yaml defaults.model. Same shape
          as Agent spec.models[].
        default: []
        items:
          type: object
          required: [model]
          additionalProperties: false
          properties:
            id:
              type: string
              default: "main"
            model:
              type: string
              description: >
                LiteLLM id, or `any` to inherit experiment.models.<id>
                (models.main / experiment.model for id main), then local
                config.yaml defaults.model.
            temperature:
              type: number
              minimum: 0.0
              maximum: 2.0
            max_tokens:
              type: integer
              minimum: 1
            max_completion_tokens:
              type: integer
              minimum: 1
            on_truncation:
              $ref: "./fragments/llm-truncation.schema.yaml"
            context_window:
              type: integer
              minimum: 1
      agents:
        description: >
          On a base MAS manifest: short form, a list of agent entries
          (equivalent to agency.agents). On an Overlay patch
          (spec.patch.agents): overlay-only, either a per-agent-id override
          map (each value is an Agent-patch object applied to that
          agency.agents entry) or a {"$op": {replace|add|remove|clear}}
          collection op on spec.agency.agents — special-cased merge logic
          (merge_mas_overlay), not part of the generic x-merge dispatch, and
          not meaningful to set in this object form on a base MAS manifest
          (there's nothing yet to override/remove from). Reserved keys
          $entry, $all, $not-entry, and $delegates expand onto agency ids
          after this overlay's workflow patch.
        oneOf:
          - type: array
            default: []
            items:
              oneOf:
                - type: object
                  required: [ref]
                  additionalProperties: false
                  properties:
                    id:
                      type: string
                    ref:
                      type: string
                - type: object
                  required: [kind, metadata, spec]
                  additionalProperties: false
                  patternProperties:
                    "^x-":
                      description: "UI extension — ignored by the runtime."
                  properties:
                    apiVersion:
                      type: string
                      const: "mas/v1"
                    kind:
                      type: string
                      const: "Agent"
                    metadata:
                      type: object
                    spec:
                      type: object
          - type: object

      transport:
        type: object
        description: "Transport / communication protocol config."
        additionalProperties: false
        properties:
          type:
            type: string
            enum: [local, agent-remote, agent-local]
            default: "local"
          mode:
            type: string
            enum: [local, remote]
            default: "local"
          emulation:
            type: boolean
            description: "When true, delegation uses in-process function calls (no HTTP)."
            default: true

      framework:
        type: object
        additionalProperties: false
        description: >
          Framework surface adapter for this MAS use-case. Selects which ctl/lab
          wrapper mounts around the native machinery skeleton (not an alternate kernel).
          Lab infers the runner from default_adapter unless execution.runner overrides.
        properties:
          default_adapter:
            type: string
            enum: [native, langgraph, autogen, crewai]
            default: native
            description: >
              Framework adapter id. native = direct default OSS kernel; others delegate
              to registered ctl framework wrappers (future release).

      agency:
        type: object
        description: "The agents and their topology."
        x-merge:
          strategy: replace
        additionalProperties: false
        properties:
          agents:
            type: array
            description: "Ordered list of agent participants and delegation targets."
            default: []
            items:
              oneOf:
                - type: object
                  required: [id]
                  additionalProperties: false
                  properties:
                    id:
                      type: string
                      description: "Logical identifier used in workflow edges and delegation lists."
                    ref:
                      type: string
                      description: "Path to the agent manifest, relative to the MAS manifest directory."
                - type: object
                  required: [kind, metadata, spec]
                  additionalProperties: false
                  patternProperties:
                    "^x-":
                      description: "UI extension — ignored by the runtime."
                  properties:
                    apiVersion:
                      type: string
                      const: "mas/v1"
                    kind:
                      type: string
                      const: "Agent"
                    metadata:
                      type: object
                    spec:
                      type: object

      workflow:
        type: object
        description: "Workflow topology — entry point and delegation graph."
        x-merge:
          strategy: replace
        additionalProperties: false
        properties:
          entry:
            type: string
            description: "ID of the entry-point agent (first to receive the user request)."
          nodes:
            type: array
            description: "Agent nodes in the workflow graph."
            default: []
            items:
              $ref: "./fragments/workflow-node.schema.yaml"

      tools_ref:
        type: [string, "null"]
        description: "MAS-level logical tool-set name resolved by the infra ToolRegistry."
        pattern: "^[a-z0-9][a-z0-9_-]*$"
        default: null

      middleware:
        description: "Middleware config (reserved for future use)."
        default: null

      memory_stores:
        type: object
        description: "Named memory store artifact paths."
        additionalProperties: false
        properties:
          episodic_ref:
            type: string
            default: ""
          semantic_ref:
            type: string
            default: ""
          procedural_ref:
            type: string
            default: ""

      telemetry:
        type: object
        description: "Telemetry output config."
        x-merge:
          strategy: mapping_merge_or_ops
        additionalProperties: false
        properties:
          path:
            type: string
            description: "Path to the event log file (JSONL), relative to mas.yaml."
            default: ""

      params:
        type: object
        description: >
          Free-form key/value params for this MAS, read by lab/benchmark
          tooling (e.g. mas.lab.lab.config.scenario_loading) — not consumed
          by the runtime kernel directly.
        x-merge:
          strategy: mapping_merge_or_ops
        additionalProperties:
          type: string
        default: {}

      capabilities:
        type: object
        description: >
          Free-form capability declarations read by lab/benchmark manifest
          loading (mas.lab.manifest.load) when synthesizing a LoadedMAS
          runtime dict — not consumed by the runtime kernel directly.
        x-merge:
          strategy: mapping_merge_or_ops
        additionalProperties: true
        default: {}

      intent:
        type: object
        description: >
          Overlay-patchable form of the top-level intent block (patches
          always land under spec.intent, not the top-level intent —
          see merge_mas_overlay). Prefer the top-level intent field when
          authoring a base MAS manifest directly.
        x-merge:
          strategy: mapping_merge_or_ops
        additionalProperties: true
        default: {}
