plugin-builder

A comprehensive skill that scaffolds production-ready elizaOS plugins with proper structure, TypeScript configuration, testing setup, and documentation.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "plugin-builder" with this command: npx skills add dexploarer/hyper-forge/dexploarer-hyper-forge-plugin-builder

Plugin Builder Skill

A comprehensive skill that scaffolds production-ready elizaOS plugins with proper structure, TypeScript configuration, testing setup, and documentation.

When to Use

This skill activates when you need to:

  • Create a new elizaOS plugin from scratch

  • Add custom actions, providers, or services

  • Extend elizaOS with new capabilities

  • Build reusable plugin packages

Trigger phrases:

  • "Create a plugin for [capability]"

  • "Build an elizaOS plugin that [does something]"

  • "Scaffold a new plugin"

  • "Generate plugin structure for [feature]"

Capabilities

This skill can:

  • 🏗️ Scaffold complete plugin structure

  • ⚡ Generate actions with validation and handlers

  • 📊 Create providers for context enrichment

  • ✅ Build evaluators for response quality

  • 🔌 Implement services for platform integrations

  • 🧪 Set up comprehensive testing

  • 📦 Configure TypeScript and build tools

  • 📚 Generate complete documentation

Plugin Architecture

interface Plugin { name: string; // Unique plugin identifier description?: string; // Plugin purpose dependencies?: string[]; // Required plugins

// Extensibility Components actions?: Action[]; // Executable operations providers?: Provider[]; // Context enrichment evaluators?: Evaluator[]; // Response quality services?: typeof Service[]; // Platform integrations models?: ModelHandlers; // Custom model handlers

// Lifecycle Hooks init?(config: any, runtime: IAgentRuntime): Promise<void>; start?(runtime: IAgentRuntime): Promise<void>; stop?(runtime: IAgentRuntime): Promise<void>; }

Workflow

Phase 1: Requirements Analysis

Ask these questions:

Plugin Purpose: "What capability does this plugin add?"

  • Platform integration (Discord, Telegram, Slack)

  • External service (API, database, search)

  • Custom action (file operations, calculations)

  • Data enrichment (context, analytics)

  • Response enhancement (formatting, validation)

Components Needed:

  • Actions: User-triggered operations?

  • Providers: Context enrichment needed?

  • Evaluators: Response validation required?

  • Services: Long-running processes?

  • Models: Custom LLM handlers?

Dependencies:

  • External npm packages?

  • API credentials required?

  • Other elizaOS plugins?

  • System requirements?

Configuration:

  • Environment variables needed?

  • Runtime settings?

