---
title: persona_update
description: Edit a persona's sections, age range or handle, guarded against overwriting someone else's concurrent change.
---

Updates a **Persona**. Only the fields you pass are changed, and the write is guarded by `base_revision` — read it with [`persona_get`](/mcp/tools/persona-get) first.

## Input

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `brand_name` | `string` | yes | The slug of the brand that owns the persona. |
| `persona_name` | `string` | yes | The current persona slug. |
| `base_revision` | `integer` | yes | The `revision` you last read. Guards against overwriting a concurrent edit. |
| `name` | `string` | no | New display name. |
| `description` | `string` | no | New one-line summary. |
| `profile` / `motivations` / `frictions` / `language` | `string \| null` | no | New section text; `null` clears it. |
| `age_min` / `age_max` | `integer \| null` | no | New age bound; `null` clears it. |
| `slug` | `string` | no | New handle (a deliberate rename). |

## Omit versus null

The distinction is load-bearing for every nullable field:

- **Omit** a field to leave it exactly as it is.
- Pass **`null`** to clear it.

So editing only `frictions` cannot silently erase `profile`, and clearing `age_max` is how a persona becomes "35 and older".

## Example

```ts
persona_update({
  brand_name: 'acme-running',
  persona_name: 'marathon-maya',
  base_revision: 3,
  language: '“My knees are shot by mile 18” — never “joint fatigue”.',
  age_max: null, // now 30 and older
});
```

:::warning[The age range is checked after your change is applied]

Passing one bound can conflict with the stored other: sending `age_min: 50` against a stored `age_max: 40` is rejected as inverted even though the input alone looks fine. Send both when moving the range across the other bound.

:::

:::info[A stale base_revision is rejected, not merged]

If the persona changed since you read it, the update fails and tells you the current revision. Re-fetch with [`persona_get`](/mcp/tools/persona-get) and decide what to keep — the write is never applied on top of a row you have not seen.

:::

Renaming via `slug` changes the handle: anything referencing the old one, including authored Skills, needs updating.

Requires the `brand:write` scope.

## 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 null for a section or age bound to clear it. 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. |
| `brand_name` | string | yes | The slug of the brand that owns the persona. |
| `description` | string | no | New one-line summary. |
| `frictions` | string or null | no | New objections and barriers. Pass null to clear the section. |
| `language` | string or null | no | New voice-of-customer wording — the audience's own words, not a locale. Pass null to clear the section. |
| `motivations` | string or null | no | New jobs, triggers and outcomes. Pass null to clear the section. |
| `name` | string | no | New display name. |
| `persona_name` | string | yes | The current persona slug identifying which to update. |
| `profile` | string or null | no | New description of who they are. Pass null to clear the section. |
| `slug` | string | no | Optional new slug handle (a deliberate rename); normalized to kebab-case. Callers of the old handle must be updated. |

### 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`
- `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.
