The runtime bundles 16 plugins that load by default; opt out per plugin via the features map on createOracleApp. One additional plugin — flows — ships in the package but is opt-in only: wire it in explicitly via the plugins array.
At a glance
| Name | Visibility | Default state | Required env | Depends on |
|---|---|---|---|---|
memory | always | Auto-detect | MEMORY_MCP_URL, MEMORY_ENGINE_URL | — |
portal | on-demand | On | — | — |
firecrawl | on-demand | Auto-detect | FIRECRAWL_MCP_URL | — |
domain-indexer | always | On | — | — |
composio | on-demand | Auto-detect | COMPOSIO_API_KEY | — |
sandbox | always | Auto-detect | SANDBOX_MCP_URL | — |
skills | always | On | — | sandbox |
editor | always | On | — | — |
agui | on-demand | On | — | — |
slack | silent | Auto-detect | SLACK_BOT_OAUTH_TOKEN | — |
tasks | on-demand | Auto-detect | REDIS_URL | — |
credits | silent | On unless DISABLE_CREDITS=true | — | — |
calls | silent | On (stub) | — | — |
user-preferences | always | On | — | — |
matrix-group-chats | on-demand | On | — | — |
vfs | always | On | — (URLs from NETWORK) | — |
flows | on-demand | Opt-in (not bundled) | — | editor Qi Flow engine |
Default state legend:
- On — loaded by default; opt out with
features: { name: false }. - Auto-detect — loaded when its env var is set; opt in by setting it, force on with
features: { name: true }, force off withfalse. - (stub) — placeholder entry in
BUNDLED_PLUGINSso feature toggles work; full implementation deferred.
How to use features
const app = await createOracleApp({
config,
features: {
composio: false, // never load even if COMPOSIO_API_KEY is set
slack: true, // force load even if SLACK_BOT_OAUTH_TOKEN is missing (will fail env validation)
'domain-indexer': 'auto', // explicit auto (same as omitting)
},
});true forces on, false forces off, 'auto' runs the plugin's autoDetect callback. Omitted keys default to 'auto'.
Browse
Durable memory across conversations.
portalBrowser-side actions on the user's Portal UI.
firecrawlWeb search and human-readable page scraping.
domain-indexerIXO entity lookup — orgs, projects, DAOs, DIDs.
composioSaaS tool catalog (Gmail, GitHub, Linear, …).
sandboxPer-user Linux box for code execution.
skillsIXO skill capsule discovery.
editorRead and edit BlockNote workspace pages.
aguiRender interactive UI components in the browser.
slackSlack bot transport.
tasksSchedule the agent to run on time-based triggers, in the background.
creditsPer-user credit enforcement and claim settlement.
callsLiveKit call integration (stub — deferred).
user-preferencesTone / format / language preferences.
matrix-group-chatsGate the bot + per-room compacted memory for Matrix group rooms.
vfsRead, write, search, and share the user's real files on their Virtual Filesystem.
flowsAuthor and inspect multi-step Qi Flow templates (opt-in).
Wiring custom-constructed plugins
Some plugins accept constructor args. Pass a custom instance via the plugins array — the loader dedupes by name, so your instance overrides the bundled default.
credits genuinely needs a Redis client. Without one the enforcement middleware loads in pass-through mode and the settlement cron is skipped, so production must construct it explicitly:
import { createOracleApp, CreditsPlugin } from '@ixo/oracle-runtime';
import Redis from 'ioredis';
const redis = new Redis(process.env.REDIS_URL!);
const app = await createOracleApp({
config,
plugins: [new CreditsPlugin({ redis, network: 'devnet' })],
});editor works from env on its own. The bundled editorPlugin is fully functional: when no matrixClient is passed it lazily builds an internal Matrix client from the MATRIX_* admin env vars. Pass matrixClient only to reuse a client your app already keeps synced:
import { createOracleApp, EditorPlugin } from '@ixo/oracle-runtime';
import * as sdk from 'matrix-js-sdk';
const matrixClient = sdk.createClient({ /* ... */ });
const app = await createOracleApp({
config,
plugins: [new EditorPlugin({ matrixClient })], // optional — env fallback otherwise
});