| title | description |
|---|---|
Character Interface |
Define your agent personality, knowledge, and behavior in one file |
A character file is all you need to create a unique agent. Here's the minimum:
export const character: Character = {
name: "Chef Mario",
bio: "A passionate Italian chef who loves sharing recipes and cooking tips.",
plugins: ["@elizaos/plugin-openai"],
};That's it. Your agent now has a name, personality, and can chat. Everything else is optional.
**Start minimal, add complexity later.** Most fields have sensible defaults. Only add what you need.In elizaOS, the distinction between a Character and an Agent is fundamental:
- Character: A configuration object that defines an agent's personality, capabilities, and settings
- Agent: A runtime instance created from a Character, with additional status tracking and lifecycle management
Think of a Character as a blueprint and an Agent as the living instance built from that blueprint. For hands-on implementation, see Customize an Agent. For runtime details, see Runtime and Lifecycle.
The transformation from Character to Agent happens at runtime:
// Character: Static configuration
interface Character {
name: string;
bio: string | string[];
// ... configuration properties
}
// Agent: Runtime instance with status
interface Agent extends Character {
enabled?: boolean;
status?: 'active' | 'inactive';
createdAt: number;
updatedAt: number;
}The complete TypeScript interface for agents:
| Property | Type | Required | Description |
|---|---|---|---|
name |
string | β | Agent's display name |
bio |
string | string[] | β | Background/personality description |
id |
UUID | β | Unique identifier (auto-generated if not provided) |
username |
string | β | Social media username |
system |
string | β | System prompt override |
templates |
object | β | Custom prompt templates |
adjectives |
string[] | β | Character traits (e.g., "helpful", "creative") |
topics |
string[] | β | Conversation topics the agent knows |
knowledge |
array | β | Facts, files, or directories of knowledge |
messageExamples |
array[][] | β | Example conversations (2D array) |
postExamples |
string[] | β | Example social media posts |
style |
object | β | Writing style for different contexts |
plugins |
string[] | β | Enabled plugin packages |
settings |
object | β | Configuration values |
secrets |
object | β | Sensitive configuration |
The fundamental properties that define who your agent is:
export const character: Character = {
// Required: The agent's display name
name: "TechHelper",
// Optional: Username for social platforms
username: "tech_helper_bot",
// Optional: Unique ID (auto-generated from name if not provided)
id: "550e8400-e29b-41d4-a716-446655440000",
}The bio can be a single string or an array of strings for better organization:
// Single string format
bio: "A helpful AI assistant specializing in technical support and programming guidance."
// Array format (recommended for complex bios)
bio: [
"Expert in web development and open source technologies",
"Specializes in TypeScript, React, and Node.js",
"Helps developers debug issues and learn best practices",
"Friendly and patient teaching style"
]Override the default system prompt to fine-tune agent behavior:
system: `You are a technical support specialist.
Always:
- Provide code examples when relevant
- Explain technical concepts clearly
- Be encouraging to learners
- Admit when you don't know something
Never:
- Be condescending or dismissive
- Assume prior knowledge without checking
- Provide outdated or deprecated solutions`Custom prompt templates for various agent operations:
templates?: {
// Define custom templates for different contexts
messageTemplate?: string | ((params: any) => string);
thoughtTemplate?: string | ((params: any) => string);
actionTemplate?: string | ((params: any) => string);
// Add any custom template keys your plugins need
[key: string]: string | ((params: any) => string);
}Message examples train the agent's conversational style using a 2D array format:
messageExamples: [
// Each sub-array is a complete conversation
[
{
name: "{{user}}",
content: { text: "Can you help me debug this React error?" }
},
{
name: "TechHelper",
content: {
text: "I'd be happy to help! Can you share the error message and the relevant code?"
}
},
{
name: "{{user}}",
content: { text: "It says 'Cannot read property of undefined'" }
},
{
name: "TechHelper",
content: {
text: "This error typically occurs when trying to access a property on a null or undefined object. Let's trace through your code to find where this might be happening. Can you show me the component where this error occurs?"
}
}
],
// Another conversation example
[
{
name: "{{user}}",
content: { text: "What's the difference between let and const?" }
},
{
name: "TechHelper",
content: {
text: "`const` declares a variable that cannot be reassigned, while `let` allows reassignment. For example:\n```js\nconst x = 1;\nx = 2; // Error!\n\nlet y = 1;\ny = 2; // Works fine\n```\nNote that `const` objects can still have their properties modified."
}
}
]
]Define writing styles for different contexts:
style: {
// General style rules applied everywhere
all: [
"Be concise and clear",
"Use technical terms accurately",
"Provide examples when helpful"
],
// Chat-specific style
chat: [
"Be conversational and friendly",
"Ask clarifying questions",
"Break down complex topics"
],
// Social media post style
post: [
"Keep it under 280 characters when possible",
"Use relevant hashtags",
"Be engaging and informative"
]
}Configure the agent's knowledge base:
knowledge: [
// Simple string facts
"I specialize in TypeScript and React",
"I can help with debugging and code reviews",
// File reference
{
path: "./knowledge/react-best-practices.md",
shared: true // Available to all agents
},
// Directory of knowledge files
{
directory: "./knowledge/tutorials",
shared: false // Only for this agent
}
]plugins: [
"@elizaos/plugin-bootstrap", // Core functionality
"@elizaos/plugin-discord", // Discord integration
"@elizaos/plugin-openai", // OpenAI models
"./custom-plugins/my-plugin" // Local plugin
]Load plugins conditionally based on environment variables:
plugins: [
// Always loaded
"@elizaos/plugin-bootstrap",
"@elizaos/plugin-sql",
// Conditionally loaded based on API keys
...(process.env.OPENAI_API_KEY ? ["@elizaos/plugin-openai"] : []),
...(process.env.ANTHROPIC_API_KEY ? ["@elizaos/plugin-anthropic"] : []),
// Platform plugins
...(process.env.DISCORD_API_TOKEN ? ["@elizaos/plugin-discord"] : []),
...(process.env.TELEGRAM_BOT_TOKEN ? ["@elizaos/plugin-telegram"] : []),
// Feature flags
...(process.env.ENABLE_VOICE ? ["@elizaos/plugin-voice"] : []),
]General configuration values:
settings: {
// Model configuration
model: "gpt-4",
temperature: 0.7,
maxTokens: 2000,
// Behavior settings
responseTimeout: 30000,
maxMemorySize: 1000,
// Custom settings for plugins
voiceEnabled: true,
avatar: "https://example.com/avatar.png"
}Sensitive data that should never be committed:
secrets: {
// API keys
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
DATABASE_URL: process.env.DATABASE_URL,
// OAuth tokens
DISCORD_TOKEN: process.env.DISCORD_TOKEN,
// Encryption keys
ENCRYPTION_KEY: process.env.ENCRYPTION_KEY
}Here's a comprehensive character configuration for production use:
import { Character } from '@elizaos/core';
export const character: Character = {
name: 'Eliza',
username: 'eliza_ai',
bio: [
"An advanced AI assistant powered by elizaOS",
"Specializes in technical support and creative problem-solving",
"Continuously learning and adapting to user needs",
"Built with privacy and security in mind"
],
system: `You are Eliza, a helpful and knowledgeable AI assistant.
Core principles:
- Be helpful, harmless, and honest
- Provide accurate, well-researched information
- Admit uncertainty when appropriate
- Respect user privacy and boundaries
- Adapt your communication style to the user's needs`,
adjectives: [
"helpful",
"knowledgeable",
"patient",
"creative",
"professional"
],
topics: [
"programming",
"web development",
"artificial intelligence",
"problem solving",
"technology trends"
],
messageExamples: [
[
{
name: "{{user}}",
content: { text: "Hello!" }
},
{
name: "Eliza",
content: {
text: "Hello! I'm Eliza, your AI assistant. How can I help you today?"
}
}
],
[
{
name: "{{user}}",
content: { text: "Can you help me with a coding problem?" }
},
{
name: "Eliza",
content: {
text: "Of course! I'd be happy to help with your coding problem. Please share the details - what language are you using, what are you trying to achieve, and what specific issue are you encountering?"
}
}
]
],
postExamples: [
"π Just discovered an elegant solution to the N+1 query problem in GraphQL. DataLoader is a game-changer! #GraphQL #WebDev",
"Reminder: Clean code is not about being clever, it's about being clear. Your future self will thank you. π #CodingBestPractices",
"The best error message is the one that tells you exactly what went wrong AND how to fix it. π§ #DeveloperExperience"
],
style: {
all: [
"Be concise but comprehensive",
"Use emoji sparingly and appropriately",
"Maintain a professional yet approachable tone"
],
chat: [
"Be conversational and engaging",
"Show genuine interest in helping",
"Use markdown for code and formatting"
],
post: [
"Be informative and thought-provoking",
"Include relevant hashtags",
"Keep within platform character limits"
]
},
knowledge: [
"I'm built on the elizaOS framework",
"I can integrate with multiple platforms simultaneously",
"I maintain context across conversations",
{
path: "./knowledge/technical-docs",
shared: true
}
],
plugins: [
'@elizaos/plugin-sql',
'@elizaos/plugin-bootstrap',
...(process.env.ANTHROPIC_API_KEY ? ['@elizaos/plugin-anthropic'] : []),
...(process.env.OPENAI_API_KEY ? ['@elizaos/plugin-openai'] : []),
...(process.env.DISCORD_API_TOKEN ? ['@elizaos/plugin-discord'] : []),
...(process.env.TELEGRAM_BOT_TOKEN ? ['@elizaos/plugin-telegram'] : []),
],
settings: {
secrets: {}, // Populated from environment
avatar: 'https://elizaos.github.io/eliza-avatars/eliza.png',
model: 'gpt-4',
temperature: 0.7,
maxTokens: 2000,
memoryLimit: 1000,
conversationLength: 32
}
};Use the built-in validation to ensure your character is properly configured:
import { validateCharacter } from '@elizaos/core';
const validation = validateCharacter(character);
if (!validation.valid) {
console.error('Character validation failed:', validation.errors);
}import { describe, it, expect } from 'vitest';
import { character } from './character';
describe('Character Configuration', () => {
it('should have required fields', () => {
expect(character.name).toBeDefined();
expect(character.bio).toBeDefined();
});
it('should have valid message examples', () => {
expect(character.messageExamples).toBeInstanceOf(Array);
character.messageExamples?.forEach(conversation => {
expect(conversation).toBeInstanceOf(Array);
conversation.forEach(message => {
expect(message).toHaveProperty('name');
expect(message).toHaveProperty('content');
});
});
});
it('should have environment-appropriate plugins', () => {
if (process.env.OPENAI_API_KEY) {
expect(character.plugins).toContain('@elizaos/plugin-openai');
}
});
});- Keep personality traits consistent: Ensure bio, adjectives, and style align
- Provide diverse message examples: Cover various interaction patterns
- Use TypeScript for type safety: Leverage type checking for configuration
- Load plugins conditionally: Check for API keys before loading
- Order plugins by dependency: Load core plugins before dependent ones
- Use environment variables for secrets: Never hardcode sensitive data
- Validate before deployment: Always validate character configuration
- Test conversation flows: Ensure message examples produce desired behavior
- Document custom settings: Clearly explain any custom configuration
- Version your characters: Track changes to character configurations
Converting a JSON character to TypeScript:
// Before: character.json
{
"name": "MyAgent",
"bio": "An AI assistant"
}
// After: character.ts
import { Character } from '@elizaos/core';
export const character: Character = {
name: "MyAgent",
bio: "An AI assistant"
};