---
title: persona_update
description: Change the body, the age range or the slug of a persona. The revision that the agent read stops it from overwriting a change that it did not see.
---

Ask for a change to a persona. The agent changes only the parts that you name.

> "The Loyalists say 'my daily trainer'. Add that to their language."

The agent reads the persona with [`persona_get`](/mcp/tools/persona-get), and then calls `persona_update`. The agent keeps the text that it read and adds the new words under the Language heading. You then see the new language, and the rest of the body as it was.

The job guide [Describe a brand](/mcp/tools/describe-a-brand) shows each step of the job.

## Reference

Update a persona. Pass base_revision (from persona_get) — the update is rejected if the persona changed since you read it. Only the fields you pass are changed; pass `body` to replace the whole body of the persona (read it with persona_get, change it, send it back). Pass null for the body or an age bound to clear it. Suggested headings for the body: "## Profile", "## Motivations", "## Frictions", "## Language". Optionally rename the slug handle.

### Input

| Argument | Type | Required | Description |
| --- | --- | --- | --- |
| `age_max` | integer, 0 to 120 or null | no | New upper age bound. Pass null to clear it ("and older"). |
| `age_min` | integer, 0 to 120 or null | no | New lower age bound. Pass null to clear it ("and younger"). |
| `base_revision` | integer | yes | The revision you last read via persona_get. Guards against overwriting a concurrent edit. |
| `body` | string, 1 to 50000 characters or null | no | The new body of the persona, as one Markdown text. It replaces the whole body. Omit it to leave the body alone. Pass null to clear it. |
| `brand_name` | string | yes | The slug of the brand that owns the persona. |
| `description` | string, 1 to 500 characters | no | New one-line summary. |
| `name` | string, 1 to 120 characters | no | New display name. |
| `persona_name` | string | yes | The current persona slug identifying which to update. |
| `slug` | string, at most 120 characters | no | Optional new slug handle (a deliberate rename); normalized to kebab-case. Callers of the old handle must be updated. |

### Output

A successful call returns this object in `structuredContent`.

| Field | Type | Always present | Description |
| --- | --- | --- | --- |
| `persona` | object | yes | The persona in full. |
| `persona.ageMax` | integer, 0 to 120 or null | yes | The highest age of the audience. `null` when the range has no upper bound. |
| `persona.ageMin` | integer, 0 to 120 or null | yes | The lowest age of the audience. `null` when the range has no lower bound. |
| `persona.body` | string or null | yes | The context of the persona, as one Markdown text. `null` when no body is written. Headings such as Profile, Motivations, Frictions and Language are the advice of the tools, and the body does not need them. |
| `persona.brandId` | string | yes | The brand that owns the persona (`brd_…`). |
| `persona.createdAt` | number | yes | Milliseconds since the Unix epoch, in UTC. |
| `persona.createdBy` | string | yes | The user who created the record (`usr_…`). |
| `persona.description` | string | yes | One line about the persona. An agent picks a persona on it. |
| `persona.id` | string | yes | The id of the persona (`psn_…`). |
| `persona.name` | string | yes | The display name. |
| `persona.revision` | number | yes | The version of the record. Each change adds 1. Send it as `base_revision` to update or delete the record. |
| `persona.slug` | string | yes | The handle of the persona. It is unique in its brand, not in the organization. The tools take it as `persona_name`. |
| `persona.updatedAt` | number or null | yes | Milliseconds since the Unix epoch, in UTC. `null` until the first change. |

### Failure codes

A failed call has `isError` set, and `structuredContent.error` holds one of these codes. [Errors](/mcp/errors) describes the shape of a failed call.

- `not_found`
- `invalid_slug`
- `invalid_age_range`
- `revision_mismatch`
- `slug_conflict`
- `organization_unentitled`
- `forbidden`
- `invalid_request`
- `internal_error`

### Scope

The token must hold `brand:write`. [Auth & scopes](/mcp/auth) lists each scope.

### Annotations

A client reads these hints. A hint that the tool does not declare has the default value of the MCP specification.

- **Writes.** The tool can change data.
- **Destructive.** The tool can make a change that you cannot undo. A client can ask you to confirm before it calls the tool.
- **Not idempotent.** A second call with the same arguments can change more.
- **Closed world.** The tool reads and writes the data of AdCrunch only.

### Example

The arguments:

```json
{
  "base_revision": 1,
  "body": "## Profile\n\nRunners of 40 to 80 kilometres a week, ten years in, with one pair in rotation and one on the shelf.\n\n## Motivations\n\nThey want the same shoe again, and proof that it is the same. A resole keeps them running on a pair they trust.\n\n## Frictions\n\nThey fear the new model is worse than the one they know. A change of sole or of last reads to them as a risk, not as progress.\n\n## Language\n\nThey say \"my daily trainer\" and \"I got 900 out of the last pair\". They ask about the drop and the stack, never about the technology.",
  "brand_name": "acme",
  "persona_name": "loyalists"
}
```

The result, in `structuredContent`:

```json
{
  "persona": {
    "ageMax": 45,
    "ageMin": 28,
    "body": "## Profile\n\nRunners of 40 to 80 kilometres a week, ten years in, with one pair in rotation and one on the shelf.\n\n## Motivations\n\nThey want the same shoe again, and proof that it is the same. A resole keeps them running on a pair they trust.\n\n## Frictions\n\nThey fear the new model is worse than the one they know. A change of sole or of last reads to them as a risk, not as progress.\n\n## Language\n\nThey say \"my daily trainer\" and \"I got 900 out of the last pair\". They ask about the drop and the stack, never about the technology.",
    "brandId": "brd_6a9c33",
    "createdAt": 1790000000000,
    "createdBy": "usr_4d8b12",
    "description": "Runners who already own a pair, and who buy the next one without looking at another brand.",
    "id": "psn_8c4a20",
    "name": "Loyalists",
    "revision": 2,
    "slug": "loyalists",
    "updatedAt": 1790086400000
  }
}
```
