Package Organization
Detailed guide to package organization, dependencies, and architectural patterns
Package Organization
ElizaOS follows a well-structured package organization that promotes modularity, reusability, and maintainability. This document provides a comprehensive overview of how packages are organized, their dependencies, and the architectural patterns used throughout the system.
Package Hierarchy
Core Layer
The core layer provides fundamental functionality that all other packages depend on:
@elizaos/core
├── Runtime System
├── Type Definitions
├── Database Abstractions
├── Plugin Interface
├── Memory Management
├── Action Framework
├── Service Architecture
└── Utility Functions
Interface Layer
The interface layer provides user-facing components and APIs:
@elizaos/client # Web-based user interface
@elizaos/cli # Command-line interface
@elizaos/api-client # TypeScript API client
@elizaos/server # Server components
Plugin Layer
The plugin layer extends core functionality:
@elizaos/plugin-sql # Database adapter
@elizaos/plugin-bootstrap # Bootstrap functionality
@elizaos/plugin-dummy-services # Testing services
@elizaos/plugin-starter # Plugin template
Development Layer
The development layer supports development and tooling:
@elizaos/autodoc # Documentation generation
@elizaos/create-eliza # Project scaffolding
@elizaos/docs # Documentation site
Package Dependencies
Dependency Graph
The packages follow a clear dependency hierarchy:
Core Dependencies
The core package has minimal external dependencies:
{
"dependencies": {
"uuid": "^10.0.0",
"zod": "^3.22.4",
"typescript": "5.8.2"
},
"peerDependencies": {
"node": "23.3.0"
}
}
Interface Dependencies
Interface packages depend on core and add UI/API specific dependencies:
// @elizaos/client
{
"dependencies": {
"@elizaos/core": "workspace:*",
"react": "19.1.0",
"react-dom": "19.1.0",
"vite": "^5.0.0"
}
}
// @elizaos/cli
{
"dependencies": {
"@elizaos/core": "workspace:*",
"commander": "^11.0.0",
"inquirer": "^9.2.0"
}
}
Plugin Dependencies
Plugin packages follow a standard dependency pattern:
{
"dependencies": {
"@elizaos/core": "workspace:*"
},
"peerDependencies": {
"specific-plugin-deps": "^1.0.0"
}
}
Package Structure Patterns
Standard Package Structure
Each package follows a consistent structure:
packages/{package-name}/
├── src/
│ ├── index.ts # Main entry point
│ ├── types/ # Type definitions
│ ├── __tests__/ # Unit tests
│ └── [feature-specific]/ # Feature implementations
├── dist/ # Built output
├── package.json # Package configuration
├── tsconfig.json # TypeScript configuration
├── tsconfig.build.json # Build-specific configuration
├── tsup.config.ts # Build configuration
├── bunfig.toml # Bun configuration
└── README.md # Package documentation
Entry Point Pattern
All packages use a standard entry point pattern:
// packages/{package}/src/index.ts
export * from "./types";
export * from "./main-feature";
export * from "./utilities";
// Default export for the main functionality
export { default } from "./main-feature";
Type Organization
Types are organized by domain and exported through barrel exports:
// packages/core/src/types/index.ts
export * from "./agent";
export * from "./components";
export * from "./database";
export * from "./events";
export * from "./plugin";
export * from "./runtime";
export * from "./service";
// ... other type exports
Core Package Deep Dive
Runtime System
The runtime system is the heart of ElizaOS:
// packages/core/src/runtime.ts
export class AgentRuntime implements IAgentRuntime {
// Core properties
readonly agentId: UUID;
readonly character: Character;
public adapter!: IDatabaseAdapter;
// Plugin system
readonly plugins: Plugin[] = [];
readonly actions: Action[] = [];
readonly evaluators: Evaluator[] = [];
readonly providers: Provider[] = [];
// Service management
services = new Map<ServiceTypeName, Service>();
models = new Map<string, ModelHandler[]>();
// Event system
events: Map<string, ((params: any) => Promise<void>)[]> = new Map();
}
Type System
The type system provides comprehensive type safety:
// packages/core/src/types/plugin.ts
export interface Plugin {
name: string;
description: string;
// Optional components
actions?: Action[];
providers?: Provider[];
evaluators?: Evaluator[];
services?: (typeof Service)[];
models?: { [key: string]: ModelHandler };
events?: PluginEvents;
routes?: Route[];
// Configuration
config?: { [key: string]: any };
init?: (config: Record<string, string>, runtime: IAgentRuntime) => Promise<void>;
// Metadata
dependencies?: string[];
priority?: number;
schema?: any;
}
Database Abstraction
Database operations are abstracted through interfaces:
// packages/core/src/types/database.ts
export interface IDatabaseAdapter {
// Core operations
init(): Promise<void>;
close(): Promise<void>;
// Agent operations
createAgent(agent: Partial<Agent>): Promise<boolean>;
getAgent(agentId: UUID): Promise<Agent | null>;
updateAgent(agentId: UUID, agent: Partial<Agent>): Promise<boolean>;
// Memory operations
createMemory(memory: Memory, tableName: string, unique?: boolean): Promise<UUID>;
getMemories(params: GetMemoriesParams): Promise<Memory[]>;
searchMemories(params: SearchMemoriesParams): Promise<Memory[]>;
// Entity operations
createEntity(entity: Entity): Promise<boolean>;
getEntityById(entityId: UUID): Promise<Entity | null>;
updateEntity(entity: Entity): Promise<void>;
// Room operations
createRoom(room: Room): Promise<UUID>;
getRoom(roomId: UUID): Promise<Room | null>;
updateRoom(room: Room): Promise<void>;
// Relationship operations
createRelationship(params: CreateRelationshipParams): Promise<boolean>;
getRelationship(params: GetRelationshipParams): Promise<Relationship | null>;
// Utility operations
log(params: LogParams): Promise<void>;
getCache<T>(key: string): Promise<T | undefined>;
setCache<T>(key: string, value: T): Promise<boolean>;
}
Plugin Architecture
Plugin Interface
All plugins implement the standard Plugin interface:
// Example plugin implementation
export const examplePlugin: Plugin = {
name: "example-plugin",
description: "Example plugin demonstrating the plugin system",
// Initialization
init: async (config: Record<string, string>, runtime: IAgentRuntime) => {
// Plugin initialization logic
},
// Components
actions: [
{
name: "EXAMPLE_ACTION",
description: "Example action",
validate: async (runtime, message, state) => true,
handler: async (runtime, message, state, options, callback) => {
// Action implementation
},
},
],
providers: [
{
name: "EXAMPLE_PROVIDER",
description: "Example provider",
get: async (runtime, message, state) => {
return {
text: "Provider data",
values: {},
data: {},
};
},
},
],
services: [ExampleService],
// Configuration
config: {
EXAMPLE_CONFIG: process.env.EXAMPLE_CONFIG,
},
// Dependencies
dependencies: ["@elizaos/plugin-sql"],
};
Service Architecture
Services provide long-running functionality:
// packages/core/src/types/service.ts
export abstract class Service {
static serviceType: ServiceTypeName;
protected runtime: IAgentRuntime;
constructor(runtime: IAgentRuntime) {
this.runtime = runtime;
}
abstract start(): Promise<void>;
abstract stop(): Promise<void>;
// Static factory method
static async start(runtime: IAgentRuntime): Promise<Service> {
const service = new this(runtime);
await service.start();
return service;
}
}
Action System
Actions define agent capabilities:
// packages/core/src/types/components.ts
export interface Action {
name: string;
similes?: string[];
description: string;
validate: (runtime: IAgentRuntime, message: Memory, state?: State) => Promise<boolean>;
handler: (
runtime: IAgentRuntime,
message: Memory,
state?: State,
options?: any,
callback?: HandlerCallback,
responses?: Memory[]
) => Promise<void>;
examples?: ActionExample[][];
}
Client Package Organization
Component Structure
The client package follows React best practices:
packages/client/src/
├── components/ # Reusable UI components
│ ├── agent-card.tsx # Agent display component
│ ├── chat.tsx # Chat interface
│ ├── memory-viewer.tsx # Memory visualization
│ └── ...
├── hooks/ # Custom React hooks
│ ├── use-agent-management.ts
│ ├── use-socket-chat.ts
│ └── ...
├── lib/ # Utility libraries
│ ├── api-client-config.ts
│ ├── utils.ts
│ └── ...
├── routes/ # Application routes
│ ├── chat.tsx
│ ├── agent-list.tsx
│ └── ...
├── types/ # Client-specific types
│ ├── index.ts
│ └── rooms.ts
└── main.tsx # Application entry point
Hook Pattern
Custom hooks encapsulate complex logic:
// packages/client/src/hooks/use-agent-management.ts
export function useAgentManagement() {
const [agents, setAgents] = useState<Agent[]>([]);
const [loading, setLoading] = useState(false);
const createAgent = useCallback(async (config: AgentConfig) => {
setLoading(true);
try {
const agent = await api.createAgent(config);
setAgents((prev) => [...prev, agent]);
return agent;
} finally {
setLoading(false);
}
}, []);
const deleteAgent = useCallback(async (agentId: UUID) => {
await api.deleteAgent(agentId);
setAgents((prev) => prev.filter((agent) => agent.id !== agentId));
}, []);
return {
agents,
loading,
createAgent,
deleteAgent,
};
}
CLI Package Organization
Command Structure
The CLI package organizes commands by functionality:
packages/cli/src/
├── commands/ # CLI command implementations
│ ├── agent.ts # Agent management commands
│ ├── create.ts # Project creation commands
│ ├── dev.ts # Development commands
│ ├── plugins.ts # Plugin management commands
│ └── start.ts # Agent startup commands
├── utils/ # CLI utilities
│ ├── plugin-creator.ts # Plugin creation utilities
│ ├── package-manager.ts # Package management
│ ├── test-runner.ts # Test execution
│ └── ...
├── templates/ # Project templates
│ ├── plugin-starter/
│ ├── project-starter/
│ └── project-tee-starter/
└── index.ts # CLI entry point
Command Pattern
CLI commands follow a consistent pattern:
// packages/cli/src/commands/agent.ts
export class AgentCommand {
static async start(options: StartOptions) {
// Load configuration
const config = await loadConfig(options.config);
// Initialize runtime
const runtime = new AgentRuntime({
character: config.character,
plugins: config.plugins,
});
// Start agent
await runtime.initialize();
// Handle shutdown
process.on("SIGINT", async () => {
await runtime.stop();
process.exit(0);
});
}
static async create(options: CreateOptions) {
// Create new agent from template
const template = await loadTemplate(options.template);
await createProject(options.name, template);
}
}
Server Package Organization
Server Architecture
The server package provides hosting capabilities:
packages/server/src/
├── index.ts # Server entry point
├── authMiddleware.ts # Authentication middleware
├── bus.ts # Message bus
├── loader.ts # Agent loader
├── types.ts # Server types
├── upload.ts # File upload handling
└── examples/ # Usage examples
├── standalone-server.ts
└── package.json
Middleware Pattern
Server middleware follows Express patterns:
// packages/server/src/authMiddleware.ts
export function createAuthMiddleware(options: AuthOptions) {
return async (req: Request, res: Response, next: NextFunction) => {
try {
const token = extractToken(req);
const user = await validateToken(token);
req.user = user;
next();
} catch (error) {
res.status(401).json({ error: "Unauthorized" });
}
};
}
Build Configuration
TypeScript Configuration
Each package has its own TypeScript configuration:
// packages/{package}/tsconfig.json
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
"composite": true,
"declaration": true,
"declarationMap": true
},
"include": ["src/**/*"],
"exclude": ["dist", "node_modules"]
}
Build Configuration
Packages use tsup for building:
// packages/{package}/tsup.config.ts
import { defineConfig } from "tsup";
export default defineConfig({
entry: ["src/index.ts"],
format: ["esm"],
dts: true,
splitting: false,
sourcemap: true,
clean: true,
outDir: "dist",
external: ["@elizaos/core"],
treeshake: true,
});
Version Management
Workspace Dependencies
Packages use workspace references:
{
"dependencies": {
"@elizaos/core": "workspace:*",
"@elizaos/plugin-sql": "workspace:*"
}
}
Version Synchronization
Lerna manages version synchronization:
{
"version": "1.0.16",
"packages": ["packages/*"],
"command": {
"version": {
"conventionalCommits": true,
"exact": true,
"forcePublish": true
}
}
}
Testing Organization
Test Structure
Tests are organized by package:
packages/{package}/
├── src/
│ └── __tests__/ # Unit tests
│ ├── component.test.ts
│ ├── integration.test.ts
│ └── utils.test.ts
├── e2e/ # End-to-end tests
│ └── feature.test.ts
└── cypress/ # Cypress tests (for UI packages)
└── integration/
Test Configuration
Each package has its own test configuration:
// packages/{package}/package.json
{
"scripts": {
"test": "bun test",
"test:watch": "bun test --watch",
"test:coverage": "bun test --coverage"
}
}
Best Practices
Package Design Principles
- Single Responsibility: Each package has a clear, focused purpose
- Dependency Minimization: Minimal external dependencies
- Clear Interfaces: Well-defined public APIs
- Consistent Structure: Standardized package organization
- Testing: Comprehensive test coverage
Dependency Management
- Workspace References: Use workspace: protocol for internal dependencies
- Peer Dependencies: Mark shared dependencies as peers
- Version Alignment: Keep dependency versions aligned
- Minimal Footprint: Avoid unnecessary dependencies
Publishing Strategy
- Semantic Versioning: Follow semantic versioning
- Conventional Commits: Use conventional commit messages
- Automated Publishing: Use Lerna for coordinated publishing
- Documentation: Maintain comprehensive documentation
The package organization in ElizaOS provides a solid foundation for building, maintaining, and extending the agent framework while ensuring code quality, reusability, and developer productivity.