# Personas A **Persona** is the unit of access control and AI identity: system prompt + model + provider config + KB bindings + grant scoping. Users interact with Personas, not raw provider configs. Admins curate which Personas are available; team admins create team-scoped Personas. **Model inheritance:** A Persona inherits all properties of its underlying model. This includes context window size, max output tokens, supported capabilities (thinking, tools, vision, streaming), input/output pricing, and provider status. When the frontend displays a Persona, it resolves the underlying model's capabilities and shows the same pills/badges (e.g. thinking, tools, 200k context) that the raw model would show. The Persona adds identity (name, avatar, system prompt, KB bindings) on top of the model's capabilities — it never masks or reduces them. Three scopes, three route namespaces, one domain: | Scope | Routes | Who manages | |-------|--------|-------------| | Personal | `GET/POST/PUT/DELETE /personas` | The user | | Team | `GET/POST/PUT/DELETE /teams/:teamId/personas` | Team admin | | Global (admin) | `GET/POST/PUT/DELETE /admin/personas` | Platform admin | All three return the same Persona object shape: ```json { "id": "uuid", "name": "Code Reviewer", "description": "Reviews code for bugs and style", "system_prompt": "You are a senior code reviewer...", "model": "claude-sonnet-4-20250514", "provider_config_id": "uuid|null", "scope": "personal|team|global", "owner_id": "uuid|null", "is_default": false, "is_active": true, "avatar_url": "/api/v1/personas/uuid/avatar?v=123", "inherited": { "context_window": 200000, "max_output_tokens": 8192, "supports_vision": true, "supports_tools": true, "supports_thinking": true, "supports_streaming": true, "input_price_per_m": 3.00, "output_price_per_m": 15.00, "provider_status": "healthy|degraded|down|null" }, "created_at": "...", "updated_at": "..." } ``` The `inherited` block is populated by the backend from the resolved model capabilities at response time — it is not stored on the persona. If the underlying model's capabilities change (e.g. provider upgrades context window), the persona inherits the new values automatically. The frontend uses `inherited` to render capability pills and context size badges identical to the raw model. ### Personal Personas Gated by `allow_user_personas` policy. ``` GET /personas → { "personas": [...] } POST /personas ← { "name", "description", "system_prompt", "model", ... } PUT /personas/:id ← partial update DELETE /personas/:id ``` ### Team Personas ``` GET /teams/:teamId/personas → { "personas": [...] } POST /teams/:teamId/personas ← same shape PUT /teams/:teamId/personas/:id DELETE /teams/:teamId/personas/:id ``` ### Admin (Global) Personas ``` GET /admin/personas → { "personas": [...] } POST /admin/personas ← same shape PUT /admin/personas/:id DELETE /admin/personas/:id ``` ### Persona KB Bindings A Persona can have Knowledge Bases bound to it. When a channel uses that Persona, the bound KBs are automatically scoped into `kb_search` tool calls. Users never see or manage the underlying KBs directly — they talk to the Persona. **Get bindings:** ``` GET /personas/:id/knowledge-bases → { "data": [KB objects] } GET /teams/:teamId/personas/:id/knowledge-bases → { "data": [...] } GET /admin/personas/:id/knowledge-bases → { "data": [...] } ``` **Set bindings** (replace all): ``` PUT /personas/:id/knowledge-bases PUT /teams/:teamId/personas/:id/knowledge-bases PUT /admin/personas/:id/knowledge-bases ``` ```json { "kb_ids": ["kb-uuid-1", "kb-uuid-2"], "auto_search": { "kb-uuid-1": true, "kb-uuid-2": false } } ``` `auto_search`: when `true`, the KB is always searched (prepended to context). When `false`, it's available via the `kb_search` tool but not auto-injected. ### Persona Avatars ``` POST /personas/:id/avatar ← multipart/form-data (field: "avatar") DELETE /personas/:id/avatar POST /admin/personas/:id/avatar DELETE /admin/personas/:id/avatar ``` ### Persona Tool Grants Control which tools a persona can use during completions. The completion handler applies tool grants as a second-pass allowlist. ``` GET /personas/:id/tool-grants → { "grants": ["web_search", "kb_search", ...] } PUT /personas/:id/tool-grants ← { "tool_ids": ["web_search", "calculator"] } ``` Admin equivalents: ``` GET /admin/personas/:id/tool-grants PUT /admin/personas/:id/tool-grants ``` When a workflow version is published, persona tool grants at that moment are frozen into the version snapshot. ### Persona Groups Saved roster templates. A persona group is a named set of personas that can be stamped onto new conversations. ``` GET /persona-groups → { "data": [...] } POST /persona-groups ← { "name", "description", "scope", "team_id" } GET /persona-groups/:id → group with members PUT /persona-groups/:id ← partial update DELETE /persona-groups/:id ``` **Members:** ``` POST /persona-groups/:id/members ← { "persona_id", "is_leader": false, "sort_order": 0 } DELETE /persona-groups/:id/members/:memberId ``` `is_leader`: the leader persona responds when no @mention is present in a group channel. Only one leader per group. **Persona Group Object:** ```json { "id": "uuid", "name": "Support Team", "description": "...", "owner_id": "uuid", "scope": "personal|team|global", "team_id": "uuid|null", "members": [ { "id": "uuid", "persona_id": "uuid", "is_leader": true, "sort_order": 0 } ], "created_at": "...", "updated_at": "..." } ``` ### Resource Grants See [teams.md](teams.md) §15.3 for the grant system. Personas use grants to control who can see and use them beyond their base scope.