Overview

The elizaOS plugin system is a comprehensive extension mechanism that allows developers to add functionality to agents through a well-defined interface. Plugins are modular extensions that enhance AI agents with new capabilities, integrations, and behaviors.

What Can Plugins Do?

  • Platform Integrations: Connect to Discord, Telegram, Slack, Twitter, etc.
  • LLM Providers: Integrate different AI models (OpenAI, Anthropic, Google, etc.)
  • Blockchain/DeFi: Execute transactions, manage wallets, interact with smart contracts
  • Data Sources: Connect to databases, APIs, or external services
  • Custom Actions: Define new agent behaviors and capabilities

Plugin Interface

Every plugin must implement the core Plugin interface, which defines the structure and capabilities of a plugin. The interface includes:
  • Identity: name and description to identify the plugin
  • Initialization: Optional init function for setup logic
  • Components: Arrays of actions, providers, evaluators, and services
  • Configuration: Settings and environment variables via config
  • Extensions: Optional database adapters, model handlers, routes, and event handlers
  • Dependencies: Other plugins this plugin requires
  • Priority: Loading order when multiple plugins are present
For the complete TypeScript interface definition, see Plugin Reference.

Plugin Initialization Lifecycle

Based on the runtime implementation, the initialization process follows a specific order:

1. Plugin Registration (registerPlugin method)

When a plugin is registered with the runtime:
  1. Validates plugin has a name
  2. Checks for duplicate plugins
  3. Adds to active plugins list
  4. Calls plugin’s init() method if present
  5. Handles configuration errors gracefully

2. Component Registration Order

Components 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);
    }
  }
}

Route Definitions for HTTP Endpoints

Plugins can expose HTTP endpoints through the route system:
export type Route = {
  type: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'STATIC';
  path: string;
  filePath?: string;                    // For static files
  public?: boolean;                     // Public access
  name?: string;                        // Route name
  handler?: (req: any, res: any, runtime: IAgentRuntime) => Promise<void>;
  isMultipart?: boolean;                // File uploads
};
Example route implementation:
routes: [
  {
    name: 'hello-world-route',
    path: '/helloworld',
    type: 'GET',
    handler: async (_req: any, res: any) => {
      res.json({ message: 'Hello World!' });
    }
  }
]

Event System Integration

Plugins can handle system events through the event system:

Event Types

Standard events include:
  • World events: WORLD_JOINED, WORLD_CONNECTED, WORLD_LEFT
  • Entity events: ENTITY_JOINED, ENTITY_LEFT, ENTITY_UPDATED
  • Room events: ROOM_JOINED, ROOM_LEFT
  • Message events: MESSAGE_RECEIVED, MESSAGE_SENT, MESSAGE_DELETED
  • Voice events: VOICE_MESSAGE_RECEIVED, VOICE_MESSAGE_SENT
  • Run events: RUN_STARTED, RUN_ENDED, RUN_TIMEOUT
  • Action/Evaluator events: ACTION_STARTED/COMPLETED, EVALUATOR_STARTED/COMPLETED
  • Model events: MODEL_USED

Plugin Event Handlers

export type PluginEvents = {
  [K in keyof EventPayloadMap]?: EventHandler<K>[];
} & {
  [key: string]: ((params: any) => Promise<any>)[];
};

Database Adapter Plugins

Plugins can provide database adapters for custom storage backends: The IDatabaseAdapter interface is extensive, including methods for:
  • Agents, Entities, Components
  • Memories (with embeddings)
  • Rooms, Participants
  • Relationships
  • Tasks
  • Caching
  • Logs
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);
  }
};

Plugin Priority System

Plugins can specify a priority to control loading order:
  • Higher priority plugins are loaded first
  • Useful for plugins that provide fundamental services
  • Model handlers use priority to determine which provider handles a model type
export const myPlugin: Plugin = {
  name: 'high-priority-plugin',
  priority: 100, // Loads before lower priority plugins
  // ...
};

Plugin Dependencies

Plugins can declare dependencies on other plugins:
export const myPlugin: Plugin = {
  name: 'my-plugin',
  dependencies: ['@elizaos/plugin-sql', '@elizaos/plugin-bootstrap'],
  testDependencies: ['@elizaos/plugin-test-utils'],
  // ...
};
The runtime ensures dependencies are loaded before dependent plugins.

Plugin Configuration

Plugins can accept configuration through multiple mechanisms:

1. Environment Variables

init: async (config, runtime) => {
  const apiKey = runtime.getSetting('MY_API_KEY');
  if (!apiKey) {
    throw new Error('MY_API_KEY not configured');
  }
}

2. Config Object

export const myPlugin: Plugin = {
  name: 'my-plugin',
  config: {
    defaultTimeout: 5000,
    retryAttempts: 3,
  },
  // ...
};

3. Runtime Settings

Settings can be accessed through runtime.getSetting() which provides a consistent interface to environment variables and character settings.

Conditional Plugin Loading

Plugins are often conditionally loaded based on environment variables:
const plugins = [
  // Always loaded
  '@elizaos/plugin-bootstrap',
  
  // 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'] : []),
];

Core Plugins

elizaOS includes two essential core plugins that provide foundational functionality:

Bootstrap Plugin

The core message handler and event system for elizaOS agents. Provides essential functionality for message processing, knowledge management, and basic agent operations. It includes:
  • 13 essential actions (REPLY, SEND_MESSAGE, etc.)
  • Core providers (time, character, recent messages)
  • Task service
  • Event handlers

SQL Plugin

Database integration and management for elizaOS. Features:
  • Automatic schema migrations
  • Multi-database support (PostgreSQL, PGLite)
  • Sophisticated plugin architecture

Best Practices

  1. Plugin Dependencies: Use the dependencies array to specify required plugins
  2. Conditional Loading: Check environment variables before loading platform-specific plugins
  3. Service Initialization: Handle missing API tokens gracefully in service constructors
  4. Event Handlers: Keep event handlers focused and delegate to specialized functions
  5. Error Handling: Use try-catch blocks and log errors appropriately
  6. Type Safety: Use TypeScript types from @elizaos/core for all plugin components
  7. Priority Management: Set appropriate priorities for plugins that need to load early
  8. Configuration: Use runtime.getSetting() for consistent configuration access

What’s Next?