packages/docs/plugins/architecture.mdx
A plugin is a bundle of capabilities you drop into an agent. No inheritance, no complex wiring - just a manifest that says "here are my actions, providers, and services."
// That's the entire contract
const myPlugin: Plugin = {
name: 'my-plugin',
actions: [...], // What the agent can DO
providers: [...], // What the agent can SEE
services: [...], // What the agent can CONNECT to
};
The elizaOS plugin system is a modular extension mechanism that allows developers to add functionality to agents through a well-defined interface. Plugins enhance AI agents with new capabilities, integrations, and behaviors.
<Tip>Guide: Create a Plugin</Tip>
Every plugin must implement the core Plugin interface, which defines the structure and capabilities of a plugin. The interface includes:
name and description to identify the plugininit function for setup logicactions, providers, evaluators, and servicesconfigFor the complete TypeScript interface definition, see Plugin Reference.
Based on the runtime implementation, the initialization process follows a specific order:
registerPlugin method)When a plugin is registered with the runtime:
init() method if presentComponents are registered in this specific sequence. For component details, see Plugin Components.
// 1. Database adapter (if provided)
if (plugin.adapter) {
this.registerDatabaseAdapter(plugin.adapter);
}
// 2. Actions
if (plugin.actions) {
for (const action of plugin.actions) {
this.registerAction(action);
}
}
// 3. Evaluators
if (plugin.evaluators) {
for (const evaluator of plugin.evaluators) {
this.registerEvaluator(evaluator);
}
}
// 4. Providers
if (plugin.providers) {
for (const provider of plugin.providers) {
this.registerProvider(provider);
}
}
// 5. Models
if (plugin.models) {
for (const [modelType, handler] of Object.entries(plugin.models)) {
this.registerModel(modelType, handler, plugin.name, plugin.priority);
}
}
// 6. Routes
if (plugin.routes) {
for (const route of plugin.routes) {
this.routes.push(route);
}
}
// 7. Events
if (plugin.events) {
for (const [eventName, eventHandlers] of Object.entries(plugin.events)) {
for (const eventHandler of eventHandlers) {
this.registerEvent(eventName, eventHandler);
}
}
}
// 8. Services (delayed if runtime not initialized)
if (plugin.services) {
for (const service of plugin.services) {
if (this.isInitialized) {
await this.registerService(service);
} else {
this.servicesInitQueue.add(service);
}
}
}
Plugins can expose HTTP endpoints through the route system:
export type Route = {
type: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "STATIC";
path: string;
filePath?: string; // For static files
public?: boolean; // Public access
name?: string; // Route name
handler?: (
req: RouteRequest,
res: RouteResponse,
runtime: IAgentRuntime,
) => Promise<void>;
isMultipart?: boolean; // File uploads
};
Example route implementation:
routes: [
{
name: "hello-world-route",
path: "/helloworld",
type: "GET",
handler: async (_req: RouteRequest, res: RouteResponse) => {
res.json({ message: "Hello World!" });
},
},
];
Plugins can handle system events through the event system:
Standard events include:
export type PluginEvents = {
[K in keyof EventPayloadMap]?: EventHandler<K>[];
} & {
[key: string]: ((params: EventPayloadMap[keyof EventPayloadMap]) => Promise<void>)[];
};
Plugins can provide database adapters for custom storage backends:
The IDatabaseAdapter interface is extensive, including methods for:
Example database adapter plugin:
export const plugin: Plugin = {
name: "@elizaos/plugin-sql",
description:
"A plugin for SQL database access with dynamic schema migrations",
priority: 0,
schema,
init: async (_, runtime: IAgentRuntime) => {
const dbAdapter = createDatabaseAdapter(config, runtime.agentId);
runtime.registerDatabaseAdapter(dbAdapter);
},
};
Plugins can specify a priority to control loading order:
export const myPlugin: Plugin = {
name: "high-priority-plugin",
priority: 100, // Loads before lower priority plugins
// ...
};
Plugins can declare dependencies on other plugins:
export const myPlugin: Plugin = {
name: "my-plugin",
dependencies: ["@elizaos/plugin-sql"],
testDependencies: ["@elizaos/plugin-test-utils"],
// ...
};
The runtime ensures dependencies are loaded before dependent plugins.
Plugins can accept configuration through multiple mechanisms:
init: async (config, runtime) => {
const apiKey = runtime.getSetting("MY_API_KEY");
if (!apiKey) {
throw new Error("MY_API_KEY not configured");
}
};
export const myPlugin: Plugin = {
name: "my-plugin",
config: {
defaultTimeout: 5000,
retryAttempts: 3,
},
// ...
};
Settings can be accessed through runtime.getSetting() which provides a consistent interface to environment variables and character settings.
Plugins are often conditionally loaded based on environment variables:
const plugins = [
// BasicCapabilities is automatically included - no need to add it!
// Conditionally loaded based on API keys
...(process.env.ANTHROPIC_API_KEY ? ["@elizaos/plugin-anthropic"] : []),
...(process.env.OPENAI_API_KEY ? ["@elizaos/plugin-openai"] : []),
// Platform plugins
...(process.env.DISCORD_API_TOKEN ? ["@elizaos/plugin-discord"] : []),
...(process.env.TELEGRAM_BOT_TOKEN ? ["@elizaos/plugin-telegram"] : []),
];
elizaOS includes essential plugins that provide foundational functionality:
The basic-capabilities plugin is built into @elizaos/core and automatically registered during runtime initialization. You don't need to import or configure it - it's included automatically when you create an AgentRuntime. It provides essential functionality for message processing, knowledge management, and basic agent operations:
Database integration and management for elizaOS. Features:
dependencies array to specify required plugins@elizaos/core for all plugin componentsruntime.getSetting() for consistent configuration access