---
title: "Agent Creation"
---

> Documentation Index
> Fetch the complete documentation index at: https://truememory-docs.mvstg.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent Creation

A user's AI agent is a **persona** stored in TIE, shared across all apps on the platform. This page covers how to correctly create and manage that agent so your app never creates duplicates or forces users to redo setup they already completed in another app.

## AI Coding Prompt

Drop this into Claude, Codex, or any AI coding assistant to implement correct agent creation for your app.

<div class="not-content" style="display: flex; justify-content: flex-end; margin-bottom: 0.5rem;">

</div>

```
Implement TIE agent creation following these rules:

TIE is the cross-app source of truth for every user's AI agent. Each user has exactly
one non-preset persona on TIE, shared across all apps (BlinkLife, Vibrantly, etc).

BASE URL: https://your-tie-host
AUTH: All persona and voice endpoints use a Bearer token issued by TIE Auth for the
      end user. Do NOT use a service key here — these are user-scoped endpoints.

---

STEP 1 — CHECK FOR EXISTING AGENT

  GET /personas
  Authorization: Bearer $USER_TOKEN

  Response: array of persona objects. Each object has:
    id: string (UUID)
    name: string
    system_prompt: string
    archetype: string | null
    description: string | null
    is_preset: boolean        ← presets are platform defaults; false = user's own agent
    is_active: boolean        ← true if currently active for this user
    created_at: ISO datetime
    updated_at: ISO datetime

  Filter for is_preset: false. If one exists → GO TO "SKIP SETUP" below.
  If none exists → GO TO STEP 2.

---

SKIP SETUP (persona already exists):
  - Do NOT create another persona. Each user has exactly one non-preset persona.
  - Do NOT prompt the user to choose a name, archetype, or voice.
  - Voice is already stored on TIE (or falls back to gemini/Kore if never set).
  - Mark this app's onboarding as complete in your own DB.
  - Route the user directly into the app.

---

STEP 2 — CREATE THE PERSONA

  POST /personas
  Authorization: Bearer $USER_TOKEN
  Content-Type: application/json

  {
    "name": "Aria",
    "system_prompt": "You are Aria, a SAGE companion...",
    "archetype": "SAGE",
    "description": null          // optional
  }

  Field rules:
    name: required, 1–255 chars
    system_prompt: required, min 1 char
    archetype: optional, max 100 chars. Recommended values: SAGE, FRIEND, COACH, REBEL, NURTURER
    description: optional

  On success: 201 with the created persona object (same shape as GET /personas items).
  Save the returned id — you need it for steps 3 and 4.

  Errors:
    422 VALIDATION_ERROR — invalid field values
    503 PERSONA_SYSTEM_UNAVAILABLE — TIE persona store is down; surface an error to the user

---

STEP 3 — SET PERSONA AS ACTIVE

  PUT /personas/active/{persona_id}
  Authorization: Bearer $USER_TOKEN

  Response: { "status": "active", "persona_id": "..." }

  Errors:
    404 PERSONA_NOT_FOUND — persona_id doesn't exist or isn't owned by this user

---

STEP 4 — SAVE VOICE PREFERENCE

  PUT /v1/voice/preferences/{persona_id}
  Authorization: Bearer $USER_TOKEN
  Content-Type: application/json

  {
    "provider": "gemini",
    "voice": "Kore",
    "language": "en"
  }

  Field rules:
    provider: string, default "gemini"
    voice: required, one of: Kore, Puck, Charon, Aoede, Fenrir, Leda, Orus, Zephyr
    language: required, BCP-47 code (e.g. "en")

  Response: { "provider": "gemini", "voice": "Kore", "language": "en" }

  If you skip this call, the persona falls back to gemini/Kore.

  Errors:
    404 PERSONA_NOT_FOUND — persona doesn't exist or not owned by user
    503 SERVICE_UNAVAILABLE — voice store is down

---

VOICE PREVIEW (during voice selection UI):

  POST /v1/audio/speech
  Authorization: Bearer $USER_TOKEN
  Content-Type: application/json

  {
    "model": "google/gemini-2.5-flash-tts",
    "input": "Hi, I'm Aria. Nice to meet you.",
    "voice": "Kore"
  }

  Returns PCM/WAV audio bytes. Play directly in browser or mobile.

---

GET SAVED VOICE (to display current selection):

  GET /v1/voice/preferences/{persona_id}
  Authorization: Bearer $USER_TOKEN

  Returns: { "provider": "gemini", "voice": "Kore", "language": "en" }
  Falls back to gemini/Kore/en defaults if never saved.

---

COMPLETE FLOW SUMMARY:

  1. GET /personas → find is_preset: false
  2a. Found   → skip setup, mark app onboarding done, enter app
  2b. Missing → POST /personas (save returned id)
               → PUT /personas/active/{id}
               → PUT /v1/voice/preferences/{id}
               → mark app onboarding done, enter app
```

---

## Core Rules

1. **One agent per user** — each user has exactly one non-preset persona on TIE. Never create a second one.
2. **Always check first** — call `GET /personas` before creating. If a non-preset persona exists, skip setup entirely and mark this app's onboarding complete.
3. **TIE is source of truth** — the agent and its voice preference live on TIE and are shared across every app.
4. **`archetype` is canonical** — always set it on create so any app can read the personality type.
5. **Voice is scoped to the persona** — stored per-persona on TIE via `/v1/voice/preferences/{persona_id}`. Collect it during setup; inherit it when skipping.

---

## Flow

```
1. GET /personas → find existing non-preset persona
2a. Found     → skip setup entirely, mark onboarding complete (voice already on TIE)
2b. Not found → run setup:
                  POST /personas to create
                  PUT  /personas/active/{id}
                  PUT  /v1/voice/preferences/{id}  (selected Gemini voice for that persona)
```

### Step 1 — Check for existing agent

```bash
GET https://your-tie-host/personas
Authorization: Bearer $USER_TOKEN
```

Filter the response for `is_preset: false`. If one exists:

- The agent is already set up.
- The voice preference is also already set (or falls back to `gemini/Kore` if never saved).
- **Skip setup entirely** — do not prompt for name, archetype, or voice. Advance the user's onboarding state past this step.

### Step 2 — No agent: create one

```bash
POST https://your-tie-host/personas
Authorization: Bearer $USER_TOKEN
Content-Type: application/json

{
  "name": "Aria",
  "system_prompt": "You are Aria, a SAGE companion...",
  "archetype": "SAGE"
}
```

Set it as active immediately after:

```bash
PUT https://your-tie-host/personas/active/{persona_id}
Authorization: Bearer $USER_TOKEN
```

### Step 3 — Save the chosen voice

```bash
PUT https://your-tie-host/v1/voice/preferences/{persona_id}
Authorization: Bearer $USER_TOKEN
Content-Type: application/json

{
  "provider": "gemini",
  "voice": "Kore",
  "language": "en"
}
```

Use the `persona_id` returned from `POST /personas` in Step 2. Accepted Gemini voice names: `Kore`, `Puck`, `Charon`, `Aoede`, `Fenrir`, `Leda`, `Orus`, `Zephyr`. If you skip this call, the persona falls back to the default (`gemini/Kore`).

For voice preview during selection, call `POST /v1/audio/speech` with `{ model: "google/gemini-2.5-flash-tts", input, voice }` and play the returned PCM/WAV bytes. See [Audio — Gemini TTS](/ai-gateway/audio/#gemini-tts-same-endpoint-different-model).

Source: https://truememory-docs.mvstg.com/platform/agent-creation/index.mdx
