426e9eeabd
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
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
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) Has been cancelled
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) Has been cancelled
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) Has been cancelled
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) Has been cancelled
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) Has been cancelled
694 lines
19 KiB
Markdown
694 lines
19 KiB
Markdown
---
|
|
title: "Local Plugins"
|
|
sidebarTitle: "Local Plugins"
|
|
description: "Develop plugins locally without publishing to npm."
|
|
---
|
|
|
|
This guide covers developing plugins locally without publishing to npm -- custom integrations, private plugins, rapid prototyping, and ejecting upstream plugins for modification.
|
|
|
|
Maintainer note: this document is for runtime/user plugin paths under `~/.local/state/eliza/plugins/*`. Eliza source-checkout development of first-party packages uses the repo-local workspaces under `eliza/plugins/*` and `eliza/packages/*` by default; the old sibling-checkout flow is no longer the primary path in this repo.
|
|
|
|
## Table of Contents
|
|
|
|
1. [Plugin Locations](#plugin-locations)
|
|
2. [Plugin Loading Priority](#plugin-loading-priority)
|
|
3. [Creating a Local Plugin](#creating-a-local-plugin)
|
|
4. [Configuration](#configuration)
|
|
5. [Plugin Installer](#plugin-installer)
|
|
6. [Ejecting Upstream Plugins](#ejecting-upstream-plugins)
|
|
7. [Development Workflow](#development-workflow)
|
|
8. [Debugging](#debugging)
|
|
9. [Environment Variables](#environment-variables)
|
|
10. [Migrating to npm](#migrating-to-npm)
|
|
|
|
---
|
|
|
|
## Plugin Locations
|
|
|
|
Eliza discovers plugins from three locations under the state directory (`~/.local/state/eliza/` by default):
|
|
|
|
### 1. Ejected Plugins
|
|
|
|
Upstream plugins cloned locally for modification:
|
|
|
|
```
|
|
~/.local/state/eliza/plugins/ejected/<plugin-name>/
|
|
```
|
|
|
|
These are created by the eject system (see [Ejecting Upstream Plugins](#ejecting-upstream-plugins)). Each subdirectory is a full git repo with editable source.
|
|
|
|
### 2. Installed Plugins
|
|
|
|
Plugins installed at runtime via the plugin manager or CLI:
|
|
|
|
```
|
|
~/.local/state/eliza/plugins/installed/<sanitised-name>/
|
|
```
|
|
|
|
Each plugin gets an isolated directory with its own `package.json` and `node_modules/`. The installer creates a minimal `{ "private": true, "dependencies": {} }` package.json, then runs `bun add <package>` (or `npm install` as fallback) inside that directory.
|
|
|
|
### 3. Custom (Drop-in) Plugins
|
|
|
|
Hand-written plugins placed directly in the custom directory:
|
|
|
|
```
|
|
~/.local/state/eliza/plugins/custom/<your-plugin>/
|
|
```
|
|
|
|
Any subdirectory here with a `package.json` is auto-discovered at startup. This is the simplest way to add a local plugin -- just drop it in and restart.
|
|
|
|
### 4. Extra Load Paths
|
|
|
|
Additional directories can be specified in `eliza.json`:
|
|
|
|
```json
|
|
{
|
|
"plugins": {
|
|
"load": {
|
|
"paths": [
|
|
"~/shared-plugins",
|
|
"/opt/team-plugins"
|
|
]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Each directory is scanned the same way as `plugins/custom/` -- subdirectories with a `package.json` are treated as plugins.
|
|
|
|
### Full Directory Layout
|
|
|
|
```
|
|
~/.local/state/eliza/
|
|
├── eliza.json # Main config file
|
|
└── plugins/
|
|
├── ejected/ # Git-cloned upstream plugins for editing
|
|
│ └── plugin-telegram/
|
|
│ ├── .upstream.json
|
|
│ ├── package.json
|
|
│ ├── src/
|
|
│ └── dist/
|
|
├── installed/ # Runtime-installed plugins (managed by plugin-installer)
|
|
│ └── _elizaos_plugin-twitter/
|
|
│ ├── package.json
|
|
│ └── node_modules/
|
|
└── custom/ # Hand-written drop-in plugins
|
|
└── my-plugin/
|
|
├── package.json
|
|
├── src/
|
|
└── dist/
|
|
```
|
|
|
|
---
|
|
|
|
## Plugin Loading Priority
|
|
|
|
When multiple sources provide the same plugin name, Eliza uses this precedence (highest first):
|
|
|
|
| Priority | Source | Path | Use case |
|
|
|----------|--------|------|----------|
|
|
| 1 | **Ejected** | `~/.local/state/eliza/plugins/ejected/` | Modifying upstream plugin source |
|
|
| 2 | **Workspace override** | Internal dev mechanism | Eliza contributors only |
|
|
| 3 | **Official npm** (with install record) | `node_modules/@elizaos/plugin-*` | Standard `@elizaos/*` plugins prefer bundled copies |
|
|
| 4 | **User-installed** (with install record) | `~/.local/state/eliza/plugins/installed/` | Third-party plugins installed at runtime |
|
|
| 5 | **Local @eliza** | `src/plugins/` (compiled dist) | Built-in Eliza plugins |
|
|
| 6 | **npm fallback** | `import(name)` | Last resort dynamic import |
|
|
|
|
Custom/drop-in plugins are merged into the install records before resolution, so they participate in priorities 3-4 depending on their package name.
|
|
|
|
The deny list (`plugins.deny` in `eliza.json`) takes absolute precedence -- denied plugins are never loaded regardless of source.
|
|
|
|
---
|
|
|
|
## Creating a Local Plugin
|
|
|
|
### Step 1: Create the Directory
|
|
|
|
```bash
|
|
mkdir -p ~/.local/state/eliza/plugins/custom/my-plugin/src
|
|
cd ~/.local/state/eliza/plugins/custom/my-plugin
|
|
```
|
|
|
|
### Step 2: Initialize package.json
|
|
|
|
```bash
|
|
cat > package.json << 'EOF'
|
|
{
|
|
"name": "my-plugin",
|
|
"version": "1.0.0",
|
|
"type": "module",
|
|
"main": "dist/index.js",
|
|
"scripts": {
|
|
"build": "tsc",
|
|
"dev": "tsc --watch"
|
|
},
|
|
"dependencies": {
|
|
"@elizaos/core": "alpha"
|
|
}
|
|
}
|
|
EOF
|
|
```
|
|
|
|
### Step 3: Add tsconfig.json
|
|
|
|
```bash
|
|
cat > tsconfig.json << 'EOF'
|
|
{
|
|
"compilerOptions": {
|
|
"target": "ES2022",
|
|
"module": "ESNext",
|
|
"moduleResolution": "bundler",
|
|
"declaration": true,
|
|
"declarationMap": true,
|
|
"sourceMap": true,
|
|
"outDir": "./dist",
|
|
"rootDir": "./src",
|
|
"strict": true,
|
|
"esModuleInterop": true,
|
|
"skipLibCheck": true
|
|
},
|
|
"include": ["src"],
|
|
"exclude": ["node_modules", "dist"]
|
|
}
|
|
EOF
|
|
```
|
|
|
|
### Step 4: Write the Plugin
|
|
|
|
```typescript
|
|
// src/index.ts
|
|
import type { Plugin, Action, Provider } from "@elizaos/core";
|
|
|
|
const greetAction: Action = {
|
|
name: "GREET_USER",
|
|
similes: ["SAY_HELLO", "WELCOME"],
|
|
description: "Greets the user by name",
|
|
validate: async () => true,
|
|
handler: async (runtime, message, state, options) => {
|
|
const name = options?.parameters?.name ?? "friend";
|
|
return {
|
|
success: true,
|
|
text: `Hello, ${name}! Welcome to Eliza.`,
|
|
};
|
|
},
|
|
parameters: [
|
|
{
|
|
name: "name",
|
|
description: "Name of the person to greet",
|
|
required: false,
|
|
schema: { type: "string", default: "friend" },
|
|
},
|
|
],
|
|
};
|
|
|
|
const statusProvider: Provider = {
|
|
name: "myPluginStatus",
|
|
get: async (runtime, message, state) => {
|
|
return {
|
|
text: "My plugin is active and running.",
|
|
};
|
|
},
|
|
};
|
|
|
|
const plugin: Plugin = {
|
|
name: "my-plugin",
|
|
description: "A local development plugin",
|
|
actions: [greetAction],
|
|
providers: [statusProvider],
|
|
init: async (config, runtime) => {
|
|
runtime.logger?.info("[my-plugin] Initialized successfully");
|
|
},
|
|
};
|
|
|
|
export default plugin;
|
|
```
|
|
|
|
### Step 5: Install Dependencies and Build
|
|
|
|
```bash
|
|
cd ~/.local/state/eliza/plugins/custom/my-plugin
|
|
bun install
|
|
bun run build
|
|
```
|
|
|
|
### Step 6: Restart Eliza
|
|
|
|
```bash
|
|
# If running in terminal
|
|
eliza start
|
|
|
|
# Or restart via the agent chat
|
|
# Type: /restart
|
|
```
|
|
|
|
On startup, you should see in the logs:
|
|
|
|
```
|
|
[eliza] Discovered 1 custom plugin(s): my-plugin
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration
|
|
|
|
### Allow and Deny Lists
|
|
|
|
Control which plugins load via `eliza.json`:
|
|
|
|
```json
|
|
{
|
|
"plugins": {
|
|
"allow": ["my-plugin", "telegram", "@elizaos/plugin-discord"],
|
|
"deny": ["@elizaos/plugin-shell"]
|
|
}
|
|
}
|
|
```
|
|
|
|
When `allow` is set, only listed plugins load (plus core plugins). The `deny` list always wins -- a denied plugin is never loaded even if it appears in `allow`.
|
|
|
|
Plugin names can be specified as:
|
|
- Full package name: `@elizaos/plugin-telegram`
|
|
- Short id: `telegram` (resolves to `@elizaos/plugin-telegram`)
|
|
- Custom name: `my-plugin` (matches the `name` field in your plugin's `package.json`)
|
|
|
|
### Per-Plugin Settings
|
|
|
|
Configure individual plugins under `plugins.entries`:
|
|
|
|
```json
|
|
{
|
|
"plugins": {
|
|
"entries": {
|
|
"my-plugin": {
|
|
"enabled": true,
|
|
"config": {
|
|
"apiEndpoint": "https://api.example.com",
|
|
"maxRetries": 3
|
|
}
|
|
},
|
|
"telegram": {
|
|
"enabled": false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Setting `enabled: false` on an entry prevents that plugin from loading, even if auto-enable logic would otherwise activate it.
|
|
|
|
### Auto-Enable System
|
|
|
|
Eliza automatically enables plugins based on your configuration:
|
|
|
|
- **Connector plugins**: If a connector (telegram, discord, slack, etc.) has credentials configured under `connectors`, its plugin is auto-enabled.
|
|
- **Provider plugins**: If an API key env var is set (e.g., `ANTHROPIC_API_KEY`), the corresponding provider plugin is auto-enabled.
|
|
- **Feature plugins**: If a feature flag is enabled under `features`, its plugin is auto-enabled.
|
|
|
|
This happens at startup via `applyPluginAutoEnable()` and does not modify your config file -- it only affects the in-memory plugin set for that session.
|
|
|
|
---
|
|
|
|
## Plugin Installer
|
|
|
|
The plugin installer (`plugin-installer.ts`) handles runtime installation of plugins from the registry.
|
|
|
|
### How It Works
|
|
|
|
1. **Resolves** the plugin name against the plugin registry
|
|
2. **Installs** via `bun add` (preferred) or `npm install` (fallback) into an isolated directory at `~/.local/state/eliza/plugins/installed/<sanitised-name>/`
|
|
3. **Falls back** to `git clone` if the npm install fails
|
|
4. **Validates** that the installed plugin has a resolvable entry point
|
|
5. **Records** the installation in `eliza.json` under `plugins.installs`
|
|
6. **Triggers** an agent restart to load the new plugin
|
|
|
|
### Package Name Sanitisation
|
|
|
|
The installer sanitises package names for directory names by replacing non-alphanumeric characters (except `.`, `-`, `_`) with underscores. For example, `@elizaos/plugin-x` becomes `_elizaos_plugin-twitter`.
|
|
|
|
### Install Record
|
|
|
|
Each installed plugin is tracked in `eliza.json`:
|
|
|
|
```json
|
|
{
|
|
"plugins": {
|
|
"installs": {
|
|
"@elizaos/plugin-x": {
|
|
"source": "npm",
|
|
"spec": "@elizaos/plugin-x@1.0.0",
|
|
"installPath": "/Users/you/.eliza/plugins/installed/_elizaos_plugin-twitter",
|
|
"version": "1.0.0",
|
|
"installedAt": "2026-02-19T12:00:00.000Z"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Serialisation
|
|
|
|
The installer uses a serialisation lock to prevent concurrent installs from corrupting the config. Multiple install requests are queued and executed sequentially.
|
|
|
|
### Uninstalling
|
|
|
|
Uninstallation removes the plugin directory from disk and deletes its record from `eliza.json`. Core/built-in plugins cannot be uninstalled. The uninstaller refuses to delete directories outside `~/.local/state/eliza/plugins/installed/` as a safety measure.
|
|
|
|
---
|
|
|
|
## Ejecting Upstream Plugins
|
|
|
|
The eject system lets you clone an upstream plugin's source, modify it, and have Eliza load your local copy instead of the npm package.
|
|
|
|
### Eject via Agent Chat
|
|
|
|
```
|
|
eject the telegram plugin so I can edit its source
|
|
```
|
|
|
|
### Eject Manually
|
|
|
|
```bash
|
|
git clone --branch 1.x --depth 1 \
|
|
https://github.com/elizaos-plugins/plugin-telegram.git \
|
|
~/.local/state/eliza/plugins/ejected/plugin-telegram
|
|
|
|
cd ~/.local/state/eliza/plugins/ejected/plugin-telegram
|
|
bun install
|
|
bun run build
|
|
```
|
|
|
|
### Upstream Tracking
|
|
|
|
Each ejected plugin has a `.upstream.json` at its root:
|
|
|
|
```json
|
|
{
|
|
"$schema": "eliza-upstream-v1",
|
|
"source": "github:elizaos-plugins/plugin-telegram",
|
|
"gitUrl": "https://github.com/elizaos-plugins/plugin-telegram.git",
|
|
"branch": "1.x",
|
|
"commitHash": "093613e...",
|
|
"ejectedAt": "2026-02-19T08:00:00Z",
|
|
"npmPackage": "@elizaos/plugin-telegram",
|
|
"npmVersion": "1.6.4",
|
|
"lastSyncAt": null,
|
|
"localCommits": 0
|
|
}
|
|
```
|
|
|
|
### Syncing with Upstream
|
|
|
|
```bash
|
|
cd ~/.local/state/eliza/plugins/ejected/plugin-telegram
|
|
git fetch origin
|
|
git pull --rebase origin 1.x
|
|
bun run build
|
|
```
|
|
|
|
Or via agent chat: `sync the ejected telegram plugin`
|
|
|
|
### Reverting (Reinject)
|
|
|
|
Remove the ejected directory to fall back to the npm version:
|
|
|
|
```bash
|
|
rm -rf ~/.local/state/eliza/plugins/ejected/plugin-telegram
|
|
# Restart eliza -- it will load the npm version again
|
|
```
|
|
|
|
Or via agent chat: `reinject the telegram plugin`
|
|
|
|
---
|
|
|
|
## Development Workflow
|
|
|
|
### Edit-Build-Restart Cycle
|
|
|
|
The standard development loop for local plugins:
|
|
|
|
```bash
|
|
# Terminal 1: Watch and rebuild on changes
|
|
cd ~/.local/state/eliza/plugins/custom/my-plugin
|
|
bun run dev # runs tsc --watch
|
|
|
|
# Terminal 2: Run eliza
|
|
eliza start
|
|
```
|
|
|
|
After making changes, the TypeScript watcher rebuilds `dist/` automatically. You still need to restart the agent to pick up the new build:
|
|
|
|
- Type `/restart` in the agent chat, or
|
|
- Press Ctrl+C and run `eliza start` again
|
|
|
|
### Testing Your Plugin
|
|
|
|
Chat with the agent and trigger your action:
|
|
|
|
```
|
|
You: Greet me as Alice
|
|
Agent: Hello, Alice! Welcome to Eliza.
|
|
```
|
|
|
|
Check the logs for your plugin's initialization message and any debug output.
|
|
|
|
### Quick Iteration Without tsc --watch
|
|
|
|
If you prefer manual builds:
|
|
|
|
```bash
|
|
cd ~/.local/state/eliza/plugins/custom/my-plugin
|
|
bun run build && eliza start
|
|
```
|
|
|
|
### Using Source Directly (Development Only)
|
|
|
|
For rapid prototyping, you can point `main` at the TypeScript source:
|
|
|
|
```json
|
|
{
|
|
"main": "src/index.ts"
|
|
}
|
|
```
|
|
|
|
Eliza's runtime can import TypeScript files directly in dev mode. Switch to `dist/index.js` before distributing.
|
|
|
|
### Configuration-Driven Loading
|
|
|
|
Load a plugin from any path using `eliza.json`:
|
|
|
|
```json
|
|
{
|
|
"plugins": {
|
|
"entries": {
|
|
"my-plugin": {
|
|
"enabled": true,
|
|
"path": "~/projects/my-plugin/dist"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Path supports tilde expansion (`~/`) and both relative and absolute paths. This is useful when your plugin lives outside the standard plugin directories.
|
|
|
|
### Rapid Iteration Tips
|
|
|
|
1. **Use `LOG_LEVEL=debug`** to see plugin loading, discovery, and initialization logs
|
|
2. **Check plugin load order** in debug logs -- look for `Loading plugin: your-plugin-name`
|
|
3. **Test actions via chat** -- type messages that trigger your action's validate function
|
|
4. **Use the REST API** for programmatic testing:
|
|
|
|
```bash
|
|
# List loaded plugins
|
|
curl http://localhost:18789/api/plugins
|
|
|
|
# Search the registry
|
|
curl http://localhost:18789/api/registry/search?q=my-plugin
|
|
```
|
|
|
|
5. **Run multiple instances** with different configs using `ELIZA_STATE_DIR`:
|
|
|
|
```bash
|
|
# Instance with your dev plugin
|
|
ELIZA_STATE_DIR=./state-dev eliza start
|
|
|
|
# Instance with production plugins
|
|
ELIZA_STATE_DIR=./state-prod eliza start
|
|
```
|
|
|
|
---
|
|
|
|
## Debugging
|
|
|
|
### Log Levels
|
|
|
|
Eliza reads the log level from `LOG_LEVEL` env var or `logging.level` in config. If `LOG_LEVEL` is set in the environment, it takes precedence over the config value.
|
|
|
|
```bash
|
|
# Verbose logging via environment variable
|
|
LOG_LEVEL=debug eliza start
|
|
```
|
|
|
|
Or set it in `eliza.json`:
|
|
|
|
```json
|
|
{
|
|
"logging": {
|
|
"level": "debug"
|
|
}
|
|
}
|
|
```
|
|
|
|
Available levels: `debug`, `info`, `warn`, `error` (default).
|
|
|
|
### Plugin Logging
|
|
|
|
Use the runtime logger inside your plugin:
|
|
|
|
```typescript
|
|
init: async (config, runtime) => {
|
|
runtime.logger?.debug("[my-plugin] Detailed debug info", { config });
|
|
runtime.logger?.info("[my-plugin] Plugin initialized");
|
|
runtime.logger?.warn("[my-plugin] Something looks off");
|
|
runtime.logger?.error("[my-plugin] Something failed", { error: "details" });
|
|
},
|
|
```
|
|
|
|
### Source Maps
|
|
|
|
Enable source maps for readable stack traces pointing to your TypeScript source:
|
|
|
|
```bash
|
|
NODE_OPTIONS="--enable-source-maps" eliza start
|
|
```
|
|
|
|
Make sure `"sourceMap": true` is set in your `tsconfig.json` (included in the template above).
|
|
|
|
### VS Code Debugging
|
|
|
|
Create `.vscode/launch.json` in your project:
|
|
|
|
```json
|
|
{
|
|
"version": "0.2.0",
|
|
"configurations": [
|
|
{
|
|
"type": "node",
|
|
"request": "launch",
|
|
"name": "Debug Eliza",
|
|
"runtimeExecutable": "bun",
|
|
"runtimeArgs": ["run", "eliza", "start"],
|
|
"cwd": "${workspaceFolder}",
|
|
"env": {
|
|
"LOG_LEVEL": "debug"
|
|
},
|
|
"console": "integratedTerminal",
|
|
"skipFiles": ["<node_internals>/**"]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Set breakpoints in your plugin's TypeScript files and launch with F5.
|
|
|
|
### Common Issues
|
|
|
|
**Plugin not discovered at startup:**
|
|
- Verify the plugin directory is directly under `~/.local/state/eliza/plugins/custom/` (not nested deeper)
|
|
- Confirm `package.json` exists and has a `name` field
|
|
- Check that `main` in `package.json` points to an existing file
|
|
- Look for `[eliza] Discovered N custom plugin(s)` in the startup logs
|
|
|
|
**Plugin discovered but fails to load:**
|
|
- Run `bun run build` -- the `dist/` directory may be missing
|
|
- Verify the default export is a valid Plugin object with `name` and `description`
|
|
- Check for import errors in the logs: `LOG_LEVEL=debug eliza start`
|
|
|
|
**Plugin denied or filtered out:**
|
|
- Check `plugins.deny` in `eliza.json` -- your plugin name may be listed
|
|
- If `plugins.allow` is set, your plugin must be in the allowlist
|
|
- Check `plugins.entries.<name>.enabled` is not set to `false`
|
|
|
|
**TypeScript compilation errors:**
|
|
```bash
|
|
cd ~/.local/state/eliza/plugins/custom/my-plugin
|
|
bunx tsc --noEmit # Type-check without emitting
|
|
```
|
|
|
|
---
|
|
|
|
## Environment Variables
|
|
|
|
These environment variables affect plugin paths and behavior. They are defined in `eliza/packages/agent/src/config/paths.ts`.
|
|
|
|
| Variable | Default | Description |
|
|
|----------|---------|-------------|
|
|
| `ELIZA_STATE_DIR` | `~/.local/state/eliza` | Override the state directory. Changes where plugins, config, and credentials are stored. |
|
|
| `ELIZA_CONFIG_PATH` | `~/.local/state/eliza/eliza.json` | Override the config file path directly. |
|
|
| `ELIZA_OAUTH_DIR` | `~/.local/state/eliza/credentials` | Override the OAuth credentials directory. |
|
|
| `LOG_LEVEL` | `error` | Set log verbosity: `debug`, `info`, `warn`, `error`. |
|
|
| `ELIZA_DISABLE_WORKSPACE_PLUGIN_OVERRIDES` | unset | Set to `1` to disable workspace plugin overrides (dev-only mechanism). |
|
|
| `ELIZA_WORKSPACE_ROOT` | unset | Override the workspace root for plugin resolution. When set, only this directory is searched for local plugin sources. |
|
|
|
|
When `ELIZA_STATE_DIR` is set, all derived paths change accordingly:
|
|
- Plugins: `$ELIZA_STATE_DIR/plugins/installed/`, `$ELIZA_STATE_DIR/plugins/custom/`, `$ELIZA_STATE_DIR/plugins/ejected/`
|
|
- Config: `$ELIZA_STATE_DIR/eliza.json` (unless `ELIZA_CONFIG_PATH` is also set)
|
|
- Models cache: `$ELIZA_STATE_DIR/models/`
|
|
|
|
---
|
|
|
|
## Migrating to npm
|
|
|
|
When your plugin is ready for distribution:
|
|
|
|
### 1. Update package.json
|
|
|
|
```json
|
|
{
|
|
"name": "@yourorg/plugin-my-feature",
|
|
"version": "1.0.0",
|
|
"type": "module",
|
|
"main": "dist/index.js",
|
|
"types": "dist/index.d.ts",
|
|
"files": ["dist"],
|
|
"scripts": {
|
|
"build": "tsc",
|
|
"prepublishOnly": "bun run build"
|
|
},
|
|
"peerDependencies": {
|
|
"@elizaos/core": ">=2.0.0"
|
|
}
|
|
}
|
|
```
|
|
|
|
### 2. Build and Publish
|
|
|
|
```bash
|
|
cd ~/.local/state/eliza/plugins/custom/my-plugin
|
|
bun run build
|
|
npm pack # Preview what gets published
|
|
npm publish --access public
|
|
```
|
|
|
|
### 3. Install via Eliza
|
|
|
|
Once published, install through the agent chat or directly in config:
|
|
|
|
```json
|
|
{
|
|
"plugins": {
|
|
"allow": ["@yourorg/plugin-my-feature"]
|
|
}
|
|
}
|
|
```
|
|
|
|
Remove the local copy from `~/.local/state/eliza/plugins/custom/` to avoid loading both versions.
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
- [Plugin Development Guide](/plugins/development) -- Full plugin API reference
|
|
- [Skills Documentation](/plugins/skills) -- Lighter-weight extensions
|
|
- [Contributing Guide](https://github.com/elizaOS/eliza/blob/develop/CONTRIBUTING.md) -- Contributing plugins upstream
|