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

# Persona

> Persona versions, drafts, presets, and the enhance routes that suggest persona changes without applying them

The persona routes manage an [agent](/concepts/agents)'s [persona](/concepts/persona) as numbered versions: create a version, make one current, generate a draft from a structured configuration, apply a preset, and ask for suggested improvements. Version routes are what `lua push agent` and `lua persona` call; drafts, presets, and the enhance routes have no CLI equivalent.

*Verified against lua-cli 3.33.0.*

## Base URL and authentication

Routes under `:agentId` check an `agents` scope on that agent: `agents:read` reads versions, `agents:write` creates, activates, drafts, publishes, enhances, and applies presets, and `agents:manage` discards a draft. The preset catalog needs only an authenticated key. The host, the bearer header, and the error envelope are on the [REST API overview](/reference/rest/overview).

## Persona version object

A persona is either a string or a channel-aware object `{ base?, voice?, text? }`; both forms are accepted wherever a persona is sent and returned as stored. Creating a version serves it from the agent's next message, and making an earlier version current switches the served persona at once, on any agent. An [agent version](/concepts/releases-and-versions) records which persona version was current, but promoting one does not change the served persona.

<ResponseField name="version" type="number">Version number.</ResponseField>
<ResponseField name="createdDate" type="number">Unix time in milliseconds.</ResponseField>
<ResponseField name="createdBy" type="string">User ID of the creator.</ResponseField>
<ResponseField name="isCurrent" type="boolean">Whether this version is the active persona.</ResponseField>
<ResponseField name="persona" type="string | object">The persona text or channel-aware object.</ResponseField>

## Endpoints

### GET /developer/agents/:agentId/persona/versions

Lists the agent's persona versions. Scope `agents:read`. Equivalent: `lua persona production versions`.

<ParamField query="status" type="string" default="all">`draft`, `published`, or `all`.</ParamField>

**Response**

