Skip to main content

Introduction

This guide will walk you through creating a simple AI agent that can hold conversations and perform actions. By the end, you’ll have a working agent running on your machine.
Prerequisites: Make sure you’ve completed the Installation guide before starting.

Step 1: Create Your First Agent

Let’s create a simple conversational agent using the AgentRuntime from @elizaos/core.
1

Create a new TypeScript file

In your project directory, create a file named my-first-agent.ts:
touch my-first-agent.ts
2

Import the core dependencies

Open the file and add these imports:
my-first-agent.ts
import { AgentRuntime, corePlugin } from "@elizaos/core";
import { v4 as uuidv4 } from "uuid";
3

Define your agent's character

Create a character configuration that defines your agent’s personality and capabilities:
my-first-agent.ts
const character = {
  name: "MyFirstAgent",
  bio: [
    "I am a helpful AI assistant built with elizaOS.",
    "I can answer questions and help with various tasks.",
  ],
  topics: [
    "technology",
    "programming",
    "artificial intelligence",
  ],
  adjectives: [
    "helpful",
    "friendly",
    "knowledgeable",
  ],
  style: {
    all: [
      "be concise and clear",
      "use examples when helpful",
    ],
    chat: [
      "be conversational and friendly",
    ],
  },
};
The character configuration shapes your agent’s personality. Experiment with different bio entries, topics, and style guidelines to create unique agents!
4

Initialize the AgentRuntime

Create and initialize your agent runtime:
my-first-agent.ts
async function main() {
  // Create the runtime with your character and plugins
  const runtime = new AgentRuntime({
    character,
    plugins: [
      corePlugin, // Provides core actions, providers, and evaluators
    ],
  });
  
  // Initialize the runtime (loads plugins, connects to database, etc.)
  await runtime.initialize();
  
  console.log(`✅ Agent "${character.name}" initialized and ready!`);
  
  return runtime;
}

main().catch(console.error);

Step 2: Add Conversation Handling

Now let’s make your agent interactive by adding the ability to process messages:
1

Create a message processing function

Add this function to handle incoming messages:
my-first-agent.ts
async function sendMessage(
  runtime: AgentRuntime,
  text: string
) {
  // Create a unique room ID for the conversation
  const roomId = uuidv4();
  
  // Create a user entity ID
  const userId = uuidv4();
  
  // Create the message object
  const message = {
    entityId: userId,
    roomId: roomId,
    content: {
      text: text,
      type: "TEXT" as const,
    },
  };
  
  console.log(`\n👤 You: ${text}`);
  
  // Process the message through the runtime
  const response = await runtime.handleMessage(message);
  
  console.log(`🤖 ${character.name}: ${response.responseContent.text}`);
  
  return response;
}
2

Test your agent

Update your main() function to send a test message:
my-first-agent.ts
async function main() {
  const runtime = new AgentRuntime({
    character,
    plugins: [corePlugin],
  });
  
  await runtime.initialize();
  
  console.log(`✅ Agent "${character.name}" initialized and ready!`);
  
  // Send a test message
  await sendMessage(
    runtime,
    "Hello! Can you tell me about elizaOS?"
  );
}

main().catch(console.error);
3

Run your agent

Execute your agent with bun:
OPENAI_API_KEY=your-key-here bun run my-first-agent.ts
You should see output like:
✅ Agent "MyFirstAgent" initialized and ready!

👤 You: Hello! Can you tell me about elizaOS?
🤖 MyFirstAgent: elizaOS is an open-source framework for building...

Step 3: Make It Interactive

Let’s add a CLI interface so you can have real conversations with your agent:
1

Add readline for user input

Import Node.js readline at the top of your file:
my-first-agent.ts
import { createInterface } from "node:readline";
2

Create an interactive loop

Add this interactive function:
my-first-agent.ts
async function startChat(runtime: AgentRuntime) {
  const rl = createInterface({
    input: process.stdin,
    output: process.stdout,
  });
  
  const roomId = uuidv4();
  const userId = uuidv4();
  
  console.log("\n💬 Chat started! Type 'exit' to quit.\n");
  
  const ask = () => {
    rl.question("You: ", async (input) => {
      const text = input.trim();
      
      if (text.toLowerCase() === "exit") {
        console.log("\n👋 Goodbye!");
        rl.close();
        process.exit(0);
      }
      
      if (text) {
        const message = {
          entityId: userId,
          roomId: roomId,
          content: { text, type: "TEXT" as const },
        };
        
        const response = await runtime.handleMessage(message);
        console.log(`${character.name}: ${response.responseContent.text}\n`);
      }
      
      ask(); // Continue the conversation
    });
  };
  
  ask();
}
3

Update main() to start the chat

my-first-agent.ts
async function main() {
  const runtime = new AgentRuntime({
    character,
    plugins: [corePlugin],
  });
  
  await runtime.initialize();
  
  console.log(`✅ Agent "${character.name}" initialized and ready!`);
  
  // Start interactive chat
  await startChat(runtime);
}

main().catch(console.error);
4

Run the interactive agent

OPENAI_API_KEY=your-key-here bun run my-first-agent.ts
Now you can have a full conversation:
✅ Agent "MyFirstAgent" initialized and ready!
💬 Chat started! Type 'exit' to quit.

You: What is elizaOS?
MyFirstAgent: elizaOS is an open-source framework...

You: How do I add plugins?
MyFirstAgent: You can add plugins to your AgentRuntime...

Step 4: Add Custom Actions

Let’s extend your agent with a custom action that can perform a specific task:
1

Define a custom action

