Studio Guide
This guide explains how each major element of Emocentric Studio works and what happens underneath when a creator uses it.
The studio is organized around one loop: design an agent, test it against the live engine, save versions, publish one version, and monitor real relationships after deployment.
Mental Model
The studio has five durable building blocks.
- Apps group blueprints, characters, API keys, deployed users, and usage. An app is the security and ownership boundary.
- Blueprints are reusable agent templates. They hold persona, behavior signals, seed knowledge, actions, corpus, field schema, and optional model defaults.
- Characters are runnable agents. A character can be created directly or instantiated from a blueprint. Characters carry version history and deployments.
- Versions are immutable revisions. Manual editor changes, AI tuner changes, raw JSON imports, and runtime model changes append or update a version.
- Relationships store per-user emotions, facts, short-term memory, simulations, and transcript. Studio tests, compare columns, and deployed end users each use isolated relationship scopes.
The most important distinction is draft versus live. Editing changes the current draft head. Publishing chooses one version to expose through live surfaces. A newer draft does not affect public users until it is deployed.
App Dashboard
The app dashboard is the first working area after sign-in. It is reached from /apps/{appId}.
Top Bar
The top bar keeps account-level navigation and recovery actions close at hand.
- Home link returns to the signed-in app list.
- Account menu shows the current creator account and sign-out controls.
- Deleted characters opens the soft-delete recovery modal for the current app.
App Header
The large app heading names the current app and summarizes the app workflow: blueprints become characters, characters go live.
The segmented control changes the visible collection.
- Blueprints shows reusable templates for the app.
- Characters shows runnable agents in the app.
- Corpus shows blueprint source material through a corpus-focused entry point.
Blueprint Cards
Each blueprint card opens the blueprint editor. Metrics summarize the blueprint's current head.
- Version is the current blueprint head version number.
- Character is how many characters have been created from the blueprint.
- Action is the number of configured actions.
- Corpus item is the count of source entries in the blueprint corpus.
The add card creates a new blueprint with a name, description, default persona, and the built-in send_message action.
Character Cards
Each character card opens the character workspace. The card shows provenance and live status.
- From blueprint appears when the character was instantiated from a blueprint version.
- Draft means no active deployment exists.
- vN live means a version is currently published.
- Integration, user, and message counts appear for deployed characters.
The delete button soft-deletes the character. Deleted characters can be restored from the top bar recovery modal.
Corpus Cards
The Corpus tab reuses blueprint cards but opens the corpus editor route. This is useful when the creator is mostly collecting source material before tuning persona or actions.
Blueprint Editor
Blueprint editor routes are reached from /apps/{appId}/blueprints/{blueprintId} and /apps/{appId}/corpra/{blueprintId}. Both routes use the same editor shell with different default tabs.
Left Rail
The icon rail switches editor sections without leaving the blueprint. Desktop shows icons; mobile uses a horizontal tab bar.
- Overview edits blueprint identity, description, and high-level metadata.
- Models edits response and planning model defaults for characters created from this blueprint.
- Profile edits persona name and system prompt.
- Behavior edits response behavior signals and conversation behavior baselines.
- Knowledge edits seed facts.
- Actions edits callable actions.
- Fields edits instantiation fields.
- Corpus edits source material.
- JSON edits the complete blueprint envelope.
Header
The header shows the blueprint name, mode, head version, and save state.
- Open corpus/Open blueprint jumps between the two focused editor modes.
- Create instantiates a character from the blueprint.
- Save writes a new immutable blueprint version when the draft differs from the saved head.
Status Panel
The right status panel is a compact control center.
- Details shows status, slug, app id, blueprint id, created date, and updated date.
- Version shows the current head and summary metrics.
- Actions repeats save, create character, companion editor, and back-to-app controls.
- Save error appears here when validation or server persistence fails.
Overview
Overview edits the blueprint envelope rather than the agent internals.
- Name is the creator-facing template name.
- Description explains when to use the template.
- Slug identifies API-driven blueprint upserts and external sync flows.
- Metrics summarize versions, characters, actions, fields, and corpus.
Models
Model routing controls Studio's planner heartbeat.
- Planning model writes
studio.planningModel; it is used by the engine loop for interpretation, appraisal, and action planning. - Blank fields fall back to
STUDIO_COACHING_MODELand then the server default. - Historical
studio.responseModelvalues remain round-trippable for old versions but are ignored. The external character sidecar owns all visible writing and media generation.
Profile
Profile edits blueprint.persona.
- Agent name is the persona name displayed in studio and used by the runtime.
- System prompt is the concise role and behavior instruction that anchors every turn.
Changes stay in the blueprint draft until saved.
Behavior
Behavior has two related editors.
- Response behavior edits the behavior signal palette. Signals become the emotion dimensions the engine tracks.
- Conversation behavior edits per-signal temperament. Baseline is the resting value, sensitivity is the gain applied to changes, and guidance describes how the agent should interpret the signal.
Changing the set of behavior signals matters at deployment time. If a published version changes the emotion palette, existing live relationships need a rebaseline before the new version can go live.
Knowledge
Knowledge writes seed facts to blueprint.seedFacts.
- Search filters visible facts in the editor.
- Kind filter narrows by agent, business, caller, or event-style knowledge.
- Source adds a new fact.
- Priority controls the fact importance from
0to1.
These seed facts become initial reliable context for characters created from the blueprint.
Actions
Actions are the tools an agent may choose when a conversation needs more than free text.
- send_message is the built-in voice action and stays available as the default reply path.
- Action name must be a slug-like identifier.
- Description tells the model what the action does and when to call it.
- Slot groups actions by purpose, such as
voiceorintent. - Parameters define a simple string schema, including required arguments.
- Advanced schema JSON is used when a parameter schema is too complex for the row editor.
Custom actions can be surfaced to API callers and action webhooks after deployment.
Fields
Fields define reusable inputs for future blueprint instantiation.
- Field id is the stable field identifier.
- Label is the creator-facing name.
- Type can be text, textarea, number, boolean, select, or json.
- Required marks whether instantiation must provide the value.
- Target path points to where the value should be applied.
- Default value and Help text make the instantiation form clearer.
- Field schema JSON lets advanced users edit the full schema array.
Corpus
Corpus stores source material and references attached to the blueprint.
- Title names the source.
- Kind groups the source, commonly as
reference,voice,example, or project-specific labels. - Content stores the actual material.
- Corpus JSON lets external tools paste or sync a complete corpus object.
Corpus is distinct from seed facts. Corpus is source material for authoring and provisioning; seed facts are runtime memory seeds.
Raw JSON
Raw JSON exposes the full blueprint envelope.
The envelope includes:
{
"name": "Blueprint name",
"description": "Creator-facing description",
"blueprint": {},
"studio": {},
"corpus": {},
"fieldSchema": []
}
Applying JSON updates the draft in memory. Saving writes a new blueprint version.
Character Workspace
The character workspace is reached from /apps/{appId}/characters/{characterId} and its surface routes such as /character, /emotions, /memory, /actions, /apps, /history, /monitor, and /deploy.
Workspace Header
The header shows the active character name and status badge.
- Draft means the current selected version is not live.
- Published means the selected version matches the deployed version.
- vN is the current version number.
- Clicking the brand returns to the app dashboard.
Agent Rail
The rail is the main workspace navigation.
- Home returns to the app dashboard.
- Character opens agent settings.
- Emotions opens behavior settings.
- Memory opens seed knowledge.
- Actions opens action configuration.
- Apps opens app and integration summary.
- History opens version history.
- Monitor opens deployed session monitoring.
- Deploy opens the publish surface.
In the current agent layout, the selected rail item controls the center pane. The assistant chat remains available in the inspector for most authoring surfaces.
Character Surface
Character is the settings surface for identity and runtime defaults.
- Model routing edits response and planning model overrides for this character.
- Agent profile edits persona name and system prompt.
- Wand buttons on editable sections set the AI tuner target and switch the assistant thread into a guided edit context.
Manual edits call the character version API and create or coalesce a saved version.
Emotions Surface
Emotions splits behavior into signal definitions and temperament.
- Response behavior is the set of tracked signals.
- Signal name is the internal emotion dimension.
- Description explains what the signal means to this agent.
- Baseline is the resting value from
0to1. - Sensitivity is optional gain from
0to2. - Conversation behavior provides quick baseline dials and detailed guidance per signal.
These settings affect how the runtime appraises turns, stores emotional state, and chooses tone.
Memory Surface
Memory edits seed facts for the character's current blueprint version.
- Search knowledge filters the list.
- Kind chips filter by fact kind.
- Source adds a new reference note.
- Reference note should be standalone, because the engine may retrieve it without surrounding UI context.
- Priority controls retrieval influence.
This is author-time knowledge. Live relationship memory is shown in Pulse and Monitor.
Actions Surface
Actions is the character-level action editor.
- Add or edit actions exactly like blueprint actions.
send_messagestays present as the default reply action.- Invalid names, missing descriptions, duplicates, or invalid schemas block saving.
- The Tune button asks the AI tuner to adjust action behavior.
When deployed, selected actions are returned inline through the REST API and can be delivered through configured action webhooks.
Apps Surface
Apps is a read-only summary of where the character sits.
- App scope shows the app id.
- Web surface shows whether a web deployment is live or draft.
- API access shows the character id when API access can be used.
- Action webhooks summarizes configured actions.
Use Deploy for actual publishing and API key management.
History Surface
History shows the version graph and version inspector.
- Version graph visualizes the character version DAG.
- Selected version changes what the workspace is editing or publishing.
- Deployed marker shows which version is live.
- Diff compares two versions.
- Compare starts a comparison simulation for the selected diff pair.
- Raw JSON edits the full current blueprint and runtime sidecar.
- Import replaces the blueprint from a
blueprint.jsonfile. - Export downloads the current blueprint JSON.
Checking out a version repoints the draft head but does not publish it.
Assistant And Simulations
The assistant panel is a persistent testing and editing companion.
New Menu
The New button opens three workspace modes.
- Simulation starts a fresh roleplay chat against the current version.
- Comparison creates a parallel compare thread.
- Tuner opens the shared AI editing thread.
History Popover
The history button lists prior simulations and comparisons.
- Select a thread to make it active.
- Branch duplicates a simulation.
- Delete soft-removes a simulation header.
Composer
The composer sends messages to the active simulation.
- Enter submits.
- Shift+Enter inserts a newline.
- Version dropdown selects which character version a roleplay simulation is bound to.
- Context dropdown changes the emulation source, such as normal chat or configured system/game contexts.
- Attach adds reference files. Text-like attachments are folded into message text, while supported images can be sent as inline payload parts.
- Send queues the turn through the server.
Studio roleplay messages are debounced into a small batch so quick multi-message input reaches the engine as one turn.
Roleplay Simulation
A roleplay simulation uses the creator's special studio relationship for the character.
On send:
- The UI appends the user message locally.
- The server ensures the studio relationship exists.
- The server loads the current character head and Studio runtime settings.
- The engine runs under a per-relationship Postgres advisory lock.
- User messages, agent replies, selected actions, trace data, and usage are persisted.
- The returned snapshot updates Pulse.
Studio traffic is excluded from deployed end-user monitoring, but it still uses persisted engine state.
Compare Simulation
Compare sends one prompt through multiple selected versions.
- Each column uses its own isolated relationship id.
- Columns never share emotion or memory state.
- Replies and snapshots are saved together for the turn.
- Pulse can inspect a selected compare column.
Use Compare when deciding whether one version is better before publishing.
Tuner
The Tuner turns natural language edit instructions into a new version.
- Section wand buttons set a target such as Agent profile, Conversation behavior, Knowledge base, or Actions.
- The target chip appears in the composer.
- Sending a tuning instruction calls the edit API.
- A successful edit appends a new version and posts a diff card.
- The version-change notice can open a diff or move the thread back to a previous version.
The Tuner is versioned like every other edit path. It does not silently overwrite live deployments.
Live Pulse
Live Pulse is the runtime inspector for the active simulation. It opens from the rail as History/Pulse or from the pulse button in the assistant header.
Feelings
Feelings shows the current emotional state for the active relationship.
- Values are sorted by strength.
- The dominant emotion is highlighted.
- In roleplay mode, values can be manually overridden.
- Overrides run through the state route and return a fresh snapshot.
Memory
Memory shows the live fact bank for the active relationship.
- Add Memory writes a relationship fact.
- Editing a memory replaces the old fact with the edited content.
- Deleting removes a fact by id.
- Importance can be adjusted from the list.
These edits affect the current simulation relationship only. They are not blueprint seed facts.
Events
Events appear when event-kind facts exist for the relationship. Studio context events and deployed context events can become event memories, depending on runtime appraisal and memory writes.
Last Decision
Last Decision shows the latest selected action and reason.
- show engine trace expands the trace.
- Trace includes interpretation, emotion deltas, facts added, and action choices for messages that carried trace data.
- Chat bubbles can deep-link to the trace for a specific message.
Deploy
Deploy publishes one selected version to one or more surfaces.
Deploy Graph
The center graph is the same version DAG used by History, but selection is publish-focused.
- Select the version to publish.
- The deployed version is marked.
- Publishing creates an immutable character release and moves the character's live pointer.
Surfaces Panel
The surfaces panel controls deployment channels.
- Character ID is the stable id used by public routes and API routes.
- Web link exposes
/c/{characterId}. - API exposes
/api/v1/emotive/{characterId}and/api/v1/emotive/{characterId}/events. - iMessage exposes a Photon/Spectrum messaging surface.
- WhatsApp exposes a Photon/Spectrum messaging surface.
Toggling a surface includes or excludes it from the next publish operation. Publishing disables live surfaces that are no longer selected.
API Keys
API keys are app-scoped and shown through the character deploy panel when the API surface is active.
- Add creates a named key.
- Plaintext is shown once.
- Rename changes the display name.
- Reset rotates the key and shows new plaintext once.
- Delete revokes the key.
The deployed REST API uses Bearer keys with scopes; keys never trust account or app ids from request bodies.
Messaging Links
iMessage and WhatsApp surface details show link helpers when a line reference is available.
- The QR encodes a message link that pre-fills a switch command for this character.
- The command pins the sender's thread to this character on shared lines.
- If no dialable line exists, the panel still shows the copyable switch command.
Rebaseline
If the selected version changes the emotion palette compared with the current live version, Deploy asks for rebaseline confirmation.
Rebaseline resets existing live relationships' emotional state to the new signal baselines. It leaves memory intact.
Monitor
Monitor is the read-only observability surface for deployed traffic. Studio test traffic is excluded.
Sessions Sidebar
The sidebar shows live deployment activity.
- Metrics summarize deployments, end users, messages, and turns.
- Refresh reloads overview and selected details.
- Search sessions searches end-user labels, external refs, relationship ids, session titles, and loaded messages.
- End-user rows expand to show their simulations.
Overview polling runs periodically while the page is visible.
Transcript Center
The center panel shows the selected deployed simulation transcript.
- It is read-only.
- If the transcript is long, the server returns the most recent messages.
- The header shows end-user label, active emotion, session title, message count, and recency.
Live State Inspector
The inspector shows the selected end user's live state.
- Feelings are read-only in monitor mode.
- Active user memories and event memories are grouped by local creation date with precise times,
- Each section supports relationship-scoped semantic search, in-place content and importance edits,
- Deleting an event removes it from character recall but does not delete its source transcript or
- Actions list the current live blueprint action menu.
- Last Decision and engine trace are shown when trace data exists.
importance/salience, and event surface/modality metadata.
and confirmed deletion for the selected person.
messages.
Monitor snapshots use the live release version when available, otherwise the head version for never-published characters.
Public And API Surfaces
Once deployed, a character can be reached through several paths.
Web Chat
The web surface serves a public chat page at:
/c/{characterId}
Public web chat uses the public chat route, not the creator's studio relationship.
REST Chat
The API surface accepts chat turns at:
POST /api/v1/emotive/{characterId}
Authorization: Bearer emo-...
Content-Type: application/json
{
"end_user": "player_42",
"text": "hi",
"clientTurnId": "4ef85f6e-b981-49b6-8eac-420a7f30f208"
}
Each stable end_user becomes an isolated relationship. With no identity block, turns, events, conversation hydration, and action-result polling all resolve the canonical external_app/api surface. An optional identity block may only use authority: "external_app" and provider api, game, or host; privileged Studio/platform identities are rejected. Callers must send the same block to all four endpoints, and omitted fields still default to external_app/api.
API-backed clients can hydrate or create the same canonical main conversation without a separate application database:
POST /api/v1/emotive/{characterId}/conversation
Authorization: Bearer emo-...
Content-Type: application/json
{ "end_user": "player_42", "ensure": true, "threadKey": "main" }
Omit ensure for a read-only existence/history check. The response includes pendingActionEventIds and pendingActionExpiresAt; the latter is the earliest authoritative ISO-8601 deadline and is null if and only if no ids remain. Poll them through POST /api/v1/emotive/{characterId}/action-results with the same end_user, simulationId, and event ids. Reusing a clientTurnId with identical text safely replays a committed turn without reserving another paid-turn slot. ensure: true is optional and creates no paid reservation; it is guarded by a separate per-deployment daily new-relationship cap. Direct REST turns and context events may create their canonical relationship atomically, and first reserve paid-turn quota in a short account-serialized transaction before identity creation or model work. Concurrent users therefore cannot overshoot the deployment/account turn caps. Read-only checks and existing conversations continue to work when new-relationship capacity is exhausted. The MVP conversation endpoint accepts only the canonical main thread.
App-scoped chat keys can also manage the same relationship's active user memories without learning Studio relationship or user ids. POST /api/v1/emotive/{characterId}/memories pages newest-first, POST /api/v1/emotive/{characterId}/memories/search performs semantic search, and PATCH or DELETE /api/v1/emotive/{characterId}/memories/{memoryId} updates or removes one memory. All four requests resolve the supplied end_user and identity without creating an unknown relationship; mutation requests include the expected current content so stale editors fail with a conflict.
Public turn errors preserve the human-readable error field and add a stable code for retry states:
503 action_execution_pendingmeans a previous turn is awaiting sidecar action results. Hydrate409 client_turn_in_progressmeans the identicalclientTurnIdrequest is running. Wait and409 client_turn_conflictmeans the id was reused for different input. Do not retry the mismatched409 client_turn_indeterminatemeans the prior outcome cannot be safely replayed. Hydrate first
the conversation and poll its pending ids instead of submitting a new turn.
hydrate before retrying that same request.
request under that id.
and do not automatically resubmit it.
Branch on code, never on mutable error prose. A code-less 409 or 503 has no implied retry semantics.
Owner-authenticated provisioning can verify an exact plaintext key with POST /api/apps/{appId}/api-keys/verify and { "apiKey": "emo-..." }. It returns only validity, the matched app id, and scopes; cross-app/account, altered, disabled, and revoked keys return { "valid": false }. The check is read-only. A failed downstream provisioning flow can revoke its newly minted key through DELETE /api/apps/{appId}/api-keys/{keyId}. Both responses are private and non-cacheable.
Context Events
The API surface accepts structured events at:
POST /api/v1/emotive/{characterId}/events
Authorization: Bearer emo-...
Content-Type: application/json
{
"end_user": "player_42",
"payload": {
"kind": "action",
"name": "opened_chest",
"description": "The player opened the crypt chest."
}
}
Events enter the same relationship memory and emotional-state system as chat turns.
Action Results
When a deployed turn selects an action, callers receive structured action intents plus pendingActionEventIds and pendingActionExpiresAt. Conversation hydration and action-result polling return the same pending envelope; terminal responses use an empty id list and null expiry. Action webhook executors can report outcomes through:
POST /api/v1/action-events/{eventId}/result
Authorization: Bearer emo-...
The signed agent.action.selected body always includes top-level createdAt and expiresAt values. For ordinary actions, Studio persists expiresAt once as createdAt + ACTION_EXECUTION_TIMEOUT_MS using the creation-time setting (clamped to 30 seconds–60 minutes). Changing the setting later affects only new events. A first callback is accepted only when Studio evaluates it strictly before this deadline; callbacks at or after it return 409, and Studio terminalizes the timed-out action without materializing late transcript output. Scheduled followups instead use the active 30-minute claim lease: the body expiresAt exactly equals the claim wrapper's leaseExpiresAt, and ordinary expiry scans do not shorten that lease. Claim token, action event, and an unexpired lease are all required through result write, outbound queueing, and no-output finalization.
Migration 0035 intentionally leaves older rows nullable because their original signed deadline was not stored. Keep ACTION_EXECUTION_TIMEOUT_MS frozen while those rows drain (no more than 60 minutes); the legacy computed fallback is isolated to nullable rows and is never used for newly-created work.
Studio tests persist action transcripts but suppress production action webhook delivery.
Versioning Rules
The studio is intentionally version-heavy.
- Manual persona, behavior, memory seed, action, model, and raw JSON changes save through version routes.
- AI tuner changes create a new version.
- Blueprint editor saves create immutable blueprint versions.
- Deploy publishes a chosen version rather than "whatever is currently open."
- Version checkout changes the working draft head but does not change live traffic.
- Diff and Compare are the main tools for understanding what changed before publishing.
This makes it possible to experiment aggressively without accidentally changing deployed behavior.
Runtime Guarantees
The server runtime provides several important guarantees.
- Tenant isolation: all database work runs under the signed-in account or app-key tenant.
- Relationship isolation: studio, compare, and deployed users use distinct relationship ids.
- Concurrency control: turns acquire a Postgres advisory lock for the relationship before mutating memory or emotional state.
- Atomic persistence: engine state, messages, selected actions, usage, and trace data commit together for a turn.
- Blueprint scope safety: imported or authored blueprint ids are overridden with the server-derived character id at runtime.
- Live pointer safety: public traffic resolves through the character's live release, not the editable draft head.
Common States
- No simulation selected: create a Simulation, Comparison, or Tuner thread from the assistant New menu.
- No Pulse data: send a simulation message first. Pulse needs a snapshot.
- No monitor sessions: deploy the character and run public or API traffic.
- Rebaseline required: the new version changed behavior signals. Confirm only when resetting live emotional state is acceptable.
- API key hidden: plaintext is only shown immediately after create or reset.
- Messaging QR missing: bind the deployment to a Photon line ref or set
NEXT_PUBLIC_SPECTRUM_LINE_REF.
Docs Route
This page is served from docs/studio.md. The /docs route first looks for local Markdown pages and renders them. If a local page does not exist and DOCS_ORIGIN is configured, the request is proxied to that origin.