Files
wehub-resource-sync 426e9eeabd
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Waiting to run
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Waiting to run
Build Agent Image / build-and-push (push) Waiting to run
Chat shell gestures / Chat shell gesture + parity e2e (push) Waiting to run
Cloud Gateway Discord / Test (push) Waiting to run
Cloud Gateway Webhook / Test (push) Waiting to run
Cloud Tests / lint-and-types (push) Waiting to run
Cloud Tests / unit-tests (push) Waiting to run
Cloud Tests / integration-tests (push) Waiting to run
Cloud Tests / e2e-tests (push) Blocked by required conditions
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Deploy Apps Worker (Product 2) / Determine environment (push) Waiting to run
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Blocked by required conditions
Deploy Eliza Provisioning Worker / Determine environment (push) Waiting to run
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Blocked by required conditions
Dev Smoke / Classify changed paths (push) Waiting to run
Dev Smoke / bun run dev onboarding chat (push) Blocked by required conditions
Dev Smoke / Vite HMR dependency-level smoke (push) Blocked by required conditions
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Waiting to run
Publish @elizaos/example-code / check_npm (push) Waiting to run
Publish @elizaos/example-code / publish_npm (push) Blocked by required conditions
Publish @elizaos/plugin-elizacloud / verify_version (push) Waiting to run
Publish @elizaos/plugin-elizacloud / publish_npm (push) Blocked by required conditions
Sandbox Live Smoke / Sandbox live smoke (push) Waiting to run
Snap Build & Test / Build Snap (amd64) (push) Waiting to run
Snap Build & Test / Build Snap (arm64) (push) Waiting to run
supply-chain / sbom (push) Waiting to run
supply-chain / vulnerability-scan (push) Waiting to run
Build, Push & Deploy to Phala Cloud / build-and-push (push) Waiting to run
Test Packaging / Validate Packaging Configs (push) Waiting to run
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Waiting to run
Test Packaging / Pack & Test JS Tarballs (push) Waiting to run
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Waiting to run
UI Fixture E2E / ui-fixture-e2e (push) Waiting to run
UI Fixture E2E / fixture-e2e (push) Waiting to run
UI Story Gate / story-gate (push) Waiting to run
vault-ci / test (macos-latest) (push) Waiting to run
vault-ci / test (ubuntu-latest) (push) Waiting to run
vault-ci / test (windows-latest) (push) Waiting to run
vault-ci / app-core wiring tests (push) Waiting to run
verify-patches / verify patches/CHECKSUMS.sha256 (push) Waiting to run
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Waiting to run
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Waiting to run
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Waiting to run
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Waiting to run
Voice Benchmark Smoke / voice bench smoke summary (push) Blocked by required conditions
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Waiting to run
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Waiting to run
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Waiting to run
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Waiting to run
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Waiting to run
Test Packaging / Build & Test PyPI Package (push) Waiting to run
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

956 lines
22 KiB
Plaintext

