# AUTO-GENERATED tier-A mirror spec — do not edit.
# Source: openapi/runtime/memories.yaml (runtime 0.71.2)
#  + policy: openapi/mirror-policies/memories.json
# Regenerate: node scripts/generate-mirror-specs.mjs
openapi: 3.0.3
info:
  title: naturali.ai — Memories API
  version: 1.0.0
  description: >-
    Memories: the individual facts inside a memory store — written by hand or learned in a
    conversation, each embedded so knowledge search can rank it against a query. 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: Memories
    description: Manage individual memories (the knowledge items stored in a memory store)
security:
  - bearerAuth: []
  - oauth2:
      - mcp:access
paths:
  /v1/projects/{project_id}/memories:
    get:
      tags:
        - Memories
      summary: List memories
      description: Returns all memories in a memory store
      operationId: listMemories
      x-iam-action: memories:ListMemories
      parameters:
        - name: memory_store_id
          in: query
          required: true
          description: Memory store to list memories from (mstore_...)
          schema:
            type: string
            example: mstore_V1StGXR8Z5jdHi6B
        - $ref: "#/components/parameters/TagsQuery"
        - 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
        - name: include_invalidated
          in: query
          required: false
          description: Include invalidated memories — superseded or retracted. They are excluded by default;
            set this to audit what a store once held.
          schema:
            type: boolean
            default: false
      responses:
        "200":
          description: List of memories
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - total
                  - limit
                  - offset
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Memory"
                  total:
                    type: integer
                  limit:
                    type: integer
                  offset:
                    type: integer
        "401":
          description: Unauthorized
        "403":
          description: Forbidden
        "404":
          description: Memory store not found
        "500":
          description: Internal server error
    post:
      tags:
        - Memories
      summary: Create a memory
      description: "Writes a fact to the specified memory store through the standard write algorithm: the
        content is embedded (or matched to text the store already holds), compared against the most
        similar currently-valid memory, and resolved to exactly one of three outcomes — `skipped` at
        or above `duplicate_threshold`, `superseded` at or above `supersede_threshold`, `created`
        below it. `supersedes` overrides that comparison entirely, retiring the memory it names.
        Every call records one assertion, whatever the outcome."
      operationId: createMemory
      x-naturali-resource:
        kind: memory_store
        from: memory_store_id
      x-iam-action: memories:CreateMemory
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - memory_store_id
                - content
              additionalProperties: false
              properties:
                memory_store_id:
                  x-naturali-ref: memory-stores
                  type: string
                  description: Memory store to add the memory to (mstore_...)
                  example: mstore_V1StGXR8Z5jdHi6B
                content:
                  type: string
                  description: The text content of the memory
                  example: The customer prefers email communication over phone calls
                source_type:
                  type: string
                  enum:
                    - manual
                    - conversation
                  description: Whether there is a source to point at. `conversation` requires `source_id`; `manual`
                    rejects it.
                  default: manual
                  example: manual
                source_id:
                  type: string
                  description: The conversation this fact was learned in. Required when `source_type` is
                    `conversation`, and rejected otherwise.
                  example: conv_V1StGXR8Z5jdHi6B
                tags:
                  description: Per-memory key-value tags, used for memory-granularity filtering by `tags` in
                    search-knowledge.
                  allOf:
                    - $ref: "#/components/schemas/TagBag"
                metadata:
                  description: Arbitrary structured metadata attached to the memory
                  example:
                    evidence: high
                    quarter: Q3
                  allOf:
                    - $ref: "#/components/schemas/MetadataBag"
                supersedes:
                  type: string
                  description: 'The memory this write replaces, named outright. The declaration outranks the
                    thresholds in both directions: the target is retired and the write returns
                    `superseded` however similar or distant the two texts are. This is what reaches
                    a contradiction cosine cannot see ("The office is in Lisbon" then "We closed the
                    Lisbon office"). The target must be a still-valid memory in the same memory
                    store, and the caller needs `memories:UpdateMemory` on it as well as
                    `memories:CreateMemory` on the store.'
                  example: mem_V1StGXR8Z5jdHi6B
                duplicate_threshold:
                  type: number
                  description: Cosine similarity at or above which the incoming content is a duplicate of an existing
                    memory and the write is skipped. Overrides the store's `duplicate_threshold` for
                    this call; falls back to the store's value, then to `0.95`.
                  minimum: 0
                  maximum: 1
                  example: 0.95
                supersede_threshold:
                  type: number
                  description: "Cosine similarity at or above which the incoming content restates a fact that has
                    changed: the top match is invalidated and a new memory replaces it. Overrides
                    the store's `supersede_threshold` for this call; falls back to the store's
                    value, then to `0.90`. The effective pair must satisfy `supersede_threshold <
                    duplicate_threshold`, and the check runs against the effective pair — so
                    overriding only one value cannot invert it against the store's other one."
                  minimum: 0
                  maximum: 1
                  example: 0.9
      responses:
        "200":
          description: The write resolved against an existing memory — `action` is `skipped` (the fact was
            already known) or `superseded` (the fact had changed, and the returned memory is the
            replacement).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MemoryWriteResult"
        "201":
          description: Memory created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MemoryWriteResult"
        "400":
          description: Bad request — a missing required field, a threshold pair whose effective values are not
            `supersede_threshold < duplicate_threshold`, or a `supersedes` that is not a memory id,
            or names a memory in another memory store or one already superseded.
        "401":
          description: Unauthorized
        "403":
          description: Forbidden — the caller may not write to the memory store, or may not update the memory
            named by `supersedes`.
        "404":
          description: Memory store not found, or no memory matches `supersedes`
        "409":
          description: The project's `storage_bytes` quota is exceeded (`QUOTA_STORAGE_EXCEEDED`). Delete
            stored content, or raise the quota — no window reset clears a stored total, so no
            `Retry-After` is sent.
        "500":
          description: Internal server error
    parameters:
      - $ref: "#/components/parameters/ProjectId"
  /v1/projects/{project_id}/memories/{memory_id}:
    get:
      tags:
        - Memories
      summary: Get a memory
      description: Returns a single memory by ID
      operationId: getMemory
      x-naturali-resource:
        kind: memory
        from: memory_id
      x-iam-action: memories:GetMemory
      parameters:
        - name: memory_id
          in: path
          required: true
          schema:
            type: string
            example: mem_V1StGXR8Z5jdHi6B
      responses:
        "200":
          description: Memory found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Memory"
        "401":
          description: Unauthorized
        "403":
          description: Forbidden
        "404":
          description: Memory store or memory not found
        "500":
          description: Internal server error
    put:
      tags:
        - Memories
      summary: Update a memory
      description: Updates an existing memory. Regenerates the embedding if content changes.
      operationId: updateMemory
      x-naturali-resource:
        kind: memory
        from: memory_id
      x-iam-action: memories:UpdateMemory
      parameters:
        - name: memory_id
          in: path
          required: true
          schema:
            type: string
            example: mem_V1StGXR8Z5jdHi6B
        - $ref: "#/components/parameters/IfMatchVersion"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                content:
                  type: string
                  description: Updated text content
                tags:
                  description: Replaces the memory's tags. Pass null or an empty object to clear.
                  allOf:
                    - $ref: "#/components/schemas/NullableTagBag"
                metadata:
                  description: Replaces the memory's metadata. Pass null to clear.
                  allOf:
                    - $ref: "#/components/schemas/NullableMetadataBag"
                expected_version:
                  description: Refuses the write unless the memory is at this version.
                  allOf:
                    - $ref: "#/components/schemas/ExpectedVersion"
      responses:
        "200":
          description: Memory updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Memory"
        "401":
          description: Unauthorized
        "403":
          description: Forbidden
        "404":
          description: Memory store or memory not found
        "409":
          $ref: "#/components/responses/VersionConflict"
        "500":
          description: Internal server error
    delete:
      tags:
        - Memories
      summary: Delete a memory
      description: Deletes a memory
      operationId: deleteMemory
      x-naturali-resource:
        kind: memory
        from: memory_id
      x-iam-action: memories:DeleteMemory
      parameters:
        - name: memory_id
          in: path
          required: true
          schema:
            type: string
            example: mem_V1StGXR8Z5jdHi6B
      responses:
        "204":
          description: Memory deleted
        "401":
          description: Unauthorized
        "403":
          description: Forbidden
        "404":
          description: Memory store or memory not found
        "500":
          description: Internal server error
    parameters:
      - $ref: "#/components/parameters/ProjectId"
  /v1/projects/{project_id}/memories/{memory_id}/retract:
    post:
      tags:
        - Memories
      summary: Retract a memory
      description: >
        Retires a fact that stopped holding with nothing replacing it. The memory leaves the default
        listing, [knowledge search](/docs/api/knowledge/search-knowledge) and write deduplication,
        so restating the fact later lands as a new memory.


        It is an invalidation with no successor, which is what tells it apart from a supersede:
        `invalidated_at` is set and `superseded_by_memory_id` stays null. The retraction is appended
        to the assertion ledger with outcome `retracted`, so who withdrew the fact is part of the
        record.


        The memory stays readable by id, with its text and its assertions. `DELETE` remains the way
        to remove it outright.
      operationId: retractMemory
      x-naturali-resource:
        kind: memory
        from: memory_id
      x-iam-action: memories:RetractMemory
      parameters:
        - name: memory_id
          in: path
          required: true
          schema:
            type: string
            example: mem_V1StGXR8Z5jdHi6B
        - $ref: "#/components/parameters/IfMatchVersion"
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                expected_version:
                  description: Refuses the retraction unless the memory is at this version.
                  allOf:
                    - $ref: "#/components/schemas/ExpectedVersion"
      responses:
        "200":
          description: The retracted memory
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Memory"
        "401":
          description: Unauthorized
        "403":
          description: Forbidden
        "404":
          description: Memory store or memory not found
        "409":
          description: The memory is already invalidated (`MEMORY_ALREADY_INVALIDATED`), or it has moved past
            the version this write read (`VERSION_CONFLICT`, with `meta.current_version`).
        "500":
          description: Internal server error
    parameters:
      - $ref: "#/components/parameters/ProjectId"
  /v1/projects/{project_id}/memories/{memory_id}/assertions:
    get:
      tags:
        - Memories
      summary: List a memory's assertions
      description: "Returns every write that resolved into this memory, oldest first: the one that created
        it, the duplicates it absorbed, and the assertion that superseded another memory in its
        favour. A superseded memory keeps its own assertions, so the chain can be walked in both
        directions."
      operationId: listMemoryAssertions
      x-naturali-resource:
        kind: memory
        from: memory_id
      x-iam-action: memories:ListMemoryAssertions
      parameters:
        - name: memory_id
          in: path
          required: true
          schema:
            type: string
            example: mem_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 assertions
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - total
                  - limit
                  - offset
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/MemoryAssertion"
                  total:
                    type: integer
                  limit:
                    type: integer
                  offset:
                    type: integer
        "401":
          description: Unauthorized
        "403":
          description: Forbidden
        "404":
          description: Memory store or memory not found
        "500":
          description: Internal server error
    parameters:
      - $ref: "#/components/parameters/ProjectId"
  /v1/projects/{project_id}/memories/{memory_id}/tags:
    get:
      tags:
        - Memories
      summary: Get memory tags
      description: Returns all tags attached to the memory
      operationId: getMemoryTags
      x-naturali-resource:
        kind: memory
        from: memory_id
      x-iam-action: memories:GetMemory
      parameters:
        - name: memory_id
          in: path
          required: true
          description: Memory ID
          schema:
            type: string
            example: mem_V1StGXR8Z5jdHi6B
      responses:
        "200":
          description: Memory tags
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TagBag"
        "401":
          description: Unauthorized
        "403":
          description: Forbidden
        "404":
          description: Memory store or memory not found
    put:
      tags:
        - Memories
      summary: Replace memory tags
      description: Replaces all tags on the memory with the provided tags (not merged)
      operationId: replaceMemoryTags
      x-naturali-resource:
        kind: memory
        from: memory_id
      x-iam-action: memories:UpdateMemory
      parameters:
        - name: memory_id
          in: path
          required: true
          description: Memory ID
          schema:
            type: string
            example: mem_V1StGXR8Z5jdHi6B
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TagBag"
      responses:
        "200":
          description: Tags replaced
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TagBag"
        "400":
          description: Body is not an object of string values
        "401":
          description: Unauthorized
        "403":
          description: Forbidden
        "404":
          description: Memory store or memory not found
    patch:
      tags:
        - Memories
      summary: Merge memory tags
      description: Merges provided tags into the memory's existing tags (existing tags are preserved
        unless overridden)
      operationId: mergeMemoryTags
      x-naturali-resource:
        kind: memory
        from: memory_id
      x-iam-action: memories:UpdateMemory
      parameters:
        - name: memory_id
          in: path
          required: true
          description: Memory ID
          schema:
            type: string
            example: mem_V1StGXR8Z5jdHi6B
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TagBag"
      responses:
        "200":
          description: Tags merged
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TagBag"
        "400":
          description: Body is not an object of string values
        "401":
          description: Unauthorized
        "403":
          description: Forbidden
        "404":
          description: Memory store or memory not found
    parameters:
      - $ref: "#/components/parameters/ProjectId"
