> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xtrace.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Update memory group_ids

> Add or remove ``group_ids`` on a single memory — the sharing
axis. Group tags control who can reach a row via
``filters: {group_ids: <id>}`` on search / list, so this is how a
memory becomes shared (or un-shared) after ingest.

Scope is group tags only: ``text`` and the entity ids
(``user_id`` / ``agent_id`` / ``conv_id`` / ``app_id``) are
immutable post-ingest and are not editable here. The operation is
set-based and idempotent — re-sending the same patch is a no-op and
skips the write entirely. See :class:`MemoryGroupPatchRequest` for
the full contract.



## OpenAPI

````yaml https://api.staging.xtrace.ai/openapi.public.json patch /v1/memories/{memory_id}
openapi: 3.1.0
info:
  title: XTrace Vec DB
  description: XTrace API
  version: 1.0.0
servers:
  - url: https://api.production.xtrace.ai
    description: Production
security:
  - ApiKeyHeader: []
  - BearerToken: []
paths:
  /v1/memories/{memory_id}:
    patch:
      tags:
        - memories
      summary: Update memory group_ids
      description: |-
        Add or remove ``group_ids`` on a single memory — the sharing
        axis. Group tags control who can reach a row via
        ``filters: {group_ids: <id>}`` on search / list, so this is how a
        memory becomes shared (or un-shared) after ingest.

        Scope is group tags only: ``text`` and the entity ids
        (``user_id`` / ``agent_id`` / ``conv_id`` / ``app_id``) are
        immutable post-ingest and are not editable here. The operation is
        set-based and idempotent — re-sending the same patch is a no-op and
        skips the write entirely. See :class:`MemoryGroupPatchRequest` for
        the full contract.
      operationId: patch_memory_group_ids_v1_memories__memory_id__patch
      parameters:
        - name: memory_id
          in: path
          required: true
          schema:
            type: string
            title: Memory Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MemoryGroupPatchRequest'
      responses:
        '200':
          description: Updated. Returns the full memory with its new `group_ids`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Memory'
        '401':
          description: >-
            Authentication failed. Missing / invalid API key. Body carries
            `detail.code = "unauthorized"`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '404':
          description: >-
            `detail.code = "memory_not_found"` — no readable row with that id
            under this org.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '422':
          description: >-
            `detail.code` is one of: `empty_patch` (neither list supplied),
            `contradictory_group_ids` (same id in both lists),
            `invalid_group_ids` (an added id is unknown or archived), or
            `invalid_request` (resulting tag count exceeds
            `MAX_GROUP_IDS_PER_INGEST`).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '429':
          description: >-
            Rate-limit or daily-cap exceeded. `Retry-After` and `RateLimit-*`
            response headers indicate when to retry.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '500':
          description: '`detail.code = "patch_failed"` — storage error writing the tags.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
