Documentation Index Fetch the complete documentation index at: https://docs.elizaos.ai/llms.txt
Use this file to discover all available pages before exploring further.
20 minutes. That’s all it takes to build a plugin that generates AI videos from text prompts. No boilerplate, no complex setup - just code that works.
What We’ll Build
This guide shows how to build a fal.ai plugin that lets your agent generate 6-second, 768p videos from text prompts using the MiniMax Hailuo-02 model. For architectural concepts, see Plugin Architecture .
You’ll learn:
Actions (what the agent can DO)
Progressive development (start simple, organize as you grow)
Local plugin testing (character.plugins array method)
Plugin testing (component and E2E tests)
For component details and patterns, see Plugin Components and Plugin Patterns .
Step 1: Quick Start
Create Project and Plugin
Create a project with a plugin inside using CLI commands:
Create project
elizaos create --type project my-eliza-project
Configure when prompted:
Database : PgLite (perfect for local development)
Model : OpenAI
Create plugin inside project
elizaos create --type plugin plugin-fal-ai
When prompted, choose Quick Plugin (we don’t need frontend UI) Your structure now looks like: my-eliza-project/
├── src/character.ts # Default Eliza character
└── plugin-fal-ai/ # 👈 Plugin lives alongside project
├── src/
│ ├── index.ts # Plugin exports
│ ├── plugin.ts # Main plugin (start here)
│ └── __tests__/ # Plugin tests
└── package.json
Add plugin to character
In my-eliza-project/src/character.ts, add the local path to Eliza’s plugins array: export const character : Character = {
name: 'Eliza' ,
plugins: [
'@elizaos/plugin-sql' ,
'@elizaos/plugin-openai' ,
'@elizaos/plugin-bootstrap' ,
'./plugin-fal-ai'
],
};
Connect and Test
Build plugin and test connection
The plugin needs to be built first to create the dist/ folder that ElizaOS loads from: # Build the plugin first
cd plugin-fal-ai
bun run build
# Go back to project and start
cd ..
elizaos start
Verify it’s loaded:
Check the console logs for Successfully loaded plugin 'plugin-fal-ai'
Visit http://localhost:3000 → click your agent → Plugins tab
Step 2: Development
Research the API
Let’s research what we want to build by exploring fal.ai for a good text-to-video model. MiniMax Hailuo-02 Text to Video looks pretty good.
Navigate to the JavaScript/Typescript section of the docs to see how to call the API:
Install: bun add @fal-ai/client
Import: import { fal } from "@fal-ai/client"
Use: fal.subscribe("model-endpoint", { input: {...} })
Returns: { data, requestId }
Now we know exactly what to build and how to call it, so let’s start developing our plugin.
Edit Default Plugin Template
Add fal.ai dependency
cd plugin-fal-ai
bun add @fal-ai/client
This adds the fal.ai client package to your plugin dependencies.
Study the template structure
Open plugin-fal-ai/src/plugin.ts to see the sample code patterns for plugins:
quickAction - example Action (what agent can DO)
quickProvider - example Provider (gives agent CONTEXT)
StarterService - example Service (manages state/connections)
Plugin events, routes, models - other comprehensive patterns
Create your text-to-video action using plugin patterns
Copy the plugin file and rename it to create your action: mkdir src/actions
cp src/plugin.ts src/actions/generateVideo.ts
Now let’s edit the example plugin into our generateVideo action: Add the fal.ai import (from the fal.ai docs): src/actions/generateVideo.ts
import {
Action , ActionResult , IAgentRuntime , Memory , HandlerCallback , State , logger
} from '@elizaos/core' ;
import { fal } from '@fal-ai/client' ;
Update the action identity for video generation: const quickAction : Action = {
export const generateVideoAction: Action = {
name: 'QUICK_ACTION' ,
name: 'TEXT_TO_VIDEO' ,
similes: [ 'GREET' , 'SAY_HELLO' , 'HELLO_WORLD' ],
similes: [ 'CREATE_VIDEO' , 'MAKE_VIDEO' , 'GENERATE_VIDEO' , 'VIDEO_FROM_TEXT' ],
description: 'Responds with a simple hello world message' ,
description: 'Generate a video from text using MiniMax Hailuo-02' ,
Replace validation with API key check: validate : async ( _runtime , _message , _state ) => {
return true ; // Always valid
},
validate : async ( runtime : IAgentRuntime , message : Memory ) => {
const falKey = runtime . getSetting ( 'FAL_KEY' );
if ( ! falKey ) {
logger . error ( 'FAL_KEY not found in environment variables' );
return false ;
}
return true ;
},
Replace hello world logic with video generation: handler : async ( _runtime , message , _state , _options , callback ) => {
const response = 'Hello world!' ;
if ( callback ) {
await callback ({
text: response ,
actions: [ 'QUICK_ACTION' ],
source: message . content . source ,
});
}
return {
text: response ,
success: true ,
data: { actions: [ 'QUICK_ACTION' ], source: message . content . source }
};
},
handler : async (
runtime : IAgentRuntime ,
message : Memory ,
state : State | undefined ,
options : any ,
callback ?: HandlerCallback
) : Promise < ActionResult > => {
try {
fal . config ({ credentials: runtime . getSetting ( 'FAL_KEY' ) });
let prompt = message . content . text . replace ( / ^ ( create video: | make video: ) / i , '' ). trim ();
if ( ! prompt ) return { success: false , text: 'I need a description' };
const result = await fal . subscribe ( "fal-ai/minimax/hailuo-02/standard/text-to-video" , {
input: { prompt , duration: "6" }, logs: true
});
const videoUrl = result . data . video . url ;
if ( callback ) await callback ({ text: `✅ Video ready! ${ videoUrl } ` });
return { success: true , text: 'Video generated' , data: { videoUrl , prompt } };
} catch ( error ) {
return { success: false , text: `Failed: ${ error . message } ` };
}
},
Update examples for video conversations: examples : [
[{
name: '{{name1}}' ,
content: { text: 'Can you say hello?' }
}, {
name: '{{name2}}' ,
content: { text: 'hello world!' , actions: [ 'QUICK_ACTION' ] }
}]
],
examples : [
[{ name: '{{user}}' , content: { text: 'Create video: dolphins jumping' } },
{ name: '{{agent}}' , content: { text: 'Creating video!' , actions: [ 'TEXT_TO_VIDEO' ] }}]
],
};
Update index.ts to use your action
Finally, update src/index.ts to use our new plugin: import { Plugin } from '@elizaos/core' ;
import { generateVideoAction } from './actions/generateVideo' ;
export const falaiPlugin : Plugin = {
name: 'fal-ai' ,
description: 'Generate videos using fal.ai MiniMax Hailuo-02' ,
actions: [ generateVideoAction ],
providers: [],
services: []
};
export default falaiPlugin ;
export { generateVideoAction };
You can reference plugin.ts as well as other plugins from the Plugin Registry to see other plugin component examples (providers, services, etc.) as you expand your plugin.
Add Configuration
Get your fal.ai API key
Get an API key from fal.ai and copy/paste it into your .env: PGLITE_DATA_DIR = ./.eliza/.elizadb
OPENAI_API_KEY = your_openai_key_here
FAL_KEY = your_fal_key_here
Step 3: Testing
Test Plugin Functionality
Verify your plugin works as expected:
Test the updated plugin
First rebuild your plugin to effect our changes, then start from project root: # Build the plugin first
cd plugin-fal-ai
bun run build
# Start from project root
cd ..
elizaos start
Test video generation
Try your new action by chatting with Eliza in the GUI (http://localhost:3000):
"Create video: dolphins jumping in ocean"
"Make video: cat playing piano"
"Generate video: sunset over mountains"
You should see the video generation process and get a URL to view the result!
Plugin Component Tests
Plugins come default with component and E2E tests. Let’s add custom component tests:
Add a component test
Update plugin-fal-ai/src/__tests__/plugin.test.ts: src/__tests__/plugin.test.ts
import { describe , it , expect } from 'bun:test' ;
import { falaiPlugin , generateVideoAction } from '../index' ;
describe ( 'FAL AI Plugin' , () => {
it ( 'action validates with FAL_KEY' , async () => {
const mockRuntime = {
getSetting : ( key : string ) => key === 'FAL_KEY' ? 'test-key' : null
};
const isValid = await generateVideoAction . validate ( mockRuntime as any , {} as any );
expect ( isValid ). toBe ( true );
});
});
Run component tests
cd plugin-fal-ai
elizaos test --type component
Plugin E2E Tests
Let’s also add a custom E2E test:
Add an E2E test
Update src/__tests__/e2e/plugin-fal-ai.e2e.ts: src/__tests__/e2e/plugin-fal-ai.e2e.ts
export const FalAiTestSuite = {
name: 'fal-ai-video-generation' ,
tests: [{
name: 'should find video action in runtime' ,
fn : async ( runtime ) => {
const action = runtime . actions . find ( a => a . name === 'TEXT_TO_VIDEO' );
if ( ! action ) throw new Error ( 'TEXT_TO_VIDEO action not found' );
}
}]
};
Run E2E tests
cd plugin-fal-ai
elizaos test --type e2e
Step 4: Possible Next Steps
Congratulations! You now have a working video generation plugin. Here are some ways you can improve it:
Enhance Your Action
Add more similes - Handle requests like “animate this”, “video of”, “show me a clip of”
Better examples - Add more conversation examples so Eliza learns different chat patterns
Error handling - Handle rate limits, invalid prompts, or API timeouts
Add Plugin Components
Providers - Give your agent context about recent videos or video history
Evaluators - Track analytics, log successful generations, or rate video quality
Services - Add queueing for multiple video requests or caching for common prompts
The possibilities are endless!
See Also
Publish a Plugin Share your plugin with the elizaOS community
Contribute to Core Help improve elizaOS by contributing to the core framework
Plugin Registry Explore existing plugins and find inspiration
CLI Reference Master all elizaOS CLI commands for plugin development