Skip to main content

Plugins

Plugins are Cortex’s first-party extensions. You don’t write plugin code — you pick a plugin from the catalog, install it for a project with your settings, and Cortex runs it for you. (For your own logic, use serverless functions.)

There are two kinds:

KindRuns onProducesExamples
Event plugins (kind: "event")Domain events, e.g. message.createdAnnotations on messages or sessions, sanctions, emailsProfanity Filter, Session Summary, Auto-Sanction, Amanda by Aiba
Audio plugins (kind: "audio")Raw speech audio, inside the transcription botThe transcript itselfCortex Transcription, OpenAI Transcription (own key)

The catalog​

PluginSlugKindWhat it does
Profanity Filterprofanity-filtereventFlags messages with harmful content (hate speech, sexual content, violence, …) using OpenAI moderation and your OpenAI key.
Session Summarysession-summaryeventGenerates meeting minutes when a session ends — key topics, action items, optional email to recipients — using your OpenAI key.
Auto-Sanctionauto-sanctioneventSanctions players who collect flagged messages, escalating with each repeat offence. Works with the Profanity Filter. See Moderation.
Amanda by AibaamandaeventPartner moderation, a paid add-on. See Amanda by Aiba.
Cortex Transcriptioncortex-transcriptionaudioThe default transcriber: OpenAI operated by 4Players, billed per audio minute. Active for every project without installation.
OpenAI Transcription (own key)openai-transcriptionaudioTranscribe with your own OpenAI key or any OpenAI-compatible speech-to-text API. Not billed by 4Players.

Browse it from code:

const plugins = await client.pluginCatalog.list();
const summary = await client.pluginCatalog.get("session-summary");

console.log(summary.kind, summary.events, summary.settingsSchema);

Each plugin describes its configuration in settingsSchema — the list of fields (key, type, label, default, required) that the console renders as a form and that you pass as settings when installing.

Installing and configuring​

An installed plugin is a plugin instance — the plugin plus your settings, for one project.

const plugin = await client.pluginCatalog.get("profanity-filter");

const instance = await project.plugins.create({
pluginId: plugin.id,
settings: {
apiKey: process.env.OPENAI_API_KEY,
threshold: 0.5,
},
});

// Change settings later
await project.plugins.update(instance.id, {
settings: { apiKey: "********", threshold: 0.7 },
});

// List or remove
const installed = await project.plugins.list();
await project.plugins.delete(instance.id);

Secret settings​

Settings of type password — API keys, signing secrets — are secrets:

  • they are encrypted at rest,
  • every response returns them masked as ********, never in plain text,
  • sending ******** back on an update keeps the stored value, so you can change other settings without re-entering the key (send a new value to replace it).

Some plugins are paid add-ons (for example Amanda by Aiba). Installing one in the console activates the corresponding product on your 4Players account after you accept the costs; uninstalling deactivates it. Only project owners, admins and maintainers can do that.

Event plugins​

Event plugins subscribe to domain events and run once per matching event and installed instance — even though Cortex runs many workers in parallel. Typical pairings:

  • message.created → Profanity Filter or Amanda annotate the message,
  • message.annotation.created → Auto-Sanction counts flags and sanctions the player,
  • session.updated (session ended) → Session Summary writes the minutes.

Annotations​

Event plugins store their output as annotations:

  • Message annotations — attached to a single message (e.g. profanity). Emit message.annotation.created.
  • Session annotations — attached to a whole session (e.g. a summary). Emit session.annotation.created.

The annotation body is free-form and plugin-defined, carried under content in the event’s payload.data — see the Domain Events reference.

// Read annotations after the fact
const sessionAnnotations = await client.pluginCatalog.getSessionAnnotations(session.id);
const byMessage = await client.pluginCatalog.getMessageAnnotationsBatch(messageIds);

Because annotations are events too, they chain: a webhook, a serverless function or another plugin can react to them.

Plugin endpoints​

Some plugins expose their own HTTP endpoints — a connection test, or an action such as “regenerate the summary”. Call them with invokeEndpoint:

const result = await project.plugins.invokeEndpoint("session-summary", "regenerate", {
method: "POST",
sessionId: session.id,
});

Most plugins offer a health endpoint that checks your configuration (for example the API key) against the provider. For a session, session.getActions() lists the actions your installed plugins offer, ready to render as a menu. API keys need the plugin-endpoints scope to call plugin endpoints.

Audio plugins​

Audio plugins work on raw speech audio inside the transcription bot. Unlike event plugins they don’t react to events — audio is never published as a domain event, so it can never end up in a webhook, SSE stream or function. It goes only to the provider you selected.

Today audio plugins are transcribers, and each project uses exactly one:

  • With no selection, cortex-transcription transcribes your rooms (4Players’ OpenAI account, billed per audio minute).
  • Install openai-transcription with your own key — and optionally the base URL of any OpenAI-compatible speech-to-text API, including a self-hosted one — then select it with project.settings.updateTranscription(instanceId). Those minutes are not billed by 4Players.

If a transcriber you selected fails, Cortex never falls back to the billed default on its own. The full walk-through, including the connection test, is in Transcription → Bring your own key.