components:
  schemas:
    MemoryGroupPatchRequest:
      properties:
        add_group_ids:
          items:
            type: string
          type: array
          title: Add Group Ids
          description: >-
            Group ids to add to the row. Each must be an active group on the
            org. Ids already present are ignored (no duplicates). Blank entries
            are trimmed away.
          examples:
            - - grp_eng
              - grp_oncall
        remove_group_ids:
          items:
            type: string
          type: array
          title: Remove Group Ids
          description: >-
            Group ids to remove from the row. Ids not currently on the row are
            ignored. Not validated against the group registry, so an archived
            group's tag can still be removed.
          examples:
            - - grp_personal
      type: object
      title: MemoryGroupPatchRequest
      description: |-
        ``PATCH /v1/memories/{id}`` — add or remove ``group_ids`` on an
        existing memory row.

        Scope is intentionally narrow: this endpoint mutates the row's
        group tags only — the *sharing* axis. It does not edit ``text`` or
        any entity id (``user_id`` / ``agent_id`` / ``conv_id`` /
        ``app_id``); those are immutable once ingested.

        Semantics are set-based and order-independent — ``group_ids`` is an
        unordered set of tags. Adding an id already present is a no-op, and
        removing an id that isn't there is a no-op, so the whole operation
        is idempotent and safe to retry. ``remove`` is applied before
        ``add``; the same id may not appear in both lists (``422
        contradictory_group_ids``). At least one list must be non-empty
        (``422 empty_patch``).

        Every id in ``add_group_ids`` must be an **active** group on the
        org (see ``POST /v1/groups``); an unknown or archived id is
        rejected with ``422 invalid_group_ids``. ``remove_group_ids`` is
        *not* validated against the registry — a tag can always be removed,
        including one whose group was archived after it was applied.
    Memory:
      properties:
        id:
          type: string
          title: Id
          description: Stable UUID for this memory row.
        object:
          type: string
          const: memory
          title: Object
          description: Constant discriminator for the resource type.
          default: memory
        type:
          type: string
          enum:
            - fact
            - artifact
            - episode
            - lesson
            - procedure
          title: Type
          description: >-
            Memory subtype. `fact` = a single semantic claim extracted from a
            turn; `artifact` = a structured object (code, doc, image) referenced
            by the conversation; `episode` = a session-scoped summary of a
            stretch of turns; `lesson` / `procedure` = a situated directive
            recalled by the symbol tripwire (see `DirectiveDetails`).
        text:
          type: string
          title: Text
          description: >-
            Short readable preview. For facts: the claim statement. For
            artifacts: a summary or title (full body lives in
            `details.full_content`, opt-in via `include=full_content`). For
            episodes: a summary of the session.
        user_id:
          anyOf:
            - type: string
            - type: 'null'
          title: User Id
          description: User scope this row belongs to.
        agent_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Agent Id
          description: Agent scope, if any.
        conv_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Conv Id
          description: Conversation anchor.
        app_id:
          anyOf:
            - type: string
            - type: 'null'
          title: App Id
          description: App scope, if any.
        group_ids:
          items:
            type: string
          type: array
          title: Group Ids
          description: >-
            Group ids associated with this row — the sharing axis. Stamped at
            ingest time and editable afterward via `PATCH /v1/memories/{id}`
            (`add_group_ids` / `remove_group_ids`). Reachable as a filter axis
            via `filters: {group_ids: <id>}` or `{group_ids: {"$in": [<id>,
            ...]}}`.
        categories:
          items:
            type: string
          type: array
          title: Categories
          description: Optional category labels from the extraction pipeline.
        score:
          anyOf:
            - type: number
            - type: 'null'
          title: Score
          description: >-
            Vector-similarity score. Present **only** on search responses; null
            on list / get-by-id / patch / ingest result rows.
        created_at:
          anyOf:
            - type: string
            - type: 'null'
          format: date-time
          title: Created At
          description: ISO-8601 timestamp of original ingest.
        updated_at:
          anyOf:
            - type: string
            - type: 'null'
          format: date-time
          title: Updated At
          description: ISO-8601 timestamp of the last supersede / consolidation.
        details:
          oneOf:
            - $ref: '#/components/schemas/FactDetails'
            - $ref: '#/components/schemas/ArtifactDetails'
            - $ref: '#/components/schemas/EpisodeDetails'
            - $ref: '#/components/schemas/DirectiveDetails'
          type: object
          title: Details
          description: >-
            Type-specific extension. Shape depends on `type` — see `FactDetails`
            / `ArtifactDetails` / `EpisodeDetails` schemas. Always an object;
            never null.
      type: object
      required:
        - id
        - type
        - text
      title: Memory
      description: |-
        Unified memory resource — facts, artifacts, episodes marshal to
        this shape. ``type`` is the discriminator; ``details`` is the
        type-specific extension.

        Invariant: ``text`` is always a short readable preview, regardless
        of type (fact statement / artifact summary / episode summary).
    ErrorEnvelope:
      properties:
        detail:
          $ref: '#/components/schemas/ErrorDetail'
      type: object
      required:
        - detail
      title: ErrorEnvelope
      description: |-
        Standard error body for non-2xx responses raised by the memory
        API. Pydantic field-validation failures (422) use the FastAPI-
        default ``HTTPValidationError`` shape instead, where ``detail`` is
        an array of per-field error entries — switch on the response
        status code to pick the right shape.
    FactDetails:
      description: |-
        Per-row fact details — sits under ``Memory.details`` when
        ``Memory.type == "fact"``.
      properties:
        fact_type:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Fact Type
        status:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Status
        supersedes:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Supersedes
        source_role:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Source Role
        episode_id:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Episode Id
        artifact_id:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Artifact Id
        artifact_ids:
          items:
            type: string
          title: Artifact Ids
          type: array
        source_event_ids:
          items:
            type: string
          title: Source Event Ids
          type: array
      title: FactDetails
      type: object
    ArtifactDetails:
      description: |-
        Per-row artifact details under ``Memory.details`` when
        ``Memory.type == "artifact"``.

        ``full_content`` is opt-in — omitted on list/search by default,
        included on ``GET /v1/memories/{id}`` and when
        ``include=["full_content"]`` is set on list/search.
      properties:
        title:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Title
        rationale:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Rationale
        version:
          anyOf:
            - type: integer
            - type: 'null'
          default: null
          title: Version
        root_id:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Root Id
        source_fact_ids:
          items:
            type: string
          title: Source Fact Ids
          type: array
        episode_ids:
          items:
            type: string
          title: Episode Ids
          type: array
        full_content:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Full Content
      title: ArtifactDetails
      type: object
    EpisodeDetails:
      description: |-
        Per-row episode details under ``Memory.details`` when
        ``Memory.type == "episode"``.
      properties:
        title:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Title
        started_at:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Started At
        ended_at:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Ended At
        fact_ids:
          items:
            type: string
          title: Fact Ids
          type: array
        artifact_ids:
          items:
            type: string
          title: Artifact Ids
          type: array
      title: EpisodeDetails
      type: object
    DirectiveDetails:
      description: >-
        Per-row directive details under ``Memory.details`` when ``Memory.type``
        is

        ``"lesson"`` or ``"procedure"`` — a directive recalled by the symbol
        tripwire.


        Populated from the recalled ``Fact`` plus the relevance gate.
        ``because`` /

        ``confidence`` are filled only under ``mode=compose`` (the gate ran);
        under

        ``mode=retrieve`` they are null (deterministic stage-1 tripwire only).
      properties:
        fact_type:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: '`lesson` or `procedure`.'
          title: Fact Type
        trigger_entities:
          description: The concrete file/symbol anchors this directive fires on.
          items:
            type: string
          title: Trigger Entities
          type: array
        matched_on:
          description: >-
            The subset of `trigger_entities` the in-flight action actually
            matched.
          items:
            type: string
          title: Matched On
          type: array
        because:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Why the gate kept this directive for the current task. Null under
            `mode=retrieve`.
          title: Because
        confidence:
          anyOf:
            - type: number
            - type: 'null'
          default: null
          description: Gate confidence (0–1). Null under `mode=retrieve`.
          title: Confidence
        observation_count:
          anyOf:
            - type: integer
            - type: 'null'
          default: null
          description: How many times this directive has been re-confirmed.
          title: Observation Count
        last_confirmed_at:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: ISO-8601 of the last re-confirmation.
          format: date-time
          title: Last Confirmed At
        steps:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          default: null
          description: >-
            Typed procedure steps, in order (`type: "procedure"` only). The
            row's `text` already renders them as a numbered list; this is the
            structured form for callers that format their own.
          examples:
            - - Run the build
              - Push the image
          title: Steps
      title: DirectiveDetails
      type: object
    ErrorDetail:
      properties:
        code:
          type: string
          title: Code
          description: >-
            Stable error identifier. Switch on this rather than parsing the
            message. Common values: `invalid_request`, `invalid_messages`,
            `memory_not_found`, `job_not_found`, `immutable_field`,
            `reserved_field`, `empty_text_field`, `missing_user_id`,
            `missing_conv_id`, `unsupported_include_option`, `cursor_mismatch`,
            `unauthorized`, `forbidden`, `rate_limited`, `delete_failed`,
            `search_failed`, `ingest_failed`, `server_error`.
          examples:
            - memory_not_found
        message:
          type: string
          title: Message
          description: Human-readable summary; safe to log but not safe to switch on.
          examples:
            - Memory 0fa1c0e6-... not found
      type: object
      required:
        - code
        - message
      title: ErrorDetail
      description: |-
        Inner ``detail`` block on every non-2xx response raised by a
        memory-API route handler. ``code`` is the stable identifier
        clients should switch on; ``message`` is a sanitized human-
        readable summary.
  securitySchemes:
    ApiKeyHeader:
      type: apiKey
      in: header
      name: x-api-key
      description: 'Long-lived org API key. Alternative: `Authorization: Bearer <key>`.'
    BearerToken:
      type: http
      scheme: bearer
      bearerFormat: Token
      description: 'Long-lived API key sent as `Authorization: Bearer <api-key>`.'

````