  • Secrets management?

Phase 2: Plugin Structure

plugin-{name}/ ├── package.json ├── tsconfig.json ├── .env.example ├── README.md ├── src/ │ ├── index.ts # Plugin export │ ├── types.ts # TypeScript interfaces │ ├── actions/ # Action implementations │ │ ├── index.ts │ │ └── {actionName}.ts │ ├── providers/ # Provider implementations │ │ ├── index.ts │ │ └── {providerName}.ts │ ├── evaluators/ # Evaluator implementations │ │ ├── index.ts │ │ └── {evaluatorName}.ts │ ├── services/ # Service implementations │ │ ├── index.ts │ │ └── {serviceName}.ts │ └── utils/ # Utility functions │ └── index.ts ├── tests/ # Tests │ ├── actions.test.ts │ ├── providers.test.ts │ ├── evaluators.test.ts │ └── integration.test.ts └── examples/ # Usage examples └── basic-usage.ts

Phase 3: Implementation

Step 1: Initialize Plugin

Create directory structure

mkdir -p plugin-{name}/{src/{actions,providers,evaluators,services,utils},tests,examples} cd plugin-{name}

Step 2: Package Configuration

{ "name": "@elizaos/plugin-{name}", "version": "1.0.0", "description": "{Plugin description}", "type": "module", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { "build": "tsc", "dev": "tsc --watch", "test": "vitest", "test:coverage": "vitest --coverage", "lint": "eslint src//*.ts", "format": "prettier --write "src//*.ts"" }, "dependencies": { "@elizaos/core": "latest", "zod": "^3.22.0" }, "devDependencies": { "@types/node": "^20.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "eslint": "^8.0.0", "prettier": "^3.0.0", "typescript": "^5.0.0", "vitest": "^1.0.0" }, "keywords": [ "elizaos", "plugin", "{keywords}" ], "author": "{Your Name}", "license": "MIT", "repository": { "type": "git", "url": "https://github.com/{org}/plugin-{name}" } }

Step 3: TypeScript Configuration

{ "compilerOptions": { "target": "ES2022", "module": "ES2022", "lib": ["ES2022"], "moduleResolution": "node", "esModuleInterop": true, "declaration": true, "declarationMap": true, "sourceMap": true, "outDir": "./dist", "rootDir": "./src", "strict": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "allowSyntheticDefaultImports": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "tests"] }

Step 4: Create Types

// src/types.ts

import type { Action, Provider, Evaluator, Service, IAgentRuntime, Memory, State } from '@elizaos/core';

// Plugin Configuration export interface {PluginName}Config { apiKey?: string; baseUrl?: string; timeout?: number; // Add your config properties }

// Action Types export interface {Action}Input { // Input parameters }

export interface {Action}Output { // Output structure }

// Provider Types export interface {Provider}Data { // Provider data structure }

// Service Types export interface {Service}Config { // Service configuration }

// Export plugin type export interface {PluginName}Plugin { name: string; description: string; actions?: Action[]; providers?: Provider[]; evaluators?: Evaluator[]; services?: typeof Service[]; }

Step 5: Create Action

// src/actions/{actionName}.ts

import { type Action, type IAgentRuntime, type Memory, type State, type HandlerCallback } from '@elizaos/core'; import { z } from 'zod';

// Input validation schema const {action}Schema = z.object({ param1: z.string().min(1), param2: z.number().optional(), // Add your parameters });

export const {action}Action: Action = { name: '{ACTION_NAME}',

// Similar action names for triggering similes: [ 'SIMILAR_NAME_1', 'SIMILAR_NAME_2', 'ALTERNATIVE_NAME' ],

description: '{What this action does and when to use it}',

// Usage examples for training examples: [ [ { user: "{{user}}", content: { text: "Can you {action example}?" } }, { user: "{{agentName}}", content: { text: "{I'll {action} for you}", action: "{ACTION_NAME}" } } ], [ { user: "{{user}}", content: { text: "{Another way to trigger action}" } }, { user: "{{agentName}}", content: { text: "{Response}", action: "{ACTION_NAME}" } } ] ],

// Validate if action should execute validate: async ( runtime: IAgentRuntime, message: Memory, state?: State ): Promise<boolean> => { try { // Extract parameters from message const params = extractParams(message);

  // Validate with Zod
  {action}Schema.parse(params);

  // Additional validation logic
  if (!hasRequiredPermissions(runtime, message)) {
    return false;
  }

  return true;
} catch (error) {
  console.error('Validation failed:', error);
  return false;
}

},

// Execute action handler: async ( runtime: IAgentRuntime, message: Memory, state?: State, options?: any, callback?: HandlerCallback ): Promise<string | null> => { try { // Extract and validate parameters const params = extractParams(message); const validated = {action}Schema.parse(params);

  // Send progress update
  if (callback) {
    callback({
      text: 'Processing {action}...',
      action: '{ACTION_NAME}'
    });
  }

  // Execute action logic
  const result = await performAction(validated, runtime);

  // Store result in memory if needed
  await runtime.createMemory({
    entityId: runtime.agentId,
    roomId: message.roomId,
    content: {
      text: `Action {ACTION_NAME} completed`,
      metadata: { result }
    }
  });

  // Return success message
  return formatSuccessResponse(result);

} catch (error) {
  console.error('Action failed:', error);

  // Return error message
  return formatErrorResponse(error);
}

} };

// Helper functions function extractParams(message: Memory): any { // Extract parameters from message content return { param1: message.content.param1, param2: message.content.param2 }; }

async function performAction(params: any, runtime: IAgentRuntime): Promise<any> { // Implement action logic // Access runtime.getService() for services // Use runtime.createMemory() for storing data

return { success: true, data: {} }; }

function hasRequiredPermissions(runtime: IAgentRuntime, message: Memory): boolean { // Check permissions return true; }

function formatSuccessResponse(result: any): string { return ✅ {Action} completed successfully: ${JSON.stringify(result)}; }

function formatErrorResponse(error: any): string { return ❌ {Action} failed: ${error.message}; }

Step 6: Create Provider

// src/providers/{providerName}.ts

import { type Provider, type IAgentRuntime, type Memory, type State } from '@elizaos/core';

export const {provider}Provider: Provider = { name: '{PROVIDER_NAME}',

description: '{What context this provider adds}',

// Optional: only execute when explicitly requested dynamic: false,

// Optional: hide from public context private: false,

// Execution order (lower = earlier) position: 100,

// Gather and format context get: async ( runtime: IAgentRuntime, message: Memory, state?: State ): Promise<{ values: Record<string, any>; data: Record<string, any>; text: string; }> => { try { // Gather data const data = await gatherData(runtime, message);

  // Format for template usage
  const values = {
    key1: data.value1,
    key2: data.value2
  };

  // Format as text for LLM context
  const text = formatAsText(data);

  return {
    values,  // For template variables
    data,    // For programmatic access
    text     // For LLM context
  };

} catch (error) {
  console.error('Provider failed:', error);

  // Return empty result on error
  return {
    values: {},
    data: {},
    text: ''
  };
}

} };

