Studio Backend

Domain Model

Most domain types are defined in promethist-common and promethist-lib, because the engine reads the same documents the platform writes. The platform adds its own documents for what only Studio needs. In the Studio and in user-facing text an account is called an account; in code and in the API it is a tenant.

Hierarchy

Account (Tenant)
 ├── members and invitations             accessControlList, invitation
 ├── account settings                    accountSettings
 ├── billing details                     billingDetails, usage
 └── Project
      ├── agents (revisions)             agent
      ├── evaluations                    evaluationDefinition, evaluationInsightDefinition, ...
      ├── test suites                    testSuite (+ the bridge's own documents)
      ├── feedback surveys               feedbackDefinition, feedbackQuestionDefinition
      └── asset specifications, embedded in the project document:
           knowledge, MCP servers, MCP connectors, webhooks, interactive content,
           content navigation, skills

An account is the billing and access boundary; a project is a workspace whose agents share its assets.

Accounts

Tenant holds little more than a unique name and an optional logo. Any signed-in user can create one (POST /api/v1/tenants); TenantService.createTenant then

  • gives the creator an Owner row for the account,

  • creates the Stripe customer (BillingDetails, see Usage and Billing),

  • and adds a first project — a copy of the seed project when tenant seeding is configured (promethist.tenant-seeding.*), otherwise an empty default project. The REST endpoint always asks for one; the AI Assistant’s account creation creates the project in a separate step.

There is no endpoint that deletes an account or a project.

Projects

Project (common) is the document the engine reads to run a project’s agents. Besides name (unique within the account), a globally unique ref, description, logo and colors it carries:

Field Meaning

terms

Terms and conditions (Markdown) the client app asks a user to accept before they can talk to the project’s agents. The app remembers an acceptance by the exact text, so any change asks every user again. Edited only through PUT /api/v1/project/{projectId}/terms (Editor); the project PATCH leaves them as they are. A project seeded from a seed project starts with the seed’s terms.

featuredAgentRef

The project’s main agent — for example the coach of an Empower project. Evaluations can inject their results into it.

packageType

The product package the project is built as: EMPOWER (coaching with roleplay agents), ENGAGE (kiosk lead capture), USER_GUIDANCE, SALES_CONVERSION, SUPPORT_RESOLUTION or INSIGHT_EXTRACTION. The AI Assistant adapts its guidance to it; the engine enables the long-term development profile for EMPOWER. Projects stored with a retired package name are rewritten at startup by ProjectPackageTypeMigration.

identityProviders, isIdentityRequired, isUsingExternalRoles

Who may use the project’s agents, see Identity Providers and External Roles.

*Specifications

The project’s assets, embedded as lists in the project document (next section).

Asset Specifications

Assets live inside the project document rather than in collections of their own, and each is addressed by a ref that is unique within the project:

List Studio name Content

knowledgeSpecifications

Knowledge

Knowledge sources: file and url (optionally live, scraped at conversation time), with retrieval settings topK, similarity and language. The extracted chunks are stored separately, see Knowledge Processing.

webhookSpecifications

Integrations (pre- and post-session)

HTTP calls before a conversation (PreSessionWebhook, whose result can be given to the model) and after it (PostSessionWebhook, for example to deliver a transcript).

mcpServerSpecifications

Integrations (MCP)

A customer’s MCP server the agent can call during a conversation: URL, transport (Streamable HTTP or SSE), an optional authentication header and the selected tools.

mcpConnectorSpecifications

Integrations (connectors)

A connector from the platform’s catalog enabled for the project, with the selected tools.

multimodalInteractionSpecifications

Interactive content

Elements an agent can show or ask for during a conversation: website, image, video, input, choice and handover (passing the conversation to another agent).

navigationSpecifications

Content navigation

The menu of the client application: text, action, route and url items arranged in a tree, optionally unlocked by a condition on an evaluation result, or always locked.

skillSpecifications

Skills

Global skills assigned to the project (assignment is staff-only).

The isGlobal flag of an asset decides whether every agent of the project gets it, or only agents that reference it in their instructions with a tool reference such as @knowledge:pricing;, @multimodal:product-photo;, @skill:negotiation; or, for one tool of an MCP integration, @MCP:crm_lookupCustomer; (see Referencing Integrations from Agents). The trailing semicolon is part of the syntax; text generated by the AI Assistant is repaired deterministically when a model drops it (String.repairToolReferences() in util/Functions.kt).

Because the specifications are polymorphic and stored with Spring Data’s _class discriminators, they are read through hand-written Jackson converters in configuration/MongoConfig.kt. They hand Jackson the stored document as JSON, with a UUID (such as the evaluation id of a navigation condition) as its canonical string and any other binary value as base64. A new polymorphic specification type, or one that nests another polymorphic value, needs its converter adjusted — otherwise the write succeeds and the next read fails: the converter logs the item and puts null in its place. The project read leaves such items out (Project.sanitized() in repository/ProjectRepository.kt), so the project, its asset listings and the Studio pages keep working without them, and the unreadable items stay stored as they are. That holds because an existing project is never saved whole: ProjectService writes only the fields an edit changes (the settings, terms, identity providers or logo), together with the lastModified and lastModifiedBy audit fields a save would set, and every asset write adds, replaces or removes its own item.

Agents

Agent (common, collection agent) has three kinds. The kind is chosen at creation and cannot change.

Kind (AgentKind) Class Content

RELATIONAL

RelationalAgent

The full "digital employee": identityDescription, purpose, businessProcessSteps, guardrails, a businessImpact weight and an initialPlan, which a language model generates asynchronously from the business process steps when the agent is created and whenever the steps change. Has cross-session memory.

LIGHTWEIGHT

BasicAgent

A single-purpose agent with identityDescription, purpose and guardrails (and an optional raw systemPrompt), no business process and no generated plan.

TEST

TestAgent

A simulated user for test suites: a persona and scenario (systemPrompt) and a text-only switch (noAudio). It always runs on a fixed realtime configuration and without avatar animation.

All kinds share ref, name, title, description, locales, the voice (realtimeConfigurationId, a realtime configuration), the visual (visualProperties: avatar, environment, camera preset, animation type), hasMemory, the attached evaluations (evaluationDefinitionRefs, see Evaluations) and the template they were created from (templateRef, templateRevision, templateVariables).

Revisions and States

An agent is identified by its ref, which is unique across the platform; each revision is a separate document with its own id, a revision number and a state — Draft, Preview, Published or Archived (AgentService).

Operation Effect

Create (POST /api/v1/project/{projectId}/agents)

Revision 0 in Draft. A ref is derived from the name and made unique.

Edit (PUT /api/v1/agents/{id})

Never changes a revision in place: it copies the latest non-archived revision, applies the request and saves it as a new Draft with the next revision number. Edits therefore stack on the newest revision whatever id they were sent to.

Promote to preview (POST /api/v1/agents/{id}/preview)

Only from Draft. The revision becomes Preview; an older Preview revision is archived.

Publish (POST /api/v1/agents/{id}/publish)

Only from Preview. The revision becomes Published — live for end users — and the previously published revision is archived.

Revert (POST /api/v1/agents/{id}/revert?revision={n})

Makes revision n the newest by archiving every newer revision. n must not be archived and must not be older than the newest Preview or Published revision.

Archive (POST /api/v1/agents/{id}/archive), archive all (.../archive-all)

Archives one revision, or every revision of the ref. Agents are never deleted; "deleting" an agent in the Studio or the assistant archives all of its revisions.

Clone (POST /api/v1/agents/{id}/clone)

A new agent (new ref) in Draft, copied from the revision.

So an agent has at most one Preview and one Published revision at any time. Client applications address an agent by its pipeline key, agent:{ref} or agent:{ref}.{revision}.

Templates

Agent templates (RelationalAgentTemplate, BasicAgentTemplate) are global and versioned like agents. A template presets the content fields, declares variables that are substituted into them, and can lock individual fields so that agents created from it cannot change them. Everyone sees the published templates (GET /api/v1/templates); authoring is staff-only (/api/v1/admin/templates), and publishing a revision archives the previously published one.

Evaluations

An EvaluationDefinition (collection evaluationDefinition) describes what a language model judges about a conversation. Its output data elements — insights in code, EvaluationInsightDefinition — are typed:

Type Value

Bool (boolean)

Yes or no, with a label for each.

Number (number)

An integer between minValue and maxValue.

Text (text)

Free text.

TextList (list)

One or more values from a fixed list — a classification.

Elements can be put into groups (EvaluationGroupDefinition), which are scored together in one model call. An evaluation may also define one featured result (a Bool or a Number), the headline figure of the analytics and the condition of content-navigation items.

Further fields decide when and where an evaluation runs: executionModes (ON_CONVERSATION_END, or PER_TURN with an optional lookbackWindow), and its destinations — shown to the user (userFacing), to the Studio (adminFacing), injected into the next session or into the project’s featured agent, or posted to a webhook. testMode marks the agent evaluations used by test suites, which are kept apart from the regular ones.

Evaluations are versioned like agents: every revision is its own document with its own groups and elements, sharing the evaluation’s ref, and moves Draft → Preview → Published → Archived. A new evaluation is Draft revision 0; a Studio save writes a new Draft, and the assistant’s and the MCP tools' per-item edits stack on one. An element keeps its ref from revision to revision, so its results aggregate across revisions; a clone is a new evaluation with refs of its own. Deleting an evaluation deletes every revision; nothing else removes one, as results point at the revision that produced them.

Agents link evaluations by ref (evaluationDefinitionRefs) and the engine runs the Published revision of each, so only an evaluation with a Published revision can be attached; the API and the tools still speak evaluation ids, of any revision, and answer with the Published one. An agent links only its own project’s evaluations: the engine finds a definition by ref across projects but loads its elements by the session’s project, so a link to another project’s evaluation would score nothing, and a save that newly names one is refused. The shared test catalogue is used by copying instead — the MCP tool copy_catalog_evaluation writes the catalogue evaluation’s Published revision into the caller’s project as a Published test-mode evaluation of its own, with the master’s element refs kept so results stay comparable, without its webhook, injection or user-facing settings, and with a line in its description naming the master revision it holds, which is what makes a second call return the same copy. A testMode evaluation is refused on any agent that is not a TEST agent. Publishing re-points the content-navigation conditions on the featured result to the new revision. Such a condition can be met only while that revision has a featured result of the kind its match reads — Always reads either — so removing the featured result, switching its kind or deleting the evaluation leaves the item locked for every user who has not unlocked it yet. Nothing blocks the change: the navigation editor warns about a condition that cannot be met, and the assistant’s and the MCP tools' delete and publish name the items they leave locked. The engine writes the results as EvaluationResult (with the featured outcome) and per-element insight results; the platform reads them for the analytics and the test-suite verdicts.

Data Saved Before Versioning

EvaluationVersioningMigration brings older data up to date at every start, and once more 15 minutes later, when no pod of the previous version is left to save data the old way. It writes only what is missing and deletes nothing:

  • Evaluation definitions saved without ref, state or revision get them stored — their own id as the ref, Published, revision 0 — because the engine finds an agent’s evaluations with a query on ref and state, which does not match a missing field.

  • Clones that still share their source’s ref get refs of their own. The evaluationRef of their results follows, and in a project other than the source’s so do the agents that link the shared ref.

  • Agent revisions that link evaluations only by id (evaluationDefinitionIds) get the refs added; the ids stay.

  • The {ref, state} index, the evaluationId indexes of elements and groups, and the unique {projectId, ref, revision} index are ensured.

It needs an engine of 2026.35 or newer on the same database, because agents saved now link their evaluations by ref alone. A rollback of the platform does not undo it, and a version from before versioning mishandles the migrated data: it lists every revision as an evaluation of its own, rewrites the revision it saves in place (an Archived one, which results point at, included) and shows no evaluations on agents saved since. After such a rollback, leave evaluations and the evaluations of agents unedited until the platform is forward again.

Members and Invitations

Membership is the set of access control list rows described in Roles and Access Control Lists. People join an account or a project in two ways:

  • Invitation (invitation collection) — an Owner invites email addresses; each gets an email rendered from a stored Mailgun template with a link to /invite/{id}. The invitation can be accepted only by the user whose email matches; accepting creates the ACL row. Pending invitations older than seven days are removed by a nightly job (when scheduling is enabled).

  • Direct grant (MemberService, POST /api/v1/{tenant|project}/{id}/members) — the ACL row is created immediately, and a user record is created for an address that has never signed in, so the grant applies on their first login.

Voices and Visuals

A voice is a RealtimeConfiguration (common): the realtime model and speech settings an agent’s conversations run on, with gender and supported locales. They are global; staff manage them in the Studio’s Admin → Voices (/api/v1/admin/realtime-configurations), everyone reads the active ones (GET /api/v1/realtime-configurations).

Visuals — avatars and environments — are not stored by the platform. They come from the public asset bundle index at https://repository.promethist.ai/public/arc/bundles/default/index.json (VisualsVoicesFetcher, only entries marked public), and an agent stores the chosen refs in its visualProperties.

Conversation Records

The engine writes the record of every conversation into the shared database; the platform only reads it.

Collection Content

session

One conversation: agent and revision, user, project, testMode, turn count, timestamps, rating, interactive-content usage.

turn

One exchange of a session: input and output, transcript, locale, testMode.

evaluationResult, insight results

The evaluations of a session.

feedback

Answers to feedback surveys.

edr

Usage records of realtime conversations, with their duration, from which billing and the analytics' conversation length are computed.

The engine also indexes turns and LLM calls into Elasticsearch; the MCP server’s conversation-data tools read those indexes.

Platform-Owned Collections

Collection Content

accountSettings, accountSettingsAuditLog

The account privacy settings and the log of every change.

billingDetails, package, usageProcessingTask, usage

Stripe customer per account, purchasable packages, and the usage pipeline (Usage and Billing).

knowledge

The extracted chunks of each knowledge source (the first 200) and its generated description.

testSuite

Test suites (Test Suites).

chat-messages, agenticChatMessage

The AI Assistant’s model memory and the chat history shown in the UI.

conversationExport, mcpFileUpload

Records behind the capability links of exports and uploads; export files themselves are in GridFS.

secret

LiveAvatar API keys of accounts and projects.

session-summaries

Cached session summaries.