components:
  schemas:
    Memory:
      type: object
      properties:
        id:
          type: string
          example: mem_V1StGXR8Z5jdHi6B
        memory_store_id:
          x-naturali-ref: memory-stores
          type: string
          example: mstore_V1StGXR8Z5jdHi6B
        content:
          type: string
          description: The text this memory currently holds. Stored once per distinct text per store and
            shared with every assertion that stated it, so a memory carries no copy of its own.
          example: The customer prefers email communication over phone calls
        source_type:
          type: string
          enum:
            - manual
            - conversation
          description: Whether there is a source to point at. `conversation` means `source_id` names the
            conversation this fact was learned in; `manual` means there is nothing to point at — a
            direct API write, or an agent write made outside a conversation.
          example: manual
        source_id:
          type: string
          nullable: true
          description: The conversation this fact was learned in, when `source_type` is `conversation`; null
            when it is `manual`. Deliberately a loose pointer rather than a foreign key, so deleting
            the conversation leaves the id in place — the record of where the fact came from
            outlives its source.
          example: conv_V1StGXR8Z5jdHi6B
        tags:
          description: Per-memory key-value tags, matched at memory granularity by knowledge search.
          allOf:
            - $ref: "#/components/schemas/NullableTagBag"
        metadata:
          description: Arbitrary structured metadata attached to the memory
          example:
            evidence: high
          allOf:
            - $ref: "#/components/schemas/NullableMetadataBag"
        invalidated_at:
          type: string
          format: date-time
          nullable: true
          description: When the memory stopped holding, whether a supersede replaced it or a retraction
            withdrew it. Null means the memory is currently valid. Invalidated memories are excluded
            from listing, from write deduplication, and from knowledge search, but remain readable
            by ID — with their original text — for audit.
        superseded_by_memory_id:
          type: string
          nullable: true
          description: The memory that replaced this one, when it was superseded. Null for a valid memory and
            for a retracted one, which nothing replaced.
          example: mem_V1StGXR8Z5jdHi6B
        version:
          type: integer
          description: The memory's write version, starting at 1 and incremented on every update. States a
            precondition against it with `expected_version` or `If-Match` on `PUT
            /memories/{memory_id}`.
          example: 1
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    MemoryWriteResult:
      allOf:
        - $ref: "#/components/schemas/Memory"
        - type: object
          properties:
            action:
              type: string
              enum:
                - created
                - superseded
                - skipped
              description: "The outcome of the write. `created` means the fact was distinct and a new memory holds
                it. `superseded` means it restated a fact that had changed: the matched memory was
                invalidated, points at the replacement, and the replacement is what is returned.
                `skipped` means the fact was already known and the existing memory is returned
                unchanged. Every outcome is recorded as an assertion, readable at `GET
                /v1/projects/{project_id}/memories/{memory_id}/assertions`."
    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
    MetadataBag:
      type: object
      description: >-
        Caller-owned annotations on a resource, stored as the object they were written as: the types
        a value was written with are the types a read returns, so a filter can ask an ordering
        question about a number. Unlike other body fields, keys are stored and returned verbatim in
        the casing supplied — they are not converted between snake_case and camelCase.


        No key is reserved, and that is the point: every piece of state the platform owns lives in
        its own typed column, so nothing written here reaches platform state. The platform never
        reads the bag — it is not an IAM context, not a policy input and not part of a prompt —
        which is what separates it from a tag bag.
      example:
        author: John
        revision: 2
    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
    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
    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
    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.
    MemoryAssertion:
      type: object
      description: "One write attempt against a memory store: some principal, through some mechanism,
        claimed a fact. Append-only, and recorded whatever the outcome — including the skips, which
        left no record anywhere before."
      properties:
        id:
          type: string
          example: massert_V1StGXR8Z5jdHi6B
        memory_store_id:
          x-naturali-ref: memory-stores
          type: string
          example: mstore_V1StGXR8Z5jdHi6B
        memory_id:
          type: string
          nullable: true
          description: "The memory this assertion resolved into: the new memory for `created` and
            `superseded`, the existing memory that matched for `skipped`, the memory withdrawn for
            `retracted`. Null only once that memory has been deleted."
          example: mem_V1StGXR8Z5jdHi6B
        superseded_memory_id:
          type: string
          nullable: true
          description: The memory this assertion retired, on a `superseded` outcome; null otherwise, a
            retraction included — it retires its own memory, which `memory_id` already names. Read
            back from `memories.superseded_by_memory_id` rather than stored here, because validity
            lives on the memory — where every read filters it — and exactly one memory is superseded
            per assertion.
          example: mem_V1StGXR8Z5jdHi6B
        content:
          type: string
          description: "The text as asserted, which is not necessarily the memory's text: a `skipped`
            assertion records what was claimed, while the memory keeps what it already held."
          example: The customer prefers email communication over phone calls
        mechanism:
          type: string
          enum:
            - tool
            - rule
            - api
            - formation
          description: Which door the write came through. `tool` is the agent's `write_memory` call mid-turn;
            `rule` is a post-turn pass over the finished turn; `api` is `POST
            /v1/projects/{project_id}/memories`; `formation` is a `memory` resource in an applied
            template. It answers *how*, never *who* — the principal fields answer that.
          example: tool
        rule_id:
          x-naturali-ref: memory-rules
          type: string
          nullable: true
          description: The memory rule whose firing wrote this, set only when `mechanism` is `rule` — the
            built-in extractor included, since that is a rule with no handler. Null once the rule
            has been deleted, and on assertions written before memory rules shipped.
          example: mrule_V1StGXR8Z5jdHi6B
        generation_id:
          x-naturali-ref: generations
          type: string
          nullable: true
          description: The turn that asserted the fact — the origin of anything an agent wrote, and the edge a
            conversation is reachable from. Null on the `api` and `formation` doors, which have no
            generation behind them.
          example: gen_V1StGXR8Z5jdHi6B
        principal_type:
          type: string
          description: Who claimed the fact, in the vocabulary a generation records its starter with, plus
            `agent`. On both agent doors the principal is the agent itself — the extractor runs
            under its identity.
          example: agent
        principal_id:
          type: string
          example: agent_V1StGXR8Z5jdHi6B
        outcome:
          type: string
          enum:
            - created
            - superseded
            - skipped
            - retracted
          description: What the write resolved to. `created` is a distinct fact, `superseded` is the same fact
            changed (the top match was invalidated and replaced), `skipped` is a fact already known,
            `retracted` is a fact that stopped holding with nothing replacing it.
          example: created
        similarity:
          type: number
          nullable: true
          description: The cosine similarity the outcome was decided against — the top match's, or the
            declared target's when `declared` is true, where it decides nothing and only records how
            far apart the two statements were. Null when there was nothing to compare against, when
            the content could not be embedded, and on a `retracted` outcome, which compares nothing.
          example: 0.97
        declared:
          type: boolean
          description: Whether the write named the memory it replaced (`supersedes` on create) instead of the
            thresholds choosing one. Always false on a `created`, `skipped` or `retracted` outcome.
          example: false
        created_at:
          type: string
          format: date-time
  parameters:
    ProjectId:
      name: project_id
      in: path
      required: true
      description: Project public ID (proj_ prefix).
      schema:
        type: string
        example: proj_V1StGXR8Z5jdHi6B
    TagsQuery:
      name: tags
      in: query
      required: false
      description: >
        Filter by tag pairs, written `key:value` (split on the first colon, so a value may contain
        colons). Repeat the parameter for several pairs; **all** must be present with exactly that
        value.
      schema:
        type: array
        items:
          type: string
      style: form
      explode: true
      example:
        - env:prod
    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"