async function gatherData(runtime: IAgentRuntime, message: Memory): Promise<any> { // Fetch data from external sources // Query database // Process information

return { value1: 'data', value2: 123 }; }

function formatAsText(data: any): string { // Format data as natural language for LLM return ` {Provider Name} Context:

  • Value 1: ${data.value1}
  • Value 2: ${data.value2} `.trim(); }

Step 7: Create Service

// src/services/{serviceName}.ts

import { Service, ServiceTypeName, type IAgentRuntime } from '@elizaos/core';

export class {Service}Service extends Service { static serviceType: ServiceTypeName = '{SERVICE_TYPE}' as ServiceTypeName;

capabilityDescription: string = '{What this service provides}';

private client: any; private config: any;

constructor(runtime: IAgentRuntime) { super(runtime);

// Initialize configuration
this.config = {
  apiKey: runtime.character.settings.{service}ApiKey,
  baseUrl: runtime.character.settings.{service}BaseUrl || 'https://api.example.com',
  timeout: runtime.character.settings.{service}Timeout || 30000
};

}

// Start service static async start(runtime: IAgentRuntime): Promise<Service> { const service = new {Service}Service(runtime); await service.initialize(); return service; }

// Initialize service async initialize(): Promise<void> { try { // Initialize client this.client = createClient(this.config);

  // Test connection
  await this.client.healthCheck();

  console.log('✅ {Service} initialized successfully');
} catch (error) {
  console.error('❌ {Service} initialization failed:', error);
  throw error;
}

}

// Stop service async stop(): Promise<void> { try { // Cleanup resources if (this.client) { await this.client.close(); }

  console.log('✅ {Service} stopped successfully');
} catch (error) {
  console.error('❌ {Service} stop failed:', error);
}

}

// Service methods async doSomething(params: any): Promise<any> { try { return await this.client.request(params); } catch (error) { console.error('Service request failed:', error); throw error; } } }

function createClient(config: any): any { // Create and return API client return { healthCheck: async () => true, request: async (params: any) => ({ success: true }), close: async () => {} }; }

Step 8: Create Plugin Index

// src/index.ts

import type { Plugin } from '@elizaos/core';

// Import components import { {action}Action } from './actions/{actionName}.js'; import { {provider}Provider } from './providers/{providerName}.js'; import { {Service}Service } from './services/{serviceName}.js';

// Export types export * from './types.js';

// Export plugin export const {plugin}Plugin: Plugin = { name: '@elizaos/plugin-{name}', description: '{Plugin description}',

// Optional: Dependencies dependencies: [],

// Components actions: [{action}Action], providers: [{provider}Provider], services: [{Service}Service],

// Lifecycle hooks async init(config: any, runtime: any): Promise<void> { console.log('Initializing {plugin} plugin...'); // Initialization logic },

async start(runtime: any): Promise<void> { console.log('Starting {plugin} plugin...'); // Startup logic },

async stop(runtime: any): Promise<void> { console.log('Stopping {plugin} plugin...'); // Cleanup logic } };

export default {plugin}Plugin;

Step 9: Create Tests

// tests/actions.test.ts

import { describe, it, expect, beforeEach } from 'vitest'; import { {action}Action } from '../src/actions/{actionName}'; import { createMockRuntime, createMockMessage } from '@elizaos/core/test';

describe('{Action} Action', () => { let runtime: any; let message: any;

beforeEach(() => { runtime = createMockRuntime(); message = createMockMessage({ content: { text: 'test message', param1: 'value1' } }); });

it('validates correct input', async () => { const isValid = await {action}Action.validate(runtime, message); expect(isValid).toBe(true); });

it('rejects invalid input', async () => { message.content.param1 = ''; const isValid = await {action}Action.validate(runtime, message); expect(isValid).toBe(false); });

it('executes successfully', async () => { const result = await {action}Action.handler(runtime, message); expect(result).toContain('success'); });

it('handles errors gracefully', async () => { // Force an error runtime.createMemory = () => { throw new Error('Test error'); };

const result = await {action}Action.handler(runtime, message);
expect(result).toContain('failed');

}); });

Step 10: Create Documentation

@elizaos/plugin-{name}

{Brief description of plugin purpose and capabilities}

Features

  • ✨ {Feature 1}
  • ⚡ {Feature 2}
  • 🔒 {Feature 3}

Installation

npm install @elizaos/plugin-{name}

Configuration

Add the plugin to your character configuration:

import { {plugin}Plugin } from '@elizaos/plugin-{name}';

export const character: Character = {
  // ... other config
  plugins: [
    '@elizaos/plugin-bootstrap',
    {plugin}Plugin
  ],
  settings: {
    {service}ApiKey: process.env.{SERVICE}_API_KEY,
    {service}BaseUrl: 'https://api.example.com',
    {service}Timeout: 30000
  }
};

Environment Variables

# Required
{SERVICE}_API_KEY=your-api-key

# Optional
{SERVICE}_BASE_URL=https://api.example.com
{SERVICE}_TIMEOUT=30000

Actions

{ACTION_NAME}

{Action description}

Usage:

User: Can you {action}?
Agent: {I'll do the action}

Parameters:

- param1
 (string, required): {Description}

- param2
 (number, optional): {Description}

Providers

{PROVIDER_NAME}

{Provider description}

Adds the following to agent context:

- {Context item 1}

- {Context item 2}

Services

{Service}Service

{Service description}

Methods:

- doSomething(params)
: {Method description}

Usage Examples

Basic Usage

import { AgentRuntime } from '@elizaos/core';
import { {plugin}Plugin } from '@elizaos/plugin-{name}';
import character from './character';

const runtime = new AgentRuntime({
  character,
  plugins: [{plugin}Plugin]
});

await runtime.initialize();

Using Actions Programmatically

import { {action}Action } from '@elizaos/plugin-{name}';

const result = await {action}Action.handler(
  runtime,
  message,
  state,
  options,
  callback
);

Testing

# Run tests
npm test

# Run with coverage
npm run test:coverage

# Run in watch mode
npm run test:watch

Development

# Build
npm run build

# Watch mode
npm run dev

# Lint
npm run lint

# Format
npm run format

API Reference

{Detailed API documentation}

Contributing

Contributions welcome! Please:

- Fork the repository

- Create a feature branch

- Make your changes

- Add tests

- Submit a pull request

License

MIT

Support

- 📚 Documentation

- 💬 Discord

- 🐛 Issues

## Plugin Templates

### 1. Platform Integration Plugin

For integrating new chat platforms (Slack, WhatsApp, etc.):

- Service for platform connection
- Actions for platform-specific features
- Message formatting providers
- Platform event handlers

### 2. External API Plugin

For accessing external services:

- Actions for API operations
- Providers for data enrichment
- Error handling and retries
- Rate limiting and caching

### 3. Data Processing Plugin

For data transformation and analysis:

- Actions for processing operations
- Providers for context enrichment
- Evaluators for result validation
- Caching for performance

### 4. Custom Model Plugin

For integrating custom LLMs:

- Model handlers for inference
- Token counting utilities
- Streaming support
- Fallback mechanisms

## Best Practices

1. **Type Safety**: Use TypeScript strictly, no `any` types
2. **Error Handling**: Catch and log all errors gracefully
3. **Validation**: Use Zod for input validation
4. **Testing**: Achieve >80% code coverage
5. **Documentation**: Document all public APIs
6. **Security**: Never log sensitive data
7. **Performance**: Implement caching where appropriate
8. **Compatibility**: Test with multiple elizaOS versions
9. **Dependencies**: Minimize external dependencies
10. **Versioning**: Follow semantic versioning

## Output Checklist

After generating a plugin:

✅ Directory structure created
✅ Package configuration
✅ TypeScript configuration
✅ Type definitions
✅ Actions implemented
✅ Providers implemented
✅ Services implemented
✅ Tests written (>80% coverage)
✅ Documentation complete
✅ Examples provided
✅ Environment template
✅ Build scripts configured

Then display:

🔌 Plugin "@elizaos/plugin-{name}" created successfully!

📋 Summary:
Name: @elizaos/plugin-{name}
Actions: {count}
Providers: {count}
Services: {count}
Dependencies: {list}

📂 Structure:
✅ src/index.ts - Plugin entry point
✅ src/actions/ - Action implementations
✅ src/providers/ - Provider implementations
✅ src/services/ - Service implementations
✅ tests/ - Test suite
✅ README.md - Documentation

🚀 Next steps:

- Install dependencies: npm install

- Build plugin: npm run build

- Run tests: npm test

- Test integration with character

- Publish to npm: npm publish

📖 Read README.md for usage instructions

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

developer-portal-generator

No summary provided by upstream source.

Repository SourceNeeds Review
General

threejs-scene-builder

No summary provided by upstream source.

Repository SourceNeeds Review
General

deployment-helper

No summary provided by upstream source.

Repository SourceNeeds Review