# Lifecycle

This page covers the endpoints that control whether a persona is **running** and what state she's in: start, stop, restart, sleep, update, delete.

A persona's persisted status is one of three — `active`, `hibernate`, `sick` (defined in [Vocabulary](../vocabulary.md)). Whether she's running is separate from her status: the `running` flag reflects the live in-memory agent registry. `start`/`stop`/`restart` change *running* directly; `update` changes *status* and lets the manager reconcile running to match.

All routes take the persona's `id` as a path param.

---

## Start

Bring a persona up — construct her agent and begin her cognitive cycle. Works whether she's stopped or already running; reads her config from disk.

**`POST /api/persona/{persona_id}/start`**

| Path param | Type | Description |
| --- | --- | --- |
| `persona_id` | string | Her UUID. |

No request body.

### Response

`200`:

```json
{ "status": "started" }
```

If she was already running, no-op:

```json
{ "status": "already running" }
```

### Errors

| Status | Meaning |
| --- | --- |
| `404` | No persona with that id. |
| `400` | Found on disk but failed to start (e.g. her thinking model's engine is unreachable). `detail` carries the reason. |

### Example

```bash
curl -s -X POST http://localhost:5000/api/persona/6c17c83c-3158-450d-8e43-0e7efea717c1/start
```

---

## Stop

Tear down a running persona's agent — no cycles, no cost. Her files are untouched; her status on disk is unchanged. This stops the *process side*, not her status.

**`POST /api/persona/{persona_id}/stop`**

| Path param | Type | Description |
| --- | --- | --- |
| `persona_id` | string | Her UUID. |

No request body.

### Response

`200`:

```json
{ "status": "stopped" }
```

### Errors

| Status | Meaning |
| --- | --- |
| `404` | She isn't running (`"Persona is not running."`). |

### Example

```bash
curl -s -X POST http://localhost:5000/api/persona/6c17c83c-3158-450d-8e43-0e7efea717c1/stop
```

---

## Restart

Re-read the persona from disk and rebuild her running agent. This is how config changes (a swapped organ, an added channel) take effect without a full daemon restart. If she wasn't running, it starts her instead.

**`POST /api/persona/{persona_id}/restart`**

| Path param | Type | Description |
| --- | --- | --- |
| `persona_id` | string | Her UUID. |

No request body.

### Response

`200`:

```json
{ "status": "restarted" }
```

### Errors

| Status | Meaning |
| --- | --- |
| `404` | She wasn't running and no persona with that id exists on disk. |
| `400` | She wasn't running and failed to start from disk. `detail` carries the reason. |

### Example

```bash
curl -s -X POST http://localhost:5000/api/persona/6c17c83c-3158-450d-8e43-0e7efea717c1/restart
```

---

## Sleep

Send a running persona into her nightly ritual — consolidate the day, write her diary, wake fresh. A resting state, not a stopped one; she stays running. **Requires a live agent** (see [API overview](index.md)).

**`POST /api/persona/{persona_id}/sleep`**

| Path param | Type | Description |
| --- | --- | --- |
| `persona_id` | string | Her UUID. |

No request body.

### Response

`200` with a `null` body. The sleep ritual returns no data — success is the `200` itself. (Internally the outcome's `data` is `None`, and the route returns it as-is.)

```json
null
```

### Errors

| Status | Meaning |
| --- | --- |
| `409` | She isn't running (`"Persona is not active."`). |
| `400` | The sleep ritual failed (`"Sleep failed unexpectedly."`). |

### Example

```bash
curl -s -X POST http://localhost:5000/api/persona/6c17c83c-3158-450d-8e43-0e7efea717c1/sleep
```

---

## Update

Change a persona's **status** and/or her **organs** in one call, persist to disk, then reconcile her running agent to match. This is the single route for "set her status" and "swap a model."

**`POST /api/persona/{persona_id}/update`**

| Path param | Type | Description |
| --- | --- | --- |
| `persona_id` | string | Her UUID. |

### Request body

A JSON object. Every field is optional — send only what you're changing.

| Field | Type | Description |
| --- | --- | --- |
| `status` | string | New status. Accepts only `active`, `sick`, `hibernate`. (Sleeping is the separate [sleep](#sleep) action — not a status set here.) |
| `thinking` | object | Replace the Mind organ. See **organ object** below. |
| `imagination` | object | Replace the Imagination organ. |
| `mouth` | object | Replace the Mouth organ. |
| `eye` | object | Replace the Eye organ. |
| `ear` | object | Replace the Ear organ. |
| `teacher` | object | Replace the Teacher organ. |
| `researcher` | object | Replace the Researcher organ. |
| `clear_imagination` | boolean | `true` removes the Imagination organ. |
| `clear_mouth` | boolean | `true` removes the Mouth organ. |
| `clear_eye` | boolean | `true` removes the Eye organ. |
| `clear_ear` | boolean | `true` removes the Ear organ. |
| `clear_teacher` | boolean | `true` removes the Teacher organ. |
| `clear_researcher` | boolean | `true` removes the Researcher organ. |

Passing `null` for an organ is the same as omitting it ("don't touch"). To **remove** an organ you must set its `clear_*` flag — that's why the flags exist separately. Each `clear_*` flag, when `true`, wins over any organ object sent for the same slot. There is no `clear_thinking`: the Mind organ is required and can only be replaced, never removed.

**Organ object** (for each organ field). Each is validated by preparing the model before it's saved:

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `model` | string | yes | Model name (e.g. `gpt-4o`, `qwen2.5:14b`). |
| `provider` | string | no | `anthropic`, `openai`, `xai`, `gemini`. Omit (or `local`/empty) for an Ollama model. |
| `url` | string | no | Override the provider's base URL. Defaults to the provider's configured URL. |
| `api_key` | string | no | API key for a cloud provider. |

### Transition semantics

After the new config is saved, the manager reconciles the running agent to the **resulting status** (`update_persona`):

| Resulting status | Agent already running? | Action taken |
| --- | --- | --- |
| `active` | yes | **Restart** — pick up any new organs. |
| `active` | no | **Start** — bring her up. |
| `hibernate` or `sick` | yes | **Remove** — tear the agent down. |
| `hibernate` or `sick` | no | Nothing. |
| (status unchanged, only organs changed) | yes | **Restart** — pick up the new organs. |
| (status unchanged, only organs changed) | no | Nothing. |

So: setting her to `active` brings her up (or restarts her if up); setting her to `hibernate`/`sick` stops her; changing only an organ while she's `active` and running restarts her so the swap takes effect.

### Response

`200`:

```json
{ "status": "active", "running": true }
```

`status` is her resulting status; `running` reflects the agent registry after reconciliation.

### Errors

| Status | Meaning |
| --- | --- |
| `404` | No persona with that id. |
| `400` | Invalid `status`, or an organ model couldn't be prepared (unreachable engine, bad key…). `detail` carries the reason. |
| `500` | Saved, but the lifecycle change (start/stop/restart) failed afterward. `detail` carries the reason. |

### Examples

Hibernate her (stops her running agent):

```bash
curl -s -X POST http://localhost:5000/api/persona/6c17c83c-3158-450d-8e43-0e7efea717c1/update \
  -H 'Content-Type: application/json' \
  -d '{"status": "hibernate"}'
```

Wake her back up:

```bash
curl -s -X POST http://localhost:5000/api/persona/6c17c83c-3158-450d-8e43-0e7efea717c1/update \
  -H 'Content-Type: application/json' \
  -d '{"status": "active"}'
```

Swap her Eye organ to a different model (restarts her if she's active and running):

```bash
curl -s -X POST http://localhost:5000/api/persona/6c17c83c-3158-450d-8e43-0e7efea717c1/update \
  -H 'Content-Type: application/json' \
  -d '{"eye": {"model": "gpt-4o", "provider": "openai", "api_key": "sk-XXXX"}}'
```

Remove her Mouth organ entirely:

```bash
curl -s -X POST http://localhost:5000/api/persona/6c17c83c-3158-450d-8e43-0e7efea717c1/update \
  -H 'Content-Type: application/json' \
  -d '{"clear_mouth": true}'
```

---

## Delete

Permanently remove a persona and all her data. If she's running she's stopped first; her home directory is deleted, and a local thinking model is unregistered from Ollama. **Irreversible** — only her [diary](../files/workspace-diary-logs.md) (if one exists) could restore her, and only with the recovery phrase.

**`POST /api/persona/{persona_id}/delete`**

| Path param | Type | Description |
| --- | --- | --- |
| `persona_id` | string | Her UUID. |

No request body.

### Response

`200` — the delete outcome's data (no meaningful body; success is the `200` itself).

### Errors

| Status | Meaning |
| --- | --- |
| `404` | No persona with that id. |
| `400` | Deletion failed (e.g. couldn't remove her files, or couldn't reach Ollama to drop a local model). `detail` carries the reason. |

### Example

```bash
curl -s -X POST http://localhost:5000/api/persona/6c17c83c-3158-450d-8e43-0e7efea717c1/delete
```

---

## Related

- [Vocabulary](../vocabulary.md) — the three `status` values and what running means.
- [Personas](personas.md) — read current status and organs (`GET /api/personas`).
- [Create and migrate](create-migrate.md) — bring a persona into being.
- [The panel — Status](../panel/status.md) — the screen these routes sit behind.
