# speakers_avatar_mutate

Canonical HTML page: https://bitterclip.com/docs/assistants/tools/speakers_avatar_mutate

Surface: app-only

Product release: 8e56699756c9c201f2428c4aabba1b0af2dcfb67
Public contract commit: 1ce47f7857ae3d9b6933fe83d5c33de3ae5efc64
Public contract SHA-256: 241d47d25e4b4c1dae9d2263793874d06fc4ba7bc3c78d4cf2bc63fbb32ed7dc
Descriptor SHA-256: 885d46f3ca3939dec2ace0cd6e93611c8b3f741f2d8f7a82e0adfe1452cc9a9e
Captured: 2026-09-25T06:43:18.135Z
Source: https://app.bitterclip.com/api/v1/mcp_descriptors.json

One profile-photo change per call: set_from_reference is the profile-picture chooser — it copies one cropped reference-gallery candidate (from speakers_list_avatar_candidates) into durable history and makes it current, and because it copies, later rejecting or invalidating that reference never alters the photo, and being the photo never adds it to the matching set; set_from_upload does the same from an uploaded image; clear removes the current photo while preserving history; restore brings back a prior history item. No action accepts a whole sampled frame — the retired set_from_candidate lane served frames that could show the wrong person; a recording's own frame pick lives on speakers_track_mutate set_avatar_from_recording and never touches the saved photo. App-only human repair actions — none of them change identity, voice memory, transcript labels, captions, exports, or merge state. Pass a caller-stable idempotency key with every action; the profile-photo lane has no structural revision, so expected_revision is carried optionally toward the standard mutation contract.

The JSON blocks below are the exact MCP descriptor projections served by Rails for the named profiles at capture time. Security schemes and resource URIs may vary by connected host.

## App descriptor

```json
{
  "name": "speakers_avatar_mutate",
  "title": "Change a profile photo",
  "description": "One profile-photo change per call: set_from_reference is the profile-picture chooser — it copies one cropped reference-gallery candidate (from speakers_list_avatar_candidates) into durable history and makes it current, and because it copies, later rejecting or invalidating that reference never alters the photo, and being the photo never adds it to the matching set; set_from_upload does the same from an uploaded image; clear removes the current photo while preserving history; restore brings back a prior history item. No action accepts a whole sampled frame — the retired set_from_candidate lane served frames that could show the wrong person; a recording's own frame pick lives on speakers_track_mutate set_avatar_from_recording and never touches the saved photo. App-only human repair actions — none of them change identity, voice memory, transcript labels, captions, exports, or merge state. Pass a caller-stable idempotency key with every action; the profile-photo lane has no structural revision, so expected_revision is carried optionally toward the standard mutation contract.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "speaker_profile_id": {
        "type": "string",
        "description": "Person public ID, slug, or UUID that owns the profile photo."
      },
      "expected_revision": {
        "type": "integer",
        "description": "Optional: carried toward the standard mutation contract. The profile-photo lane exposes no structural revision yet; omit until it does."
      },
      "idempotency_key": {
        "type": "string",
        "description": "Caller-stable retry key for this exact change."
      },
      "action": {
        "type": "object",
        "description": "One profile-photo action. Use the canonical field names in the matching action shape.",
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "set_from_reference"
                ]
              },
              "reference_asset_id": {
                "type": "string",
                "description": "Reference-gallery asset ID from speakers_list_avatar_candidates. Those candidates are cropped and attributed to this person, never whole frames."
              }
            },
            "required": [
              "type",
              "reference_asset_id"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "set_from_upload"
                ]
              },
              "uploaded_blob_signed_id": {
                "type": "string",
                "description": "Signed ID for an uploaded image blob."
              }
            },
            "required": [
              "type",
              "uploaded_blob_signed_id"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "clear"
                ]
              }
            },
            "required": [
              "type"
            ],
            "additionalProperties": false
          },
          {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "restore"
                ]
              },
              "portrait_event_id": {
                "type": "string",
                "description": "Profile photo history item public ID."
              }
            },
            "required": [
              "type",
              "portrait_event_id"
            ],
            "additionalProperties": false
          }
        ]
      }
    },
    "required": [
      "speaker_profile_id",
      "idempotency_key",
      "action"
    ],
    "additionalProperties": false
  },
  "annotations": {
    "readOnlyHint": false,
    "destructiveHint": false,
    "idempotentHint": false,
    "openWorldHint": false
  },
  "securitySchemes": [
    {
      "type": "noauth"
    }
  ],
  "_meta": {
    "securitySchemes": [
      {
        "type": "noauth"
      }
    ],
    "ui": {
      "visibility": [
        "app"
      ]
    },
    "openai/widgetAccessible": true,
    "openai/visibility": "private"
  },
  "outputSchema": {
    "type": "object",
    "properties": {
      "speaker_profile_id": {
        "type": "string"
      },
      "avatar_id": {
        "type": "string"
      },
      "avatar_url": {
        "type": [
          "string",
          "null"
        ]
      },
      "receipt_id": {
        "type": "string"
      },
      "state_sentence": {
        "type": "string"
      }
    },
    "required": [],
    "additionalProperties": false
  }
}
```

## Errors

```json
[
  "speaker_not_found",
  "invalid_input"
]
```

## Examples

```json
[]
```
