# AUTO-GENERATED tier-A mirror spec — do not edit.
# Source: openapi/runtime/formations.yaml (runtime 0.71.2)
#  + policy: openapi/mirror-policies/formations.json
# Regenerate: node scripts/generate-mirror-specs.mjs
openapi: 3.0.3
info:
  title: naturali.ai — Formations API
  version: 1.0.0
  description: >-
    Formations: a declarative deployment layer for a whole agent stack — one template naming the
    agents, tools, memories and everything else a project needs, validated and planned before it is
    applied, then deployed, updated and torn down as one unit with dependency ordering, reference
    resolution and rollback owned by the runtime. What CloudFormation is to AWS resources, this is
    to a project's runtime resources. A fully runtime-backed module — this spec is generated
    verbatim from the runtime's own, re-rooted under /v1/projects/{project_id}. The project in the
    path is authorized by naturali and enforced upstream by the project's scoped credential.


    This module mirrors the upstream runtime verbatim (tier A, #304): paths are the runtime's own
    re-rooted under /v1/projects/{project_id}, and every field, method, status code and error shape
    passes through unchanged. Errors raised by the runtime arrive in its envelope; errors raised by
    naturali itself (authentication, project resolution, an unreachable runtime) use naturali's.
  contact:
    name: naturali.ai
    url: https://naturali.ai
servers:
  - url: "{baseUrl}"
    description: Host of your naturali.ai deployment; every path carries the /v1 prefix.
    variables:
      baseUrl:
        description: Base host URL.
        default: https://api.naturali.ai
tags:
  - name: Formations
    description: Manage declarative formation stacks
security:
  - bearerAuth: []
  - oauth2:
      - mcp:access
paths:
  /v1/projects/{project_id}/formations/validate:
    post:
      tags:
        - Formations
      summary: Validate a formation template
      description: >
        Validates a formation template without creating any resources. Returns a list of errors and
        warnings. Accepts the template as a JSON object or as a YAML/JSON string.
      operationId: validateFormation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                template:
                  $ref: "#/components/schemas/FormationTemplateInput"
                parameters:
                  type: object
                  additionalProperties:
                    type: string
                  description: >
                    Runtime parameter values that override or supply template parameter defaults.
                    Keys must match parameter names declared in `template.parameters`. When
                    provided, the validation result also reports required parameters that are still
                    missing after applying these values.
                  nullable: true
      responses:
        "200":
          description: Validation result
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValidationResult"
        "401":
          description: Unauthorized
    parameters:
      - $ref: "#/components/parameters/ProjectId"
  /v1/projects/{project_id}/formations/plan:
    post:
      tags:
        - Formations
      summary: Plan a formation deployment
      description: >
        Computes a diff between the desired template and the current stack state without making any
        changes. Returns the list of planned actions.
      operationId: planFormation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - template
              additionalProperties: false
              properties:
                formation_id:
                  x-naturali-ref: formations
                  type: string
                  description: Existing formation ID to compare against. Omit for new formation planning.
                template:
                  $ref: "#/components/schemas/FormationTemplateInput"
                parameters:
                  type: object
                  additionalProperties:
                    type: string
                  description: >
                    Runtime parameter values that override or supply template parameter defaults.
                    Keys must match parameter names declared in `template.parameters`. A parameter
                    declared with `use_previous_value: true` may be omitted to reuse its stored
                    value.
                  nullable: true
      responses:
        "200":
          description: Plan result
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanResult"
        "400":
          description: Bad Request
        "401":
          description: Unauthorized
        "403":
          description: Forbidden
    parameters:
      - $ref: "#/components/parameters/ProjectId"
  /v1/projects/{project_id}/formations:
    get:
      tags:
        - Formations
      summary: List formations
      description: Returns all formation stacks for a project
      operationId: listFormations
      parameters:
        - name: limit
          in: query
          required: false
          description: Maximum number of results to return
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
        - name: offset
          in: query
          required: false
          description: Number of results to skip
          schema:
            type: integer
            default: 0
      responses:
        "200":
          description: List of formations
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - total
                  - limit
                  - offset
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Formation"
                  total:
                    type: integer
                  limit:
                    type: integer
                  offset:
                    type: integer
        "401":
          description: Unauthorized
        "403":
          description: Forbidden
    post:
      tags:
        - Formations
      summary: Create a new formation
      description: >
        Validates the template, creates the formation record, then provisions all declared resources
        in dependency order.


        A **template-shape** error is refused with `400`. A **deploy** failure is not: the operation
        ran, so the formation is returned with `201` and `status: "failed"`, and `error` explains
        why (the resources created before the failure are rolled back). Read `status` — a `2xx` here
        means the deploy was attempted, not that it worked. The `naturali` CLI exits non-zero on
        that body so `create-formation && …` does not lie.
      operationId: createFormation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - template
              additionalProperties: false
              properties:
                name:
                  type: string
                  description: Human-readable name for the formation stack
                  example: my-agent-stack
                template:
                  $ref: "#/components/schemas/FormationTemplateInput"
                parameters:
                  type: object
                  additionalProperties:
                    type: string
                  description: >
                    Runtime parameter values that override or supply template parameter defaults.
                    Keys must match parameter names declared in `template.parameters`. Required
                    parameters (those without a default) must be provided here.
                  nullable: true
                metadata:
                  description: >
                    Static annotations stored on the formation record. This field is NOT a
                    substitution site: `sub`/`param`/`ref` expressions are rejected with 400
                    (`FORMATION_INVALID_METADATA`). For deploy-time substitution use the template's
                    top-level `metadata` block, which is resolved into `resolved_metadata`.
                  allOf:
                    - $ref: "#/components/schemas/NullableMetadataBag"
      responses:
        "201":
          description: Formation created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Formation"
        "400":
          description: Bad Request
        "401":
          description: Unauthorized
        "403":
          description: Forbidden — either the caller may not operate on formations in the project, or it lacks
            an action a resource this template declares requires. `error.meta.denied_actions` names
            every missing action; nothing is applied.
        "409":
          description: Formation with this name already exists
    parameters:
      - $ref: "#/components/parameters/ProjectId"
  /v1/projects/{project_id}/formations/{formation_id}:
    get:
      tags:
        - Formations
      summary: Get a specific formation
      description: Returns the formation stack including its current resources.
      operationId: getFormation
      parameters:
        - name: formation_id
          in: path
          required: true
          schema:
            type: string
          example: form_V1StGXR8Z5jdHi6B
      responses:
        "200":
          description: Formation details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Formation"
        "401":
          description: Unauthorized
        "403":
          description: Forbidden
        "404":
          description: Not Found
    put:
      tags:
        - Formations
      summary: Update an formation
      description: >
        Applies a new template to the formation. Resources are created, updated, or deleted to
        reconcile the current state with the desired state.


        A **template-shape** error is refused with `400`. A **deploy** failure is not: the operation
        ran, so the formation is returned with `200` and `status: "failed"`, and `error` explains
        why. Read `status` — a `2xx` here means the deploy was attempted, not that it worked. The
        `naturali` CLI exits non-zero on that body so `update-formation && …` does not lie.


        A deploy that replaced a resource and could not delete the superseded one answers `status:
        "active"` with `error.code: "FORMATION_REPLACE_CLEANUP_FAILED"` — the desired state is
        realised, and `error.meta.failures` names every resource still live. The next deploy retries
        the disposal.
      operationId: updateFormation
      parameters:
        - name: formation_id
          in: path
          required: true
          schema:
            type: string
          example: form_V1StGXR8Z5jdHi6B
      requestBody:
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                template:
                  $ref: "#/components/schemas/FormationTemplateInput"
                parameters:
                  type: object
                  additionalProperties:
                    type: string
                  description: >
                    Runtime parameter values that override or supply template parameter defaults.
                    Keys must match parameter names declared in `template.parameters`. Required
                    parameters (those without a default) must be provided here, unless the parameter
                    is declared with `use_previous_value: true`, in which case omitting it reuses
                    the previously stored value.
                  nullable: true
                metadata:
                  description: >
                    Static annotations stored on the formation record. This field is NOT a
                    substitution site: `sub`/`param`/`ref` expressions are rejected with 400
                    (`FORMATION_INVALID_METADATA`). For deploy-time substitution use the template's
                    top-level `metadata` block, which is resolved into `resolved_metadata`.
                  allOf:
                    - $ref: "#/components/schemas/NullableMetadataBag"
      responses:
        "200":
          description: Updated formation
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Formation"
        "400":
          description: Bad Request
        "401":
          description: Unauthorized
        "403":
          description: Forbidden — either the caller may not operate on formations in the project, or it lacks
            an action a resource this template declares requires. `error.meta.denied_actions` names
            every missing action; nothing is applied.
        "404":
          description: Not Found
    delete:
      tags:
        - Formations
      summary: Delete an formation
      description: >
        Deletes the formation stack and all its managed resources in reverse dependency order.


        A resource the platform refuses to delete on its own — most often an agent that has
        generation or trace history — fails the teardown with `409 FORMATION_DELETE_FAILED`, naming
        every blocking resource in `error.meta.failures`. Resolve the blockers (for an agent,
        `DELETE /v1/projects/{project_id}/agents/{agent_id}?force=true` also removes its generations
        and traces, and `deletion_policy: retain` exempts it from teardown entirely) and delete the
        formation again.


        A refusal the platform can foresee is found by a pre-flight, before the first delete:
        nothing is removed, and the formation stays `active` and intact for the retry. An
        unforeseeable error surfaces mid-teardown instead, where resources deleted before the
        blocker stay deleted and the formation is left in `delete_failed`. The error message states
        which happened.
      operationId: deleteFormation
      parameters:
        - name: formation_id
          in: path
          required: true
          schema:
            type: string
          example: form_V1StGXR8Z5jdHi6B
      responses:
        "200":
          description: Deleted
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                required:
                  - success
        "401":
          description: Unauthorized
        "403":
          description: Forbidden — either the caller may not operate on formations in the project, or it lacks
            an action a resource this template declares requires. `error.meta.denied_actions` names
            every missing action; nothing is applied.
        "404":
          description: Not Found
        "409":
          description: >
            One or more resources could not be deleted (`FORMATION_DELETE_FAILED`).
            `error.meta.failures` lists each one as `{ logical_id, resource_type, error }`. The
            `message` says whether the pre-flight caught it (nothing deleted, formation still
            `active`) or it surfaced mid-teardown (formation left in `delete_failed`).
    parameters:
      - $ref: "#/components/parameters/ProjectId"
  /v1/projects/{project_id}/formations/{formation_id}/events:
    get:
      tags:
        - Formations
      summary: List formation operation events
      description: >
        Returns all operations (create, update, delete) with their event logs for the formation,
        ordered chronologically.
      operationId: listFormationEvents
      parameters:
        - name: formation_id
          in: path
          required: true
          schema:
            type: string
          example: form_V1StGXR8Z5jdHi6B
        - name: limit
          in: query
          required: false
          description: Maximum number of results to return
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
        - name: offset
          in: query
          required: false
          description: Number of results to skip
          schema:
            type: integer
            default: 0
      responses:
        "200":
          description: List of operations
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - total
                  - limit
                  - offset
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/FormationOperation"
                  total:
                    type: integer
                  limit:
                    type: integer
                  offset:
                    type: integer
        "401":
          description: Unauthorized
        "403":
          description: Forbidden
        "404":
          description: Not Found
    parameters:
      - $ref: "#/components/parameters/ProjectId"
components:
  schemas:
    FormationTemplateInput:
      description: >
        A formation template supplied as either a JSON object or a YAML/JSON string. When a string
        is provided the server parses it with a YAML parser (JSON is valid YAML) before processing.
      oneOf:
        - $ref: "#/components/schemas/FormationTemplate"
        - type: string
          description: YAML or JSON string representation of a FormationTemplate
    FormationTemplate:
      type: object
      required:
        - resources
      properties:
        parameters:
          type: object
          additionalProperties:
            $ref: "#/components/schemas/ParameterDeclaration"
          description: >
            Declared parameters for this template. Each parameter may have a default value and an
            optional description. Parameters without a default must be supplied in the `parameters`
            field of the deploy request.
          nullable: true
        resources:
          type: object
          additionalProperties:
            $ref: "#/components/schemas/ResourceDeclaration"
          description: Map of logical resource IDs to resource declarations
        outputs:
          type: object
          additionalProperties: true
          description: >
            Map of output names to values. Values may use `{ "ref": "logicalId" }` to reference
            physical IDs of created resources, or `{ "param": "ParamName" }` and `{ "sub": "text
            ${ParamName}" }` to embed parameter values. `{ "ref_attr": "LogicalId.attribute" }`
            resolves a named attribute of a created resource, except one carrying credential
            material — a trigger's or webhook's `secret` is refused with 400 VALIDATION_FAILED,
            since a formation is readable by anyone holding `formations:GetFormation`. Read those
            from the resource's own secret route instead.
          nullable: true
        metadata:
          description: >
            Arbitrary metadata attached to the template. Supports the same substitution as
            `outputs`: `{ "ref": "logicalId" }` resolves to a created resource's physical ID, and `{
            "param": "ParamName" }` / `{ "sub": "text ${ParamName}" }` embed parameter values. The
            raw expressions are preserved here; the resolved values from the last deploy are exposed
            on the formation's `resolved_metadata` field.
          allOf:
            - $ref: "#/components/schemas/NullableMetadataBag"
    ParameterDeclaration:
      type: object
      properties:
        type:
          type: string
          description: Parameter type (currently only 'string' is supported)
          example: string
        default:
          type: string
          description: Default value used when the parameter is not supplied at deploy time
          nullable: true
        description:
          type: string
          description: Human-readable description of what this parameter represents
          nullable: true
        no_echo:
          type: boolean
          description: >
            When true, the parameter value should be treated as sensitive and not echoed in logs or
            UI. Analogous to NoEcho in CloudFormation.
          nullable: true
        use_previous_value:
          type: boolean
          description: >
            When true, omitting this parameter on update reuses its previously stored value instead
            of failing the required-parameter check — analogous to CloudFormation's
            UsePreviousValue, declared in the template. An explicitly supplied value still
            overrides. Has no effect on create (there is no previous value yet). The value is reused
            only where the underlying resource retains it (e.g. a secret's encrypted value);
            otherwise the last-applied value is used.
          nullable: true
    AgentResourceProperties:
      description: Creates an AI agent backed by a provider. The agent handles requests, runs tools, and
        can be attached to actors. Exactly one of `ai_provider_id` or `model_route_id` must be
        declared. Switching an existing agent between the two declares the new field together with
        an explicit `null` for the old one.
      type: object
      additionalProperties: false
      properties:
        ai_provider_id:
          x-naturali-ref: ai-providers
          type: string
          nullable: true
          description: Public ID of the AI provider to pin. Mutually exclusive with `model_route_id`.
        model_route_id:
          x-naturali-ref: model-routes
          type: string
          nullable: true
          description: Public ID of a model route in the same project — the agent's completion model is
            resolved through the route's ordered targets with failover. Mutually exclusive with
            `ai_provider_id` and `model`.
        name:
          type: string
          nullable: true
          description: Agent display name
        instructions:
          type: string
          nullable: true
          description: System instructions for the agent
        model:
          type: string
          nullable: true
          description: Model identifier (overrides provider default)
        tool_bindings:
          type: array
          nullable: true
          items:
            type: object
            additionalProperties: false
            properties:
              tool_id:
                x-naturali-ref: tools
                type: string
                description: Public ID of the tool to attach.
              tool:
                type: object
                nullable: true
                description: "Inline tool definition. Not supported in a template: declare a tool resource and
                  reference it via `tool_id`."
          description: 'Tools to attach, one binding object per tool: `{ tool_id }`. Tool-call gating is owned
            by guardrails (attached via `guardrail_ids` on the project, agent, or tool), not by the
            binding. Inline `tool` entries are not supported in templates; declare a tool resource
            and reference it via `tool_id` (a `{ "ref": … }` to a tool resource in the same template
            resolves at deploy time).'
        max_steps:
          type: integer
          nullable: true
          description: Maximum number of agentic steps per generation
        tool_choice:
          description: 'Controls how the model selects tools. Accepts a string (`"auto"`, `"required"`) or an
            object (`{ "type": "tool", "tool_name": "my_tool" }`).'
        stop_conditions:
          type: array
          nullable: true
          description: Conditions that stop the agent's work early — turn-scoped (`has_tool_call`) or
            chain-scoped (`max_chain_generations`).
          items:
            type: object
            additionalProperties: false
            properties:
              type:
                type: string
                description: Condition type — `has_tool_call` or `max_chain_generations`
              tool_name:
                type: string
                nullable: true
                description: Tool name to match when type is `has_tool_call`
              max_generations:
                type: integer
                nullable: true
                description: Generations the continuation chain may reach when type is `max_chain_generations`
        active_tool_ids:
          x-naturali-ref: tools
          type: array
          nullable: true
          items:
            type: string
          description: Subset of the bound tools that are active
        guardrail_ids:
          x-naturali-ref: guardrails
          type: array
          nullable: true
          items:
            type: string
          description: Guardrails attached at the agent scope.
        step_rules:
          type: array
          nullable: true
          description: Per-step overrides applied during multi-step generation. Steps not covered by a rule
            use the agent defaults.
          items:
            type: object
            additionalProperties: false
            properties:
              step:
                type: integer
                description: 1-indexed step number this rule applies to
              tool_choice:
                type: object
                nullable: true
                description: "Tool choice override for this step, e.g. `auto`, `required`, or `{ type: tool,
                  tool_name: search }`"
              active_tool_ids:
                x-naturali-ref: tools
                type: array
                nullable: true
                items:
                  type: string
                description: Tool IDs active on this step
        boundary_policy:
          type: object
          nullable: true
          description: Restricts which runtime actions the agent may invoke. Evaluated as the intersection
            with the caller's own policy.
          additionalProperties: false
          properties:
            statement:
              type: array
              description: List of IAM policy statements
              items:
                type: object
                additionalProperties: false
                properties:
                  effect:
                    type: string
                    description: Effect — `Allow` or `Deny`
                  action:
                    type: array
                    items:
                      type: string
                    description: IAM action strings, e.g. `memories:*` or `agents:DeleteAgent`
                  resource:
                    type: array
                    nullable: true
                    items:
                      type: string
                    description: Resource SRN patterns (optional; omit to match all resources)
                  condition:
                    type: object
                    nullable: true
                    additionalProperties: true
                    description: "Condition block, in the same grammar a policy document uses: keys are condition
                      operators mapping to context-key/value maps."
        temperature:
          type: number
          nullable: true
          description: Sampling temperature
        max_context_messages:
          type: integer
          nullable: true
          description: Maximum number of recent messages to include in the context window sent to the model.
            When null, all messages are included.
        single_session_per_actor:
          type: boolean
          nullable: true
          description: When true, only one open session per actor_id is allowed for this agent.
        trace_content_mode:
          type: string
          nullable: true
          description: Agent-scope zero-retention setting (`full` or `none`). `null` inherits the project's
            setting. `full` is refused when the project's own mode is `none`.
        on_approval_expiry:
          type: string
          nullable: true
          description: "What happens when a held tool call expires un-approved: `terminate` (the default when
            null) ends the chain, `react` spawns a continuation that reports the staleness to the
            agent."
        knowledge_config:
          type: object
          nullable: true
          description: Knowledge retrieval configuration. When set, relevant documents and memories are
            injected into every generation.
          additionalProperties: false
          properties:
            memory_store_ids:
              x-naturali-ref: memory-stores
              type: array
              items:
                type: string
              description: Public IDs of memory stores to retrieve from
            document_ids:
              x-naturali-ref: documents
              type: array
              items:
                type: string
              description: Public IDs of documents to retrieve from
            document_paths:
              type: array
              items:
                type: string
              description: Retrieve from all documents matching these path prefixes
            tags:
              description: Retrieve from documents and memories whose tags contain all these key-value pairs.
              allOf:
                - $ref: "#/components/schemas/TagBag"
            min_score:
              type: number
              description: Minimum raw cosine similarity (0–1) a vector candidate must reach to be ranked.
                Omitted, there is no floor.
            rrf_k:
              type: integer
              description: The `k` in the fusion term `1 / (k + rank)`; smaller weights the top of each ranking
                more heavily
            recency_half_life_days:
              type: number
              description: Half-life in days of the decay applied to memory results after fusion; `0` disables it
            limit:
              type: integer
              description: Maximum number of chunks to inject
            write_memory_store_id:
              x-naturali-ref: memory-stores
              type: string
              nullable: true
              description: Public ID of the memory store the agent can write to. When set, a `write_memory` tool
                is automatically available to the agent.
        output_schema:
          type: object
          nullable: true
          description: JSON Schema describing the structured object the model must return. Non-streaming
            generations are constrained to this schema; the parsed value is returned as
            `output.object`.
        prompt_caching:
          type: object
          nullable: true
          description: "Prompt caching for this agent's turns. `{\"enabled\": true}` marks a cache breakpoint
            at the end of the turn's static prefix — the tool definitions and the instructions
            together. Null or omitted is off."
          additionalProperties: false
          properties:
            enabled:
              type: boolean
              description: Whether the breakpoint is marked. Defaults to false.
    ActorResourceProperties:
      description: Creates a stateful conversation actor that wraps an agent or chat session and
        optionally links to a memory store.
      type: object
      additionalProperties: false
      required:
        - name
      properties:
        name:
          type: string
          description: Actor display name
        external_id:
          type: string
          nullable: true
          description: External identifier for idempotent actor creation
        instructions:
          type: string
          nullable: true
          description: Persona-specific instructions
        agent_id:
          x-naturali-ref: agents
          type: string
          nullable: true
          description: Linked agent ID (mutually exclusive with chat_id)
        chat_id:
          x-naturali-ref: chats
          type: string
          nullable: true
          description: Linked chat ID (mutually exclusive with agent_id)
    AiProviderResourceProperties:
      description: Configures an LLM provider connection (API key, model, endpoint) that agents use to
        generate responses.
      type: object
      additionalProperties: false
      required:
        - name
        - provider
        - default_model
      properties:
        name:
          type: string
          description: Provider display name
        provider:
          type: string
          enum:
            - openai
            - anthropic
            - google
            - xai
            - groq
            - ollama
            - azure
            - bedrock
            - vertex
            - gateway
            - custom
          description: Provider type
        default_model:
          type: string
          description: Default model identifier (e.g. gpt-4o, claude-3-7-sonnet)
        secret_id:
          x-naturali-ref: secrets
          type: string
          nullable: true
          description: Public ID of the secret containing the API key
        base_url:
          type: string
          nullable: true
          description: Custom base URL for the provider API (self-hosted or proxy)
        config:
          type: object
          nullable: true
          description: Provider-specific extra configuration
    ToolResourceProperties:
      description: Defines a tool (HTTP endpoint, MCP server, the runtime action, or pipeline) that agents
        can invoke during a generation.
      type: object
      additionalProperties: false
      required:
        - name
      properties:
        name:
          type: string
          description: Tool display name
        type:
          type: string
          nullable: true
          description: Tool type hint (e.g. http, mcp, pipeline)
        description:
          type: string
          nullable: true
          description: Tool description shown to the model
        parameters:
          type: object
          nullable: true
          description: JSON Schema describing the tool's input parameters (free-form, user-defined)
        execute:
          type: object
          nullable: true
          description: HTTP execution configuration. Required for `http` tools.
          additionalProperties: false
          properties:
            url:
              type: string
              description: Endpoint URL. Supports `{param}` placeholders resolved from tool arguments.
            method:
              type: string
              nullable: true
              description: "HTTP method (default: `POST`)"
            headers:
              type: object
              nullable: true
              description: Static headers included in every request
            body_mode:
              type: string
              nullable: true
              description: "Request body encoding for `POST`/`PUT`/`PATCH`: `json` (default) or `multipart`.
                Incompatible with `auth.type: aws_sigv4`."
            auth:
              type: object
              nullable: true
              additionalProperties: false
              description: Computed request credential. `type` is `aws_sigv4` (with `region`, `service`,
                `access_key_id`, `secret_access_key` and optional `session_token`) or
                `gcp_service_account` (with `credentials` and `scopes`). Credential fields accept
                `{{secret:...}}` references.
              properties:
                type:
                  type: string
                  description: "`aws_sigv4` or `gcp_service_account`"
                region:
                  type: string
                  nullable: true
                  description: "`aws_sigv4`: the signing region"
                service:
                  type: string
                  nullable: true
                  description: "`aws_sigv4`: the signing service"
                access_key_id:
                  type: string
                  nullable: true
                  description: "`aws_sigv4`: the access key id"
                secret_access_key:
                  type: string
                  nullable: true
                  description: "`aws_sigv4`: the secret access key"
                session_token:
                  type: string
                  nullable: true
                  description: "`aws_sigv4`: the temporary credential's session token"
                credentials:
                  type: string
                  nullable: true
                  description: "`gcp_service_account`: the service account key file JSON, as a string"
                scopes:
                  type: array
                  nullable: true
                  items:
                    type: string
                  description: "`gcp_service_account`: the scopes to mint for"
        mcp:
          type: object
          nullable: true
          description: MCP server connection configuration. Required for `mcp` tools.
          additionalProperties: false
          properties:
            url:
              type: string
              description: MCP server URL
            headers:
              type: object
              nullable: true
              description: Headers included in every MCP request
        actions:
          type: array
          nullable: true
          items:
            type: string
          description: "Allowlist of actions the tool exposes. For `mcp` tools: an optional allowlist of MCP
            tool names to scope the server surface (`null` exposes every tool)."
        denied_actions:
          type: array
          nullable: true
          items:
            type: string
          description: "For `mcp` tools: an optional denylist of MCP tool names to hide. Applied after
            `actions` and taking precedence over it — the ergonomic way to scope a read+write MCP
            server read-only by denying just the write tools. `null` denies nothing."
        context_keys:
          type: array
          nullable: true
          items:
            type: string
          description: Optional allowlist of `tool_context` keys forwarded to this tool as prefixed context
            headers. `null` or omitted forwards every key; `[]` forwards none. The server-pinned
            identity keys (`session_id`, `actor_id`, `actor_external_id`) are always forwarded, and
            a key consumed by a `{{context:<key>}}` token in this tool's own headers is substituted
            regardless of this list.
        preset_parameters:
          type: object
          nullable: true
          description: Pre-filled parameter values injected at execution time
        pipeline:
          type: object
          nullable: true
          description: "Pipeline definition for `pipeline` tools: an ordered `steps` array, each invoking
            another tool by `tool_id` (optional `action`) with an `input` built from earlier results
            via JSON Logic over `{ input, steps }`, plus an optional `output` mapping. Step `input`
            keys and `var` paths use camelCase (the runtime form). Free-form, user-defined."
        output_mapping:
          type: object
          nullable: true
          description: "Universal JSON Logic mapping applied to the tool's raw result, for every tool type.
            Evaluated over `{ output: <raw result> }`, e.g. `{ \"var\": \"output.text\" }`. For
            `pipeline` tools this runs after the pipeline's own `output` mapping."
        guardrail_ids:
          x-naturali-ref: guardrails
          type: array
          nullable: true
          items:
            type: string
          description: Guardrails attached at the tool scope.
    DatasetResourceProperties:
      description: Declares an evaluation dataset — the named fixture suite an eval runs an agent against.
        Its test cases are declared separately as `dataset_item` resources, so an item curated
        through the API is never collateral of a formation apply. Deleting the dataset deletes its
        items and the evals bound to it.
      type: object
      additionalProperties: false
      required:
        - name
      properties:
        name:
          type: string
          description: Dataset name, unique within the project
        description:
          type: string
          nullable: true
          description: Optional description
    DatasetItemResourceProperties:
      description: "One test case in a dataset: the messages sent to the agent under test and, optionally,
        the reference answer scorers compare against. Editing or removing an item never rewrites a
        run that already scored it — each result froze its own copy."
      type: object
      additionalProperties: false
      required:
        - dataset_id
        - input
      properties:
        dataset_id:
          x-naturali-ref: datasets
          type: string
          description: Public ID of the parent dataset (or ref expression)
        input:
          type: array
          items:
            type: object
          description: The messages sent to the agent, as `{role, content}` objects
        expected_output:
          type: string
          nullable: true
          description: Reference answer for exact_match / contains / embedding_similarity / llm_judge scorers
        metadata:
          description: 'Free-form tags on the case, e.g. `{"topic": "billing"}`'
          allOf:
            - $ref: "#/components/schemas/NullableMetadataBag"
    EvalResourceProperties:
      description: Binds an agent under test to a dataset and the scorers its outputs are judged by.
        `pass_threshold` is the pass rate a run must reach for its `passed` verdict — the gate an
        agent-version promotion consumes.
      type: object
      additionalProperties: false
      required:
        - name
        - agent_id
        - dataset_id
        - scorers
      properties:
        name:
          type: string
          description: Eval name, unique within the project
        agent_id:
          x-naturali-ref: agents
          type: string
          description: Public ID of the agent under test (or ref expression)
        dataset_id:
          x-naturali-ref: datasets
          type: string
          description: Public ID of the dataset to run against (or ref expression)
        scorers:
          type: array
          items:
            type: object
          description: Scorer configs — `exact_match`, `contains`, `json_logic`, `output_schema`,
            `embedding_similarity`, `llm_judge`, `tool`, or `decider`. Same shape as the evals REST
            contract.
        pass_threshold:
          type: number
          nullable: true
          description: 0–1. A run passes when its pass rate over non-errored items reaches this. Omit for a
            run that reports scores without a verdict.
        group_by:
          type: string
          nullable: true
          minLength: 1
          maxLength: 255
          description: A key of the items' `metadata`; a run rolls its scores up per string value of it. Omit
            for no grouping.
    DocumentResourceProperties:
      description: Stores a text document in a project, optionally indexing it for knowledge retrieval.
      type: object
      additionalProperties: false
      required:
        - content
      properties:
        content:
          type: string
          description: Document text content
        path:
          type: string
          nullable: true
          description: Virtual path for organising the document
        filename:
          type: string
          nullable: true
          description: Original filename
        title:
          type: string
          nullable: true
          description: Document title
        metadata:
          description: Arbitrary metadata key-value pairs
          allOf:
            - $ref: "#/components/schemas/NullableMetadataBag"
        tags:
          type: object
          nullable: true
          description: Tag key-value pairs for filtering
        chunk_strategy:
          type: string
          enum:
            - page
            - whole
            - size
          description: How to split the content into embeddable chunks, matching `POST /documents`. `whole`
            (default) stores the content as a single chunk; `size` splits into fixed-size character
            windows with overlap. `page` is equivalent to `whole` for plain text.
          default: whole
        chunk_size:
          type: integer
          description: Window size in characters when `chunk_strategy=size`. Defaults to 1000.
        chunk_overlap:
          type: integer
          description: Overlap in characters between consecutive windows when `chunk_strategy=size`. Defaults
            to 200.
    MemoryStoreResourceProperties:
      description: Creates a named memory store that actors can read from and write to across conversations.
      type: object
      additionalProperties: false
      required:
        - name
      properties:
        name:
          type: string
          description: Memory store display name
        description:
          type: string
          nullable: true
          description: What this memory store stores
        tags:
          $ref: "#/components/schemas/NullableTagBag"
        duplicate_threshold:
          type: number
          nullable: true
          minimum: 0
          maximum: 1
          description: "Cosine similarity at or above which an incoming fact is already known and the write is
            skipped. Null uses the algorithm constant (0.95). This is where a template sets the
            corpus's dedup policy: a `memory` resource has no threshold of its own."
        supersede_threshold:
          type: number
          nullable: true
          minimum: 0
          maximum: 1
          description: Cosine similarity at or above which an incoming fact restates a known one that has
            changed, retiring it. Null uses the algorithm constant (0.90). Must be lower than the
            effective `duplicate_threshold`.
    MemoryResourceProperties:
      description: Adds a single memory to a memory store.
      type: object
      additionalProperties: false
      required:
        - memory_store_id
        - content
      properties:
        memory_store_id:
          x-naturali-ref: memory-stores
          type: string
          description: Public ID of the parent memory store (or ref expression)
        content:
          type: string
          description: Text content of the memory
        source_type:
          type: string
          enum:
            - manual
            - conversation
          description: Whether there is a source to point at (defaults to manual). `conversation` requires
            `source_id`.
        source_id:
          type: string
          nullable: true
          description: The conversation this fact was learned in, when `source_type` is `conversation`; null
            when it is `manual`.
        tags:
          description: Per-memory key-value tags for memory-granularity filtering in knowledge search.
          allOf:
            - $ref: "#/components/schemas/NullableTagBag"
        metadata:
          description: Arbitrary structured metadata attached to the memory
          allOf:
            - $ref: "#/components/schemas/NullableMetadataBag"
    ModelRouteResourceProperties:
      description: "Declares a model route within the formation's project: a named, ordered list of
        provider+model failover targets with retry and circuit-breaker configuration. Consumers
        reference it through their own `model_route_id`, or inherit it as the project's
        `default_model_route_id`."
      type: object
      additionalProperties: false
      required:
        - name
        - targets
      properties:
        name:
          type: string
          description: Route name, unique within the project
        targets:
          type: array
          description: Ordered failover targets, tried in array order. Each entry is `{ ai_provider_id, model,
            timeout_seconds?, max_retries? }`; every provider must belong to this project, and the
            total attempt budget (sum of `1 + max_retries`) is capped at 10.
          items:
            type: object
            additionalProperties: false
            required:
              - ai_provider_id
              - model
            properties:
              ai_provider_id:
                x-naturali-ref: ai-providers
                type: string
                description: AI provider in the route's project.
              model:
                type: string
                description: Model name to call on that provider.
              timeout_seconds:
                type: integer
                nullable: true
                description: Per-attempt deadline. Omitted means no per-target deadline.
              max_retries:
                type: integer
                nullable: true
                description: Retries on this target before falling through to the next one.
        retry_on:
          type: array
          description: "Which failure classes fail over: any of `provider_error`, `timeout`, `rate_limited`.
            Defaults to all three. Deterministic rejections (400-class, auth, content policy) never
            fail over."
          items:
            type: string
        failure_threshold:
          type: integer
          nullable: true
          description: Consecutive retryable failures before a target is skipped (default 3)
        cooldown_seconds:
          type: integer
          nullable: true
          description: How long a tripped target is skipped before being probed again (default 60)
    TriggerResourceProperties:
      description: Binds a starter (manual, webhook, schedule, or event) to an executable target
        (orchestration, agent, tool, or eval). Firings run under the confined run-as identity of the
        caller who deployed the formation, so a firing never exceeds what that caller could do
        directly.
      type: object
      additionalProperties: false
      required:
        - name
        - type
        - target_type
        - target_id
      properties:
        name:
          type: string
          description: Trigger display name (unique within the project)
        description:
          type: string
          nullable: true
          description: Optional description
        type:
          type: string
          enum:
            - manual
            - webhook
            - schedule
            - event
          description: Starter type. Immutable after creation
        target_type:
          type: string
          enum:
            - orchestration
            - agent
            - tool
            - eval
          description: The kind of resource this trigger activates
        target_id:
          type: string
          description: 'Public ID of the target resource. Use { "ref": "LogicalId" } to reference an
            orchestration, agent, tool, or eval defined in the template.'
        action:
          type: string
          nullable: true
          description: Tool targets only — the action for mcp tools
        input:
          type: object
          nullable: true
          description: Static input shallow-merged under each firing's runtime input
        tool_context:
          type: object
          nullable: true
          additionalProperties:
            type: string
          description: Caller context every firing forwards to the run it starts, so an agent whose tools
            authorize through `{{context:<key>}}` can be scheduled. Write-only. A value may be a
            `{{secret:sec_...}}` reference, which is what a template should carry — the credential
            stays in the secret store and only its id is checked in (a `sub` such as
            `{{secret:${MySecret}}}` for a template secret); a secret's name does not resolve and is
            refused
        cron:
          type: string
          nullable: true
          description: 5-field cron expression (UTC). Required when type is schedule
        event_pattern:
          type: string
          nullable: true
          description: Internal-event subscription pattern (`*`, `prefix.*`, or an exact event name). Required
            when type is event, rejected otherwise
        active:
          type: boolean
          description: Whether the trigger fires (default true)
        policy_id:
          x-naturali-ref: policies
          type: string
          nullable: true
          description: Optional boundary policy that further confines the run-as identity
    ConversationResourceProperties:
      description: Creates a conversation within the formation's project.
      type: object
      additionalProperties: false
      properties:
        name:
          type: string
          nullable: true
          description: Human-readable label for the conversation
        status:
          type: string
          description: Initial status of the conversation (open or closed)
        actor_id:
          x-naturali-ref: actors
          type: string
          nullable: true
          description: Public ID of an actor to associate with this conversation
    FileResourceProperties:
      description: Registers a file record within the formation's project.
      type: object
      additionalProperties: false
      properties:
        prefix:
          type: string
          nullable: true
          description: Directory within the project. Optional; defaults to / (root). Combined with filename to
            form the file's key (path).
        filename:
          type: string
          nullable: true
          description: Original / download name and the key's leaf segment.
        content_type:
          type: string
          nullable: true
          description: MIME type of the file
        size:
          type: integer
          nullable: true
          description: File size in bytes
        metadata:
          description: Caller-owned annotations on the file, stored as the object they were written as; `null`
            clears the bag. Keys are stored and returned verbatim in the casing supplied.
          allOf:
            - $ref: "#/components/schemas/NullableMetadataBag"
    SecretResourceProperties:
      description: Creates an encrypted secret within the formation's project.
      type: object
      additionalProperties: false
      required:
        - name
        - value
      properties:
        name:
          type: string
          description: Human-readable label for the secret
        value:
          type: string
          description: The secret value to encrypt and store
    SessionResourceProperties:
      description: Creates a session attached to an agent within the formation's project.
      type: object
      additionalProperties: false
      required:
        - agent_id
      properties:
        agent_id:
          x-naturali-ref: agents
          type: string
          description: Public ID of the agent that owns this session
        name:
          type: string
          nullable: true
          description: Human-readable label for the session
        actor_id:
          x-naturali-ref: actors
          type: string
          nullable: true
          description: Public ID of an actor to associate with this session
        auto_generate:
          type: boolean
          description: Whether to automatically generate a response when messages are sent
        inactivity_ttl_seconds:
          type: integer
          description: Number of seconds of inactivity after which the session expires. 0 means never expires.
        tool_context:
          type: object
          additionalProperties: true
          nullable: true
          description: "Optional context object passed to tool calls. Write-only: no read of a session returns
            it."
    IngestionRuleResourceProperties:
      description: Routes a file content_type to a converter (tool or agent) so ingestion can turn
        non-native files (images, audio, scanned PDFs) into Documents. See the Ingestion Rules
        module docs for the matching and converter-invocation model.
      type: object
      additionalProperties: false
      required:
        - content_type_glob
      properties:
        content_type_glob:
          type: string
          description: MIME type glob matched against a file's content_type (e.g. image/*, audio/mpeg,
            application/pdf)
        tool_id:
          x-naturali-ref: tools
          type: string
          nullable: true
          description: Converter tool ID (mutually exclusive with agent_id)
        agent_id:
          x-naturali-ref: agents
          type: string
          nullable: true
          description: Converter agent ID (mutually exclusive with tool_id)
        action:
          type: string
          nullable: true
          description: Operation id, required for mcp tool converters
        preset_parameters:
          type: object
          nullable: true
          description: Merged into the tool input before invocation (tool converters only)
        native_extraction:
          type: string
          nullable: true
          description: "For native types (PDF/text): `first` (default) converts only when native extraction
            yields no text; `skip` always converts."
        file_delivery:
          type: string
          nullable: true
          description: How the file reaches a tool converter — base64 (default) or download_url
        chunk_strategy:
          type: string
          nullable: true
          description: Default chunk strategy (page/whole/size), overridable per ingest request
        chunk_size:
          type: integer
          nullable: true
          description: Default window size in characters for the size strategy
        chunk_overlap:
          type: integer
          nullable: true
          description: Default overlap in characters for the size strategy
        metadata:
          description: Arbitrary JSON metadata
          allOf:
            - $ref: "#/components/schemas/NullableMetadataBag"
    MemoryRuleResourceProperties:
      description: "Declares what a memory store accepts from completed agent turns: a selector, an event,
        and a handler. With neither `agent_id` nor `tool_id` the built-in extractor runs,
        configurable through `prompt`, `ai_provider_id` and `model`. See the Memory Rules section of
        the Memories module docs."
      type: object
      additionalProperties: false
      required:
        - memory_store_id
        - on
      properties:
        memory_store_id:
          x-naturali-ref: memory-stores
          type: string
          description: Public ID of the destination memory store
        on:
          type: string
          description: "`agents.generation.completed` (once per completed turn, and the only event the
            built-in extractor may bind to) or `conversations.message.generated` (per persisted
            assistant reply, custom handlers only)."
        source_agent_ids:
          x-naturali-ref: agents
          type: array
          nullable: true
          description: Agents whose turns this rule reads; null is every agent in the project
          items:
            type: string
        agent_id:
          x-naturali-ref: agents
          type: string
          nullable: true
          description: Handler agent ID (mutually exclusive with tool_id)
        tool_id:
          x-naturali-ref: tools
          type: string
          nullable: true
          description: Handler tool ID (mutually exclusive with agent_id)
        action:
          type: string
          nullable: true
          description: Operation id, for a tool handler
        preset_parameters:
          type: object
          nullable: true
          description: Merged into a tool handler's input before invocation
        prompt:
          type: string
          nullable: true
          description: Replaces the built-in extractor's task instructions (no handler only)
        ai_provider_id:
          x-naturali-ref: ai-providers
          type: string
          nullable: true
          description: Provider override for the built-in extractor (no handler only)
        model:
          type: string
          nullable: true
          description: Model override for the built-in extractor (no handler only)
        enabled:
          type: boolean
          description: A disabled rule is kept and never fires
    OrchestrationResourceProperties:
      description: "Creates a DAG orchestration that wires agents, tools, and knowledge lookups into a
        repeatable pipeline within the formation's project. Node resource references (`agent_id`,
        `tool_id`, `memory_store_id`, `orchestration_id`) accept `{ \"ref\": \"LogicalId\" }`
        expressions to point at other resources declared in the same template — the basis for
        deploying an agent \"squad\" (a team of agents plus the flow that coordinates them) as a
        single stack."
      type: object
      additionalProperties: false
      required:
        - name
        - nodes
        - edges
      properties:
        name:
          type: string
          description: Human-readable name for the orchestration
        description:
          type: string
          nullable: true
          description: Optional description of what the orchestration does
        nodes:
          type: array
          description: "Ordered list of node definitions. A node's resource references (`agent_id`, `tool_id`,
            `memory_store_id`, `orchestration_id`) may use `{ \"ref\": \"LogicalId\" }` to bind to
            other resources in the template."
          items:
            type: object
            additionalProperties: true
        edges:
          type: array
          description: Directed connections between nodes
          items:
            type: object
            additionalProperties: true
        state_schema:
          type: object
          nullable: true
          additionalProperties: true
          description: Optional JSON Schema describing the run state
        input_schema:
          type: object
          nullable: true
          additionalProperties: true
          description: Optional JSON Schema describing the run input
        output_mapping:
          type: object
          nullable: true
          additionalProperties: true
          description: "Optional shape of a succeeded run's `output`: each key an output field, each value
            JSON Logic over `{ \"state\": <final run state> }`. Omitted keys `output` by terminal
            node id."
    WorkflowResourceProperties:
      description: 'Creates a workflow — a state-machine definition (named states, allowed transitions,
        guards, and per-state automation) that tasks live in. State and transition dispatch
        references (`agent_id`, `orchestration_id`, `tool_id` inside an `on_enter` block) accept `{
        "ref": "LogicalId" }` expressions to point at agents, orchestrations or tools declared in
        the same template, so a workflow plus the agents and tools that service its states can
        deploy as one stack. Mirrors the workflows REST contract (`states`, `transitions`,
        `payload_schema`).'
      type: object
      additionalProperties: false
      required:
        - name
        - states
        - transitions
      properties:
        name:
          type: string
          description: Human-readable name for the workflow, unique within the project
        description:
          type: string
          nullable: true
          description: Optional description of what the workflow models
        states:
          type: array
          description: "Named states. Exactly one must be `initial: true`; any number may be `terminal: true`.
            A `kind: human` state parks the task until a transition fires; an `on_enter` block
            dispatches one agent generation or orchestration run on entry."
          items:
            type: object
            additionalProperties: true
        transitions:
          type: array
          description: Named, directional moves between states. Each has `from` (source states) and `to` (one
            target), an optional JSON Logic `guard`, and an optional `requires_approval` gate.
          items:
            type: object
            additionalProperties: true
        payload_schema:
          type: object
          nullable: true
          additionalProperties: true
          description: Optional JSON Schema describing a task's payload
    MetadataSchemaResourceProperties:
      description: "Declares what `metadata` must satisfy for one resource type under one selector, so a
        template ships the corpus and the rule governing it together. `resource_type` is immutable:
        changing it in a template is a delete and a create."
      type: object
      additionalProperties: false
      required:
        - resource_type
        - schema
      properties:
        resource_type:
          type: string
          enum:
            - document
          description: The resource whose metadata this declaration governs.
        path_prefix:
          type: string
          description: "The selector a `document` declaration must carry: the directory it governs, matched on
            a path boundary."
        schema:
          type: object
          description: A JSON Schema, stored as written.
    QuotaResourceProperties:
      description: Creates a quota — a project-scoped cap that blocks (`enforce`) or reports (`monitor`)
        when a windowed aggregate is exceeded. `requests` quotas are enforced by the request
        middleware; `tokens`/`cost_usd` quotas at the pre-generation check. Mirrors the quotas REST
        contract; `scope`, `metric`, `window`, and `meter_type` are immutable after creation (only
        `limit`, `mode`, and `on_unpriced` update).
      type: object
      additionalProperties: false
      required:
        - scope
        - metric
        - window
        - limit
      properties:
        scope:
          type: string
          enum:
            - project
            - api_key
            - agent
            - actor
          description: The scope the quota applies to
        scope_ref:
          type: string
          nullable: true
          description: Public id of the api key / agent / actor the quota applies to. For `api_key` and
            `agent` scope, NULL means all entities of that scope type in the project. For `actor`
            scope, NULL means one budget *per* actor rather than a pooled total across all actors.
        metric:
          type: string
          enum:
            - requests
            - tokens
            - cost_usd
            - storage_bytes
          description: The metric being capped
        window:
          type: string
          enum:
            - rolling_1m
            - rolling_1h
            - rolling_24h
            - calendar_month
            - current
          description: The window over which the metric is aggregated. storage_bytes caps a stored total
            rather than a windowed one, so it takes current and refuses every other value; current
            is refused for every other metric.
        limit:
          type: number
          description: The cap. Positive integer for requests/tokens/storage_bytes (bytes); fractional allowed
            for cost_usd.
        mode:
          type: string
          enum:
            - enforce
            - monitor
          description: enforce blocks with 429; monitor fires the webhook only
        on_unpriced:
          type: string
          enum:
            - block
            - allow
          description: Only for metric cost_usd. What an enforce quota does over a pricing blackout — block
            (the default) refuses generations with 409 QUOTA_UNENFORCEABLE, allow accepts the
            unmeasurable spend. See the quotas REST contract.
        meter_type:
          type: string
          enum:
            - llm_tokens
            - compute_execution
            - api_request
            - storage
            - tool_execution
          description: Only for metric cost_usd. The meter this cap answers for; omit it and the cap sums
            every priced meter. See the quotas REST contract.
    GuardrailResourceProperties:
      description: "Creates a guardrail — an action-class document (`class`/`guard`) that gates tool-call
        autonomy. Attach it to a tool or agent via that resource's `guardrail_ids` (a `{ \"ref\": …
        }` to this resource in the same template resolves to its physical id at deploy time).
        Mirrors the guardrails REST contract; `class`/`default_class`/`guard`/`escalate` are
        flattened here from the REST API's single `document` object."
      type: object
      additionalProperties: false
      required:
        - name
        - class
      properties:
        name:
          type: string
          description: Human-readable name
        description:
          type: string
          nullable: true
          description: Optional description
        class:
          description: A class literal (`A` / `B` / `C` / `D`) or a JSON Logic expression returning one. An
            invalid result resolves to `default_class`.
          oneOf:
            - type: string
              enum:
                - A
                - B
                - C
                - D
            - type: object
        default_class:
          type: string
          enum:
            - A
            - B
            - C
            - D
          description: Applied when the `class` expression returns anything other than a valid class. Defaults
            to `C` (fail-closed).
        guard:
          type: object
          nullable: true
          description: A single JSON Logic expression; when the call classifies as `B` it executes only if
            this evaluates truthy.
        escalate:
          type: boolean
          nullable: true
          description: When true, a passing guard still files an approval item.
        context_tool_id:
          x-naturali-ref: tools
          type: string
          nullable: true
          description: Optional tool the platform calls at evaluation time to fetch fresh guardrail context.
        context_mode:
          type: string
          nullable: true
          enum:
            - merge
            - replace
            - null
          description: How tool-fetched context combines with the caller-supplied context.
    DeciderResourceProperties:
      description: "Creates a decider — a versioned question set answered against a caller's state. Names
        exactly one backend: `agent_id` (a tool-less agent) or `tool_id` (an `http` or `pipeline`
        tool), either a `{ \"ref\": … }` to a resource in the same template. Only a change to
        `questions` archives a new version. Mirrors the deciders REST contract."
      type: object
      additionalProperties: false
      required:
        - name
        - questions
      properties:
        name:
          type: string
          description: Human-readable name, unique per project
        description:
          type: string
          nullable: true
          description: Optional description
        agent_id:
          x-naturali-ref: agents
          type: string
          description: The tool-less agent that answers
        tool_id:
          x-naturali-ref: tools
          type: string
          description: The http or pipeline tool that answers
        questions:
          type: object
          additionalProperties: true
          description: Question id → question (`type`, `instructions`, `criteria`), 1 to 20 of them, validated
            as the deciders REST contract validates them.
    ResourceDeclaration:
      type: object
      required:
        - type
        - properties
      properties:
        type:
          type: string
          pattern: ^[a-z][a-z0-9_]*$
          description: >
            Resource type. The types this API accepts are `ai_provider`, `tool`, `agent`, `actor`,
            `conversation`, `dataset`, `dataset_item`, `decider`, `document`, `file`, `guardrail`,
            `ingestion_rule`, `memory_store`, `memory`, `memory_rule`, `metadata_schema`,
            `model_route`, `eval`, `orchestration`, `quota`, `secret`, `session`, `trigger` and
            `workflow` — plus two naturali registers itself and handles through its own lifecycle:
            `channel`, taking the same property names the channels API takes (its credential
            properties are write-only, so a tenant credential never lands in the resource ledger),
            and `naturali_ai_provider`, which takes a `default_model` from the model catalog and
            provisions a provider running on naturali's own model access (it carries no credential
            of yours, so it accepts none). A template naming any other type is refused with `400
            unsupported_resource_type` before it reaches the runtime — including the runtime's own
            `api_key`, `chat`, `policy`, `project_price` and `webhook` types, which this API does
            not expose.


            This is deliberately not an enum: a deployment operator can register additional resource
            types backed by their own handler, and those are declared here exactly like a built-in
            one. The set a given deployment accepts is authoritative in the server, which rejects an
            unregistered type with `VALIDATION_FAILED` and lists what it does support.
        properties:
          type: object
          additionalProperties: true
          description: >
            Resource properties, as authored in the template and echoed back verbatim. The allowed
            fields, required fields, and field types for each resource `type` are defined by the
            corresponding `<Type>ResourceProperties` schema in this document (e.g. `model_route` →
            `ModelRouteResourceProperties`), which the server enforces at validate/deploy time. The
            declaration itself is free-form here because property values may be substitution
            expressions rather than final values: `{ "ref": "logicalId" }` references another
            resource's physical ID, `{ "param": "ParamName" }` substitutes a parameter value, and `{
            "sub": "text ${ParamName}" }` interpolates parameters into a string.
        depends_on:
          type: array
          items:
            type: string
          description: Explicit dependency list. In addition to implicit `ref` dependencies.
          nullable: true
        deletion_policy:
          type: string
          enum:
            - delete
            - retain
          description: >
            Controls what happens to the physical resource when it is removed from the stack.
            `delete` (default) deletes the physical resource. `retain` keeps the physical resource
            alive and only removes the formation record. Omit it to get `delete`; an explicit `null`
            is rejected.
        metadata:
          $ref: "#/components/schemas/NullableMetadataBag"
    FormationResource:
      type: object
      properties:
        id:
          type: string
          description: Public ID of the resource record
        logical_id:
          type: string
          description: Logical identifier from the template
        resource_type:
          type: string
          description: Resource type (e.g. `agent`, `memory_store`)
        physical_resource_id:
          type: string
          nullable: true
          description: Public ID of the physical the runtime resource
        status:
          type: string
          enum:
            - pending
            - created
            - updated
            - deleted
            - failed
          description: Current resource status
    Formation:
      type: object
      properties:
        id:
          type: string
          description: Public ID of the formation
          example: form_V1StGXR8Z5jdHi6B
        project_id:
          x-naturali-ref: projects
          type: string
          description: Project public ID
        name:
          type: string
          description: Human-readable formation name
        template:
          allOf:
            - $ref: "#/components/schemas/FormationTemplate"
          description: >
            The template as deployed. Credential-bearing properties — a `secret` resource's `value`,
            and any property a custom resource type declares `write_only` — read back as `{
            "no_echo": true }` rather than the value that was supplied.
        outputs:
          type: object
          additionalProperties:
            type: string
          nullable: true
          description: >
            Resolved output values after stack deployment. An output that resolved a credential
            attribute on a formation deployed before those were refused is omitted.
        status:
          type: string
          enum:
            - creating
            - active
            - updating
            - failed
            - deleting
            - deleted
            - delete_failed
          description: Formation status
        metadata:
          description: >
            Static annotations stored on the formation record (supplied at create/update). Not a
            substitution site — `sub`/`param`/`ref` expressions are rejected. Use the template's
            top-level `metadata` block for deploy-time substitution (see `resolved_metadata`).
          allOf:
            - $ref: "#/components/schemas/NullableMetadataBag"
        resolved_metadata:
          type: object
          additionalProperties: true
          nullable: true
          description: >
            The template's top-level `metadata` block after parameter (`sub`/`param`) and resource
            (`ref`) substitution at the last deploy. Null when the template declares no metadata.
        resolved_parameters:
          type: object
          additionalProperties:
            type: string
          nullable: true
          description: >
            Parameter values applied at the last deploy, for auditability. `no_echo` parameters are
            masked (`***`). Null when the template declares no parameters.
        error:
          allOf:
            - $ref: "#/components/schemas/FormationError"
          nullable: true
          description: >
            Why the formation is `failed` or `delete_failed`, in the same `{ code, message, meta }`
            shape as an error response. Null in every other status, and cleared by the next
            successful deploy. This is the reason a `2xx` deploy response can report `status:
            "failed"` without a second call to `list-formation-events`.


            One case carries an error while the formation is `active`:
            `FORMATION_REPLACE_CLEANUP_FAILED`, when a deploy replaced a resource and the superseded
            one could not be deleted. The desired state is realised, so the deploy succeeded — but
            the old resource is still live, and `meta.failures` names it. It stays on the formation
            as pending cleanup and is retried on the next deploy or teardown, which clears the error
            once it is gone.
        resources:
          type: array
          items:
            $ref: "#/components/schemas/FormationResource"
          description: Resources managed by this formation (present on get/create/update)
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    ValidationError:
      type: object
      properties:
        path:
          type: string
          description: JSON path to the field with the error
        message:
          type: string
          description: Error description
    ValidationResult:
      type: object
      properties:
        valid:
          type: boolean
        errors:
          type: array
          items:
            $ref: "#/components/schemas/ValidationError"
        warnings:
          type: array
          items:
            $ref: "#/components/schemas/ValidationError"
    PlanChange:
      type: object
      properties:
        logical_id:
          type: string
        resource_type:
          type: string
        action:
          type: string
          enum:
            - create
            - update
            - delete
            - no-op
        physical_resource_id:
          type: string
          description: The existing resource's physical ID. Present for update / no-op / delete actions,
            absent for create.
        diff:
          type: object
          description: Resolved desired-state properties (post parameter/ref substitution) and, when
            available, the current live or last-applied properties they were compared against.
            Omitted when neither side could be computed (e.g. an unregistered resource type).
          properties:
            desired:
              type: object
              additionalProperties: true
            current:
              type: object
              additionalProperties: true
              nullable: true
    PlanResult:
      type: object
      properties:
        changes:
          type: array
          items:
            $ref: "#/components/schemas/PlanChange"
        unauthorized_actions:
          type: array
          description: The per-resource actions the caller may not perform. A formation may only do what the
            caller could do directly, so applying this template would be refused while any of these
            remain. Absent when the caller may perform every action the plan implies. A plan itself
            changes nothing, so it reports them rather than failing.
          items:
            $ref: "#/components/schemas/UnauthorizedFormationAction"
    UnauthorizedFormationAction:
      type: object
      required:
        - logical_id
        - resource_type
        - action
      properties:
        logical_id:
          type: string
          description: The template's own name for the resource.
          example: MyGuardrail
        resource_type:
          type: string
          description: The declared resource type.
          example: guardrail
        action:
          type: string
          description: The action the caller lacks.
          example: guardrails:CreateGuardrail
    FormationError:
      type: object
      description: Why a deploy or teardown failed, in the one error shape the API has. Carried on the
        formation itself and on the operation that failed.
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: The failing operation's error code (`VALIDATION_FAILED`, `RESOURCE_NOT_FOUND`,
            `FORMATION_DELETE_FAILED`, `FORMATION_REPLACE_CLEANUP_FAILED`, …), or `UNKNOWN` when the
            underlying failure carried no code.
          example: VALIDATION_FAILED
        message:
          type: string
          description: The failure, as reported by the resource that raised it.
          example: "dataset_id is immutable: item 'dsit_V1StGXR8Z5jdHi6B' belongs to 'dset_V1StGXR8Z5jdHi6B'.
            Declare a new dataset_item instead."
        meta:
          type: object
          additionalProperties: true
          description: Context for the failure. A failed apply names the resource that broke it (`logical_id`,
            `resource_type`); a failed teardown lists every blocker under `failures`, and so does a
            succeeded deploy that could not dispose of a replaced resource — there each entry adds
            the `physical_resource_id` still live.
          example:
            logical_id: case1
            resource_type: dataset_item
    FormationEvent:
      type: object
      properties:
        timestamp:
          type: string
          format: date-time
        logical_id:
          type: string
        resource_type:
          type: string
        action:
          type: string
          description: "What the deploy did to the resource: `create`, `update`, `delete`, `no-op`, `rollback`
            (a resource created earlier in this deploy that was walked back after a later failure),
            or `rollback-skipped` (a `deletion_policy: retain` resource left standing by that
            unwind)."
          example: rollback
        status:
          type: string
          enum:
            - succeeded
            - failed
        physical_resource_id:
          type: string
          nullable: true
        error:
          type: string
          nullable: true
    FormationOperation:
      type: object
      properties:
        id:
          type: string
          description: Public ID of the operation
        operation_type:
          type: string
          enum:
            - validate
            - plan
            - create
            - update
            - delete
        status:
          type: string
          enum:
            - pending
            - running
            - succeeded
            - failed
        events:
          type: array
          items:
            $ref: "#/components/schemas/FormationEvent"
          nullable: true
        plan:
          allOf:
            - $ref: "#/components/schemas/PlanResult"
          nullable: true
        error:
          allOf:
            - $ref: "#/components/schemas/FormationError"
          nullable: true
          description: Why this operation failed. Null for a succeeded or running operation. The same bag the
            formation itself carries while that failure is its current state.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    NullableMetadataBag:
      type: object
      nullable: true
      description: A `MetadataBag` on a field where `null` is meaningful — a full-replacement update that
        clears the bag, or a record whose bag was never set.
      example:
        author: John
        revision: 2
    TagBag:
      type: object
      additionalProperties:
        type: string
      x-cli-flag-name: tags
      description: >-
        Key-value labels on a resource. A flat object of string values — an array, a nested object
        or a number is rejected with `400 VALIDATION_FAILED`, never coerced. Keys are opaque and
        stored verbatim, so `cost_center` and `costCenter` are two different tags. Matched by JSONB
        containment wherever tags are read: the `?tags=` filter and knowledge search.


        Keys beginning `system.` are reserved: the platform writes them to record which
        conversation, actor, agent and role a row came from, and a write naming one is refused with
        `400 RESERVED_TAG_KEY`. They are read and filtered like any other tag.


        The bag is bounded, because every pair reaches the IAM context of every access check on the
        resource: at most 50 keys, each key at most 128 characters and each value at most 256. A
        write past a bound — including a merge that would grow the stored bag past the key count —
        is `400 VALIDATION_FAILED` with `meta.limit` naming the bound it crossed. `system.*` keys
        are the platform's and do not count against the 50.
      example:
        team: finance
        env: prod
    NullableTagBag:
      type: object
      nullable: true
      additionalProperties:
        type: string
      description: A `TagBag` on a field where `null` is meaningful — a full-replacement update that
        clears the bag, or a record whose bag was never set.
      example:
        team: finance
        env: prod
  parameters:
    ProjectId:
      name: project_id
      in: path
      required: true
      description: Project public ID (proj_ prefix).
      schema:
        type: string
        example: proj_V1StGXR8Z5jdHi6B
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: A naturali API key (nat_sk_…) or a session JWT.
    oauth2:
      type: oauth2
      description: "A connected app's OAuth access token, issued by this API's authorization server
        (discovery: /.well-known/oauth-authorization-server). Its one scope carries every operation,
        confined to the projects the user chose when approving the app."
      flows:
        authorizationCode:
          authorizationUrl: https://api.naturali.ai/authorize
          tokenUrl: https://api.naturali.ai/token
          refreshUrl: https://api.naturali.ai/token
          scopes:
            mcp:access: Every operation this API serves, on the projects the grant covers.