`200` with `{ status, message, versions }`, each entry a [persona version object](#persona-version-object).

### GET /developer/agents/:agentId/persona/version/:version

Returns one version with the configuration it was built from. Scope `agents:read`.

**Response**

`200` with `{ status, message, version }`, where `version` carries `id`, `agentId`, `version`, `persona`, `config` (the structured configuration used to build it, when any), `createdBy`, and `createdAt`, plus the storage fields `_id` and `__v`.

### POST /developer/agents/:agentId/persona/version

Creates a new persona version from text you supply. Scope `agents:write`. Equivalent: `lua push agent`, which creates a version from `LuaAgent.persona`.

<ParamField body="persona" type="string | object" required>The persona text, or `{ base?, voice?, text? }`.</ParamField>

**Response**

`201` with `{ status, message, version }`, where `version` is the new version number.

### POST /developer/agents/:agentId/persona/version/:version

Makes a version the current persona. Scope `agents:write`. Equivalent: `lua persona production deploy --persona-version <n>` or `lua deploy persona`. The agent serves that version from its next message, and a later agent-version promote does not change it, as described under [Persona version object](#persona-version-object).

**Response**

`201` with `{ status, message, version }`.

### POST /developer/agents/:agentId/persona

Builds a persona from business details and stores it as a new version. Scope `agents:write`. The model writes the text.

<ParamField body="businessType" type="string">What the business does.</ParamField>
<ParamField body="businessWebsite" type="string">Website to draw details from.</ParamField>
<ParamField body="agentName" type="string">Name the agent should use.</ParamField>
<ParamField body="brandPersonality" type="string" deprecated>Use the draft routes' `personalityAndVoice` instead.</ParamField>
<ParamField body="brandTraits" type="string" deprecated>Use the draft routes' `personalityAndVoice` instead.</ParamField>

**Response**

`201` with `{ status, message, persona, version }`.

### POST /developer/agents/:agentId/persona/draft

Generates a draft from a structured configuration. Scope `agents:write`. A draft is a generated persona version held for testing until you publish or discard it; only one exists at a time, and creating another answers the existing one with `status: "draft_exists"` instead of replacing it. Each `has…` flag includes or omits its section; each list supplies that section's statements.

<ParamField body="agentName" type="string">Name the agent should use.</ParamField>
<ParamField body="businessWebsite" type="string">Website to draw details from.</ParamField>
<ParamField body="presetId" type="string">Preset to base the configuration on.</ParamField>
<ParamField body="voiceChips" type="object[]">Each `{ title, isEnabled }`: tone choices.</ParamField>
<ParamField body="roleAndPurpose" type="string[]">Role statements. Included when `hasRoleAndPurpose` is true.</ParamField>
<ParamField body="contextAndAudience" type="string[]">Audience statements. Included when `hasContextAndAudience` is true.</ParamField>
<ParamField body="personalityAndVoice" type="string[]">Personality traits. Included when `hasPersonalityAndVoice` is true.</ParamField>
<ParamField body="rulesAndBoundaries" type="string[]">Rules. Included when `hasRulesAndBoundaries` is true.</ParamField>
<ParamField body="businessType" type="string">What the business does.</ParamField>
<ParamField body="aboutProductsOrServices" type="string[]">Product statements. Included when `hasBusinessInfo` is true.</ParamField>
<ParamField body="hasRoleAndPurpose, hasContextAndAudience, hasPersonalityAndVoice, hasRulesAndBoundaries, hasBusinessInfo" type="boolean">Section switches.</ParamField>
<ParamField body="persona" type="string">Existing persona text to extract a configuration from, instead of the structured fields.</ParamField>
<ParamField body="brandPersonality, brandTraits" type="string" deprecated>Use `personalityAndVoice`.</ParamField>

**Response**

`201` with `{ status: "draft", message, version, versionStatus: "draft", persona, config }`, or `status: "draft_exists"` and the existing draft's fields when one already exists.

### PUT /developer/agents/:agentId/persona/draft

Regenerates the existing draft from a new configuration, with the same body and response as create. Scope `agents:write`.

### POST /developer/agents/:agentId/persona/publish

Publishes the draft, making it the current persona. Scope `agents:write`. A draft whose text is empty is built from its configuration first.

<ParamField body="version" type="number" required>The draft's version number.</ParamField>

**Response**

`201` with `{ status: "success", message, version, persona, versionStatus: "published" }`.

### DELETE /developer/agents/:agentId/persona/draft

Discards the draft without publishing. Scope `agents:manage`.

**Response**

`200` with `{ status, message }`.

### GET /developer/agents/persona/presets

Lists presets. Any authenticated key. A preset is a named, ready-made persona configuration, for example `customer-support-expert`, that you can start a draft from or apply to an agent's configuration without generating new persona text.

**Response**

`200` with `{ status, presets: [{ id, title, description }] }`.

### GET /developer/agents/persona/presets/:presetId

Returns one preset. Any authenticated key.

**Response**

`200` with `{ status, preset }`, where `preset` is the configuration object.

### POST /developer/agents/:agentId/persona/preset/apply

Copies a preset into the agent's persona configuration. Scope `agents:write`. Only the configuration changes; no persona version is generated.

<ParamField body="presetId" type="string" required>Preset to apply.</ParamField>

**Response**

`201` with `{ status, message, config }`, where `config` is the applied configuration.

### POST /developer/agents/:agentId/enhance/website

Reads a website and suggests persona text and configuration from it. Scope `agents:write`. The three enhance routes are non-destructive: each runs the model, can take minutes, and returns a suggestion for you to review without changing the agent. When `currentPersona` and `currentConfig` are omitted, the agent's current values are used.

<ParamField body="websiteUrl" type="string" required>Site to read.</ParamField>
<ParamField body="currentPersona" type="string">Persona text to improve.</ParamField>
<ParamField body="currentConfig" type="object">Configuration to improve.</ParamField>

**Response**

`201` with `{ suggestedPersona, suggestedConfig }`.

### POST /developer/agents/:agentId/enhance/storytelling

Suggests a version with more narrative depth and personality. Scope `agents:write`.

<ParamField body="currentPersona" type="string">Persona text to improve.</ParamField>
<ParamField body="currentConfig" type="object">Configuration to improve.</ParamField>

**Response**

`201` with `{ suggestedPersona, suggestedConfig }`.

### POST /developer/agents/:agentId/enhance/instructions

Refines the persona from written instructions, from example replies that need improving, or both. Scope `agents:write`.

<ParamField body="instructions" type="string">For example `Make the agent more formal and professional`.</ParamField>
<ParamField body="examples" type="object[]">Each `{ agentReply, reason, expectedReply }`: a reply the agent gave, why it was wrong, and what it should have said.</ParamField>
<ParamField body="currentPersona" type="string">Persona text to improve.</ParamField>
<ParamField body="currentConfig" type="object">Configuration to improve.</ParamField>

**Response**

`201` with `{ suggestedPersona, suggestedConfig }`.

## Errors

| Status | Code or message                                | Meaning                                                                                  | Fix                                  |
| ------ | ---------------------------------------------- | ---------------------------------------------------------------------------------------- | ------------------------------------ |
| `400`  | A validation message                           | `persona` is neither a string nor `{ base?, voice?, text? }`, or `websiteUrl` is invalid | Fix the field                        |
| `403`  | `Insufficient permissions`                     | The key lacks the `agents` scope on this agent                                           | Grant the scope                      |
| `404`  | `SubAgent not found`                           | Unknown agent                                                                            | Check the agent ID with `lua agents` |
| `404`  | `Persona version <n> not found for agent <id>` | Unknown version number                                                                   | List versions first                  |
| `404`  | `Draft version <n> not found for agent <id>`   | Publish of a version that is not the draft                                               | Create a draft first                 |
| `404`  | `Preset with ID <id> not found`                | Unknown preset ID                                                                        | List presets                         |

## Example

Create a persona version from text; the agent serves it from its next message. The second call, `POST …/persona/version/:version`, is how you switch back to an earlier version, and on the version just created it changes nothing. To keep agent versions in step with the served persona, follow with `lua version create` and `lua version promote`.

<CodeGroup>
  ```bash CLI theme={null}
  lua push agent
  lua persona production deploy --persona-version latest --force
  ```

  ```ts TypeScript theme={null}
  interface PersonaVersionResult {
    status: string;
    message: string;
    version: number;
  }

  async function pushPersona(apiKey: string, agentId: string, persona: string): Promise<number> {
    const base = `https://api.heylua.ai/developer/agents/${agentId}/persona/version`;
    const headers = { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' };

    const created = await fetch(base, { method: 'POST', headers, body: JSON.stringify({ persona }) });
    if (!created.ok) {
      throw new Error(`Create failed: ${created.status} ${await created.text()}`);
    }
    const { version } = (await created.json()) as PersonaVersionResult;

    const activated = await fetch(`${base}/${version}`, { method: 'POST', headers });
    if (!activated.ok) {
      throw new Error(`Activate failed: ${activated.status} ${await activated.text()}`);
    }
    return version;
  }
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.heylua.ai/developer/agents/<<YOUR_AGENT_ID>>/persona/version" \
    -H "Authorization: Bearer <<YOUR_API_KEY>>" \
    -H "Content-Type: application/json" \
    -d '{ "persona": "You help customers of Acme with orders. Be concise." }'

  curl -X POST "https://api.heylua.ai/developer/agents/<<YOUR_AGENT_ID>>/persona/version/7" \
    -H "Authorization: Bearer <<YOUR_API_KEY>>"
  ```
</CodeGroup>

## See also

* [About the persona](/concepts/persona) — writing guidance and the channel-aware object form
* [`lua persona`](/reference/cli/persona) — view, list, and deploy persona versions
* [Versions](/reference/rest/versions) — agent versions, which pin the persona
* [Releasing](/ship/releasing) — push, version, promote
* [REST API overview](/reference/rest/overview) — authentication, scopes, errors
