Monorepo Workflow
Complete guide to working with Eliza's monorepo structure, including package development, build processes, and publishing workflows
Eliza uses a modern monorepo architecture powered by Bun, Lerna, and Turbo to manage multiple packages efficiently. This guide covers everything you need to know about developing, building, and publishing packages in the Eliza ecosystem.
Monorepo Overview
The Eliza monorepo is structured to support rapid development and deployment of AI agents with a plugin-based architecture.
Technology Stack
- Bun (v1.2.15) - JavaScript runtime and package manager
- Lerna (v8.1.4) - Multi-package repository management
- Turbo (v2.5.4) - Build system and task orchestration
- TypeScript (v5.8.2) - Type safety across all packages
- Node.js (v23.3.0) - Runtime environment
Directory Structure
Development Workflow
Initial Setup
-
Clone the repository
git clone https://github.com/elizaos/eliza.git cd eliza
-
Install dependencies
bun install
This automatically runs the
postinstall
script which initializes submodules. -
Build all packages
bun run build
Development Commands
Starting Development Environment
The most efficient way to develop is using the integrated dev environment:
# Start full development environment with hot reload
bun run dev
This command:
- Builds the CLI server
- Starts the backend server
- Waits for server health check
- Starts Vite dev server with HMR for the frontend
- Provides coordinated logging from all services
Individual Package Development
# Start CLI in development mode
bun run start
# Start with debug logging
bun run start:debug
# Start the web app
bun run start:app
# Start documentation site
bun run start:docs
Build System
Eliza uses Turbo for orchestrating builds across packages. The build pipeline respects package dependencies automatically.
Build Commands
# Build all packages (except docs)
bun run build
# Build specific packages
bun run build:cli # Build CLI only
bun run build:core # Build core package
bun run build:client # Build client package
bun run build:docs # Build documentation
# Clean build (removes all build artifacts)
bun run clean
Turbo Configuration
The turbo.json
file defines task pipelines:
{
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"test": {
"dependsOn": ["^build"],
"outputs": ["coverage/**"]
}
}
}
Key features:
^build
means "build dependencies first"- Automatic caching of build outputs
- Parallel execution where possible
Package Development
Creating a New Package
-
Create package directory
mkdir packages/my-new-package cd packages/my-new-package
-
Initialize package.json
{ "name": "@elizaos/my-new-package", "version": "1.2.0", "type": "module", "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { "build": "tsup", "dev": "tsup --watch", "test": "bun test" }, "dependencies": { "@elizaos/core": "workspace:*" } }
-
Add tsup configuration
// tsup.config.ts import { defineConfig } from "tsup"; export default defineConfig({ entry: ["src/index.ts"], outDir: "dist", clean: true, format: ["esm"], target: "node18", dts: true, });
Local Package Development
For developing packages locally without publishing:
-
Use workspace protocol
{ "dependencies": { "@elizaos/core": "workspace:*" } }
-
Link packages during development Bun automatically resolves workspace dependencies.
-
Test integration
# From your package directory bun run build # From another package that depends on it bun run dev
Plugin Development
Creating a Plugin in the Monorepo
There are two approaches for plugin development:
Option 1: Internal Plugin (Recommended for core plugins)
Use the plugin starter template:
-
Copy the starter
cp -r packages/plugin-starter packages/plugin-myservice cd packages/plugin-myservice
-
Update package.json
{ "name": "@elizaos/plugin-myservice", "description": "My service integration for Eliza", "version": "1.2.0", "private": false }
-
Implement plugin interface
// src/index.ts import { Plugin } from "@elizaos/core"; export const myServicePlugin: Plugin = { name: "myservice", version: "1.0.0", actions: [], providers: [], evaluators: [], }; export default myServicePlugin;
Option 2: External Plugin via Git Submodule (For third-party plugins)
Add external plugins as git submodules:
-
Add the submodule
# Add external plugin repository as submodule git submodule add https://github.com/elizaos-plugins/plugin-telegram packages/plugin-telegram # Initialize and update submodule git submodule update --init --recursive
-
Ensure it's in workspaces
The
packages/*
pattern inpackage.json
will automatically include it:"workspaces": [ "packages/*", "plugin-specification/*" ]
-
Install dependencies
bun install
Using Plugins as Workspace Dependencies
Once a plugin is in the monorepo (either internal or via submodule), use it as a workspace dependency:
// In your character or agent package.json
{
"dependencies": {
"@elizaos/plugin-myservice": "workspace:*",
"@elizaos/plugin-telegram": "workspace:*"
}
}
The workspace:*
protocol ensures Bun uses the local version of the plugin from the monorepo instead of trying to fetch it from npm.
Benefits of Workspace Dependencies
- Hot Reload: Changes to plugins are immediately available
- Type Safety: TypeScript can resolve types across packages
- Version Consistency: All packages use the same plugin version
- Faster Builds: No network fetches for local dependencies
Plugin Configuration
Plugins can define configuration requirements:
{
"agentConfig": {
"pluginType": "elizaos:plugin:1.0.0",
"pluginParameters": {
"API_KEY": {
"type": "string",
"description": "API key for the service"
}
}
}
}
Testing
Running Tests
# Run all tests
bun test
# Run tests for specific packages
bun run test:core
bun run test:client
bun run test:app
# Run tests with coverage
bun test --coverage
# Watch mode
bun test --watch
Test Configuration
Tests are configured per package. The root configuration excludes certain packages:
# Runs tests excluding starter packages and docs
bun test --concurrency 3 \
--filter=!./packages/plugin-starter \
--filter=!./packages/project-starter \
--filter=!./packages/docs
Code Quality
Linting and Formatting
# Run ESLint and Prettier
bun run lint
# Format code
bun run format
# Check formatting
bun run format:check
# Pre-commit hook (runs automatically)
bun run pre-commit
Git Hooks
The project uses Husky for Git hooks:
- Pre-commit: Runs linting on staged files
- Configured via
.husky/
directory
Publishing Workflow
Version Management
Eliza uses Lerna for version management:
# Version all packages
bun run release
# Alpha release
bun run release:alpha
Publishing Process
-
Update versions
lerna version --no-private --force-publish
-
Build all packages
bun run build
-
Run linting
bun run lint
-
Publish to npm
lerna publish from-package --no-private
Publishing Configuration
- Only public packages are published (not those marked
"private": true
) - Uses Bun as the npm client
- Publishes from the
dist
directory
Advanced Workflows
Database Migrations
ElizaOS uses a dynamic migration system that automatically handles database schema changes:
- Automatic Migration: Migrations run automatically when the server starts
- Plugin-Based Schemas: Each plugin defines its schema which is discovered and migrated dynamically
- No Manual Steps: There's no manual migration process - everything is handled by the
DatabaseMigrationService
// Example: Plugin with schema
export const plugin: Plugin = {
name: '@elizaos/plugin-example',
schema: mySchema, // Drizzle ORM schema
// ... other plugin properties
}
The migration service will:
- Discover plugin schemas on startup
- Create tables and constraints as needed
- Handle schema updates automatically
The bun run migrate
commands in package.json are for development purposes only and are not used in the standard workflow.
Docker Development
# Build Docker image
bun run docker:build
# Run container
bun run docker:run
# Access container shell
bun run docker:bash
# All-in-one
bun run docker
Performance Optimization
-
Use Turbo caching
- Turbo automatically caches build outputs
- Clean cache with
bun run clean
-
Parallel execution
- Tests run with limited concurrency to prevent overload
- Builds run in parallel where possible
-
Watch modes
- Use
bun run dev
for automatic rebuilds - Individual packages support
--watch
flag
- Use
Troubleshooting
Common Issues
-
Build failures
# Clean everything and rebuild bun run clean
-
Dependency issues
# Reinstall dependencies rm -rf node_modules bun.lockb bun install
-
Type errors
- Ensure TypeScript versions match across packages
- Check
resolutions
in root package.json
Debug Mode
Enable debug logging:
cross-env LOG_LEVEL=debug bun run start
Best Practices
- Always use workspace protocol for internal dependencies
- Run tests before committing - use pre-commit hooks
- Use Turbo for builds - it handles dependencies automatically
- Keep packages focused - one responsibility per package
- Document plugin interfaces - use TypeScript types
- Version packages together - use Lerna for consistency