---
title: "Development"
description: "Build plugins for elizaOS in TypeScript, Python, or Rust"
---
## Your Plugin in 3 Steps
<Tabs>
<Tab title="TypeScript">
1. **Scaffold** - `elizaos create my-plugin --template plugin` 2.
**Build** - Add actions, providers, or services 3. **Test** - `bun run
test`
</Tab>
<Tab title="Python">
1. **Create** - `mkdir plugin-my-plugin && cd plugin-my-plugin` 2. **Build**
- Define your plugin with actions and providers 3. **Test** - `pytest`
</Tab>
<Tab title="Rust">
1. **Create** - `cargo new plugin-my-plugin --lib` 2. **Build** - Implement
the Plugin trait 3. **Test** - `cargo test`
</Tab>
</Tabs>
That's it. No complex setup, no boilerplate to maintain.
<Tip>
**30 minutes to your first plugin.** Focus on your logic, not infrastructure.
elizaOS plugins work identically across TypeScript, Python, and Rust.
</Tip>
## Quick Start: Scaffolding Plugins with CLI
The easiest way to create a new plugin is using the elizaOS CLI, which provides interactive scaffolding with pre-configured templates.
### Using `elizaos create`
The CLI offers two plugin templates to get you started quickly:
```bash
# Interactive plugin creation
elizaos create
# Or specify the name directly
elizaos create my-plugin --template plugin
```
When creating a plugin, you'll be prompted to choose between:
1. **Quick Plugin (Backend Only)** - Simple backend-only plugin without frontend
- Perfect for: API integrations, blockchain actions, data providers
- Includes: Basic plugin structure, actions, providers, services
- No frontend components or UI routes
2. **Full Plugin (with Frontend)** - Complete plugin with React frontend and API routes
- Perfect for: Plugins that need web UI, dashboards, or visual components
- Includes: Everything from Quick Plugin + React frontend, Vite setup, API routes
- Tailwind CSS pre-configured for styling
### Quick Plugin Structure
After running `elizaos create` and selecting "Quick Plugin", you'll get:
```
plugin-my-plugin/
├── src/
│ ├── index.ts # Plugin manifest
│ ├── actions/ # Your agent actions
│ │ └── example.ts
│ ├── providers/ # Context providers
│ │ └── example.ts
│ └── types/ # TypeScript types
│ └── index.ts
├── package.json # Pre-configured with elizaos deps
├── tsconfig.json # TypeScript config
├── build.ts # Build script using Bun.build
└── README.md # Plugin documentation
```
### Full Plugin Structure
Selecting "Full Plugin" adds frontend capabilities:
```text
plugin-my-plugin/
├── src/
│ ├── index.ts # Plugin manifest with routes
│ ├── actions/
│ ├── providers/
│ ├── types/
│ └── frontend/ # React frontend
│ ├── App.tsx
│ ├── main.tsx
│ └── components/
├── public/ # Static assets
├── index.html # Frontend entry
├── vite.config.ts # Vite configuration
├── tailwind.config.js # Tailwind setup
└── [other config files]
```
### After Scaffolding
Once your plugin is created:
```bash
# Navigate to your plugin
cd plugin-my-plugin
# Install dependencies (automatically done by CLI)
bun install
# Build your plugin for distribution
bun run build
# Run tests
bun run test
```
The scaffolded plugin includes:
- ✅ Proper TypeScript configuration
- ✅ Build setup with Bun.build (and Vite for full plugins)
- ✅ Example action and provider to extend
- ✅ Integration with `@elizaos/core`
- ✅ Development scripts ready to use
- ✅ Basic tests structure
<Tip>
The CLI templates follow all elizaOS conventions and best practices, making it
easy to get started without worrying about configuration.
</Tip>
## Manual Plugin Creation
If you prefer to create a plugin manually or need custom configuration:
### 1. Initialize the Project
```bash
mkdir plugin-my-custom
cd plugin-my-custom
bun init
```
### 2. Install Dependencies
```bash
# Core dependency
bun add @elizaos/core
# Development dependencies
bun add -d typescript @types/node
```
### 3. Configure TypeScript
Create `tsconfig.json`:
```json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2022"],
"rootDir": "./src",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"types": ["node"]
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
```
### 4. Configure Build
Create `build.ts`:
```typescript
#!/usr/bin/env bun
/**
* Build script for your plugin
* Uses Bun.build for bundling
*/
import { existsSync } from "node:fs";
import { rm } from "node:fs/promises";
const externalDeps = ["@elizaos/core"];
async function buildPlugin() {
console.log("🔨 Building plugin...\n");
// Clean dist directory
if (existsSync("dist")) {
await rm("dist", { recursive: true, force: true });
}
// Build with Bun
console.log("📦 Bundling with Bun...");
const buildResult = await Bun.build({
entrypoints: ["src/index.ts"],
outdir: "dist",
target: "node",
format: "esm",
sourcemap: "external",
minify: false,
external: externalDeps,
});
if (!buildResult.success) {
console.error("Build failed:");
for (const log of buildResult.logs) {
console.error(log);
}
process.exit(1);
}
console.log(`✅ Built ${buildResult.outputs.length} file(s)`);
// Generate type declarations with tsc
console.log("📝 Generating type declarations...");
const tscProcess = Bun.spawn(["bunx", "tsc", "-p", "tsconfig.build.json"], {
stdout: "inherit",
stderr: "inherit",
});
await tscProcess.exited;
if (tscProcess.exitCode !== 0) {
console.error("TypeScript declaration generation failed");
process.exit(1);
}
console.log("\n✅ Build complete!");
}
buildPlugin().catch((error) => {
console.error("Build failed:", error);
process.exit(1);
});
```
### 5. Create Plugin Structure
<Tabs>
<Tab title="TypeScript">
Create `src/index.ts`:
```typescript
import type { Plugin } from "@elizaos/core";
import { myAction } from "./actions/myAction";
import { myProvider } from "./providers/myProvider";
import { MyService } from "./services/myService";
export const myPlugin: Plugin = {
name: "my-custom-plugin",
description: "A custom plugin for elizaOS",
actions: [myAction],
providers: [myProvider],
services: [MyService],
init: async (config, runtime) => {
console.log("Plugin initialized");
},
};
export default myPlugin;
```
</Tab>
<Tab title="Python">
Create `plugin.py`:
```python
from elizaos import Plugin, Action, Provider
from .actions.my_action import my_action
from .providers.my_provider import my_provider
my_plugin = Plugin(
name="my-custom-plugin",
description="A custom plugin for elizaOS",
actions=[my_action],
providers=[my_provider],
)
async def init(config, runtime):
print("Plugin initialized")
my_plugin.init = init
```
</Tab>
<Tab title="Rust">
Create `src/lib.rs`:
```rust
use elizaos::{Plugin, Action, Provider, IAgentRuntime};
use anyhow::Result;
mod actions;
mod providers;
pub fn create_my_plugin() -> Result<Plugin> {
Ok(Plugin {
name: "my-custom-plugin".to_string(),
description: "A custom plugin for elizaOS".to_string(),
actions: vec![actions::my_action()],
providers: vec![providers::my_provider()],
init: Some(Box::new(|_config, _runtime| {
Box::pin(async {
println!("Plugin initialized");
Ok(())
})
})),
..Default::default()
})
}
```
</Tab>
</Tabs>
### 6. Update package.json
```json
{
"name": "@myorg/plugin-custom",
"version": "0.1.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"type": "module",
"scripts": {
"build": "bun run build.ts",
"dev": "bun --hot build.ts",
"test": "vitest"
}
}
```
## Using Your Plugin in Projects
### Option 1: Plugin Inside the Monorepo
If developing within the elizaOS monorepo:
1. Add your plugin to the root `package.json` as a workspace dependency:
```json
{
"dependencies": {
"@yourorg/plugin-myplugin": "workspace:*"
}
}
```
2. Run `bun install` in the root directory
3. Use the plugin in your project:
```typescript
import { myPlugin } from "@yourorg/plugin-myplugin";
const agent = {
name: "MyAgent",
plugins: [myPlugin],
};
```
### Option 2: Plugin Outside the Monorepo
For plugins outside the elizaOS monorepo:
1. In your plugin directory, build and link it:
```bash
# In your plugin directory
bun install
bun run build
bun link
```
2. In your project directory, link the plugin:
```bash
# In your project directory
cd packages/project-starter
bun link @yourorg/plugin-myplugin
```
3. Add to your project's `package.json`:
```json
{
"dependencies": {
"@yourorg/plugin-myplugin": "link:@yourorg/plugin-myplugin"
}
}
```
<Note>
When using `bun link`, remember to rebuild your plugin (`bun run build`) after
making changes for them to be reflected in your project.
</Note>
## Testing Plugins
### Test Environment Setup
#### Directory Structure
```
src/
__tests__/
test-utils.ts # Shared test utilities (real runtime helpers)
index.test.ts # Main plugin tests
actions.test.ts # Action tests
providers.test.ts # Provider tests
evaluators.test.ts # Evaluator tests
services.test.ts # Service tests
actions/
providers/
evaluators/
services/
index.ts
```
#### Base Test Imports
```typescript
import {
describe,
expect,
it,
vi,
beforeEach,
afterEach,
} from "vitest";
import {
type IAgentRuntime,
type Memory,
type State,
type HandlerCallback,
type Action,
type Provider,
type Evaluator,
ModelType,
logger,
} from "@elizaos/core";
```
### Creating Test Utilities
Create a `test-utils.ts` file with test helpers. All tests use **real runtime instances** with PGLite:
```typescript
import {
type IAgentRuntime,
type Memory,
type State,
type Character,
type UUID,
} from "@elizaos/core";
import { AgentRuntime } from "@elizaos/core";
import { v4 as uuidv4 } from "uuid";
/**
* Creates a real AgentRuntime for testing with PGLite database.
* NO MOCKS - all tests use actual runtime infrastructure.
*/
export async function createTestRuntime(
characterOverrides?: Partial<Character>,
): Promise<IAgentRuntime> {
const agentId = uuidv4() as UUID;
const character: Character = {
id: agentId,
name: "TestAgent",
bio: "A test agent",
plugins: [],
settings: {},
...characterOverrides,
};
const runtime = new AgentRuntime({
agentId,
character,
logLevel: "error",
});
await runtime.initialize();
return runtime;
}
/**
* Cleans up a test runtime after tests complete
*/
export async function cleanupRuntime(runtime: IAgentRuntime): Promise<void> {
await runtime.stop();
}
/**
* Creates a test Memory object
*/
export function createTestMemory(overrides?: Partial<Memory>): Memory {
return {
id: uuidv4() as UUID,
entityId: uuidv4() as UUID,
roomId: uuidv4() as UUID,
content: {
text: "Test message",
...overrides?.content,
},
createdAt: Date.now(),
...overrides,
} as Memory;
}
/**
* Creates a test State object
*/
export function createTestState(overrides?: Partial<State>): State {
return {
values: {
test: "value",
...overrides?.values,
},
data: overrides?.data || {},
text: overrides?.text || "Test state",
} as State;
}
```
### Testing Actions
All tests use **real runtime instances** - no mocks:
```typescript
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import { myAction } from "../src/actions/myAction";
import {
createTestRuntime,
cleanupRuntime,
createTestMemory,
createTestState,
} from "./test-utils";
import type { IAgentRuntime, Memory, State } from "@elizaos/core";
describe("MyAction", () => {
let runtime: IAgentRuntime;
let message: Memory;
let state: State;
beforeEach(async () => {
// Create real runtime with PGLite database
runtime = await createTestRuntime();
runtime.setSetting("MY_API_KEY", "test-key");
message = createTestMemory({ content: { text: "Do the thing" } });
state = createTestState();
});
afterEach(async () => {
await cleanupRuntime(runtime);
});
describe("validation", () => {
it("should validate when all requirements are met", async () => {
const isValid = await myAction.validate(runtime, message, state);
expect(isValid).toBe(true);
});
it("should not validate without required setting", async () => {
runtime.setSetting("MY_API_KEY", null);
const isValid = await myAction.validate(runtime, message, state);
expect(isValid).toBe(false);
});
});
describe("handler", () => {
it("should return success ActionResult on successful execution", async () => {
const callback = vi.fn();
const result = await myAction.handler(
runtime,
message,
state,
{},
callback,
);
expect(result.success).toBe(true);
expect(result.text).toContain("completed");
expect(result.values).toHaveProperty("lastActionTime");
expect(callback).toHaveBeenCalled();
});
it("should handle errors gracefully", async () => {
// Remove required setting to trigger error
runtime.setSetting("MY_API_KEY", null);
const result = await myAction.handler(runtime, message, state);
expect(result.success).toBe(false);
expect(result.error).toBeDefined();
expect(result.text).toContain("Failed");
});
});
describe("examples", () => {
it("should have valid example structure", () => {
expect(myAction.examples).toBeDefined();
expect(Array.isArray(myAction.examples)).toBe(true);
// Each example should be a conversation array
for (const example of myAction.examples!) {
expect(Array.isArray(example)).toBe(true);
// Each message should have name and content
for (const message of example) {
expect(message).toHaveProperty("name");
expect(message).toHaveProperty("content");
}
}
});
});
});
```
### Testing Providers
```typescript
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { myProvider } from "../src/providers/myProvider";
import {
createTestRuntime,
cleanupRuntime,
createTestMemory,
createTestState,
} from "./test-utils";
import type { IAgentRuntime, Memory, State } from "@elizaos/core";
describe("MyProvider", () => {
let runtime: IAgentRuntime;
let message: Memory;
let state: State;
beforeEach(async () => {
runtime = await createTestRuntime();
message = createTestMemory();
state = createTestState();
});
afterEach(async () => {
await cleanupRuntime(runtime);
});
it("should return provider result with text and data", async () => {
const result = await myProvider.get(runtime, message, state);
expect(result).toBeDefined();
expect(result.text).toContain("Current");
expect(result.data).toBeDefined();
expect(result.values).toBeDefined();
});
it("should handle missing data gracefully", async () => {
// Test with empty message content
message.content.text = "";
const result = await myProvider.get(runtime, message, state);
expect(result.text).toBeDefined();
});
});
```
### Testing Services
```typescript
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { MyService } from "../src/services/myService";
import { createTestRuntime, cleanupRuntime } from "./test-utils";
import type { IAgentRuntime } from "@elizaos/core";
describe("MyService", () => {
let runtime: IAgentRuntime;
let service: MyService;
beforeEach(async () => {
runtime = await createTestRuntime();
runtime.setSetting("MY_API_KEY", "test-api-key");
});
afterEach(async () => {
if (service) {
await service.stop();
}
await cleanupRuntime(runtime);
});
it("should initialize successfully with valid config", async () => {
service = await MyService.start(runtime);
expect(service).toBeDefined();
expect(service.capabilityDescription).toBeDefined();
});
it("should throw error without API key", async () => {
runtime.setSetting("MY_API_KEY", null);
await expect(MyService.start(runtime)).rejects.toThrow(
"MY_API_KEY not configured",
);
});
it("should clean up resources on stop", async () => {
service = await MyService.start(runtime);
await service.stop();
// Verify cleanup happened
});
});
```
### E2E Testing
For integration testing with a live runtime:
```typescript
// tests/e2e/myPlugin.e2e.ts
export const myPluginE2ETests = {
name: "MyPlugin E2E Tests",
tests: [
{
name: "should execute full plugin flow",
fn: async (runtime: IAgentRuntime) => {
// Create test message
const message: Memory = {
id: generateId(),
entityId: "test-user",
roomId: runtime.agentId,
content: {
text: "Please do the thing",
source: "test",
},
};
// Store message
await runtime.createMemory(message, "messages");
// Compose state
const state = await runtime.composeState(message);
// Execute action
const result = await myAction.handler(
runtime,
message,
state,
{},
async (response) => {
// Verify callback responses
expect(response.text).toBeDefined();
},
);
// Verify result
expect(result.success).toBe(true);
// Verify side effects
const memories = await runtime.getMemories({
roomId: message.roomId,
tableName: "action_results",
count: 1,
});
expect(memories.length).toBeGreaterThan(0);
},
},
],
};
```
### Running Tests
```bash
# Run all tests
npx vitest
# Run specific test file
npx vitest src/__tests__/actions.test.ts
# Run with watch mode
npx vitest --watch
# Run with coverage
npx vitest --coverage
```
### Test Best Practices
1. **Use Real Runtime**: All tests use actual `AgentRuntime` with PGLite - no mocks
2. **Isolate Tests**: Use `beforeEach`/`afterEach` to create and cleanup runtime instances
3. **Test Happy Path and Errors**: Cover both success and failure cases
4. **Test Validation Logic**: Ensure actions validate correctly
5. **Test Examples**: Verify example structures are valid
6. **Test Side Effects**: Verify database writes with real database operations
7. **Use Descriptive Names**: Make test purposes clear
8. **Keep Tests Fast**: PGLite provides fast in-memory database
## Development Workflow
### 1. Development Mode
```bash
# Watch mode with hot reloading
bun run dev
# Run the generated development script when present
bun run dev
```
### 2. Building for Production
```bash
# Build the plugin
bun run build
# Output will be in dist/
```
### 3. Publishing
#### To npm
```bash
# Login to npm
npm login
# Publish
npm publish --access public
```
#### To GitHub Packages
Update `package.json`:
```json
{
"name": "@yourorg/plugin-name",
"publishConfig": {
"registry": "https://npm.pkg.github.com"
}
}
```
Then publish:
```bash
npm publish
```
### 4. Version Management
```bash
# Bump version
npm version patch # 0.1.0 -> 0.1.1
npm version minor # 0.1.0 -> 0.2.0
npm version major # 0.1.0 -> 1.0.0
```
## Debugging
### Enable Debug Logging
```typescript
import { logger } from "@elizaos/core";
// In your plugin
logger.debug("Plugin initialized", { config });
logger.info("Action executed", { result });
logger.error("Failed to connect", { error });
```
### VS Code Debug Configuration
Create `.vscode/launch.json`:
```json
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug Plugin",
"runtimeExecutable": "bun",
"program": "${workspaceFolder}/src/index.ts",
"cwd": "${workspaceFolder}",
"console": "integratedTerminal"
}
]
}
```
## Common Issues and Solutions
### Issue: Plugin not loading
**Solution**: Check that your plugin is properly exported and added to the agent's plugin array.
### Issue: TypeScript errors
**Solution**: Ensure `@elizaos/core` is installed and TypeScript is configured correctly.
### Issue: Service not available
**Solution**: Verify the service is registered in the plugin and started properly.
### Issue: Tests failing with module errors
**Solution**: Make sure your `tsconfig.json` has proper module resolution settings for Bun.
## See Also
<CardGroup cols={2}>
<Card title="Plugin Components" icon="cube" href="/plugins/architecture">
Deep dive into Actions, Providers, Evaluators, and Services
</Card>
<Card title="Common Patterns" icon="lightbulb" href="/plugins/patterns">
Learn proven plugin development patterns
</Card>
<Card title="Plugin Schemas" icon="list" href="/plugins/schemas">
Understand plugin configuration and validation
</Card>
<Card title="Plugin Reference" icon="book" href="/plugins/schemas">
Complete API reference for all interfaces
</Card>
<Card title="Publish a Plugin" icon="upload" href="/plugins/publish">
Share your plugin with the community
</Card>
<Card title="Deploy to Cloud" icon="cloud" href="/eliza-cloud-deployment">
Ship your agent with plugins to production
</Card>
</CardGroup>