# AUTO-GENERATED tier-A mirror spec — do not edit.
# Source: openapi/runtime/guardrails.yaml (runtime 0.71.2)
#  + policy: openapi/mirror-policies/guardrails.json
# Regenerate: node scripts/generate-mirror-specs.mjs
openapi: 3.0.3
info:
  title: naturali.ai — Guardrails API
  version: 1.0.0
  description: >-
    Guardrails: the rules that decide whether a proposed tool call runs, needs a human, or is
    refused — a versioned policy document per guardrail, the archive of every version it has had,
    and a dry-run evaluate that shows what a document would decide before it is attached. 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: Guardrails
    description: Manage guardrails
security:
  - bearerAuth: []
  - oauth2:
      - mcp:access
paths:
  /v1/projects/{project_id}/guardrails:
    post:
      tags:
        - Guardrails
      summary: Create a guardrail
      description: >
        Creates a new guardrail in the project, archiving its document as version 1. The `document`
        is validated on write: `class` must be a literal (A/B/C/D) or a JSON Logic expression, and
        every variable it (and `guard`) reference must resolve to the `args.*` / `context.*` /
        `runtime.*` namespaces — an out-of-catalog `runtime.*` key is rejected with 400.
      operationId: createGuardrail
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateGuardrailRequest"
            examples:
              always_approve:
                summary: Always require human sign-off
                value:
                  name: Sign-off Guardrail
                  document:
                    class: C
              budget_threshold:
                summary: Class B below a threshold, C at or above, guarded by 24h spend
                value:
                  name: Budget Update Guardrail
                  document:
                    default_class: C
                    class:
                      if:
                        - <:
                            - var: args.amount
                            - 500
                        - B
                        - C
                    guard:
                      <:
                        - var: runtime.projects.cost_usd.24h
                        - 1000
      responses:
        "201":
          description: Guardrail created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Guardrail"
        "400":
          description: Bad Request — invalid document or variable reference
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    get:
      tags:
        - Guardrails
      summary: List guardrails
      description: Returns all guardrails in the project.
      operationId: listGuardrails
      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 guardrails
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - total
                  - limit
                  - offset
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Guardrail"
                  total:
                    type: integer
                  limit:
                    type: integer
                  offset:
                    type: integer
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    parameters:
      - $ref: "#/components/parameters/ProjectId"
  /v1/projects/{project_id}/guardrails/{guardrail_id}:
    get:
      tags:
        - Guardrails
      summary: Get a guardrail
      description: Returns a single guardrail by ID.
      operationId: getGuardrail
      x-naturali-resource:
        kind: guardrail
        from: guardrail_id
      parameters:
        - name: guardrail_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Guardrail
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Guardrail"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - Guardrails
      summary: Update a guardrail
      description: >
        Updates an existing guardrail. A `document` write that actually changes the policy
        increments `version` and archives the new document as a GuardrailVersion; metadata-only
        edits (name / description / context), and re-writing the document the guardrail already
        holds, leave the version untouched.
      operationId: updateGuardrail
      x-naturali-resource:
        kind: guardrail
        from: guardrail_id
      parameters:
        - name: guardrail_id
          in: path
          required: true
          schema:
            type: string
        - $ref: "#/components/parameters/IfMatchVersion"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateGuardrailRequest"
      responses:
        "200":
          description: Guardrail updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Guardrail"
        "400":
          description: Bad Request — invalid document or variable reference
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          $ref: "#/components/responses/VersionConflict"
    delete:
      tags:
        - Guardrails
      summary: Delete a guardrail
      description: Deletes a guardrail and its archived versions by ID.
      operationId: deleteGuardrail
      x-naturali-resource:
        kind: guardrail
        from: guardrail_id
      parameters:
        - name: guardrail_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "204":
          description: Deleted
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    parameters:
      - $ref: "#/components/parameters/ProjectId"
  /v1/projects/{project_id}/guardrails/{guardrail_id}/versions:
    get:
      tags:
        - Guardrails
      summary: List a guardrail's config versions
      description: >
        Returns the guardrail's archived configurations, newest first. A version is written on
        create and on every subsequent write that changes the policy `document` — through the REST
        API or a formation apply alike. Metadata-only edits (name, description, context binding) do
        not archive a version. See [Versioning](/docs/modules/guardrails#versioning).
      operationId: listGuardrailVersions
      x-naturali-resource:
        kind: guardrail
        from: guardrail_id
      parameters:
        - name: guardrail_id
          in: path
          required: true
          schema:
            type: string
        - 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 guardrail versions, newest first
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - total
                  - limit
                  - offset
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/GuardrailVersion"
                  total:
                    type: integer
                  limit:
                    type: integer
                  offset:
                    type: integer
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Guardrail not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    parameters:
      - $ref: "#/components/parameters/ProjectId"
  /v1/projects/{project_id}/guardrails/{guardrail_id}/versions/{version}:
    get:
      tags:
        - Guardrails
      summary: Fetch an archived guardrail version
      description: >
        Returns the exact configuration — and so the exact `document` — that governed at a given
        version. Approval items, activity entries, and exceptions record the version that governed
        them, so the audit chain survives edits.
      operationId: getGuardrailVersion
      x-naturali-resource:
        kind: guardrail
        from: guardrail_id
      parameters:
        - name: guardrail_id
          in: path
          required: true
          schema:
            type: string
        - name: version
          in: path
          required: true
          schema:
            type: integer
            minimum: 1
      responses:
        "200":
          description: Archived guardrail version
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GuardrailVersion"
        "400":
          description: Bad Request — version is not a positive integer
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    parameters:
      - $ref: "#/components/parameters/ProjectId"
  /v1/projects/{project_id}/guardrails/{guardrail_id}/versions/{version}/restore:
    post:
      tags:
        - Guardrails
      summary: Restore an archived guardrail config
      description: >
        Writes an archived version's `document` back as the guardrail's live policy, which archives
        it again as a **new** version rather than rewinding the counter — so an approval item or
        exception citing any version in between still resolves.


        The restore runs through the ordinary update path, so the archived document is re-validated;
        restoring the policy the guardrail already holds is a no-op and archives nothing.
      operationId: restoreGuardrailVersion
      x-naturali-resource:
        kind: guardrail
        from: guardrail_id
      parameters:
        - name: guardrail_id
          in: path
          required: true
          schema:
            type: string
        - name: version
          in: path
          required: true
          schema:
            type: integer
            minimum: 1
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RestoreGuardrailVersionRequest"
      responses:
        "200":
          description: The guardrail, at its new version
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Guardrail"
        "400":
          description: Bad Request — invalid version, or the archived document no longer validates
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Guardrail or version not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          $ref: "#/components/responses/VersionConflict"
    parameters:
      - $ref: "#/components/parameters/ProjectId"
  /v1/projects/{project_id}/guardrails/{guardrail_id}/evaluate:
    post:
      tags:
        - Guardrails
      summary: Dry-run evaluate a guardrail
      description: >
        Runs the full evaluation pipeline — the `class` expression, the guard, the context tool per
        `context_mode`, live `runtime.*` resolution — against caller-supplied `args` and
        `guardrail_context`, and returns the exact `guardrail_evaluation` record a real call would
        produce. Nothing executes, no approval item is filed, and no activity entry is written. This
        is the adoption path: preview a document's decisions against production-shaped calls before
        attaching it — or before editing a widely-attached one. Pass an optional `tool_id` to
        resolve `runtime.tools.*`.
      operationId: evaluateGuardrail
      x-naturali-resource:
        kind: guardrail
        from: guardrail_id
      parameters:
        - name: guardrail_id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                args:
                  type: object
                  additionalProperties: true
                  description: The proposed call's arguments (the `args.*` namespace).
                guardrail_context:
                  type: object
                  additionalProperties: true
                  description: >
                    The caller-supplied guardrail context (the `context.*` namespace), combined with
                    the context tool per `context_mode`.
                tool_id:
                  type: string
                  description: Optional tool to resolve `runtime.tools.*` against.
      responses:
        "200":
          description: The would-be evaluation record (nothing executed)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/GuardrailEvaluation"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    parameters:
      - $ref: "#/components/parameters/ProjectId"
components:
  schemas:
    GuardrailDocument:
      type: object
      required:
        - class
      additionalProperties: false
      description: >
        The action-class document. `class` maps a call to an action class; `guard` gates class-B
        autonomy. Both are single JSON Logic expressions over the `args.*` / `context.*` /
        `runtime.*` namespaces.
      properties:
        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
          description: >
            A single JSON Logic expression; when the call classifies as `B` it must evaluate truthy
            to execute autonomously. Compose multiple conditions with `{ "and": [...] }`.
        escalate:
          type: boolean
          description: |
            When `true`, a failing guard routes to approval instead of tripping fail-closed.
        expires_in:
          type: integer
          minimum: 1
          description: >
            Default approval window in seconds for a class-C approval this guardrail files. Omitted
            → the platform's 24h default. When several guardrails apply, the governing
            (strictest-matching) one's value is used.
    Guardrail:
      type: object
      properties:
        id:
          type: string
          description: Public ID of the guardrail
          example: guard_V1StGXR8Z5jdHi6B
        project_id:
          x-naturali-ref: projects
          type: string
          description: Public ID of the owning project
          example: proj_V1StGXR8Z5jdHi6B
        name:
          type: string
          description: Human-readable name
          example: Budget Update Guardrail
        description:
          type: string
          nullable: true
          description: Optional description
        version:
          type: integer
          description: Incremented on every document write; prior versions are archived
          example: 1
        document:
          $ref: "#/components/schemas/GuardrailDocument"
        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.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    GuardrailEvaluation:
      type: object
      description: >
        The record produced by evaluating a guardrail against one call — written to the audit trail
        at dispatch time (one per applying guardrail) and returned verbatim by the dry-run endpoint.
      properties:
        kind:
          type: string
          description: Always `guardrail_evaluation`.
        guardrail_id:
          x-naturali-ref: guardrails
          type: string
          example: guard_V1StGXR8Z5jdHi6B
        guardrail_version:
          type: integer
          nullable: true
          description: The governing version; null for a dangling reference (fail-closed C).
        scope:
          type: string
          enum:
            - project
            - agent
            - tool
        tool:
          type: string
          nullable: true
        action:
          type: string
          nullable: true
        class:
          type: string
          description: The resolved class (or the applied default_class).
          enum:
            - A
            - B
            - C
            - D
        decision:
          type: string
          enum:
            - execute
            - route_to_approval
            - blocked
            - tripwire
        guard_result:
          type: boolean
          nullable: true
          description: The guard outcome; null when the call did not classify as B.
        context_source:
          type: string
          enum:
            - caller
            - tool
            - merged
            - none
        context_snapshot:
          type: object
          additionalProperties: true
          description: >
            Flat map of only the vars the class/guard expressions referenced, keyed by
            fully-qualified path, frozen at evaluation-time values.
        agent_id:
          type: string
          nullable: true
        orchestration_run_id:
          type: string
          nullable: true
        generation_id:
          type: string
          nullable: true
    GuardrailVersion:
      type: object
      description: An immutable archive of a guardrail's configuration at one version.
      properties:
        id:
          type: string
          description: Public ID of the archived version
          example: guard_ver_V1StGXR8Z5jdHi6B
        guardrail_id:
          x-naturali-ref: guardrails
          type: string
          description: Public ID of the guardrail this version belongs to
          example: guard_V1StGXR8Z5jdHi6B
        version:
          type: integer
          description: The archived version number
          example: 1
        config:
          type: object
          additionalProperties: true
          description: >-
            The guardrail's versioned surface as it stood at this version. Today that is the policy
            `document` and nothing else: name, description and the context binding are metadata, and
            bumping the version when one of them changes would make two version numbers denote the
            same policy — which is exactly what an evaluation record cites.


            Deliberately open rather than a fixed schema: an archive written by an earlier release
            of the runtime reflects the guardrail surface **of its own time**, so it may carry
            fields the current API no longer documents.
          properties:
            document:
              $ref: "#/components/schemas/GuardrailDocument"
        label:
          type: string
          nullable: true
          description: Optional human tag for this version, e.g. `pre-tightening`. Set from the `label` field
            of a restore, or generated for one.
          example: restored from v2
        created_by:
          x-naturali-ref: users
          type: string
          nullable: true
          description: Public ID of the user whose action produced this version. Null for writes with no
            request user behind them.
        created_at:
          type: string
          format: date-time
    RestoreGuardrailVersionRequest:
      type: object
      additionalProperties: false
      properties:
        label:
          type: string
          description: Optional tag for the version the restore creates. Defaults to `restored from v<version>`.
          example: rollback to pre-incident policy
    CreateGuardrailRequest:
      type: object
      required:
        - name
        - document
      additionalProperties: false
      properties:
        name:
          type: string
          description: Human-readable name
          example: Budget Update Guardrail
        description:
          type: string
          nullable: true
        document:
          $ref: "#/components/schemas/GuardrailDocument"
        context_tool_id:
          x-naturali-ref: tools
          type: string
          nullable: true
        context_mode:
          type: string
          enum:
            - merge
            - replace
        version_label:
          type: string
          description: Optional tag for the config version this write archives (e.g. `initial`). Annotates the
            version only — it is not stored on the guardrail and is not part of the config, so
            labelling a change is never itself a change.
          example: initial
    UpdateGuardrailRequest:
      type: object
      additionalProperties: false
      properties:
        name:
          type: string
        description:
          type: string
          nullable: true
        document:
          $ref: "#/components/schemas/GuardrailDocument"
        context_tool_id:
          x-naturali-ref: tools
          type: string
          nullable: true
        context_mode:
          type: string
          nullable: true
          enum:
            - merge
            - replace
            - null
        version_label:
          type: string
          description: Optional tag for the config version this write archives (e.g. `pre-tightening`).
            Annotates the version only — it is not stored on the guardrail and is not part of the
            config, so labelling a change is never itself a change. Ignored when the write changes
            no policy, since no version is created.
          example: pre-tightening
        expected_version:
          description: Refuses the write unless the resource is at this version.
          allOf:
            - $ref: "#/components/schemas/ExpectedVersion"
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          description: Structured error. Every error response uses this shape, so `code` can be read without
            first checking the type of `error`.
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: "Machine-readable error code: lower_snake for an error naturali raises
                (`access_denied`), UPPER_SNAKE for one the runtime reports (`RESOURCE_NOT_FOUND`)."
              example: access_denied
            message:
              type: string
              description: Human-readable explanation.
              example: Your role in this project does not carry this action.
            details:
              type: object
              additionalProperties: true
              description: Structured context for an error naturali raises, such as the `resource` and `limit` of
                a `plan_limit_reached`.
            meta:
              type: object
              description: Structured context for an error the runtime reports.
    ExpectedVersion:
      type: integer
      minimum: 1
      nullable: true
      description: >-
        The version the caller believes the resource holds. When the resource is at any other
        version the write is refused with `409 VERSION_CONFLICT` and nothing is written;
        `meta.current_version` on that response names the version in force.


        Omit it to write unconditionally. Omitting it does not make the write unordered: two writes
        that reach the server together are still serialized, and the one whose version was taken
        first is refused the same way. What the field adds is refusing a write whose author read the
        resource some time ago and has not seen what happened since.


        The `If-Match` header carries the same precondition for a client that prefers the HTTP
        spelling. Sending both with different versions is `400 VALIDATION_FAILED`.
      example: 3
  parameters:
    ProjectId:
      name: project_id
      in: path
      required: true
      description: Project public ID (proj_ prefix).
      schema:
        type: string
        example: proj_V1StGXR8Z5jdHi6B
    IfMatchVersion:
      name: If-Match
      in: header
      required: false
      description: The version the caller believes the resource holds, as an entity tag (`3` or `"3"`).
        Equivalent to `expected_version` in the request body; `*` states no precondition beyond the
        resource existing. A mismatch is `409 VERSION_CONFLICT`.
      schema:
        type: string
      example: "3"
  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.
  responses:
    VersionConflict:
      description: "The resource has moved past the version this write read (`VERSION_CONFLICT`): a stated
        `expected_version` or `If-Match` no longer matches, or a concurrent write took the version
        first. `meta.current_version` names the version in force. Nothing is written."
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