Add this custom action that tells the current time:
my-first-agent.ts
const timeAction = {
  name: "GET_TIME",
  description: "Returns the current date and time when the user asks for it.",
  
  validate: async (context: any) => {
    // Check if the message is asking about time
    const text = context.message?.content?.text?.toLowerCase() || "";
    return text.includes("time") || text.includes("date");
  },
  
  handler: async (context: any) => {
    const now = new Date();
    const timeString = now.toLocaleString();
    
    return {
      success: true,
      message: `The current time is ${timeString}`,
    };
  },
  
  examples: [[
    {
      user: "user",
      content: { text: "What time is it?" },
    },
    {
      user: "assistant",
      content: { 
        text: "The current time is 3:45 PM on March 3, 2026",
        action: "GET_TIME",
      },
    },
  ]],
};
2

Create a custom plugin

Wrap your action in a plugin:
my-first-agent.ts
const customPlugin = {
  name: "custom-plugin",
  description: "My custom actions",
  actions: [timeAction],
};
3

Add the plugin to your runtime

my-first-agent.ts
const runtime = new AgentRuntime({
  character,
  plugins: [
    corePlugin,
    customPlugin, // Add your custom plugin
  ],
});
4

Test your custom action

Run your agent and ask for the time:
OPENAI_API_KEY=your-key-here bun run my-first-agent.ts
You: What time is it?
MyFirstAgent: The current time is 3:45 PM on March 3, 2026

Complete Example

Here’s the complete code for your first agent:
import { AgentRuntime, corePlugin } from "@elizaos/core";
import { v4 as uuidv4 } from "uuid";
import { createInterface } from "node:readline";

const character = {
  name: "MyFirstAgent",
  bio: [
    "I am a helpful AI assistant built with elizaOS.",
    "I can answer questions and help with various tasks.",
  ],
  topics: ["technology", "programming", "artificial intelligence"],
  adjectives: ["helpful", "friendly", "knowledgeable"],
  style: {
    all: ["be concise and clear", "use examples when helpful"],
    chat: ["be conversational and friendly"],
  },
};

const timeAction = {
  name: "GET_TIME",
  description: "Returns the current date and time when the user asks for it.",
  validate: async (context: any) => {
    const text = context.message?.content?.text?.toLowerCase() || "";
    return text.includes("time") || text.includes("date");
  },
  handler: async (context: any) => {
    const now = new Date();
    return {
      success: true,
      message: `The current time is ${now.toLocaleString()}`,
    };
  },
  examples: [[
    { user: "user", content: { text: "What time is it?" } },
    { 
      user: "assistant", 
      content: { 
        text: "The current time is 3:45 PM on March 3, 2026",
        action: "GET_TIME",
      },
    },
  ]],
};

const customPlugin = {
  name: "custom-plugin",
  description: "My custom actions",
  actions: [timeAction],
};

async function startChat(runtime: AgentRuntime) {
  const rl = createInterface({
    input: process.stdin,
    output: process.stdout,
  });
  
  const roomId = uuidv4();
  const userId = uuidv4();
  
  console.log("\n💬 Chat started! Type 'exit' to quit.\n");
  
  const ask = () => {
    rl.question("You: ", async (input) => {
      const text = input.trim();
      
      if (text.toLowerCase() === "exit") {
        console.log("\n👋 Goodbye!");
        rl.close();
        process.exit(0);
      }
      
      if (text) {
        const message = {
          entityId: userId,
          roomId: roomId,
          content: { text, type: "TEXT" as const },
        };
        
        const response = await runtime.handleMessage(message);
        console.log(`${character.name}: ${response.responseContent.text}\n`);
      }
      
      ask();
    });
  };
  
  ask();
}

async function main() {
  const runtime = new AgentRuntime({
    character,
    plugins: [corePlugin, customPlugin],
  });
  
  await runtime.initialize();
  
  console.log(`✅ Agent "${character.name}" initialized and ready!`);
  
  await startChat(runtime);
}

main().catch(console.error);

Using WASM Runtime (Alternative)

You can also use the Rust-based WASM runtime for better performance:
import * as elizaos from "@elizaos/rust/pkg-node/elizaos.js";
import { createInterface } from "node:readline";

async function main() {
  console.log("=== elizaOS WASM Chat ===");

  const runtime = elizaos.WasmAgentRuntime.create(
    JSON.stringify({
      name: "WasmBot",
      bio: "A fast chat bot running on WASM",
      system: "Be friendly and concise.",
    })
  );
  await runtime.initialize();

  const handler = new elizaos.JsModelHandler({
    handle: async (paramsJson: string): Promise<string> => {
      const params = JSON.parse(paramsJson);
      const prompt = params.prompt ?? "";
      // Your model logic here
      return `Echo: ${prompt}`;
    },
  });

  runtime.registerModelHandler("TEXT_LARGE", handler);

  const rl = createInterface({
    input: process.stdin,
    output: process.stdout,
  });

  while (true) {
    const input = await new Promise<string>((resolve) =>
      rl.question("You: ", resolve)
    );
    
    if (input.toLowerCase() === "exit") break;

    const messageJson = JSON.stringify({
      entityId: elizaos.generateUUID(),
      roomId: elizaos.generateUUID(),
      content: { text: input },
    });

    const responseJson = await runtime.handleMessage(messageJson);
    const response = JSON.parse(responseJson);

    console.log(`Bot: ${response.responseContent.text}`);
  }

  rl.close();
}

main().catch(console.error);

Next Steps

Congratulations! You’ve built your first AI agent with elizaOS. Here’s what to explore next:

What You Can Build

Discover use cases from chatbots to autonomous agents

Core Concepts

Deep dive into AgentRuntime, Actions, and Providers

Add Plugins

Integrate Discord, Telegram, databases, and more

Examples

Browse more complete examples and templates
Join our Discord community to share your agent and get help from other developers!

Build docs developers (and LLMs) love